backtest: full-GPU research twin (cudaBasedBacktesting.py + cuda_signal_kernels.py); books byte-identical to gpu_backtest.py (2026-09-18)

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.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Harwinder Sekhon
2026-09-18 16:11:47 -04:00
parent bac11d81eb
commit 1e8110ea5e
8 changed files with 5602 additions and 6 deletions
+156
View File
@@ -0,0 +1,156 @@
# M5 five-year book on the CUDA research twin — 2026-09-18
Owner request, the companion of `m15_5yr_cuda_2026-09-18.md`: a five-year M5 backtest with
`backtest/cudaBasedBacktesting.py`. Same owner-requested exception to the three-year cap
(CLAUDE.md rule 1), same status: a read-out of the shipped configuration on a longer window,
nothing tuned, nothing ships.
## 1. Runs
Window 2021-08-01 → 2026-08-04 (kept 5-year cache, padded files
`oanda_XAU_USD_{5min,15min,1h}_20210531_20260804.parquet`; 0 cache fallbacks; 367,394 M5 bars,
355,096 replayed; skipped 139,064 `SESSION_WINDOW`, 247 `WEEKEND_FILTER`). Factory config (M5:
hour 9 blocked and 21 open, chart-pattern entries on, pullbacks off), no overrides.
```
venv/bin/python backtest/cudaBasedBacktesting.py --pair XAUUSD --primary-tf 5min --start 2021-08-01 --end 2026-08-04 --spread 0.65 --export-csv cuda_m5_5yr_0.65.csv
venv/bin/python backtest/cudaBasedBacktesting.py --pair XAUUSD --primary-tf 5min --start 2021-08-01 --end 2026-08-04 --spread 0.30 --export-csv cuda_m5_5yr_0.30.csv
venv/bin/python backtest/gpu_backtest.py --pair XAUUSD --primary-tf 5min --start 2021-08-01 --end 2026-08-04 --spread 0.65 --workers 12 --export-csv ctrl_m5_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)` | 5.2 s (K1 520,523 bars 0.045 s, K2 355,096 bars 0.004 s, trade sim 0.38 s) | `0429885713ca34653a39754c013db501` |
| twin $0.30 | `CuPy GPU (NVIDIA GeForce RTX 4070 SUPER, cupy 14.0.1)` | 5.6 s | `87bfdba14090459f715e1ee1f751a6cb` |
| reference $0.65 | `CuPy GPU (NVIDIA GeForce RTX 4070 SUPER, cupy 14.0.1)`, `GPU cache fallbacks: 0` | 353.2 s (replay 348.7 s, 12 workers, 1,018 bars/s) | `0429885713ca34653a39754c013db501` — identical to the twin's (`cmp` equal) |
## 2. Results
905 trades at both costs (561 `TRAIL`, 290 `SL`, 54 `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 | 905 | +127.08 | 51.4% | 1.39 | 13.5 |
| $0.65 | first half 2021-08-01 → 2024-02-01 | 129 | −8.98 | 43.4% | 0.82 | 12.4 |
| $0.65 | second half 2024-02-02 → 2026-08-04 | 776 | +136.06 | 52.7% | 1.49 | 9.6 |
| $0.30 | whole | 905 | +147.83 | 52.5% | 1.46 | 10.6 |
| $0.30 | first half | 129 | −5.20 | 45.0% | 0.89 | 10.6 |
| $0.30 | second half | 776 | +153.03 | 53.7% | 1.57 | 8.9 |
Against rule 1 for the record: the five-year window fails it (first half negative), on a first
half of only 129 trades. The shipped M5 configuration was validated on 2024-09-05 → 2026-09-05
(+146.1R, PF 1.52, 781 trades) and the 12-month window (+108.8R, PF 1.54).
### Per year
| Year | Trades | $0.65 R | WR | PF | Max DD | $0.30 R | PF |
|---|---|---|---|---|---|---|---|
| 2021 (Aug–Dec) | 12 | −1.99 | 41.7% | 0.59 | 2.5 | −1.60 | 0.65 |
| 2022 | 50 | −2.18 | 44.0% | 0.90 | 11.1 | −0.71 | 0.97 |
| 2023 | 61 | −2.75 | 42.6% | 0.87 | 10.3 | −1.00 | 0.95 |
| 2024 | 102 | +0.97 | 49.0% | 1.02 | 8.2 | +4.30 | 1.11 |
| 2025 | 332 | +40.54 | 50.6% | 1.34 | 9.6 | +48.63 | 1.42 |
| 2026 (Jan–Aug 4) | 348 | +92.49 | 55.7% | 1.77 | 9.2 | +98.21 | 1.83 |
Two things the M15 window did not show as sharply:
1. **M5 barely trades before 2025.** 225 trades in the first 3.4 years against 680 in the last
1.6. Trade generation on M5 is governed by dollar-denominated floors: target 1 must clear
30 × $0.30 = $9 (`SPREAD GATE`), the generic and chart-pattern stops are floored at $8, and a
chart pattern needs a $9 height. At 2021–2023 prices and volatility an M5 ATR of $1.5–3 puts a
1.5 × ATR target far below the floor, so the spread gate vetoed almost every setup and only
high-volatility bursts survived. The pre-2025 M5 book is therefore a burst-only sample, not the
shipped strategy under normal conditions.
2. **One quarter carries the window.** 2026-Q1 made +90.2R of the +127.1R total (71%); 2025 Q1–Q2
another +32.3R. Quarterly R outside those three quarters ranges −6.5 … +5.8. This is the
fat-right-tail shape of every M5 reading (cycle 1: the top 5% of trades = 94–96% of R; here the
top 5%, 45 trades, carry +145.8R of +127.1R) compounded by a single very favourable quarter.
### Breakdowns ($0.65)
| Grade | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| A+ | 1 | −0.03 | 0.0% | 0.00 | 0.0 |
| A | 247 | +53.72 | 55.1% | 1.69 | 7.2 |
| B | 637 | +73.66 | 50.2% | 1.30 | 16.4 |
| C | 20 | −0.26 | 45.0% | 0.97 | 3.2 |
| Generator | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| GENERIC | 447 | +70.36 | 52.8% | 1.46 | 8.1 |
| XAU_CP | 427 | +48.52 | 49.9% | 1.29 | 14.4 |
| XAU_ATR | 31 | +8.20 | 51.6% | 1.89 | 3.8 |
Generator by year (trades / R): GENERIC 2021 4 / +0.4, 2022 23 / +4.4, 2023 32 / −2.9, 2024
37 / +6.6, 2025 170 / +18.1, 2026 181 / +43.8; XAU_CP 2021 8 / −2.4, 2022 27 / −6.5, 2023
29 / +0.2, 2024 65 / −5.7, 2025 159 / +21.6, 2026 139 / +41.3; XAU_ATR appears only in 2025 (3)
and 2026 (28), the same dollar-floor effect as on M15. The chart-pattern path is negative through
2024 (−14.4R over 129 trades) and positive since (+62.9R over 298); its validation
(2026-08-04, +38.9R of the 12-month book) covered the recent regime only.
| Direction | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| BUY | 808 | +119.68 | 51.4% | 1.41 | 15.2 |
| SELL | 97 | +7.40 | 51.5% | 1.21 | 11.4 |
Shorts are nearly absent before 2025 (9 trades in 2021–2024) under the M5 SELL gates; 2025 32 /
−2.8R, 2026 56 / +12.0R.
| Regime | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| trending_up | 481 | +75.44 | 53.4% | 1.44 | 11.9 |
| ranging | 174 | +24.78 | 50.0% | 1.36 | 8.3 |
| trending_down | 94 | +6.61 | 51.1% | 1.19 | 12.4 |
| transitioning | 84 | +19.59 | 46.4% | 1.69 | 6.9 |
| trending (mixed) | 72 | +0.67 | 47.2% | 1.02 | 10.5 |
| Volatility | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| low | 250 | +62.92 | 51.6% | 1.70 | 12.4 |
| normal | 169 | +0.69 | 47.9% | 1.01 | 12.5 |
| extreme | 486 | +63.47 | 52.5% | 1.38 | 13.3 |
(`high` has no row: the M5 chop-transition gate blocks it.)
| Entry hour UTC | Trades | Total R | WR | PF | | Entry hour UTC | Trades | Total R | WR | PF |
|---|---|---|---|---|---|---|---|---|---|---|
| 03 | 52 | +8.49 | 50.0% | 1.41 | | 15 | 121 | +12.81 | 53.7% | 1.30 |
| 04 | 31 | +3.22 | 61.3% | 1.27 | | 17 | 47 | −2.61 | 48.9% | 0.86 |
| 05 | 50 | +7.15 | 52.0% | 1.32 | | 18 | 51 | +13.17 | 58.8% | 1.76 |
| 06 | 56 | +24.31 | 58.9% | 2.47 | | 19 | 51 | +2.96 | 49.0% | 1.18 |
| 07 | 52 | +2.50 | 53.8% | 1.14 | | 20 | 43 | +31.45 | 46.5% | 2.80 |
| 08 | 63 | −4.88 | 41.3% | 0.81 | | 21 | 12 | +16.02 | 75.0% | 6.16 |
| 12 | 69 | +7.01 | 53.6% | 1.28 | | 22 | 37 | +4.14 | 45.9% | 1.32 |
| 14 | 170 | +1.37 | 47.6% | 1.02 | | | | | | |
(Entry hour is the open of the bar after the signal bar; M5 blocks close hours 0, 1, 2, 9, 10,
11, 13, 16 and leaves 21 open.)
| Weekday | Trades | Total R | WR | PF | Max DD |
|---|---|---|---|---|---|
| Mon | 172 | +20.80 | 55.8% | 1.36 | 12.3 |
| Tue | 180 | +24.22 | 52.8% | 1.36 | 13.2 |
| Wed | 200 | +30.84 | 48.5% | 1.43 | 11.4 |
| Thu | 167 | +5.27 | 48.5% | 1.08 | 13.3 |
| Fri | 177 | +41.41 | 50.3% | 1.62 | 9.2 |
| Sun | 9 | +4.55 | 77.8% | 3.22 | 1.0 |
Tail: median R +0.031; largest win +5.53R, largest loss −1.84R; mean hold 76.6 bars.
## 3. What to do with this
Nothing ships. Two honest readings for the owner:
- The five-year M5 figure (+127R) is not "five years of edge"; it is the validated 2024-09 →
2026-09 book plus three and a half years in which the dollar floors kept M5 almost out of the
market and the few trades that got through lost a little. The three-year cap already keeps
decisions inside the period where the gates behave as designed.
- The concentration in 2026-Q1 (71% of the window's R) is a fact about the shipped M5 edge, not
about the window length. It is consistent with every earlier M5 reading and is the reason the
advisory outcomes over a quiet fortnight can look nothing like the book.
If the owner wants the floor effect measured rather than inferred, a `--record --record-bars`
run of this window on the twin (seconds) with a by-year count of `SPREAD GATE` and `LOW ATR
FILTER` warnings per analysed bar would settle it. Changing the floors is a rule-1 event in its
own right (`round_trip_cost` drives the live target floor, CLAUDE.md rule 1) and is not proposed.