525a1cd1c1
Hard TP at N×risk beats the trail on all 2024+ windows but the grid is monotone to 3R (trend artifact) and M15 rr20 goes negative in 2021+2023 with doubled DD — trailing exits stay. Flag is research-only; its Module 22 tests land with the next commit (shared test_all.py). Claude-Session: https://claude.ai/code/session_017mbXs9HRawZhD1uZ3ze7zQ
124 lines
7.0 KiB
Markdown
124 lines
7.0 KiB
Markdown
# Fixed-RR hard-TP vs shipped trailing exit — research campaign 2026-08-05
|
||
|
||
**Verdict: DO NOT SHIP. The trailing exit stays.** The fixed 2R target beats the trail on
|
||
total R in every 2024+ window but the edge is a trend-regime artifact: it inverts in the
|
||
2021–2023 ranging years, doubles drawdown, cuts win rate 10–19 points, and doubles hold
|
||
times (amplifying the accepted live one-position divergence). Details below.
|
||
|
||
## Setup
|
||
|
||
- Code: HEAD `fc5ce85` + the `--fixed-rr-tp` research flag (uncommitted at run time).
|
||
The flag replaces every trade's TP with `mult × |entry − sl|` AFTER re-anchoring and
|
||
disables trailing (run-level and per-trade PB params) — entries, stops, gates, and the
|
||
cooldown pass are untouched, so both arms replay **trade-identical books** (verified:
|
||
paired join on entry_time+direction matches 1:1 in every window). Only the exit policy
|
||
differs → per-trade paired comparison.
|
||
- Provider: Oanda (cache-warm; keys `oanda_XAU_USD_{5min,15min,1h}_{20250603_20260804,
|
||
20240331_20250330,20210531_20260804}`). Charged cost `--spread 0.65` (real measured
|
||
round trip); $0.30 letter-cost books derived analytically as `r + 0.35/risk` and
|
||
verified exact against one real `--spread 0.30` run (max per-trade error 1.8e-15 —
|
||
spread never enters trigger detection, per the owner-declined 2026-08-04 decision).
|
||
- Control sanity gate: fresh M5 12mo control reproduced the pinned HEAD reference
|
||
exactly — 555 trades, +98.64R, PF 1.483, maxDD −10.73R.
|
||
- Commands (control = same without the flag):
|
||
`venv/bin/python backtest/gpu_backtest.py --pair XAUUSD --primary-tf {5min,15min}
|
||
--start 2025-08-04 --end 2026-08-04 --spread 0.65 [--fixed-rr-tp 2.0]
|
||
--export-csv backtest/fixedtp_*.csv`
|
||
OOS `--start 2024-06-01 --end 2025-03-30`; 5yr `--start 2021-08-01 --end 2026-08-04`.
|
||
- Books pinned as `backtest/fixedtp_{m5,m15}_{12mo,oos,5yr}_{ctrl,rr20,...}.csv`
|
||
(per-trade indicator breakdown, agreement counts, regime, vol-regime, weekday,
|
||
MAE/MFE, bars-held — the full instructions_for_backtest record).
|
||
|
||
## Headline (@ $0.65)
|
||
|
||
| Window | Arm | n | R | PF | WR | maxDD | recov | medBars | exits |
|
||
|---|---|---|---|---|---|---|---|---|---|
|
||
| M5 12mo | trail | 555 | +98.64 | 1.483 | 52.4% | −10.7 | 9.2 | 28 | TRAIL 361 / SL 183 / TO 11 |
|
||
| M5 12mo | 2R hard | 555 | +124.85 | 1.378 | 42.9% | −24.5 | 5.1 | 50 | SL 312 / TP1 210 / TO 33 |
|
||
| M15 12mo | trail | 397 | +73.93 | 1.525 | 62.2% | −10.8 | 6.8 | 28 | TRAIL 255 / SL 135 / TO 7 |
|
||
| M15 12mo | 2R hard | 397 | +95.95 | 1.431 | 44.3% | −11.2 | 8.6 | 39 | SL 215 / TP1 151 / TO 31 |
|
||
| M5 OOS | trail | 86 | +9.45 | 1.332 | 53.5% | −8.2 | 1.2 | 70 | — |
|
||
| M5 OOS | 2R hard | 86 | +18.83 | 1.407 | 45.3% | −9.7 | 1.9 | 124 | — |
|
||
| M15 OOS | trail | 299 | +38.77 | 1.360 | 59.2% | −15.5 | 2.5 | 38 | — |
|
||
| M15 OOS | 2R hard | 299 | +72.14 | 1.435 | 45.2% | −13.9 | 5.2 | 82 | — |
|
||
|
||
Halves (12mo, split 2026-02-03): M5 rr20 +67.99/+56.86 (both positive; H2 PF 1.325 vs
|
||
ctrl 1.503), M15 rr20 +73.74/+22.21 (both positive; ctrl H2 +7.23 — the known H2-flat).
|
||
At $0.30 all deltas keep the same sign (e.g. M5 12mo +109.0 vs +135.2).
|
||
|
||
So the **letter** of rule 1 passes for rr20 on both TFs. The 5yr decomposition is why it
|
||
still must not ship.
|
||
|
||
## Exit migration (paired, M5 12mo; same pattern everywhere)
|
||
|
||
- SL→SL 183 trades: ΔR 0 (identical by construction — stops untouched).
|
||
- TRAIL→TP1 207 trades: +248.9R → +424.5R (**+175.6R**) — winners the trail exits early.
|
||
- TRAIL→SL 129 trades: +19.0R → −136.8R (**−155.7R**) — retraces the trail survives
|
||
become full stop-outs.
|
||
- TRAIL→TIMEOUT 25: +7.4R. Net = +26.2R. The whole effect is these two big flows nearly
|
||
cancelling; which one wins is a regime property, not an exit-policy edge.
|
||
- Trades with ctrl MFE ≥ 2R: 95; hard cap forfeits only +10.4R vs trail on M5 (the trail
|
||
already gives ~0.75R back from peak, so a 2R cap costs little *in a trend*).
|
||
|
||
## Mini-grid (12mo @ $0.65) — the tell
|
||
|
||
| mult | M5 R / PF / DD | M15 R / PF / DD |
|
||
|---|---|---|
|
||
| trail | +98.6 / 1.483 / −10.7 | +73.9 / 1.525 / −10.8 |
|
||
| 1.0R | +52.5 / 1.205 / −12.8 | +67.1 / 1.410 / −7.3 |
|
||
| 1.5R | +80.7 / 1.263 / −21.4 | +66.9 / 1.325 / −11.2 |
|
||
| 2.0R | +124.9 / 1.378 / −24.5 | +96.0 / 1.431 / −11.2 |
|
||
| 2.5R | +147.7 / 1.426 / −23.6 | +110.4 / 1.469 / −15.9 |
|
||
| 3.0R | +155.8 / 1.432 / −21.6 | +135.8 / 1.562 / −17.5 |
|
||
|
||
Monotone in the multiple on both TFs — "2.0" is not an optimum, it's a point on a curve
|
||
that says *never take profit* (3R's M5 TIMEOUT bucket alone is +84.8R). That is the
|
||
signature of a one-way trend sample, not of a superior exit rule. It also reconfirms the
|
||
original finding that SHORT fixed targets (≤1.5R) are strictly bad (cf. RR-0.5 removal,
|
||
`config.py:126-133`: +48R → +105R).
|
||
|
||
## 5yr regime decomposition (2021-08-01 → 2026-08-04 @ $0.65) — the verdict
|
||
|
||
M15 (real sample in every year): ctrl +127.97 PF 1.209 DD −35.8; rr20 +158.97 PF 1.170
|
||
DD **−59.8**; rr30 +204.03 PF 1.203 DD **−98.3**.
|
||
|
||
| Year | n | trail | 2R hard | 3R hard |
|
||
|---|---|---|---|---|
|
||
| 2021 | 88 | **+4.00** | −16.09 | −17.41 |
|
||
| 2022 | 284 | −9.54 | −7.63 | −26.74 |
|
||
| 2023 | 227 | **+7.79** | −1.71 | −5.81 |
|
||
| 2024 | 345 | +40.44 | +64.98 | +89.14 |
|
||
| 2025 | 405 | +49.33 | +69.39 | +104.42 |
|
||
| 2026 | 229 | +35.95 | +50.04 | +60.43 |
|
||
|
||
M5 5yr mirrors it (ctrl +128.4 PF 1.387 DD −12.8 vs rr20 +160.2 PF 1.306 DD −24.7;
|
||
2022: −1.1 vs −5.2), though pre-2024 M5 samples are thin (12–60 trades/yr).
|
||
|
||
The hard target's entire outperformance lives in the 2024–2026 gold trend. In ranging
|
||
years it flips sign exactly where the trail stays positive (M15 2021, 2023), and the
|
||
further the target, the worse the ranging-year bleed and the deeper the DD. The 12mo,
|
||
halves, and OOS windows all sit inside the trend era, which is why the rule-1 letter
|
||
passes — this is precisely the within-regime-split trap rule 1's OOS clause exists to
|
||
catch, one level up.
|
||
|
||
## Additional non-ship reasons
|
||
|
||
- **Live divergence grows with hold time.** Median hold doubles (M5 28→50 bars; OOS
|
||
70→124). The daemon holds one position total; the backtester doesn't model that
|
||
blocking. Longer holds = more live signals skipped that the paper book banks.
|
||
- **WR 52→43% (M5) / 62→44% (M15), max loss streak 6→11 (M15)** — materially harder to
|
||
operate and size.
|
||
- Aggregate tables (session/day/regime/vol, streaks, quarterly equity, rolling-20 WR)
|
||
computed and consistent — no bucket reverses the conclusion; both arms' 12mo profit is
|
||
concentrated in Q1-2026 (+87.7 ctrl / +102.0 rr20).
|
||
|
||
## Status
|
||
|
||
- `--fixed-rr-tp` stays as a documented research-only flag (default off; conflicts with
|
||
`--trail-arm/--trail-dist/--set signals.*trail*` are hard errors). Module 22 tests
|
||
(5) pin the override math, TP fill + spread, SL-first tie, PB-trail-disable, and CLI
|
||
guards. Full suite: 346 green.
|
||
- Re-open only if gold's regime turns and a *regime-conditional* exit (trail in range,
|
||
target in trend) is proposed with a pre-registered mechanism — a plain fixed ratio is
|
||
now a closed hypothesis at every multiple in {0.5, 1.0, 1.5, 2.0, 2.5, 3.0}.
|