Add M5 gates 5-6 and trailing-stop exits (+48R → +105R on 12mo)

Gates 5-6 in the M5 filter: block 'high' vol regime entries (chop
transition — 61% WR, negative total while low/normal/extreme all
positive) and block SELLs with RSI<25 (dip already extended, mean-
reverts before target). 365d: 419→311 trades, +41→+48.4R, DD 11.2→8.0R.

Replace the fixed RR-0.5 take-profit with a trailing stop: arm at
+0.6R favorable excursion, trail 0.75R behind best price, stop levels
update at bar close (conservative). The RR-0.5 target was the binding
constraint — winners kept running after TP. Whole trail parameter grid
(arm 0.4-1.2 × dist 0.5-1.25) lands +90-103R, a plateau not a spike;
also +91.7R on the pre-gate 419-trade population. TP1 stays advisory;
Telegram alerts include the arm price and trail distance. max_hold
200→300 bars (trailing exits need room; +10R).

12mo M5, same 311 trades: +105.0R total, PF 2.27, DD 7.9R, 61% WR,
train/val +54.6/+50.4, every quarter positive.
This commit is contained in:
harwinder
2026-07-09 13:34:57 -04:00
parent 8687f98b39
commit 0393087168
4 changed files with 171 additions and 6 deletions
+27
View File
@@ -350,6 +350,33 @@ class SignalAggregator:
report.trade_setup = None
return
# Gate 5: block chop-transition volatility. 'high' vol on M5 is
# elevated noise without the directional expansion of 'extreme'
# — stops get swept before targets (61% WR, negative total in
# every backtest window; low/normal/extreme all positive).
if report.volatility_regime in xau_cfg.m5_blocked_vol_regimes:
report.warnings.append(
f"M5 FILTER: '{report.volatility_regime}' volatility — "
f"chop-transition regime, stops get swept"
)
report.signal_quality = "D"
report.trade_setup = None
return
# Gate 6: SELL RSI floor — shorting with RSI already < 25 means
# entering at the extreme of the dip (same pathology as Gate 4,
# visible through RSI instead of quality grade).
if is_sell:
rsi_ind = report.primary_analysis.indicators.get("rsi")
if rsi_ind is not None and rsi_ind.value < xau_cfg.m5_sell_min_rsi:
report.warnings.append(
f"M5 FILTER: SELL blocked — RSI {rsi_ind.value:.0f} < "
f"{xau_cfg.m5_sell_min_rsi:.0f}, dip already extended"
)
report.signal_quality = "D"
report.trade_setup = None
return
# ── Public: bar-replayable entry point ─────────────────────────
def analyze_from_dataframes(