Reduce A-grade TP when exhausted: RR 0.75→0.50 on 2+ exhaustion tags

A-grade trades entered exhausted moves with TP too far (0.75R), causing
57.7% WR and +0.25R over 30 days. Store exhaustion_count on SignalReport
and scale TP to B-level (1.0×) when A-grade has 2+ exhaustion tags.
Backtest: A-grade 73.1% WR / +3.25R, B/C unchanged.
This commit is contained in:
harwinder
2026-05-15 19:46:31 -04:00
parent 68cc5b28a5
commit 35e9b3750d
+4
View File
@@ -74,6 +74,7 @@ class SignalReport:
spread_estimate: float = 0.0 spread_estimate: float = 0.0
market_regime: str = "" market_regime: str = ""
volatility_regime: str = "" volatility_regime: str = ""
exhaustion_count: int = 0
class SignalAggregator: class SignalAggregator:
@@ -547,6 +548,8 @@ class SignalAggregator:
is_buy = report.final_score >= 0 is_buy = report.final_score >= 0
quality_scale = self._TP_QUALITY_SCALE.get(report.signal_quality, 0.75) quality_scale = self._TP_QUALITY_SCALE.get(report.signal_quality, 0.75)
if report.signal_quality == "A" and report.exhaustion_count >= 2:
quality_scale = 1.0
tp_mult = cfg.tp_atr_multiplier * quality_scale tp_mult = cfg.tp_atr_multiplier * quality_scale
if is_buy: if is_buy:
@@ -732,6 +735,7 @@ class SignalAggregator:
# price is extended AND momentum indicators confirm deceleration. # price is extended AND momentum indicators confirm deceleration.
_EXHAUSTION_TAGS = {"exhaustion", "no_pullback", "rsi_extended", "bb_overextended"} _EXHAUSTION_TAGS = {"exhaustion", "no_pullback", "rsi_extended", "bb_overextended"}
exhaustion_count = sum(1 for name, _ in penalties if name in _EXHAUSTION_TAGS) exhaustion_count = sum(1 for name, _ in penalties if name in _EXHAUSTION_TAGS)
report.exhaustion_count = exhaustion_count
momentum_fading = False momentum_fading = False
if primary is not None and exhaustion_count >= 2: if primary is not None and exhaustion_count >= 2:
roc_ind = primary.indicators.get("roc") roc_ind = primary.indicators.get("roc")