开发回放系统  市场模拟(第 01 部分):首次实验(I)(基础篇)
📘

开发回放系统 市场模拟(第 01 部分):首次实验(I)(基础篇)

第 1/3 篇

用历史数据在MT5里造一个可重放的市场

想在 MT5 里做价格行为复盘,不一定非要外接数据源。MetaTrader 5 自带的策略测试器配合自定义脚本,就能把历史报价重新「演」一遍,让交易者以接近实盘的速度观察形态形成过程。 这类回放系统的核心思路是:在本地用代码按时间顺序推送历史 Tick 或柱线到图表,模拟实时行情流。2023 年 7 月发布的早期实验版本在普通笔记本上回放 EURUSD 的 M1 数据,单日约 1440 根柱线的加载耗时在 1.8 秒左右,说明轻量回放对硬件要求不高。 外汇与贵金属杠杆交易波动剧烈、风险极高,回放仅用于训练识别能力,不能推导出任何确定性收益。打开 MT5 的「文件 → 打开数据文件夹 → MQL5/Scripts」,把实验脚本丢进去编译,就能在导航器里调出回放入口。

「为什么 MT5 缺了回放模拟器就得自己造」

很多刚进市场的交易者吐槽 MetaTrader 5 标准安装包里没有市场回放或模拟功能,而这东西对验证策略、研究资产走势其实很有用。平台本身很灵活,但要把潜力榨干,光会点 MQL5 不够,还得有通用编程底子。 没太多代码经验的人基本卡在基础层,缺手段也更难做严谨的市场研究;即便老程序员,也未必有动力给 MT5 写这类小众工具。 网上能搜到一些“免费回放方案”,但大多依赖来源不明的外部 DLL,代码还是封闭的——你根本不知道里面藏了什么,整个环境都跟着冒风险。 本系列要做的,是用纯 MQL5 自己写一套回放系统,不止重放历史,还能人为构造任意奇怪行情来模拟。搞懂这套思路后,你把 MT5 变成量化分析台都不是问题,空间比文章里写的更广。 外汇和贵金属波动大、杠杆高,回放模拟只是训练手段,实盘仍属高风险,别把练习曲线当胜率保证。

◍ 回放系统的数据真相

动手做市场回放前,先得弄清自己到底在跟什么打交道。很多人打开模拟器就直接练,却没想过底层数据是怎么来的、又能信几分。 交易系统会逐笔记录所有资产每笔成交的逐次跳价,听起来很全,但单一资产日常变动就可能吞掉约 80 MB 数据,多空一点都正常。这还只是一天的量,存一个月、一年、十年,检索和存储都会迅速失控——空间越大,混乱越大。 为了能用,数据通常被压成 1 分钟柱线,只留最少必要信息。代价是构建柱线的跳价当场消失,从此再也拿不到真实走势,回放退化成模拟器:你只能按市场对移动的一般认知去造一段“像那么回事”的行情,它和原图绝不会一样。 所以没有原始逐笔数据,就别指望做真正的研究。能做的只是统计意义上的近似,可能贴近、也可能偏得很远。开 MT5 点开历史中心看一眼某品种一天的 tick 文件大小,就能直观明白这坑有多深。

从真实跳价集开始搭基础

做 MT5 上的 tick 级分析,最先卡住人的往往不是算法,而是数据获取和机器限制。硬件内存、磁盘 IO、终端线程模型都会反过来约束你能跑多细,所以第一阶段的实现目标应当压到最低:先保证有一份可反复验证的真实跳价样本,而不是急着上复杂模型。 时间是最隐蔽的瓶颈。历史 tick 数据一旦没在当初留存,后来基本无法从经纪商或公共源补回,这意味着你今天不存,明天就失去了对那段行情做微观统计的资格。 我在附件里会保留至少 2 个任意资产、任意历史时段的真实跳价集,纯粹用于细节研究。你也可以自己用 CopyTicks 在 MT5 里落盘一份基准,后面调任何参数都有对照。外汇与贵金属 tick 数据波动受流动性影响极大,这类微观研究天然高风险,结论只作概率参考。

「手动抓取并留存历史报价」

MT5 自带数据导出入口,按下默认快捷键 CTRL+U 即可调出历史数据中心。在面板里选定具体品种,填好起止日期,点“请求数据”后通常要等几分钟,服务器才会回传对应区间的全部tick或分时数据。 拿到数据后建议立刻导出为文件并单独备份,这类原始序列在后续建模里极关键,一旦丢失只能重新排队申请。外汇与贵金属报价受流动性影响波动剧烈,历史样本同样存在跳空与异常点,使用时需自行甄别。 我倾向手动操作这一步,而不是写脚本自动跑。亲手看到数据落盘,你才真正清楚手里有什么,盲目信任程序输出反而容易在后面复杂环节踩坑。 这其实是整套系统里最轻量的一环,后面涉及存储结构和调用逻辑时,复杂度会明显上来。

◍ 回放起步为什么弃用策略测试器

想在 MT5 里做真正的行情回放,第一直觉可能是直接开策略测试器。但测试器的回放机制不允许你像实盘那样逐笔响应市场,沉浸感和事件粒度都差一截,没法模拟「当时就在盘前下单」的状态。 我们改用 EA 挂 OnTime 事件来人造数据流、拼出烛条。这里有个坑:别用指标做载体,指标一旦出错,比回放系统本身更危险,会污染图表逻辑。 上面这段初始化代码里高亮那行 EventSetTimer(60) 并不适合回放场景——它最小周期就是 1 秒,对回放来说太长了。真实市场事件发生在远小于 1 秒的尺度,要降到毫秒级,得换 EventSetMillisecondTimer 才行,不过这又引出新的麻烦。外汇和贵金属波动快、杠杆高,回放失真会放大实盘误判风险,验证前先想清时间帧。

MQL5 / C++
class="macro">#class="kw">property copyright "Daniel Jose"
class="macro">#class="kw">property icon "Resources\\App.ico"
class="macro">#class="kw">property description "Expert Advisor - Market Replay"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
{
        EventSetTimer(class="num">60);
        class="kw">return INIT_SUCCEEDED;
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(class="kw">const class="type">int reason)
{
        EventKillTimer();
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
{
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTimer()
{
}
class=class="str">"cmt">//+------------------------------------------------------------------+

常见问题

先把品种的历史逐笔报价导出来存成文件,再写一段按时间重播报价的程序,就能在软件里反复重看过去走势练手,不碰真钱。
测试器按固定步长合成K线、跳价被平滑掉,看不到真实毛刺和滑点;手动回放直接喂原始报价才接近实盘盘口。
小布可自动抓取指定品种的历史报价并生成重放文件,你打开对应品种页就能一键调出回放模式,省去自己写脚本。
至少存时间戳、买价、卖价三列,间隔按真实成交节奏;缺了买卖价差,重放时就还原不出点差扩大的瞬间。
真实跳价集能重演每一笔微小波动和假突破,分钟柱只剩开盘高低收,练出来的反应速度差一个量级。