开发回放系统  市场模拟(第 05 部分):加入预览(基础篇)
📘

开发回放系统 市场模拟(第 05 部分):加入预览(基础篇)

第 1/3 篇

「给回放系统加一个预览窗口」

在 MT5 里做市场回放模拟,前几篇已经能把历史报价按节奏推出来。这一节要补的是预览:在正式回放前,先把一段行情缩略地跑一遍,确认数据区间和速度没选错。 不加预览直接全量回放,很容易在 1 分钟 K 线里卡半小时才发现选了错误品种。预览的本质是用极低成本先验证输入参数。 实现上,预览和正式回放共用同一套 OnTick 驱动逻辑,只是把总帧数砍到原来的 1/20 左右,并在图表左上角用 Comment() 打出当前模拟时间戳。读者打开 MT5 新建 EA,把下面这段接进主循环之前跑一次即可。

为什么裸回放给不出可用信号

上一篇文章里我们搭了一套市场回放系统,每根 1 分钟柱线在一分钟内生成,初步能跑通模拟。但很快发现,这种只从“当下”开始吐数据的回放,没法对更早的分钟、小时或天数做预分析。 所谓预分析,是指系统从某个时间点开始生成柱线时,前面应该已经存在历史柱线。没有这些早期柱线,任何指标都拿不到可靠输入。 举个具体例子:哪怕只用 3 周期移动平均线(JOE DI NAPOLI 系统采用的那种),也得等至少 3 根柱线生成后,均线才会画出来。在只含某一天逐笔跳价的文件里,从开盘起算,前 3 分钟图表上根本没有任何均线信号,这段时间里系统完全不可操作。 如果放到 5 分钟周期做研究,得干等 15 分钟才能看到 3 周期均线,再往后才有勉强能用的信号。回放系统必须补上历史预载,否则实战验证价值很低,外汇与贵金属这类高波动品种上误判风险尤其大。 本文接下来要解决的,就是怎么给回放系统接上这段缺失的历史数据。

◍ 回放前到底要备多少根历史柱

做市场回放前先别急着写代码,第一个要拍板的是:用哪个图表周期,以及每个指标吐出有用信号最少要吃多少根柱。这没有标准模型,完全看你拿回放来干什么。把这件事想清楚,后面不只能做回放,还能顺手搭一个市场模拟器——两者唯一实质区别是数据源,回放吃真实 TICKS/BARS,模拟器靠数学合成或纯随机生成。 判定回放启动前最少要预载多少根 1 分钟柱,公式很直白:N = P × T + T。P 是指标里最长的那个周期参数,T 是你要用的图表周期分钟数。比如 5 分钟图上跑 200 周期均线,N = 200×5 + 5 = 1005,也就是回放开始前硬盘里至少得有 1005 根 1 分钟柱,均线才能从第一帧就画出来。 复杂点的情况:5 分和 15 分图上研究 21/50 周期双均线加 14 周期 RSI 和日内 VWAP,偶尔切 30 分图确认进出场。最大指标周期是 50,VWAP 与时间无关不用管;时间帧取最长的 30 分。N = 50×30 + 30 = 1530 根 1 分钟柱。这数看着吓人,但比极端情形还差得远,核心思路是:历史数据量永远要比你直觉里“够用”多一大截。 外汇贵金属高风险,B3 这类交易所还分交易时段,美元期货 9:00 开盘 18:30 收盘,单日 1 分钟柱数 = (18-9)×60 + 30 = 570 根。把所需总柱数除以每日平均柱数,就得到最短要捕多少天的文件。之所以死磕 1 分钟柱,是因为 MT5 能据此任意合成其它周期,换用 15 分柱就失去平台原生支持了。 代码里第一处改动是指定历史数据文件:input string user00 装前期柱线、user01 装回放跳价。服务启动后依次 InitSymbolReplay 建品种、LoadPrevBars 载旧柱、LoadTicksReplay 载跳价,打印等待授权,靠 GlobalVariableCheck 轮询控制指标是否挂上。下面这段是核心骨架,逐行拆完你就能在 MT5 里照抄验证。

MQL5 / C++
class="macro">#class="kw">property service
class="macro">#class="kw">property copyright "Daniel Jose"
class="macro">#class="kw">property version   "class="num">1.00"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#include <Market Replay\C_Replay.mqh>
class=class="str">"cmt">//+------------------------------------------------------------------+
input class="type">class="kw">string     user00 = "WIN$N_M1_202108030900_202108051754";   class=class="str">"cmt">//File with bars( Prev. )
input class="type">class="kw">string     user01 = "WINQ21_202108060900_202108061759";     class=class="str">"cmt">//File with ticks( Replay )
class=class="str">"cmt">//+------------------------------------------------------------------+
C_Replay         Replay;
class="type">void OnStart()
{
        class="type">ulong t1;
        class="type">int delay = class="num">3;
        class="type">long id;
        u_Interprocess Info;
        class="type">bool bTest = false;
        
        Replay.InitSymbolReplay();
        Replay.LoadPrevBars(user00);
        if (!Replay.LoadTicksReplay(user01)) class="kw">return;
        Print("Aguardando permissão para iniciar replay ...");
        id = Replay.ViewReplay();
        while (!GlobalVariableCheck(def_GlobalVariableReplay)) Sleep(class="num">750);

「拿到回放许可后的计时起点」

在 MT5 终端里调用回放服务前,先确认权限已放行。代码里用 Print 输出一条许可确认信息,这条日志只起标记作用,不影响后续逻辑,但能让你在专家日志里快速定位回放会话的起始位置。 紧接着用 GetTickCount64 给变量 t1 赋值,拿到的是系统启动后到当前的毫秒数(64 位无符号),精度足够区分同秒内多次回放触发。开 MT5 把这段塞进 OnStart,跑一次就能在日志看到 'Permission granted' 与 t1 的具体数值,方便后续和回放结束时的计时做差。 外汇与贵金属品种的历史回放涉及高频 tick 重演,属于高杠杆高风险环境,计时差值仅反映本地执行耗时,不预示任何行情走向。

MQL5 / C++
      Print("Permission granted. Replay service can now be used...");
      t1 = GetTickCount64();

常见问题

裸回放只重播价格,没有把成交量、指标状态和盘口层级一并还原,信号自然失真。回放前应把预览窗口和必要指标一起加载好再启动。
至少准备 300 根以上同周期历史柱,才能让均线类指标完成初始化。周期越大,所需根数应相应增加。
可以。小布能按你选的周期自动拉取足量历史柱、加载预览窗口并校验指标初始化,你只需点开对应品种页确认即可。
计时起点是回放引擎真正发出第一根重播柱的时刻,不是你点击许可的瞬间。中间加载延迟不计入回放时长。
预览窗口让你在回放开始前先看到即将播放的局部行情轮廓,提前框定观察区,避免回放中盲找形态浪费时间。