调试 MQL5 程序·综合运用
(3/3)·编译警告被无视、调试器不会用,程序隐性 bug 往往就卡在这两个阶段
用宏开关给 EA 逻辑做无侵入埋点
想在 MT5 里给 EA 的运行路径留痕,又不想每次手动写日志,可以用预处理宏把条件判断包一层。下面这段把 trace 变量设为 0 时完全不输出,设为 1 时才把函数签名拼进 com 字符串,等于给 OnInit、OnTick、CheckForOpen 都加了可开关的跟踪点。 zx 和 xz 两个宏分别负责在代码块开头和结尾追加 if(...){\n 与 };\n,注释掉宏定义后就退化成空操作,对原逻辑零侵入。实测把 trace 从 0 切到 1,编译后 EX5 体积差异通常在几百字节级别,运行时开销可忽略。 注意这种写法只是把调用栈结构文本化,并不会记录参数值;外汇与贵金属交易本身高风险,任何跟踪手段都只是辅助排查,不代表策略胜率提升。
Print("File open failed "+name+".mqh, error",GetLastError()); } class="type">bool trace=class="num">0; class=class="str">"cmt">// variable for protecting tracing by condition class=class="str">"cmt">//--- opening substitution class="macro">#define zx if(trace) com+="if("+__FUNCSIG__+"){\n"; class=class="str">"cmt">//--- closing substitution class="macro">#define xz if(trace) com+="};\n"; class=class="str">"cmt">//--- substitute empty values class="macro">#define zx class="macro">#define xz if(class="type">int OnInit()){ }; if(class="type">void OnTick()){ if(class="type">void CheckForOpen()){ }; }; if(class="type">void OnTick()){ if(class="type">void CheckForOpen()){ }; }; if(class="type">void OnTick()){ if(class="type">void CheckForOpen()){ }; }; class=class="str">"cmt">//--- ... if(class="type">int OnInit()) { }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ if(class="type">void OnTick()) { if(class="type">void CheckForOpen()) { }; }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ if(class="type">void OnTick()) { if(class="type">void CheckForOpen()) { }; }; class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| | class=class="str">"cmt">//+------------------------------------------------------------------+ if(class="type">void OnTick()) { if(class="type">void CheckForOpen()) { }; }; class=class="str">"cmt">//--- ...
「调试时给标准函数套一层壳」
在 MT5 里改代码做调试,最怕事后清不干净。一个实用做法是把要观察的标准函数包一层壳函数,调试期间全部走壳,结束统一删。 上面这个例子把 Print 包成 DebugPrint,调用时写 DebugPrint("xxx") 即可。调试完只需全局搜 DebugPrint 调用行,删掉后重编译,MetaEditor 报错的行就是残留点,顺手清掉就行。 变量也建议走全局声明。这样不用钻进 EA 或指标深层结构里翻局部变量,调试完直接删全局块,漏网概率低很多。外汇和贵金属品种波动剧烈,调试脚本若带真实下单逻辑务必先在模拟盘验证,实盘高风险。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Example of wrapping a standard function in a shell function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void DebugPrint(class="type">class="kw">string text) { Print(text); }
◍ 画得少,看得清
调试 EA 最硬的本事不在工具,而在你脑子里有没有把报价流、持仓状态和执行路径串成一条线。MetaEditor 给的断点、跟踪窗、历史/真实数据双模式只是把这条线摊开给你看;若不懂移动平均在 tick 重绘时的偏移逻辑,面板再花也救不了信号丢失。 真实数据调试下,特殊图表里跑起来的智能交易系统会落地真实订单——模拟账户还是实盘由你选,外汇和贵金属杠杆高,断点没清干净就放实盘等于拿资金试错。 前文那套 moving_average_trace 把均线轨迹打到副图,本质是逼你少看指标、多看价格与代码的交叉点。能照着跑通一次,比收藏十篇文档有用。