🧩
MQL5 调试三板斧:Comment、Alert、Print 与 CLogger
调试日志MQL5
三种手段:评估、逐步调试、写日志
原文把“找错”分成三类:评估结果对不对、用断点逐步调试、把过程写进日志。记录函数最常用的是 Comment、Alert、Print 三个。它们解决的问题不同:想实时看当前值用 Comment,想弹窗+声音提醒用 Alert,想持续落盘分析用 Print。
Comment / Alert / Print 的区别
- Comment():在图表左上角显示当前状态,不落盘,适合即时看变量,但输出受限、只显当前值、偏慢。
- Alert():弹独立窗口+声音,同时写入 Terminal_dir\MQL5\Logs\data.txt,但频繁调用会冻结终端,策略测试器里不适用。
- Print():写入终端“Experts”选项卡和 Logs\data.txt,无声音、最适合作持续记录,但所有信息混写一个日志、不便分组。
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) 历史调试失败:检查调试器历史模式与数据可用性,真实数据下往往正常。
常见问题
想实时在图表上盯着变量变化用 Comment;想事后分析一段运行过程、或需要落盘保留用 Print。Comment 不写文件、只显当前值,不适合长期排错;Print 静默写 Experts 日志,最适合持续记录。
Alert 每次调用都会弹窗并播放声音,且所有 EA 的 Alert 混写进同一个 data.txt。如果放在每 tick 或循环里频繁调用,终端会被卡住。需要声音提醒时也要加节流,避免每 tick 触发。
CLogger 用缓存累积消息、按条数或时间批量写入文件,避免频繁 IO。但如果忘记调 flush() 或 deinit() 就卸载 EA,缓存里没刷出的消息会丢失。习惯上在 deinit 里先 logger.flush() 再 deinit()。