2026-06-26 18:47:35 +08:00
2026-06-26 20:50:07 +08:00
2026-06-26 20:50:07 +08:00
2026-06-26 18:47:35 +08:00
2026-06-26 18:47:35 +08:00
2026-06-26 18:47:35 +08:00
2026-06-26 20:50:07 +08:00
2026-06-26 18:47:35 +08:00
2026-06-26 20:50:07 +08:00
2026-06-26 20:50:07 +08:00
2026-06-26 20:50:07 +08:00

Backtesting + Optuna + MT5 Stack

一个把 MetaTrader 5 Strategy Tester 当作"金标准"、用 Python 镜像引擎做高速贝叶斯 搜索的个人量化策略研究实验室。当前已对 GoldScalperProXAUUSD M5 trailing/BE EA 跑通完整闭环:假设 → 搜索 → MT5 验证 → 入注册表

接手者请按本文件的 §2 → §3 → §7 顺序读完即可上手。详细的架构 / 坑 / 扩展指南 在 PROJECT_GUIDE.md01-08-*.md 里。


1. 项目一句话

Idea  ─►  Python mirror engine  ─►  Optuna search (hundreds of trials, seconds each)
                                         │
                                         ▼
                               23 diverse finalists
                                         │
                                         ▼
                        MetaTrader 5 Strategy Tester (gold standard)
                                         │
                                         ▼
                      Python-vs-MT5 gap table  ─►  registry/  (append-only)
  • Tier 1Python 镜像引擎):把 EA 的填单 / 出场逻辑 bar-by-bar 重写,跑在 Parquet 历史数据上,2 年回测几秒钟。
  • Tier 2MT5 Strategy Tester:只对 finalist 跑真实 tester。MT5 数字才是 live 决策依据Python 数字只负责排序。
  • trailing/BE EA 必须 M1 tick-level 模拟——bar-level 会产生 40% 到 50% 的隐藏 gap(详见 PROJECT_GUIDE.md §1.3)。

2. 快速开始(接手者从这里读起)

2.1 环境要求

  • WindowsMetaTrader5 Python 包只在 Windows 上装得了)
  • Python 3.12+(开发用 3.12.10
  • MetaTrader 5 终端已安装并登录一个 demo 账户
  • Git(commit 历史就是项目文档的一部分)

2.2 一次性准备

# 1. clone 后建 venv 装依赖
python -m venv .venv
.\.venv\Scripts\activate
pip install -r requirements.txt

# 2. 在根目录建 .envgitignored,凭证不入库)
#    MT5_DEMO_LOGIN=52845377
#    MT5_DEMO_PASSWORD=...
#    MT5_DEMO_SERVER=ICMarketsSC-Demo
#    MT5_TERMINAL_PATH=C:\Program Files\MetaTrader 5 IC Markets Global\terminal64.exe

# 3. 打开 MT5 终端、登录 demo、确认 XAUUSD 历史已下载(M5 + M1
python scripts/download_xauusd_history.py   # → data/XAUUSD_M5_*.parquet
python scripts/download_xauusd_m1.py         # → data/XAUUSD_M1_*.parquettrailing/BE EA 必需)

# 4. 查 symbol 规格(确认 tick_value / contract_size / lot_step
python scripts/query_xauusd_spec.py

历史 parquet 在 .gitignore 里(data/ 整个忽略),所以接手后必须重跑下载脚本, 否则后续 Optuna / 评估脚本会 sys.exit("missing M5 data")

2.3 5 分钟跑通一遍

# A. 烟雾测试:30 trialsIS H1 2025<2 分钟验证全链路通
python scripts/optimize.py --smoke

# B. 全量搜索:500 trialsIS = 2025 全年,~1020 分钟
python scripts/optimize.py --trials 500
#   断点续跑(load_if_exists=True),中途 Ctrl+C 不丢
#   产物:studies/optuna/gold_scalper_pro_is2025.db + .log

# C. 用 finalist 参数重跑 Pythonwarmup 修复版),落 JSON
python scripts/reeval_finalist_forward.py
#   产物:studies/finalists/gold_scalper_pro_is2025-2026.json

# D. 生成中文 Optuna 交互式 dashboardHTML
python scripts/build_optuna_dashboard.py
#   产物:reports/optuna_dashboard_gold_scalper_pro_is2025.html

# E. 生成 ML 特征数据集(trade-level + trial-level
python scripts/build_feature_datasets.py
#   产物:studies/features/{trade,trial}_features_*.parquet + .csv

# F. 自动生成 registry markdown 条目(每 finalist 一份)
python scripts/build_registry_entry.py
#   产物:registry/gold_scalper_pro_xauusd_*_f{idx}_t{trial}.md

MT5 验证是手动步骤Strategy Tester 跑完导 HTML 到 reports/),跑完后用:

