63a829cc46
主要内容: - Phase 8 PROMOTE: finalist #1 (trial #324) registry 条目,自动生成 - Optuna objective warmup bug 修复 (shared/optimizer/objective.py) - studies/ 目录按用途重组为 optuna/ + finalists/ + features/ 三层 - reports/ 加入 Optuna 中文 dashboard (5 主图 + 18 slice + 15 contour) - 新增 PROJECT_GUIDE.md 项目说明文档 - 新增 build_registry_entry.py / build_optuna_dashboard.py / build_feature_datasets.py - .gitignore: 允许提交 studies/*.db (Optuna DB) 和 reports/*.html (MT5 + dashboard)
120 lines
5.2 KiB
Python
120 lines
5.2 KiB
Python
"""Phase 7 — Prepare finalist #1 for MT5 verification (doc 07, doc 08 step 6).
|
|
|
|
Reads the Optuna finalist from the study DB, generates a .set file in MT5's
|
|
tester profile directory, and prints the exact Strategy Tester settings for
|
|
the FORWARD test mode (one run produces both IS + OOS segments).
|
|
|
|
MT5 forward mode: set the whole window + a forward start date. MT5 splits:
|
|
history (IS) = FromDate → Forward start
|
|
forward (OOS) = Forward start → ToDate
|
|
|
|
After the user runs the tester and exports the forward HTML report, run
|
|
scripts/compare_finalist.py to print the Python-vs-MT5 table for both segments.
|
|
|
|
Usage:
|
|
python scripts/prepare_mt5_verify.py # finalist #1 (best by score)
|
|
python scripts/prepare_mt5_verify.py 2 # finalist #2
|
|
"""
|
|
from __future__ import annotations
|
|
import json
|
|
import sys
|
|
from pathlib import Path
|
|
PROJECT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(PROJECT))
|
|
|
|
import optuna
|
|
|
|
from shared.optimizer.selector import select_diverse_topn
|
|
from shared.mt5_pipeline.set_gen import write_set_file
|
|
from strategies.gold_scalper_pro.search_space import (
|
|
FROZEN_BASELINE,
|
|
SEARCH_SPACE,
|
|
)
|
|
from strategies.gold_scalper_pro.set_mappings import GOLD_SCALPER_MAPPINGS
|
|
|
|
|
|
# Windows where MT5's tester profiles live (terminal data path).
|
|
MT5_TESTER_DIR = Path(r"C:\Users\Administrator\AppData\Roaming\MetaQuotes\Terminal"
|
|
r"\010E047102812FC0C18890992854220E\MQL5\Profiles\Tester")
|
|
|
|
# Forward-mode window: one run produces IS (12 mo) + OOS (~6 mo).
|
|
# Data ends 2026-06-25 23:55; ToDate is exclusive day boundary so 2026.06.26
|
|
# picks up the last bar at 2026-06-25 23:55.
|
|
FROM_DATE = "2025.01.01" # whole-window start
|
|
TO_DATE = "2026.06.26" # whole-window end (exclusive day boundary)
|
|
FORWARD_DATE = "2026.01.01" # forward start: IS|OOS split point
|
|
INITIAL_DEPOSIT = 1000.0
|
|
|
|
|
|
def main() -> int:
|
|
finalist_idx = int(sys.argv[1]) if len(sys.argv) > 1 else 1
|
|
if finalist_idx < 1 or finalist_idx > 3:
|
|
sys.exit("finalist index must be 1, 2, or 3")
|
|
|
|
db = PROJECT / "studies" / "optuna" / "gold_scalper_pro_is2025.db"
|
|
study = optuna.load_study(
|
|
study_name="gold_scalper_pro_is2025",
|
|
storage=f"sqlite:///{db}",
|
|
)
|
|
finalists = select_diverse_topn(study, n=3, ranges=SEARCH_SPACE)
|
|
if len(finalists) < finalist_idx:
|
|
sys.exit(f"only {len(finalists)} finalists available")
|
|
t = finalists[finalist_idx - 1]
|
|
merged = {**FROZEN_BASELINE, **t.params}
|
|
|
|
# Pull the MT5-forward-aligned Python metrics (saved by reeval_finalist_forward.py).
|
|
fwd_json = PROJECT / "studies" / "finalists" / "gold_scalper_pro_is2025-2026.json"
|
|
if fwd_json.exists():
|
|
fwd = json.loads(fwd_json.read_text(encoding="utf-8"))
|
|
py_is = fwd["finalists"][finalist_idx - 1]["IS"]
|
|
py_oos = fwd["finalists"][finalist_idx - 1]["OOS"]
|
|
else:
|
|
py_is = py_oos = None
|
|
|
|
print(f"=== finalist #{finalist_idx} (trial #{t.number}) ===")
|
|
if py_is:
|
|
print(f" Python IS (12 mo) : net={py_is['net']:.2f} PF={py_is['PF']:.2f} "
|
|
f"trades={py_is['trades']} DD%={py_is['DD%']:.2%}")
|
|
print(f" Python OOS (6 mo) : net={py_oos['net']:.2f} PF={py_oos['PF']:.2f} "
|
|
f"trades={py_oos['trades']} DD%={py_oos['DD%']:.2%}")
|
|
else:
|
|
print(f" (run scripts/reeval_finalist_forward.py first to get Python metrics)")
|
|
|
|
# Write the .set to MT5's tester profile dir.
|
|
set_name = f"GoldScalperPro_finalist{finalist_idx}_trial{t.number}.set"
|
|
set_path = MT5_TESTER_DIR / set_name
|
|
write_set_file(merged, GOLD_SCALPER_MAPPINGS, set_path)
|
|
print(f"\n .set written to: {set_path}")
|
|
|
|
print(f"\n === MT5 Strategy Tester setup (FORWARD mode, ONE run) ===")
|
|
print(f" 1. Open MT5 → Ctrl+R (Strategy Tester)")
|
|
print(f" 2. Expert: GoldScalperPro")
|
|
print(f" 3. Symbol: XAUUSD")
|
|
print(f" 4. Period: M5 (chart timeframe, must match InpTimeframe)")
|
|
print(f" 5. Model: Every tick (based on real ticks) [doc 07 §2b: path-sensitive → real ticks]")
|
|
print(f" 6. Deposit: {INITIAL_DEPOSIT:.0f} USD")
|
|
print(f" 7. Leverage: 1:100")
|
|
print(f" 8. Date range:")
|
|
print(f" From: {FROM_DATE}")
|
|
print(f" To: {TO_DATE}")
|
|
print(f" 9. Forward: Custom date → {FORWARD_DATE}")
|
|
print(f" (this splits IS={FROM_DATE}..{FORWARD_DATE} | OOS={FORWARD_DATE}..{TO_DATE})")
|
|
print(f" 10. Click 'Inputs' tab → 'Load' → select: {set_name}")
|
|
print(f" (verify InpRiskPercent={merged['InpRiskPercent']}, "
|
|
f"InpAtrPeriod={merged['InpAtrPeriod']}, "
|
|
f"InpFastEmaPeriod={merged['InpFastEmaPeriod']}, "
|
|
f"InpSlowEmaPeriod={merged['InpSlowEmaPeriod']})")
|
|
print(f" 11. Click Start. The forward HTML report has TWO sections:")
|
|
print(f" - 'Backtest' (top) = IS ({FROM_DATE}..{FORWARD_DATE})")
|
|
print(f" - 'Forward' (bottom) = OOS ({FORWARD_DATE}..{TO_DATE}, ~6 mo of data)")
|
|
print(f" 12. Right-click the report → 'Save as Report' → save to:")
|
|
print(f" reports/ReportTester_forward_finalist{finalist_idx}.html")
|
|
|
|
print(f"\n When the HTML is saved, run:")
|
|
print(f" python scripts/compare_finalist.py {finalist_idx}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|