Files
ForexBot2/backtest/research/m15_5yr_cuda_2026-09-18.md
T
Harwinder Sekhon 32ad73c59a 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.
2026-09-18 16:11:47 -04:00

150 lines
8.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.