python scripts/build_registry_entry.py `
    --mt5-is-html reports\IS-ReportTester-52845377.html `
    --mt5-oos-html reports\OOS-ReportTester-52845377.html

补齐 registry 条目里的 MT5 指标和 gap 表。


3. 目录结构

backtesting-optuna-mt5-stack/
├── README.md                   ← 本文件,项目入口
├── PROJECT_GUIDE.md            ← 项目实例说明(架构+坑+使用+扩展,10 节)
├── CLAUDE.md                   ← 给 AI 助手的分阶段搭装 playbook
├── requirements.txt            ← Python 依赖清单
├── .gitignore                  ← data/ + .env 忽略;studies/*.db + reports/*.html 入库
│
├── 01-stack-and-install.md     ← 知识库 §1:技术栈 + 每个系统的安装命令
├── 02-architecture.md          ← 知识库 §2:单向依赖分层 + 数据流
├── 03-engine-design.md         ← 知识库 §3bar-by-bar engine + intra-bar 4-sub-tick
├── 04-isolation-rules.md       ← 知识库 §48 条隔离铁律
├── 05-config-and-inputs.md     ← 知识库 §54 个声明输入源
├── 06-optimization-and-robustness.md ← 知识库 §6Optuna objective + 反过拟合
├── 07-mt5-bridge.md            ← 知识库 §7:编译 EA / .set / .ini / 解析报告
├── 08-workflow-cycle.md        ← 知识库 §8:8 步可重复循环
│
├── GoldScalperPro.mq5          ← EA 源码(MQL5
├── GoldScalperPro.ex5          ← EA 编译产物
│
├── shared/                     ← 9 个单向依赖层(低调高、高不知低)
│   ├── core/                   ← engine(冻结)+ metrics
│   ├── data/                   ← Parquet loaders + MT5 HTML parser
│   ├── gates/                  ← 入场过滤 maskregime / 时段 / exhaustion
│   ├── indicators/             ← 纯函数:RSI / ATR / EMA / SMA
│   ├── instruments/            ← per-symbol configtick_value / spread / swap
│   ├── mt5_pipeline/           ← .set / .ini / compile / runner / compare
│   ├── optimizer/              ← objective / search_space / diverse top-N selector
│   ├── robustness/             ← 反过拟合分析(只读 over results
│   ├── wizard/                 ← 运行时 Q&A → wizard-answers.yaml
│   └── config.py               ← .env 加载(含 plain fallback
│
├── strategies/
│   └── gold_scalper_pro/       ← gluedata → signals → stops → engine → metrics
│       ├── instruments.py      ← XAUUSD_REAL config 对象
│       ├── params.py
│       ├── scalper_engine.py   ← ScalperEngineengine.run 的 wrapper
│       ├── search_space.py     ← 19 个可调参数 + 13 个冻结基线 + 约束
│       ├── set_mappings.py     ← Python 参数名 ↔ MQL5 input 名映射
│       ├── signals.py          ← build_signalsEMA cross + RSI + ATR
│       └── wizard_questions.py
│
├── scripts/                    ← 一次性可执行脚本(按用途分组见 §5)
│   ├── optimize.py             ← Phase 6 主入口(smoke / full
│   ├── reeval_finalist_forward.py ← finalist 参数 + warmup 修复版重跑
│   ├── build_optuna_dashboard.py  ← 中文 plotly 交互式 HTML
│   ├── build_feature_datasets.py  ← ML 特征 parquet
│   ├── build_registry_entry.py    ← 自动生成 registry markdown(命令驱动,禁手写)
│   ├── walk_forward.py
│   ├── prepare_mt5_verify.py   ← 生成 .set / .ini 给 MT5 tester
│   ├── verify_mt5.py
│   ├── compare_finalist.py     ← Python vs MT5 差距表
│   ├── diag_*.py               ← 9 个诊断脚本(ATR / 时区 / 引擎 trace / 信号)
│   └── download_xauusd_*.py     ← 历史 M5 / M1 数据下载
│
├── studies/                    ← Optuna 研究产物(committed
│   ├── optuna/                 ← SQLite DB + 运行日志(resumable
│   │   ├── gold_scalper_pro_is2025.db
│   │   ├── gold_scalper_pro_is2025.db.before-warmup-fix.bak  ← 旧 study 备份
│   │   └── gold_scalper_pro_is2025.log
│   ├── finalists/              ← 3 个 finalist 的 IS/OOS 指标 JSON
│   │   └── gold_scalper_pro_is2025-2026.json
│   └── features/               ← ML 特征数据集(parquet + csv 副本)
│       ├── trade_features_*.parquet    ← trade-level 35 列
│       └── trial_features_*.parquet    ← trial-level 聚合
│
├── reports/                    ← MT5 + dashboard HTMLcommitted
│   ├── IS-ReportTester-52845377.html
│   ├── OOS-ReportTester-52845377.html
│   └── optuna_dashboard_gold_scalper_pro_is2025.html
│
├── registry/                   ← 已批准 finalistappend-only,真相源)
│   ├── gold_scalper_pro_xauusd_*_f1_t491.md  ← finalist #1trial #491
│   ├── gold_scalper_pro_xauusd_*_f2_t297.md  ← finalist #2trial #297
│   └── gold_scalper_pro_xauusd_*_f3_t492.md  ← finalist #3trial #492
│
└── data/                       ← gitignored,历史 parquet(接手后需重下)
    ├── XAUUSD_M5_2024-06-26_2026-06-26.parquet
    └── XAUUSD_M1_2024-06-26_2026-06-26.parquet

4. 核心数据流(一个 iteration 的闭环)

        ┌──────────────────────────────────────────────────────┐
        │  scripts/optimize.py                                 │
        │    load_m5() ─► slice_window(IS_START, IS_END)       │
        │    load_m1() ─► slice_window(IS_START, IS_END)       │
        │    full_m5 ───────────────────┐  (warmup, signals_full_bars)│
        │                              ▼                       │
        │    ObjectiveConfig(bars_is, m1_is, signals_full_bars=full_m5)│
        │            │                                         │
        │            ▼                                         │
        │    build_objective(cfg)  ─►  trial loop              │
        │            │                                         │
        │            ▼                                         │
        │    build_signals(full_m5) ─► slice to IS             │
        │    engine_kwargs_from_params(params)                 │
        │    ScalperEngine.run(bars, signals, sl, tp, m1_bars)  │
        │            │                                         │
        │            ▼                                         │
        │    compute_metrics + Constraints gate               │
        │    study.optimize()  ─►  trials 0..499               │
        └──────────────────────────────────────────────────────┘
                              │
                              ▼
        ┌──────────────────────────────────────────────────────┐
        │  select_diverse_topn(study, n=3)                    │
        │  └─► 3 个 diverse finalistgreedy max-distance   │
        └──────────────────────────────────────────────────────┘
                              │
                              ▼
        ┌──────────────────────────────────────────────────────┐
        │  scripts/reeval_finalist_forward.py                 │
        │    用 finalist params 重跑 Pythonwarmup 修复版)   │
        │    ─► studies/finalists/gold_scalper_pro_is2025-2026.json│
        └──────────────────────────────────────────────────────┘
                              │
                              ▼
        ┌──────────────────────────────────────────────────────┐
        │  MT5 Strategy Tester(手动)                         │
        │    prepare_mt5_verify.py 生成 .set + .ini           │
        │    Forward mode: IS=2025, OOS=2026 H1               │
        │    导 HTML 报告到 reports/                          │
        └──────────────────────────────────────────────────────┘
                              │
                              ▼
        ┌──────────────────────────────────────────────────────┐
        │  scripts/build_registry_entry.py                     │
        │    finalist JSON + Optuna study + MT5 HTML           │
        │    ─► registry/gold_scalper_pro_xauusd_*_f{idx}.md   │
        │        (9 节自文档化 markdown,含差距表)            │
        └──────────────────────────────────────────────────────┘

5. 常用脚本速查(按场景)

场景 脚本 命令
跑 Optuna 搜索 optimize.py --smoke30 trials<2 分钟) / --trials 500(全量)
重跑 finalist reeval_finalist_forward.py 用 finalist 参数在 IS+OOS 重跑 Python,落 JSON
走前验证(forward walk_forward.py finalist 在 OOS 窗口独立验证
生成 dashboard build_optuna_dashboard.py 中文 plotly HTML5 主图 + 18 单参数 + 15 等高线)
生成 ML 特征 build_feature_datasets.py trade-level 35 列 + trial-level parquet
生成 registry build_registry_entry.py 命令驱动生成 finalist 条目(禁手写
准备 MT5 验证 prepare_mt5_verify.py 生成 .set + .ini,复制到 MT5 tester profiles
比对 finalist compare_finalist.py Python vs MT5 差距表
诊断(9 个) diag_*.py ATR / 时区 / 引擎 trace / 信号触发 / 仓位 mismatch 等
查 study inspect_study.py 打印 trials / best params
查 MT5 报告 inspect_report.py / diag_mt5_summary.py / diag_mt5_trades.py 解析 HTML
下历史数据 download_xauusd_history.pyM5/ download_xauusd_m1.pyM1 必须 MT5 终端已登录
查 symbol 规格 query_xauusd_spec.py tick_value / contract_size / lot_step

6. 当前项目状态

6.1 已完成的 Phase

Phase 内容 状态
01 设备 profile + Python 栈安装
2 仓库骨架(shared/ 9 子包 + strategies/
3 MT5 连接(分步 initialize+login+ EA 资产导入
4 ScalperEngine + M1 tick-level 模拟路径
5 XAUUSD_REAL instrument + GoldScalperPro search space
6 Optuna 500-trial 搜索 + 3 diverse finalist
7 MT5 forward mode IS/OOS 验证(旧 finalist+ 差距根因
8 APPROVAL + PROMOTEregistry 第一条)
Optuna warmup bug 修复(2026-06-26 重跑)

6.2 当前 finalistwarmup 修复后,2026-06-27 重跑)

来自 studies/finalists/gold_scalper_pro_is2025-2026.json

# trial score IS net OOS net registry
1 #491 186,075 $263,527 $10,632 f1_t491.md
2 #297 68,772 $94,197 $11,153 f2_t297.md
3 #492 129,575 $165,740 $6,969 f3_t492.md

这三个 finalist 尚未通过 MT5 验证——registry 条目标记为 "已记录(无 MT5 验证 — 待 Phase 7 MT5 验证)"。需要先在 MT5 Strategy Tester 跑出 IS+OOS HTML 报告,再用 build_registry_entry.py --mt5-is-html ... --mt5-oos-html ... 补齐 MT5 部分和差距表。


7. 接手者必读(续做指南)

7.1 三条铁律(违反任一条等于把项目搞烂)

  1. trailing/BE EA 必须传 m1_bars=engine.run()——否则 net profit 会有 40% 到 50% 的隐藏 gap。这不是噪声,是 bug。详见 03-engine-design.md §7

  2. ObjectiveConfig 必须传 signals_full_bars=full_m5——否则 EMA/RSI/ATR 在 IS_START 才开始预热,首笔交易会比 MT5 晚 14 小时,整个 finalist 集合都 是错的。详见 scripts/optimize.pymake_objective_config() docstring。

  3. Engine 一旦验证就冻结,要试新想法就 fork——直接改 validated engine 可能让所有已信任的数字都失效。Fork + default-OFF 实验 hook + 证明 fork-with-change-off == 原版 1:1 + 再 A/B。详见 04-isolation-rules.md Rule 2

7.2 已知坑(接手时大概率还会遇到)

症状 修复
MT5 连接 IPC 超时(-10005 mt5.initialize() 直接传所有参数 分步:先 mt5.initialize(path=...),再 mt5.login(login, password, server)
终端路径反斜杠 IPC 超时 / 连不上 路径必须用正斜杠 /,不是 \
MT5 进程残留 新连接失败 任务管理器清掉所有 terminal64.exe 进程后重试
.set 文件加载失败 MT5 tester 找不到参数 文件必须以 BOM 开头write_set_file 已处理)
Plotly 图表看不见 HTML 渲染 0 高度 fig.update_layout(height=<像素>) + CDN + 单列 flex(见 build_optuna_dashboard.py
参数切片图标签重叠 5400px 宽复合图挤一起 拆成每参数独立 900×420 小图(render_slice_grid
Optuna warmup bug IS 起点附近 14h 没信号 signals_full_bars 字段,详见 §7.1 第 2 条

7.3 急需做的下一步(按优先级)

  1. 跑 MT5 验证新 finalist #1trial #491 —— 用 scripts/prepare_mt5_verify.py 生成 .set + .ini,在 MT5 Strategy Tester forward mode 跑 IS=2025 + OOS=2026 H1,导 HTML 到 reports/,然后用 build_registry_entry.py --mt5-is-html ... --mt5-oos-html ... 补齐 registry。

  2. 重新诊断 ATR 数据差异 —— 旧的 diag_atr_check.py / diag_mt5_trades.py 是针对 trial #324 的,新 finalist 需重跑。

  3. 实现自动化 MT5 pipeline —— shared/mt5_pipeline/runner.py 现在只是骨架, 把"打开 tester → 等跑完 → 拷 HTML"自动化掉。

  4. 补全 robustness 层 —— shared/robustness/layers.py 只有 stability_region,缺 doc 06 §5 描述的其它层(parameter stability、 monte-carlo perturbation、walk-forward aggregate)。

  5. MT5 数据对齐 —— Python parquet M5 OHLC 与 MT5 tester 内部 history 在 IS 起点附近有微差,复利下被指数放大。需要决定是接受差距(旧 finalist #324 已接受)还是修对齐。

7.4 不要做的事

  • 不要手写 registry 条目——必须用 scripts/build_registry_entry.py 生成。 脚本会从 finalist JSON + Optuna study + MT5 HTML 三源自动提取,包含 9 节内容(标识 / 参数表含百分位 / 三个 finalist 对比 / Python 指标 / MT5 指标 / 差距分析 / 搜索统计 / 复现命令 / 已知限制)。

  • 不要编辑已批准的 registry 条目——append-only。新发现是新条目, 旧条目就算被超越也保留(负面结果也是数据)。

  • 不要在 engine.run() 里加策略逻辑——engine 只决定"价格是否触到 止损"从不决定止损放在哪。换策略改 caller 和数组,engine 不动。

  • 不要在 mt5.initialize() 里塞所有参数——分步连接,详见 §7.2 第 1 条。

  • 不要给单个 strategy import 另一个 strategy——copy,不要 import。 iteration 各自拥有 snapshot,几个月前的 iteration 仍要能跑。

7.5 改动约定

  • 改了 engine / objective / search space → 跑 --smoke 先验证全链路通
  • 改了 finalist 挑选逻辑 → 重跑 reeval_finalist_forward.py + 重生 dashboard
  • 改了 MT5 报告解析 → 用 diag_mt5_summary.py 对比新旧解析结果
  • commit 时分小步、写清楚 why(不只是 what),git log 就是项目文档的一部分

8. 文档地图

你想做的事 读这个
跑一遍流程 本文件 §2 + §5
理解架构为什么这样搭 PROJECT_GUIDE.md §1 + 02-architecture.md
看具体踩过的坑 PROJECT_GUIDE.md §5 + 本文件 §7.2
写新策略 02-architecture.md §4 + 08-workflow-cycle.md
改 engine 03-engine-design.md + 04-isolation-rules.md Rule 2
改 Optuna objective 06-optimization-and-robustness.md + shared/optimizer/objective.py
接 MT5 07-mt5-bridge.md + shared/mt5_pipeline/
看 finalist 参数 studies/finalists/gold_scalper_pro_is2025-2026.json + registry/
看 Optuna trials python scripts/inspect_study.py 或直接打开 studies/optuna/gold_scalper_pro_is2025.db

9. License & Disclaimer

个人研究项目,不构成投资建议。EA 源码 GoldScalperPro.mq5 属于其原作者; 本项目仅用于参数优化方法论研究,不重新分发 EA 本体。

S
Description
No description provided
Readme 3.4 MiB
Languages
Python 92.3%
MQL5 7.7%