开发回放系统  市场模拟(第 03 部分):调整设置(I)·综合运用
📘

开发回放系统 市场模拟(第 03 部分):调整设置(I)·综合运用

第 3/3 篇

用回放服务驱动离线行情重演

MQL5 的回放接口允许把历史行情按可控节奏重新推送到图表,用来验证策略逻辑而不占用实时连接。下面这段调用链先创建符号回放,再打开观察窗口并等待跨进程全局变量就位。 代码中 while(!GlobalVariableCheck(def_GlobalVariableReplay)) Sleep(750); 表示每 750 毫秒轮询一次,直到回放控制器写好全局变量才继续,避免抢跑读取空状态。 主循环里用 GetTickCount64() 记录时间戳 t1,每次判断 GetTickCount64()-t1 >= (uint)delay 来决定是否推进下一帧;delay 来自 Replay.Event_OnTime(),该函数返回小于 0 时直接 break 退出。这套机制让你在 MT5 里能以自定义速度重跑某段贵金属或外汇行情,外汇与贵金属杠杆高、滑点跳空频繁,重演结果仅代表历史数据下的概率表现,不等于实盘收益。 把 Replay.CreateSymbolReplay(user01) 的 user01 参数换成你自己的回放配置,编译后运行 EA,就能在离线图表看到价格被逐帧复现,进而手动或自动检验入场条件。

MQL5 / C++
Replay.CloseReplay();
Print("Replay service finished ...");
}
class=class="str">"cmt">//+------------------------------------------------------------------+
if (!Replay.CreateSymbolReplay(user01)) class="kw">return;
id = Replay.ViewReplay();
class="kw">while (!GlobalVariableCheck(def_GlobalVariableReplay)) Sleep(class="num">750);
t1 = GetTickCount64();
class="kw">while ((ChartSymbol(id) != "") && (GlobalVariableGet(def_GlobalVariableReplay, Info.Value)))
  u_Interprocess Info;
class=class="str">"cmt">//...
  if (!Info.s_Infos.isPlay)
if (!bTest) bTest = (Replay.Event_OnTime() > class="num">0); else t1 = GetTickCount64();
else if ((GetTickCount64() - t1) >= (class="type">uint)(delay))
if ((delay = Replay.Event_OnTime()) < class="num">0) class="kw">break;
Replay.CloseReplay();

「ViewReplay 卡住整个回放系统的那几行」

C_Replay 里的 ViewReplay 只有 4 行,却直接决定回放能不能跑起来。哪怕前面所有逻辑都对,只要这里出错,整个系统会无声无息地失败。 它先以回放资产名开一张 M1 图表,再把名为 Market Replay.tpl 的模板套上去。这个模板不是随便存的——里面必须带着回放系统的 EA,否则 ChartOpen 和 ChartApplyTemplate 执行完,服务系统也收不到「已就绪」的全局变量。 模板缺失或 EA 没嵌进去,是实测中最常见的崩点:你什么都没改,但回放就是不触发。用指标替代 EA 理论上能绕开,但作者刻意用 EA 就是为了简化加载链路,所以老老实实存好那个 tpl 文件最稳。 套完模板后调一次 ChartRedraw 强制重绘,是为了让控件尽快显示,不必等终端自己慢吞吞刷新。最后返回图表 ID,后续服务要靠它判断图表是否被关掉。外汇与贵金属回测环境波动大、点差跳变频繁,跑这套前先确认 tpl 就位,否则白费时间。

MQL5 / C++
class="type">long ViewReplay(class="type">void)
{
    m_IdReplay = ChartOpen(def_SymbolReplay, PERIOD_M1);  class=class="str">"cmt">// 用回放资产名开一张 class="num">1 分钟周期图表,并把 ID 存进成员变量
    ChartApplyTemplate(m_IdReplay, "Market Replay.tpl");  class=class="str">"cmt">// 把含回放 EA 的指定模板应用到新开的图表窗口
    ChartRedraw(m_IdReplay);  class=class="str">"cmt">// 强制重绘该图表,加速控件显示,不必等终端自动刷新
    class="kw">return m_IdReplay;  class=class="str">"cmt">// 返回回放图表 ID,供服务系统监测图表关闭等状态
}

◍ 画得少,看得清

随文附带的 Market_Replay.zip 约 10.3 MB,解压后直接在 MT5 加载,就能看到回放系统从启动到跑出 K 线的全过程,比读文字直观得多。 下一阶段要做的是位置控制系统,用来指定回放从哪一刻开始,不必每次都从头播。外汇与贵金属复盘虽能暴露盘感盲区,但模拟和实盘存在滑点与时区差异,高风险仍在。 先把这个 ZIP 跑通,等你能在画布上只留关键位、删掉多余指标线,对价格行为的判断反而更准。

常见问题

多半是 ViewReplay 里等待帧提交的那几行逻辑没释放阻塞,检查是否漏了超时退出或事件轮询,否则会拖住整个回放线程。
通常是帧间隔与数据块读取没有解耦,把行情回放速率和渲染节奏分开配置,速度就能稳定下来。
可以,小布能按你给的品种和参数批量驱动回放,并在 ViewReplay 类阻塞时直接高亮提示,省去你逐行查日志。
只保留突破位和成交密集区的少量画线,隐藏次要网格与指标,视觉负荷降下来更容易抓价格行为。
先确认文件路径权限和缓存清理逻辑,再查服务启动顺序是否早于回放调用,顺序错就会随机掉线。