Tune EUR/USD trade setup: quality-scaled TP and tighter SL

EUR/USD A-grade signals had inverted quality curve (-1.65R) because all
trades got RR≈0.50 and mature_move logic penalized high-score entries.

Fix: add per-pair trade setup params (sl_atr_floor=1.2, min_rr=1.0,
mature_move_threshold=35) and apply quality_scale to both tp_mult and
min_rr so A-grade gets wider TP targets. Also wire EUR config into
backtest via PAIR_PRODUCERS registry.

Result: A-grade now +1.24R (was -1.65R), total EUR/USD +10.06R (was +4.20R).
XAU/USD unchanged at +13.01R.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
harwinder
2026-05-18 12:56:34 -04:00
parent 3146a632d4
commit 74b723ba06
4 changed files with 77 additions and 18 deletions
+30 -11
View File
@@ -53,10 +53,12 @@ from config import ( # noqa: E402
SignalStrength,
Timeframe,
XAUUSD,
EURUSD,
)
from data_provider import ForexDataProvider # noqa: E402
from engine import IndicatorSignal, TechnicalAnalysis, TechnicalEngine # noqa: E402
from signal_aggregator import SignalAggregator, SignalReport, TradeSetup # noqa: E402
from pair_signals import PAIR_PRODUCERS # noqa: E402
# ─────────────────────────────────────────────────────────────────────
# GPU shim — CuPy if available AND CUDA runtime works, else NumPy.
@@ -96,6 +98,8 @@ PAIR_ALIASES = {
"XAUUSD": XAUUSD,
"XAU/USD": XAUUSD,
"GOLD": XAUUSD,
"EURUSD": EURUSD,
"EUR/USD": EURUSD,
}
# Bar duration in seconds — used to compute "fully-closed" cutoffs so
@@ -1310,6 +1314,16 @@ def _is_xau_blocked_by_calendar(ts: pd.Timestamp, cfg: PlatformConfig) -> Option
return None
def _is_pair_blocked_by_calendar(ts: pd.Timestamp, cfg: PlatformConfig) -> Optional[str]:
"""Generic weekend + weekday filter using FilterConfig (backtest field)."""
bt = cfg.backtest
if ts.weekday() >= 5:
return "WEEKEND_FILTER"
if bt.allowed_weekdays and ts.weekday() not in bt.allowed_weekdays:
return "DAY_FILTER"
return None
def run_backtest(
bt_cfg: BacktestConfig,
platform_cfg: Optional[PlatformConfig] = None,
@@ -1387,12 +1401,14 @@ def run_backtest(
# Decision time = close of the current primary bar.
decision_time = ts + primary_dur
# XAU calendar filter (matches live analyze_pair behavior).
# Calendar filter (matches live analyze_pair behavior).
if PAIR_INFO[bt_cfg.pair]["display"] == "XAU/USD":
block = _is_xau_blocked_by_calendar(ts, platform_cfg)
if block:
skipped_reasons[block] = skipped_reasons.get(block, 0) + 1
continue
else:
block = _is_pair_blocked_by_calendar(ts, platform_cfg)
if block:
skipped_reasons[block] = skipped_reasons.get(block, 0) + 1
continue
# Cooldown.
if pos - last_entry_pos < bt_cfg.cooldown_bars:
@@ -1890,13 +1906,16 @@ def main(argv: Optional[List[str]] = None) -> int:
f"Pair: {PAIR_INFO[pair]['display']} | Window: {start.date()} → {end.date()}"
)
platform_cfg = PlatformConfig(
symbol=pair,
display_name=PAIR_INFO[pair]["display"],
pip_value=PAIR_INFO[pair]["pip_value"],
primary_timeframe=primary_tf,
confirmation_timeframes=confirm_tfs,
)
if pair in PAIR_PRODUCERS:
platform_cfg = PAIR_PRODUCERS[pair](primary_tf, confirm_tfs)
else:
platform_cfg = PlatformConfig(
symbol=pair,
display_name=PAIR_INFO[pair]["display"],
pip_value=PAIR_INFO[pair]["pip_value"],
primary_timeframe=primary_tf,
confirmation_timeframes=confirm_tfs,
)
if args.swing_sr_lookback > 0:
platform_cfg.technical.swing_sr_lookback = args.swing_sr_lookback