Optimize EUR/USD M5 signals: 1:1 RR, vol/agreement filters, disable XAU

Tune EUR/USD M5 trade setup for balanced profitability (78% WR, 1.68 PF,
+26.5R over 365d) under a 4-hour max hold constraint. Key changes:
- Raise min RR from 0.5 to 1.0 and TP multiplier from 1.0x to 1.2x ATR
- Tighten SL floor (0.8→0.7 ATR) and swing lookback (50→20 bars)
- Add volatility regime filter (block "high" vol) and min 6 indicator
  agreement gate in signal_aggregator
- Raise BE trigger 0.2→0.3R, buffer 0.05→0.15R to let winners run
- Block weak hours (06, 09, 11 UTC) on M5
- Disable XAU strategy checks by default; XAU pair config re-enables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
harwinder
2026-05-21 19:12:58 -04:00
parent 9a2b1f7b1e
commit 25791fefa3
5 changed files with 38 additions and 11 deletions
+7 -5
View File
@@ -142,7 +142,7 @@ class XauStrategyConfig:
Legacy gates (H4 RSI, H1 MACD, M15 score) removed in favor of
new momentum indicators (ROC, Keltner squeeze, ADX slope).
"""
enabled: bool = True
enabled: bool = False
rsi_entry_threshold: float = 45.0
tp_atr_multiplier: float = 1.0
sl_atr_multiplier: float = 2.0
@@ -172,10 +172,10 @@ class EurUsdStrategyConfig:
allowed_weekdays: List[int] = field(default_factory=lambda: [0, 1, 2, 3, 4])
min_atr_threshold: float = 0.0003
sl_atr_multiplier: float = 1.5
tp_atr_multiplier: float = 1.0
tp_atr_multiplier: float = 1.2
sl_atr_floor: float = 1.2
min_rr_ratio: float = 0.5
min_rr_ratio: float = 1.0
mature_move_threshold: float = 35.0
tp_quality_scale: Dict[str, float] = field(default_factory=lambda: {
"A+": 1.0, "A": 1.0, "B": 1.0, "C": 1.0,
@@ -188,8 +188,10 @@ class EurUsdStrategyConfig:
min_entry_score: float = 38.0
min_entry_confidence: float = 60.0
block_rsi_extended: bool = True
be_trigger_r: float = 0.2
be_buffer_r: float = 0.05
blocked_vol_regimes: List[str] = field(default_factory=list)
min_indicator_agreement: int = 0
be_trigger_r: float = 0.3
be_buffer_r: float = 0.15
@dataclass
+5 -2
View File
@@ -77,12 +77,15 @@ def make_config(
if primary_tf == Timeframe.M5:
config.technical.regime_weights_override = M5_REGIME_WEIGHTS
config.eur_strategy.sl_atr_floor = 0.8
config.technical.swing_sr_lookback = 20
config.eur_strategy.sl_atr_floor = 0.7
config.eur_strategy.sl_atr_multiplier = 0.3
config.eur_strategy.min_quality_grades = ["A+", "A", "B"]
config.eur_strategy.min_entry_score = 35.0
config.eur_strategy.min_entry_confidence = 50.0
config.backtest.blocked_hours_utc = [22, 23, 0, 1, 2, 3, 4, 19, 21]
config.eur_strategy.blocked_vol_regimes = ["high"]
config.eur_strategy.min_indicator_agreement = 6
config.backtest.blocked_hours_utc = [22, 23, 0, 1, 2, 3, 4, 6, 9, 11, 19, 21]
else:
config.technical.regime_weights_override = EUR_REGIME_WEIGHTS
+1
View File
@@ -16,6 +16,7 @@ def make_config(
confirmation_tfs: Optional[List[Timeframe]] = None,
) -> PlatformConfig:
config = PlatformConfig()
config.xau_strategy.enabled = True
config.primary_timeframe = primary_tf
config.confirmation_timeframes = (
confirmation_tfs or _CONFIRMATIONS.get(primary_tf, [Timeframe.M15, Timeframe.H4])
+21
View File
@@ -474,6 +474,27 @@ class SignalAggregator:
f"EUR CONF FILTER: {report.final_confidence} < {eur.min_entry_confidence}"
)
report.signal_quality = "F"
if (report.signal_quality != "F"
and eur.blocked_vol_regimes
and report.volatility_regime):
if report.volatility_regime in eur.blocked_vol_regimes:
report.warnings.append(
f"EUR VOL FILTER: {report.volatility_regime} volatility blocked"
)
report.signal_quality = "F"
if (report.signal_quality != "F"
and eur.min_indicator_agreement > 0
and report.primary_analysis):
agree_count = sum(
1 for ind in report.primary_analysis.indicators.values()
if ind.signal.value != 0
and (ind.signal.value > 0) == (report.final_score > 0)
)
if agree_count < eur.min_indicator_agreement:
report.warnings.append(
f"EUR AGREE FILTER: {agree_count} < {eur.min_indicator_agreement}"
)
report.signal_quality = "F"
if (report.signal_quality != "F"
and eur.block_rsi_extended
and report.primary_analysis):
+4 -4
View File
@@ -190,7 +190,7 @@ def _():
@test("XauStrategyConfig defaults")
def _():
xc = XauStrategyConfig()
assert xc.enabled is True
assert xc.enabled is False
assert xc.rsi_entry_threshold == 45.0
assert xc.min_ema200_tfs == 2
assert xc.allow_generic_trades is True
@@ -1656,7 +1656,7 @@ def _():
assert 6 not in cfg.allowed_weekdays # No Sunday
assert cfg.min_atr_threshold == 0.0003
assert cfg.sl_atr_floor == 1.2
assert cfg.min_rr_ratio == 0.5
assert cfg.min_rr_ratio == 1.0
assert cfg.mature_move_threshold == 35.0
assert cfg.tp_quality_scale["A+"] == 1.0
assert cfg.tp_quality_scale["A"] == 1.0
@@ -1755,13 +1755,13 @@ def _():
config.eur_strategy.blocked_regimes = []
config.eur_strategy.min_quality_grades = []
assert config.eur_strategy.sl_atr_floor == 1.2
assert config.eur_strategy.min_rr_ratio == 0.5
assert config.eur_strategy.min_rr_ratio == 1.0
agg = SignalAggregator(config)
df = make_ohlcv(n=300, start_price=1.0800, trend=0.0003, seed=77)
dfs = {Timeframe.H1: df, Timeframe.M15: df, Timeframe.H4: df}
report = agg.analyze_from_dataframes(symbol=EURUSD, dfs=dfs, use_news=False)
if report.trade_setup:
assert report.trade_setup.risk_reward >= 0.5 - 0.01
assert report.trade_setup.risk_reward >= 1.0 - 0.01
# ══════════════════════════════════════════════════════════════════════