查找错误和记录·综合运用
🔍

查找错误和记录·综合运用

(3/3)·从结果反推、断点调试到日志埋点,收尾篇把排查链路一次打通

偏理论进阶 第 3/3 篇
很多交易者写 EA 只靠肉眼看最终输出,错了就从头翻代码,一晚上耗在找括号上。其实 MetaEditor 的调试器和日志埋点能直接把错误行亮出来。本篇把三种排查路径和一款看日志的小工具串起来,省下的时间你用来复盘行情更划算。

「用分级变量控住 EA 的消息噪音」

写 EA 最烦的不是报错,而是日志被无用信息淹没。把消息分成几档:级别 0 是致命错误,1 是交易动作或临时异常通知,2 及以上通常是调试用的变量快照。 用 input int dLvl=2 当总开关,数值越大可见消息越多;若赋 -1 则全部静默,适合挂实盘不想被刷屏时。比较逻辑只看 lvl<=dLvl,所以调 dLvl 不必动函数体。 下面这段代码在 CLogger 对象创建后声明即可直接用。级别 0 的消息走红色标记,其余按默认色输出,调用时传文本和级别两个参数: [CODE] input int dLvl=2; void debug(string debugMsg, // 消息文本 int lvl ) // 消息级别 { if (lvl<=dLvl) // 以消息输出级别比较消息级别 { if (lvl==0) // 如果消息是紧急 (级别 = 0) {logger.write(debugMsg,"",Red);} // 标记为红色 else {logger.write(debugMsg);} // 否则打印省缺颜色 } } debug("EA 错误!",0); // 紧急错误 debug("止损执行",1); // 通知 int i = 99; debug("变量 i:"+(string)i,2); // 调试信息,变量内容 [/CODE] 逐行拆一下:第 1 行 dLvl 默认 2,代表 0/1/2 三档都打印;debug 函数先判 lvl<=dLvl 决定是否出场,再判 lvl==0 决定染红。示例里 i=99 被强转成字符串拼进调试消息,这种写法在排查数组越界或订单重推时很实用。 把 dLvl 改成 1,上面那行「变量 i:99」立刻消失,日志只剩错误和通知。外汇与贵金属波动剧烈、滑点频繁,用分级日志能更快定位是报价断流还是仓位计算错,但 EA 失效风险始终存在,任何日志方案都不保证不出错。

MQL5 / C++
input class="type">int dLvl=class="num">2;
class="type">void debug(class="type">class="kw">string debugMsg,             class=class="str">"cmt">// 消息文本
          class="type">int lvl        )              class=class="str">"cmt">// 消息级别
{
   if (lvl<=dLvl)                       class=class="str">"cmt">// 以消息输出级别比较消息级别
   {
       if (lvl==class="num">0)                     class=class="str">"cmt">// 如果消息是紧急 (级别 = class="num">0)
       {logger.write(debugMsg,"",Red);} class=class="str">"cmt">// 标记为红色
       else
       {logger.write(debugMsg);}       class=class="str">"cmt">// 否则打印省缺颜色
   }
}
debug("EA 错误!",class="num">0);      class=class="str">"cmt">// 紧急错误
debug("止损执行",class="num">1);      class=class="str">"cmt">// 通知
class="type">int i = class="num">99;
debug("变量 i:"+(class="type">class="kw">string)i,class="num">2); class=class="str">"cmt">// 调试信息,变量内容

◍ 用 LogMon 把日志从乱麻变成树状视图

CLogger 跑起来后,日志文件动辄几千行,全挤在一起没分类,肉眼翻找基本无效。作者用 WinAPI 写了个 C++ 小工具 LogMon,免费、体积小、启动快,专门读 CLogger 产出的日志。 部署分两种场景:普通看盘就把 exe 丢进 Client_Terminal_dir\MQL5\Files\ 直接运行;回测或优化时则放到 Agents_dir\Agent\MQL5\Files\ 再跑。程序左侧树状视图列出 MQL5\Files\log\ 下的项目,项目名由 CLogger 的 SetSetting() 定,展开后是真实日志文件,再往下是按 write() 指定的分类,括号里的数字就是该分类消息条数。 工具栏几个键值得记住:删除/复位键能停掉所有扫描线程,Delete and Flush 会清掉选中文件或项目,Reset 只清空树;置顶键让窗口压在所有窗口上;最小化到托盘并开监控后,勾选分类、文件或项目旁的复选框,对应层级来新消息就会弹窗加声音。想换提示音,在同目录塞个 alert.wav 即可。 双击分类出消息框,可搜索、锁最前、关自动滚动;消息颜色由 write() 逐个设定,背景高亮。双击单条过长消息会弹独立窗口。MT5 上跑完 EA 别再硬翻文件,开 LogMon 勾几项就能实时盯分类异常,外汇贵金属策略调试的高频报错大概率第一时间撞进你眼里。

记住这一条就够了

给 EA 挂上事件记录不是锦上添花,而是排雷的底裤。CLogger 这类封装把缓存刷盘和句柄关闭都收进 deinit,能在 MT5 退出时保住最后几行诊断信息,避免你事后对着黑盒猜哪根新柱触发了异常。 上面这段私有 flush 声明加 deinit 实现,就是整套日志方案里最该抄走的两行半:退出前先 flush() 把缓冲落盘,再 FileClose(handleFile) 释放句柄。忘掉刷新这一步,nelson75 在评论里提过,历史回测里可能直接丢尾段数据。 外汇和贵金属杠杆高、滑点野,任何日志类工具只帮你看见错误,不替你挡亏损。把 testlogger.mq5 拖进 MT5 跑一遍真实与历史数据,比对输出差异,比看十篇概述都实在。

MQL5 / C++
class="kw">private:
  class="type">void               flush(class="type">void);                     class=class="str">"cmt">// 将缓存刷新到文件中
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 退出初始化|
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void CLogger::deinit(class="type">void)
  {
  flush();   class=class="str">"cmt">// 清除数据
  FileClose(handleFile); class=class="str">"cmt">// 关闭文件
  }
把日志巡检交给小布
这些诊断逻辑小布盯盘已内置,打开对应品种页即可看到运行异常与日志摘要,把重复劳动交给小布,你专注决策。

常见问题

可以在断点悬停查看局部值,但循环多次建议加进 Watch,否则每步切窗口很费眼,效率不如日志埋点。
可以,小布盯盘的 AIGC 模块会抓取品种页关联程序的异常输出并做摘要,不用你手动开 LogMon 刷屏。
取决于 Print 频次,高频循环内写日志可能让优化时长翻倍,实盘影响有限,优化前建议临时注释掉调试输出。
它侧重轻量实时监控与高亮过滤,适合长时间挂 EA 时快速扫异常,不必在终端里翻几千行文本。