Owner decisions: research only (live scans stay on the CPU code), gpu_backtest.py stays the base reference, every research flag supported, the one exemption from instructions item 6 recorded in backtest/instructions_for_backtest.txt. - backtest/cuda_signal_kernels.py: the CUDA decision stage. K1 = engine.py + the GPUTechnicalEngine overrides (one thread per bar), K2 = analyze_from_dataframes end to end incl. gates 6b-6i, the four setup generators and the regime filter (one thread per primary bar), K3 = position_sizing.build_features, K4 cooldown, K5 prefix median, K6 recorder bar rows. Config packer with generated #defines; leaf module; --fmad=false; Python evaluation order kept (ternary min/max, pairwise sums, Neumaier sum(), exact round(x, 2)). - backtest/cudaBasedBacktesting.py: same CLI, cache files and writers as the reference; the host turns kernel codes into the exact strings; no CPU path. - test_all.py Module 37 (16 tests): every stage pinned against the live code; suite 552 / 552 on the GPU, without CUDA and with FB2_BACKEND=cpu. - Proof: five reference MD5s, four 6-month acceptance books (M5/M15, $0.65/$0.30), M15 OOS --export-features and --record --record-bars tables, ten research-flag variants, and the owner's five-year M5 and M15 books, all byte-identical to gpu_backtest.py. Wall time 0.8-6.6 s per book against 13-353 s. - CLAUDE.md sections 1, 3, 6, 7, 9, 10, 11 and the instructions addendum: any signal change is now a parity event for the twin.
8.0 KiB
M15 five-year book on the CUDA research twin — 2026-09-18
Owner request: a five-year M15 backtest with backtest/cudaBasedBacktesting.py. This window goes
past the three-year cap the owner set on 2026-09-05 (CLAUDE.md rule 1); it was run as an explicit
owner-requested exception. It is a read-out of the shipped configuration on a longer window, not
a candidate change: nothing was tuned, nothing ships from it.
1. Runs
Window 2021-08-01 → 2026-08-04 (the kept 5-year cache, padded files
oanda_XAU_USD_{5min,15min,1h}_20210531_20260804.parquet; 0 cache fallbacks; 122,489 M15 bars,
118,389 replayed; skipped 43,245 SESSION_WINDOW, 247 WEEKEND_FILTER). Factory config, no
overrides.
venv/bin/python backtest/cudaBasedBacktesting.py --pair XAUUSD --primary-tf 15min --start 2021-08-01 --end 2026-08-04 --spread 0.65 --export-csv cuda_m15_5yr_0.65.csv
venv/bin/python backtest/cudaBasedBacktesting.py --pair XAUUSD --primary-tf 15min --start 2021-08-01 --end 2026-08-04 --spread 0.30 --export-csv cuda_m15_5yr_0.30.csv
venv/bin/python backtest/gpu_backtest.py --pair XAUUSD --primary-tf 15min --start 2021-08-01 --end 2026-08-04 --spread 0.65 --workers 12 --export-csv ctrl_m15_5yr_0.65.csv # paired reference
| Run | Backend line (verbatim) | Wall | Book MD5 |
|---|---|---|---|
| twin $0.65 | CuPy GPU (NVIDIA GeForce RTX 4070 SUPER, cupy 14.0.1) |
6.6 s (K1 520,523 bars 0.046 s, K2 118,389 bars 0.001 s, trade sim 0.80 s) | d5e432bdb3dc9923e00594125b4867dd |
| twin $0.30 | CuPy GPU (NVIDIA GeForce RTX 4070 SUPER, cupy 14.0.1) |
5.3 s | 4ac5c0307123557c0740e57f5b91ff72 |
| reference $0.65 | CuPy GPU (NVIDIA GeForce RTX 4070 SUPER, cupy 14.0.1), GPU cache fallbacks: 0 |
93.7 s (replay 89.2 s, 12 workers) | d5e432bdb3dc9923e00594125b4867dd — identical to the twin's (cmp equal) |
The paired reference run is the parity evidence the 2026-09-18 addendum in
backtest/instructions_for_backtest.txt requires before a number from the twin is quoted.
2. Results
1,822 trades at both costs (1,087 TRAIL, 666 SL, 69 TIMEOUT, no NO_DATA). Halves split at
2024-02-02.
| Cost | Segment | Trades | Total R | Win rate | PF | Max DD (R) |
|---|---|---|---|---|---|---|
| $0.65 | whole 2021-08-01 → 2026-08-04 | 1822 | +157.43 | 56.8% | 1.22 | 43.6 |
| $0.65 | first half 2021-08-01 → 2024-02-01 | 704 | −9.61 | 52.4% | 0.97 | 43.6 |
| $0.65 | second half 2024-02-02 → 2026-08-04 | 1118 | +167.04 | 59.5% | 1.40 | 17.1 |
| $0.30 | whole | 1822 | +196.77 | 57.7% | 1.28 | 36.3 |
| $0.30 | first half | 704 | +9.38 | 54.0% | 1.03 | 36.3 |
| $0.30 | second half | 1118 | +187.39 | 60.1% | 1.46 | 14.9 |
Read against rule 1 for the record: the five-year window does not pass it (the first half is negative at $0.65 and the whole-window PF is 1.22). The shipped M15 configuration was validated on 2024-09-05 → 2026-09-05 (+146.1R, PF 1.43) and the 2024-06 → 2025-03 out-of-sample window (+60.7R, PF 1.49); the extra 2021–2023 years are where the R is missing, which is the same picture the Oanda re-pin of 2026-08-04 gave ("all timeframes earn only 2024+") and the reason for the three-year cap.
Per year
| Year | Trades | $0.65 R | WR | PF | Max DD | $0.30 R | PF |
|---|---|---|---|---|---|---|---|
| 2021 (Aug–Dec) | 97 | +1.17 | 47.4% | 1.03 | 15.5 | +3.85 | 1.10 |
| 2022 | 318 | −15.37 | 51.9% | 0.89 | 39.1 | −6.73 | 0.95 |
| 2023 | 264 | +10.91 | 55.7% | 1.10 | 15.7 | +17.86 | 1.17 |
| 2024 | 397 | +52.86 | 58.7% | 1.36 | 17.1 | +62.53 | 1.44 |
| 2025 | 480 | +77.35 | 60.0% | 1.43 | 14.8 | +85.69 | 1.48 |
| 2026 (Jan–Aug 4) | 266 | +30.51 | 58.3% | 1.30 | 13.2 | +33.57 | 1.34 |
The 43.6R drawdown is entirely 2021-Q4 → 2022-Q3 (quarterly R: −13.5, +13.5, −7.6, −22.6); from 2024 on the worst quarter is −3.4R (2024-Q2) and the worst since is −8.3R for the five weeks of 2026-Q3 in the window.
Breakdowns ($0.65)
| Grade | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| A+ | 36 | +5.48 | 63.9% | 1.41 | 3.3 |
| A | 970 | +92.30 | 56.5% | 1.24 | 21.3 |
| B | 728 | +41.16 | 56.5% | 1.14 | 31.3 |
| C | 88 | +18.49 | 59.1% | 1.55 | 4.8 |
| Generator | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| GENERIC | 1658 | +153.28 | 57.0% | 1.24 | 43.6 |
| XAU_ATR | 164 | +4.15 | 54.3% | 1.06 | 17.0 |
XAU_ATR produces no trade before 2024 (5 in 2024, 48 in 2025, 111 in 2026). The gold ATR setup
is gated by dollar-denominated floors (min_atr_threshold, the $8 stop floor, the 30 × $0.30
target floor); at 2021–2023 gold prices and volatility they blocked the generator and the GENERIC
swing setup took every A-grade signal. The pre-2024 book therefore runs under an effectively
different setup mix. Observation only; no proposal.
| Direction | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| BUY | 1212 | +147.91 | 58.3% | 1.32 | 48.3 |
| SELL | 610 | +9.52 | 53.8% | 1.04 | 36.2 |
Direction by year (trades / R): BUY 2021 58 / −9.8, 2022 215 / −28.9, 2023 166 / +10.9, 2024
273 / +56.8, 2025 344 / +95.2, 2026 156 / +23.7; SELL 2021 39 / +10.9, 2022 103 / +13.6, 2023
98 / 0.0, 2024 124 / −3.9, 2025 136 / −17.9, 2026 110 / +6.8. Shorts carried the book in the
2021–2022 bear phase and lost in the 2024–2025 rally; the parked cycle-2 candidate (block M15
grade-A SELLs, cycle_2026-09-10.md) is about the recent years only and this table does not
change its status.
| Regime | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| ranging | 168 | +45.30 | 61.3% | 1.73 | 7.7 |
| transitioning | 400 | +51.25 | 58.2% | 1.33 | 7.0 |
| trending_up | 788 | +55.43 | 56.9% | 1.18 | 37.3 |
| trending_down | 466 | +5.44 | 53.6% | 1.03 | 26.0 |
(The mixed trending regime is blocked on M15, so it has no row.)
| Volatility | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| low | 193 | +34.75 | 60.1% | 1.48 | 11.2 |
| normal | 251 | +41.65 | 61.0% | 1.50 | 20.6 |
| high | 393 | +2.77 | 53.7% | 1.02 | 19.2 |
| extreme | 985 | +78.27 | 56.2% | 1.20 | 32.0 |
| Entry hour UTC | Trades | Total R | WR | PF | Entry hour UTC | Trades | Total R | WR | PF | |
|---|---|---|---|---|---|---|---|---|---|---|
| 03 | 98 | +8.18 | 60.2% | 1.24 | 14 | 381 | +24.60 | 55.4% | 1.16 | |
| 04 | 38 | +4.62 | 55.3% | 1.29 | 15 | 146 | +17.60 | 57.5% | 1.30 | |
| 05 | 77 | +16.50 | 61.0% | 1.58 | 17 | 79 | +27.77 | 68.4% | 2.20 | |
| 06 | 117 | +27.74 | 66.7% | 1.85 | 18 | 112 | −6.65 | 50.9% | 0.87 | |
| 07 | 116 | −9.29 | 50.0% | 0.83 | 19 | 80 | +10.95 | 62.5% | 1.40 | |
| 08 | 158 | +1.62 | 53.2% | 1.03 | 20 | 55 | +11.68 | 61.8% | 1.66 | |
| 09 | 145 | −7.31 | 49.7% | 0.89 | 22 | 40 | +12.48 | 67.5% | 2.01 | |
| 12 | 180 | +16.94 | 54.4% | 1.22 |
(Entry hour is the open of the bar after the signal bar; the blocked close hours 0, 1, 2, 10, 11, 13, 16, 21 leave the gaps.)
| Weekday | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| Mon | 309 | +25.97 | 57.3% | 1.21 | 15.8 |
| Tue | 394 | +40.58 | 60.2% | 1.29 | 17.4 |
| Wed | 386 | −18.07 | 50.5% | 0.90 | 25.4 |
| Thu | 356 | +50.99 | 56.5% | 1.37 | 22.3 |
| Fri | 358 | +47.13 | 58.4% | 1.35 | 19.3 |
| Sun | 19 | +10.82 | 78.9% | 3.64 | 2.1 |
Tail: the top 5% of trades (91) carry +249.8R of the +157.4R total; median R +0.113; largest win +9.07R, largest loss −2.04R; mean hold 70.5 bars. Same fat-right-tail shape as the 3-year cycle-1 reading (94–96% of R in the top 5% there).
3. What to do with this
Nothing. The numbers describe the shipped configuration on a window the owner does not use for
decisions; the per-hour, per-weekday and per-direction tables are in-book statistics on a
five-year mix of setup gates and must not be turned into filters (rule 1 needs a control-vs-
candidate run on the validated windows, and the 2026-08-04 age/stretch and 2026-09-06 sizing
verdicts already refute the obvious ones). If the owner wants the pre-2024 weakness explained,
the honest next step is a --record --record-bars run on this window with the twin (seconds) and
a scorecard on the dollar-floor gates by year, not a parameter change.