"""Compare the dry-run MT5 report against Python on the SAME window + deposit. The dry-run MT5 report shows the tester was run on 2026.04.16 - 2026.05.08 with initial deposit 1000 USD. To make a fair Python-vs-MT5 comparison we re-slice the bars to that exact window and re-run the engine with the same deposit. Then we print the side-by-side table. """ from __future__ import annotations import sys from pathlib import Path PROJECT = Path(__file__).resolve().parent.parent sys.path.insert(0, str(PROJECT)) import pandas as pd from shared.core.engine import SizingInputs from shared.core.metrics import compute_metrics from shared.data.loaders import load_bars from shared.data.mt5_report import parse_mt5_report from shared.mt5_pipeline.compare import build_comparison_table from strategies.gold_scalper_pro.instruments import XAUUSD_REAL from strategies.gold_scalper_pro.scalper_engine import ( ScalperEngine, engine_kwargs_from_params, ) from strategies.gold_scalper_pro.search_space import FROZEN_BASELINE from strategies.gold_scalper_pro.signals import build_signals def main() -> int: # ── Parse the MT5 report ────────────────────────────────────────────── report = PROJECT / "reports" / "ReportTester-52845377.html" mt5 = parse_mt5_report(report) print("=== MT5 report (dry run) ===") for k, v in mt5.items(): if k.startswith("_"): continue print(f" {k:24s}: {v}") # The MT5 window + deposit (parsed from the report's _all dict). all_fields = mt5["_all"] window_label = all_fields.get("期间:", "") print(f" window (raw) : {window_label}") deposit = mt5.get("Initial Deposit") or 1000 print(f" initial deposit: {deposit}") # ── Slice Python bars to the same window ───────────────────────────── bars = load_bars(PROJECT / "data" / "XAUUSD_M5_2024-06-26_2026-06-26.parquet") # MT5 tester's ToDate is exclusive of the day (uses 00:00 of that day), # so the actual data ends at 2026.05.08 00:00 (not 23:59). Match it exactly. start = pd.Timestamp("2026-04-16 00:00:00") end = pd.Timestamp("2026-05-08 00:00:00") window = bars[(bars["timestamp"] >= start) & (bars["timestamp"] < end)].reset_index(drop=True) print(f"\n=== Python (matched window) ===") print(f" bars : {len(window):,}") print(f" window : {window['timestamp'].iloc[0]} → {window['timestamp'].iloc[-1]}") print(f" deposit : {deposit}") # ── Run the engine on the matched window ───────────────────────────── # Override InpAtrPeriod to 15 to match the MT5 manual run (user changed # it from the .set's 14 to 15 in the tester UI). RSI stays at 14. params = dict(FROZEN_BASELINE) params["InpAtrPeriod"] = 15 pack = build_signals(params, window, XAUUSD_REAL) # Load M1 data for tick-level exit simulation (closes the bar-level # optimism gap on BE/trailing — doc 03 §7). m1_path = PROJECT / "data" / "XAUUSD_M1_2024-06-26_2026-06-26.parquet" m1_bars = load_bars(m1_path) if m1_path.exists() else None if m1_bars is not None: # Slice M1 to the same window as M5 (exclusive end, matching MT5). m1_bars = m1_bars[ (m1_bars["timestamp"] >= start) & (m1_bars["timestamp"] < end) ].reset_index(drop=True) print(f" m1 bars : {len(m1_bars):,} (tick-level exit simulation ON)") engine = ScalperEngine() result = engine.run( window, pack.signals_long, pack.signals_short, pack.sl_prices, pack.tp_prices, XAUUSD_REAL, SizingInputs(), float(deposit), m1_bars=m1_bars, **engine_kwargs_from_params(params), ) py = compute_metrics(result) print(f" trades : {py.total_trades}") print(f" net : {py.net_profit:+.2f}") print(f" PF : {py.profit_factor:.2f}") print(f" DD : {py.max_equity_dd:.2f} ({py.max_equity_dd_pct:.2%})") # ── Build the comparison table ─────────────────────────────────────── # Map Python Metrics → keys the compare table expects. py_mapped = { "net_profit": py.net_profit, "profit_factor": py.profit_factor, "total_trades": py.total_trades, "max_equity_dd": py.max_equity_dd, "win_rate": py.win_rate, "sharpe": py.sharpe, } mt5_mapped = { "net_profit": mt5.get("Total Net Profit"), "profit_factor": mt5.get("Profit Factor"), "total_trades": mt5.get("Total Trades"), "max_equity_dd": mt5.get("Equity Drawdown Maximal"), "win_rate": None, "sharpe": mt5.get("Sharpe Ratio"), } print(f"\n=== Python vs MT5 (matched window {start.date()} → {end.date()}) ===") print(build_comparison_table(py_mapped, mt5_mapped)) return 0 if __name__ == "__main__": raise SystemExit(main())