Files
mymt5opp/scripts/compare_dryrun.py
2026-06-26 20:50:07 +08:00

115 lines
5.0 KiB
Python

"""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())