开发回放系统 市场模拟(第 02 部分):首次实验(II)·综合运用
◍ 逐笔回放时如何拼出当前K线
做历史逐笔回放(tick replay)时,核心是把同一毫秒内的多笔 tick 累加成一根实时更新的蜡烛。下面这段逻辑就干这件事:只要回放指针所指 tick 的毫秒值还等于当前 mili,就持续刷新第 0 根 Rate 的 OHLC 与成交量。 别把 open 写死 新蜡烛的第一笔 tick 用 close 填 open;之后同毫秒的 tick 不再改 open,只更新 close、high、low。high/low 用三元判断兜底:新笔或破极值才更新,否则沿用。tick_volume 同理,新笔直接取该 tick 成交量,否则累加。 回放指针与推送节奏 每处理完一笔 m_ReplayCount 自增,退出 while 后把 m_Rate[0].time 设为当前 datetime,调用 CustomRatesUpdate 推给图表。下一毫秒差 mili 按「跨秒则补到千毫秒差,否则相减」算,控制下次循环间隔。外汇与贵金属 tick 回放属高风险验证,实盘前务必在策略测试器跑通。
while (mili == m_ArrayInfoTicks[m_ReplayCount].milisec) { m_Rate[class="num">0].close = m_ArrayInfoTicks[m_ReplayCount].Last; m_Rate[class="num">0].open = (isNew ? m_Rate[class="num">0].close : m_Rate[class="num">0].open); m_Rate[class="num">0].high = (isNew || (m_Rate[class="num">0].close > m_Rate[class="num">0].high) ? m_Rate[class="num">0].close : m_Rate[class="num">0].high); m_Rate[class="num">0].low = (isNew || (m_Rate[class="num">0].close < m_Rate[class="num">0].low) ? m_Rate[class="num">0].close : m_Rate[class="num">0].low); m_Rate[class="num">0].tick_volume = (isNew ? m_ArrayInfoTicks[m_ReplayCount].Vol : m_Rate[class="num">0].tick_volume + m_ArrayInfoTicks[m_ReplayCount].Vol); isNew = class="kw">false; m_ReplayCount++; } mili++; }while (mili == m_ArrayInfoTicks[m_ReplayCount].milisec); m_Rate[class="num">0].time = m_dt; CustomRatesUpdate(def_SymbolReplay, m_Rate, class="num">1); mili = (m_ArrayInfoTicks[m_ReplayCount].milisec < mili ? m_ArrayInfoTicks[m_ReplayCount].milisec + (class="num">1000 - mili) : m_ArrayInfoTicks[m_ReplayCount].milisec - mili); if ((macroGetMin(m_dt) == class="num">1) && (_dt > class="num">0)) {
「把计时器收尾打印出来」
这段收尾代码负责把计时结果输出到 MT5 专家日志,并把内部变量清零。 Print("Elapsed time: ", TimeToString(TimeLocal() - _dt, TIME_SECONDS)); 先把本地当前时间减去起始时间戳 _dt,再用秒精度转成字符串,前缀写上 Elapsed time: 方便你一眼看到耗时。 _dt = 0; 这一行把起始时间清零,避免下一次调用时拿到脏值。return (mili < 0 ? 0 : mili); 则做了兜底:若计算出的毫秒数为负,直接返回 0,否则返回真实毫秒。 开 MT5 把这段贴进你的 EA,跑一轮后按 Ctrl+T 看日志里的 Elapsed time,就能确认函数开销是否如预期在毫秒级。外汇与贵金属行情跳动密集,这类微观耗时在高频率逻辑里可能放大延迟,属高风险环境下的细节优化。
Print("Elapsed time: ", TimeToString(TimeLocal() - _dt, TIME_SECONDS)); _dt = class="num">0; } class="kw">return (mili < class="num">0 ? class="num">0 : mili); }; class="macro">#undef macroGetMin
回放系统才刚搭起骨架
前三篇我们把 MT5 回放系统的底层逻辑跑通了:用 MQL5 的设置与函数解决历史数据重演、时间轴对齐的问题,证明这门语言能做的远比多数人以为的多。但代码层面只是起了个头,Replay.zip 里那 10.7 MB 的工程文件,目前也仅覆盖最基础的行情回放。 真正要落地,还得补订单撮合延迟、点差漂移和滑点模拟——外汇与贵金属本身高杠杆、高波动,回放里不显形的那些摩擦成本,实盘里可能直接吃掉策略盈利。 下一篇接 SQL 入门,把 tick 数据塞进本地库再做随机抽样回放,那时候你才能拿自己的参数去 MT5 里撞一遍真历史。