首页 / 交易学院 / 小布知识库 / MQL5 调试三板斧:Comment、Alert、Print 与 CLogger
MQL5 调试三板斧:Comment、Alert、Print 与 CLogger
🧩

MQL5 调试三板斧:Comment、Alert、Print 与 CLogger

MQL5 编程 难度 · 入门 2013 10 分钟阅读
调试日志MQL5

一、三种手段:评估、逐步调试、写日志

原文把“找错”分成三类:评估结果对不对、用断点逐步调试、把过程写进日志。记录函数最常用的是 Comment、Alert、Print 三个。它们解决的问题不同:想实时看当前值用 Comment,想弹窗+声音提醒用 Alert,想持续落盘分析用 Print。

二、Comment / Alert / Print 的区别

三、CLogger:把日志写进独立文件

三个内置函数不够灵活,原文给出 CLogger.mqh 把日志封装成文件类:按项目名+日期建文件、自动加时间戳、支持消息分类与颜色、带缓存按条数/时间刷盘。用法:

#include <CLogger.mqh>
CLogger logger;
logger.SetSetting("我的项目","我的日志","注释",60);
logger.init();
logger.write("测试消息","错误",Red,__FILE__,__LINE__);
logger.flush(); logger.deinit();

四、调试技巧:分级输出

原文用一个 input int dLvl 控制输出级别(0 紧急红、1 通知、2 调试),再用 debug() 函数比较级别决定是否输出。这样不用改源码就能在“安静运行”和“详细排错”之间切换。配合 Print/Alert 快速定位:循环里 Print(i) 能找出“本该赋值却没赋”的漏网之鱼。

五、常见错误与排查清单

⚠ 最容易踩的坑
1) 循环条件写错(for i<9 漏了第 9 个元素)导致数组部分未赋值,应 i<10 或 i<=9。2) Alert 每 tick 调用会冻结终端,持续监控请用 Print。3) 忘记 flush()/deinit() 会让缓存日志丢失,deinit 里应先 flush。4) 历史数据调试若失败,检查调试器的历史模式设置与数据可用性。

六、实战建议

小 EA 用 Print+级别宏足够;大型项目用 CLogger 分文件、分类、带缓存更可控。日志路径在 MQL5\Files\ 下,超 10MB 自动分新文件。推荐配合 LogMon 这类查看器按分类/颜色/声音监控。切记:调试代码在发布前应降级或移除,避免污染正式日志。

七、把调试输出封装成可分级宏

正式项目推荐把 Print/Alert 包一层级别判断,这样发布时把级别调高就能静默,排错时调低就详细。下面这种轻量宏思路既不需要 CLogger 也能用:

#define DBG_LVL 2  // 0 紧急 1 通知 2 调试
void dbg(int lvl, string msg)
  {
   if(lvl<=DBG_LVL) PrintFormat("[DBG %d] %s", lvl, msg);
  }
// 用法:dbg(2, "i="+(string)i); 发布时 DBG_LVL 设 0 即可屏蔽调试输出

八、排错清单(按出现频率)

⚠ 遇到异常先查这 5 项
1) 结果不对:先用评估法看整体,再逐步调试/写日志定位是哪一步算错。2) 循环漏赋值:for 条件写成 i<9 漏了第 9 个元素,改 i<10 或 i<=9。3) 终端卡死:Alert 在循环里频繁调用,改 Print 或加节流。4) 日志丢失:忘调 CLogger.flush()/deinit(),析构里先 flush。5) 历史调试失败:检查调试器历史模式与数据可用性,真实数据下往往正常。

九、分级日志设计

日志别只 Print 一把梭,要分级:INFO 记录正常流程、WARN 记录可疑(如滑点偏大)、ERROR 记录异常(下单失败)。分级后你能在海量输出里只筛 ERROR,快速定位问题。

每条日志带时间戳、上下文(品种、ticket、函数名),出事时才能还原现场。没上下文的日志等于没记。

十、用日志定位两类经典 bug

「不开仓」:开 INFO 日志看信号函数每 tick 的返回值,若长期是 0,说明信号条件永远不满足或数据未就绪;「重复开仓」:看 OnTrade 是否在事件里又发单,或信号没去重每 tick 都触发。

void Log(int level, string ctx, string msg)
{
   if(level < LOG_LEVEL) return;
   Print(TimeToString(TimeCurrent()), " [", ctx, "] ", msg);
}
✦ 日志带上下文
没上下文的 Print 等于没记。每条带时间、品种、函数名,出事才能还原现场、快速定位。

十一、日志性能:高频 Print 的代价

每 tick 都 Print 到终端会严重拖慢 EA,尤其多品种。正确做法:调试期用 Print,上线前改用 CLogger 写文件(异步、批量),或只记录 WARN/ERROR 级。文件日志还能事后离线分析。

CLogger 把日志落盘到 Files 目录,配合回测日志,你能精确复盘「哪笔在什么行情下成交」,这是系统化最被低估的透明度红利。

十二、小结

✦ 小结
调试日志要分级(INFO/WARN/ERROR)且带时间上下文,才能快速定位「不开仓」(信号恒为0/数据未就绪)与「重复开仓」(OnTrade 内发单/信号未去重)。高频 Print 拖慢终端,上线改 CLogger 异步写文件,既省性能又利复盘。

常见问题

想实时在图表上盯着变量变化用 Comment;想事后分析一段运行过程、或需要落盘保留用 Print。Comment 不写文件、只显当前值,不适合长期排错;Print 静默写 Experts 日志,最适合持续记录。
Alert 每次调用都会弹窗并播放声音,且所有 EA 的 Alert 混写进同一个 data.txt。如果放在每 tick 或循环里频繁调用,终端会被卡住。需要声音提醒时也要加节流,避免每 tick 触发。
CLogger 用缓存累积消息、按条数或时间批量写入文件,避免频繁 IO。但如果忘记调 flush() 或 deinit() 就卸载 EA,缓存里没刷出的消息会丢失。习惯上在 deinit 里先 logger.flush() 再 deinit()。