查找错误和记录·综合运用
(3/3)·从结果反推、断点调试到日志埋点,收尾篇把排查链路一次打通
「用分级变量控住 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 失效风险始终存在,任何日志方案都不保证不出错。
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 跑一遍真实与历史数据,比对输出差异,比看十篇概述都实在。
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">// 关闭文件 }