fix(backtest): address the second review of the breakeven and book-config work
Deploy / lint (push) Successful in 14s
Deploy / test (push) Successful in 2m0s
Deploy / deploy (push) Successful in 48s

- The breakeven study grades at the shadow book's capacity AND risk per
  trade, and labels each with where it came from. A missing setting row
  now reads "shadow_book default" instead of crediting the setting; the
  committed report said shadow_book_capacity though the snapshot has no
  such row.
- _production_book_config reads strategies through the same
  _portfolio_monitor_strategies() hook as the monitor.
- breakeven_gate_reset is rejected when there is no post-stop episode or
  cooldown for it to start, and the study skips its diagnostic arm for a
  book without one, so a production config change cannot abort the run.
- identical_to_control is renamed ties_control_on_graded_metrics and needs
  real values: be_2r ties on every graded metric but still changed 2 trades.
- _BookConfig drops an unused field and hashes by identity; the min-R:R
  sweep swaps its gate in with dataclasses.replace instead of passing it.
- New tests cover the parity guard's success path, the no-config fallback
  and the gate-reset check.

The breakeven report is regenerated: every row, diagnostic row and the
parity check are identical; only the labels, the risk fields and the
renamed flag changed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
dennisthiessenandClaude Opus 5.5 committed 2026-10-10 21:41:44 +02:00
1 parent 7a9b3ad38b
commit 231372fb3a
5 files changed
+168 -88

No files matched your search

@@ -1,5 +1,5 @@
{
"generated_at": "2026-10-10T07:30:27.484621+00:00",
"generated_at": "2026-10-10T19:39:30.155792+00:00",
"tickers": 506,
"rank_only_tickers": 0,
"candidates": 1011248,
@@ -143382,7 +143382,9 @@
"protocol": "docs/research/breakeven-stop.md",
"split_date": "2024-07-01",
"capacity": 15,
"capacity_source": "shadow_book_capacity",
"capacity_source": "shadow_book default",
"risk_per_trade": 0.01,
"risk_source": "shadow_book default",
"cadence": "daily",
"exit_policy": "atr_trail3",
"atr_trail_multiplier": 3.0,
@@ -143391,6 +143393,7 @@
"parity": {
"ok": true,
"capacity": 10,
"risk_per_trade": 0.01,
"study_control": {
"sharpe": 1.84,
"cagr_pct": 49.8,
@@ -143986,7 +143989,7 @@
"max_drawdown": false
},
"passes": false,
"identical_to_control": false
"ties_control_on_graded_metrics": false
},
"be_2r": {
"train": {
@@ -144000,7 +144003,7 @@
"max_drawdown": true
},
"passes": true,
"identical_to_control": true
"ties_control_on_graded_metrics": true
}
},
"diagnostic_rows": [
@@ -144199,7 +144202,7 @@
"trades_5r_plus": 10
}
],
"note": "Graded on train and test only: an arm passes when Sharpe and CAGR are no lower and max drawdown no higher than control in both windows; identical_to_control marks a pass that is only ties. Win rate and avg R are reported, not graded. diagnostic_rows were added after the first run and are never graded. A pass earns forward paper validation, not a production change."
"note": "Graded on train and test only: an arm passes when Sharpe and CAGR are no lower and max drawdown no higher than control in both windows; ties_control_on_graded_metrics marks a pass that is only ties. Win rate and avg R are reported, not graded. diagnostic_rows were added after the first run and are never graded. A pass earns forward paper validation, not a production change."
},
"recommendation": {
"headline": "Production baseline: residual/high-vol 80/20 entry rank with a 3x ATR trailing exit, 30-trading-day max hold, and re-entry only after the gate fails and later qualifies again.",