调试 MQL5 程序·综合运用
🐞

调试 MQL5 程序·综合运用

(3/3)·编译警告被无视、调试器不会用,程序隐性 bug 往往就卡在这两个阶段

含代码示例偏理论 第 3/3 篇
把编译器里的黄色警告当摆设,是多数半路出家 MQL5 开发者的通病。一个 = 写成 == 的疏忽,程序照跑不误却悄悄改了逻辑。等策略在实盘出怪异信号,你才意识到调试第一阶段就没过关。

用宏开关给 EA 逻辑做无侵入埋点

想在 MT5 里给 EA 的运行路径留痕,又不想每次手动写日志,可以用预处理宏把条件判断包一层。下面这段把 trace 变量设为 0 时完全不输出,设为 1 时才把函数签名拼进 com 字符串,等于给 OnInit、OnTick、CheckForOpen 都加了可开关的跟踪点。 zx 和 xz 两个宏分别负责在代码块开头和结尾追加 if(...){\n 与 };\n,注释掉宏定义后就退化成空操作,对原逻辑零侵入。实测把 trace 从 0 切到 1,编译后 EX5 体积差异通常在几百字节级别,运行时开销可忽略。 注意这种写法只是把调用栈结构文本化,并不会记录参数值;外汇与贵金属交易本身高风险,任何跟踪手段都只是辅助排查,不代表策略胜率提升。

MQL5 / C++
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 或指标深层结构里翻局部变量,调试完直接删全局块,漏网概率低很多。外汇和贵金属品种波动剧烈,调试脚本若带真实下单逻辑务必先在模拟盘验证,实盘高风险。

MQL5 / C++
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 把均线轨迹打到副图,本质是逼你少看指标、多看价格与代码的交叉点。能照着跑通一次,比收藏十篇文档有用。

把编译与断点检查交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到脚本运行状态与异常标记,把重复劳动交给小布,你专注决策。

常见问题

语法错误以红色显示,不修正就无法生成程序;警告以黄色显示,代码仍能编译但运行行为可能偏离预期,不能忽视。
调试器是 MetaEditor 5 的新功能,MetaEditor 4 没有,启动仿真逐步执行的热键是 F5。
编译器会把 if(a=b) 解析成先赋值再判断真假,语法上合法,所以只给警告,但逻辑已被改变,属于典型隐性 bug。
可以,小布盯盘内置了对接品种页的 AIGC 诊断,能呈现脚本运行异常与标记,减少你手动盯编译日志的负担。
在 Toolbox 的 Errors 选项卡里,高亮描述行按 Enter 即可直接定位源码中的错误位置。