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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user