M15 trail arm 0.70 (validated grid) + backtest/live parity hardening
Parity: replay now applies the live _apply_regime_filter_live method under the live guard (function-identity, default-off); unregistered-pair fallback applies the config.json overlay; parity sweep gains direct ATR/vol-regime assertions; regime-filter semantics test added. Trail campaign: --trail-arm/--trail-dist research flags; 30-cell grid on 5yr M15 refuted the earlier-arm hypothesis and found the 0.70-0.80 arm plateau. Shipped M15-only trail_arm_r=0.70 (factory override): +210.7R PF 1.35 WR 57.8% vs +175.7R PF 1.30 WR 53.9% baseline; both halves and 2024-06->2025-03 OOS better (+57.4 vs +45.4); 5yr max-DD clause (33.9R vs 29.1R) explicitly waived by owner. M5 unchanged. Factory replay reproduces the grid cell trade-for-trade; 201/201 tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VPNF37MP9Kuv62B1VBrZ1b
This commit is contained in:
@@ -1530,6 +1530,13 @@ def _replay_span(span: Tuple[int, int]):
|
||||
use_news=False,
|
||||
)
|
||||
|
||||
# Live parity: analyze_pair applies the optional higher-TF ADX
|
||||
# regime filter after delegation, under this exact guard. Calling
|
||||
# the SAME method on the SAME sliced dfs keeps the two paths
|
||||
# identical if the (default-off) filter is ever enabled.
|
||||
if platform_cfg.backtest.regime_filter:
|
||||
aggregator._apply_regime_filter_live(report, slice_dfs)
|
||||
|
||||
if report.trade_setup is None:
|
||||
continue
|
||||
if report.signal_quality not in bt_cfg.quality_filter:
|
||||
@@ -2141,6 +2148,10 @@ def _parse_args(argv: Optional[List[str]] = None) -> argparse.Namespace:
|
||||
p.add_argument("--max-hold-bars", type=int, default=300)
|
||||
p.add_argument("--swing-sr-lookback", type=int, default=0,
|
||||
help="Override TechnicalConfig.swing_sr_lookback (0 = use config default)")
|
||||
p.add_argument("--trail-arm", type=float, default=None,
|
||||
help="Override signals.trail_arm_r for this run (research knob)")
|
||||
p.add_argument("--trail-dist", type=float, default=None,
|
||||
help="Override signals.trail_dist_r for this run (research knob)")
|
||||
p.add_argument("--quality", default="A+,A,B,C", help="Comma-separated allowed grades")
|
||||
p.add_argument("--strategies", default="",
|
||||
help="Comma-separated strategy tags to include (XAU,XAU_PB,XAU_CP,GENERIC). Empty = all.")
|
||||
@@ -2214,8 +2225,16 @@ def main(argv: Optional[List[str]] = None) -> int:
|
||||
primary_timeframe=primary_tf,
|
||||
confirmation_timeframes=confirm_tfs or [Timeframe.H1, Timeframe.H4],
|
||||
)
|
||||
# The factory path applies the config.json overlay inside
|
||||
# make_config; the fallback must match (live == backtest).
|
||||
from app_config import apply_pair_overrides # noqa: E402
|
||||
apply_pair_overrides(platform_cfg)
|
||||
if args.swing_sr_lookback > 0:
|
||||
platform_cfg.technical.swing_sr_lookback = args.swing_sr_lookback
|
||||
if args.trail_arm is not None:
|
||||
platform_cfg.signals.trail_arm_r = args.trail_arm
|
||||
if args.trail_dist is not None:
|
||||
platform_cfg.signals.trail_dist_r = args.trail_dist
|
||||
if args.cp:
|
||||
platform_cfg.xau_strategy.cp_enabled = True
|
||||
if args.cp_patterns:
|
||||
|
||||
Reference in New Issue
Block a user