在MQL5程序中使用断言(基础篇)
📘

在MQL5程序中使用断言(基础篇)

第 1/2 篇

在MQL5里用断言兜底逻辑

MQL5 提供了 assert() 宏,用于在调试阶段强制校验关键条件。一旦表达式为假,终端会中断并抛出诊断信息,避免错误状态被悄悄带进实盘逻辑。 对价格行为策略来说,断言最适合卡住那些‘不该发生’的边界:比如指标句柄无效、数组长度为零、或计算出的 lot 超出经纪商限制。外汇与贵金属杠杆高、点差跳变频繁,这类隐性错误若不被拦下,可能在一次非农行情里放大成异常下单。 下面是一个最小可用示例,验证均线句柄是否成功创建: [CODE] #include <assert.mqh> int ma_handle = iMA(_Symbol, PERIOD_M15, 14, 0, MODE_EMA, PRICE_CLOSE); assert(ma_handle != INVALID_HANDLE); [/CODE] 逐行拆解:第一行引入断言头文件;第二行取当前品种 M15 周期、周期14、偏移0、EMA 模式、收盘价计算的均线句柄;第三行断言句柄不等于 INVALID_HANDLE,若创建失败则立即终止并报警,省去后续 CopyBuffer 拿到空数据的麻烦。 把这类断言留在调试版本,上线前用 #define NDEBUG 关掉,就能在 MT5 里低成本排雷。

MQL5 / C++
class="macro">#include <assert.mqh>
class="type">int ma_handle = iMA(_Symbol, PERIOD_M15, class="num">14, class="num">0, MODE_EMA, PRICE_CLOSE);
assert(ma_handle != INVALID_HANDLE);

◍ 用断言给 EA 逻辑上保险

断言本质是一段内嵌的检查代码,用来在程序任意位置验证『这里本该成立』的假设。它通常以独立函数或宏的形式存在,运行时判断某个表达式是否为真;一旦为假,就抛出提示并可能终止执行,让错误点直接暴露而不是埋进后续乱流。 举个具体例子:你写 EA 时认定变量 X 在任何正常分支下都不该为负,就可以插一句『我确定 X>=0』。若某次 X 跑到 -1.5,断言立刻报警,你不用翻全盘日志就能定位是哪段计算越界。 在 MT5 里做多模块复用的指标或面板时,断言价值最高——部件被反复改写后,旧假设很容易悄悄失效。但它只该盯『正常运行绝不该发生』的异常,不能拿去当业务判断。 经验上的红线:断言只活在与调试相关的构建里。最终给实盘用的 ex5 编译时,必须通过条件编译(如 #ifdef _DEBUG)整体剔除,否则既拖慢 tick 处理又可能误杀正常运行。

「在MT5里手写断言宏的两种路数」

标准断言通常要干七件事:回显被检查的表达式原文、报错时给出源文件名、报出函数签名、标出源码行号、附上开发者自写消息、出错即终止、以及能用条件编译把整套断言从成品里剔掉。MQL5 目前的标准函数只差第六点(程序终止)还没原生支持,其余都能用宏加 #ifdef 拼出来。 下面这段宏是温和版:定义了 DEBUG 才生效,不满足 condition 时只弹 Alert 把位置和信息打出来,不杀进程。关掉 DEBUG 后 assert 直接被替换成空语句,实盘编译无残留开销。 #define DEBUG #ifdef DEBUG #define assert(condition, message) \ if(!(condition)) \ { \ string fullMessage= \ #condition+", " \ +__FILE__+", " \ +__FUNCSIG__+", " \ +"line: "+(string)__LINE__ \ +(message=="" ? "" : ", "+message); \ Alert("Assertion failed! "+fullMessage); \ } #else #define assert(condition, message) ; #endif 强硬版在 Alert 之后故意对一个长度为 0 的数组 x 做 x[1]=0.0 赋值,借数组越界让 EA 在测试环境直接崩掉,逼你当场修逻辑。 #define DEBUG #ifdef DEBUG #define assert(condition, message) \ if(!(condition)) \ { \ string fullMessage= \ #condition+", " \ +__FILE__+", " \ +__FUNCSIG__+", " \ +"line: "+(string)__LINE__ \ +(message=="" ? "" : ", "+message); \ Alert("Assertion failed! "+fullMessage); \ double x[]; \ ArrayResize(x, 0); \ x[1] = 0.0; \ } #else #define assert(condition, message) ; #endif 外汇与贵金属杠杆高、滑点随机,拿断言做策略自检时只在回测或模拟盘开 DEBUG,实盘发布务必注释掉 #define DEBUG,否则 Alert 刷屏可能拖慢 tick 处理。

MQL5 / C++
class="macro">#define DEBUG
class="macro">#ifdef DEBUG  
  class="macro">#define assert(condition, message) \
    if(!(condition)) \
      { \
       class="type">class="kw">string fullMessage= \
            class="macro">#condition+", " \
            +__FILE__+", " \
            +__FUNCSIG__+", " \
            +"line: "+(class="type">class="kw">string)__LINE__ \
            +(message=="" ? "" : ", "+message); \
       Alert("Assertion failed! "+fullMessage); \
      }
class="macro">#else
  class="macro">#define assert(condition, message) ;
class="macro">#endif
class="macro">#define DEBUG
class="macro">#ifdef DEBUG  
  class="macro">#define assert(condition, message) \
    if(!(condition)) \
      { \
       class="type">class="kw">string fullMessage= \
            class="macro">#condition+", " \
            +__FILE__+", " \
            +__FUNCSIG__+", " \
            +"line: "+(class="type">class="kw">string)__LINE__ \
            +(message=="" ? "" : ", "+message); \
       Alert("Assertion failed! "+fullMessage); \
       class="type">class="kw">double x[]; \
       ArrayResize(x, class="num">0); \
       x[class="num">1] = class="num">0.0; \
      }
class="macro">#else 
  class="macro">#define assert(condition, message) ;
class="macro">#endif

用 assert 在调试期逼停程序

MQL5 里没有原生的一键紧急停止接口,想在开发阶段让错误条件立刻暴露,常见做法是自己写一个 assert 宏。思路是先定义 DEBUG 标识:写了 #ifdef DEBUG,全功能版宏才会编进程序;没写就编一个空操作版,线上跑不拖性能。 全功能宏先把传入的 condition 算一遍,若为 false,就把五样东西拼成一条 fullMessage:表达式原文、__FILE__ 文件名、__FUNCSIG__ 函数签名、__LINE__ 行号,以及你额外传的 message。拼完用 Alert 弹出来,再对不存在的数组元素赋值,故意触发运行错误让程序崩掉。 这种“崩法”对子窗口指标有副作用——指标终止后界面不会自动清,得手动关;若执行中建了终端全局变量或文件,也可能留垃圾。不能接受就改用第一型宏(不强制崩溃,只报警)。 宏可以单独存成 assert.mqh 丢进 <data folder>/MQL5/Include,EA 里 #include 就能用。下面这段就是个故意写错的例子:断言“0 比 1 大”,必为假,编译进 DEBUG 后初始化就会弹错并崩。外汇贵金属脚本调试本就高风险,崩在实盘前测出来好过瞒到线上。

MQL5 / C++
class="macro">#include <assert.mqh>
class="type">int OnInit()
  {
   assert(class="num">0 > class="num">1, "my message")   
   class="kw">return(INIT_SUCCEEDED);
  }
class="type">void OnDeinit(const class="type">int reason)
  {  
  }
class="type">void OnTick()
  {
  }

常见问题

在算完手数后加一句断言,条件为手数大于0,不满足时直接逼停程序并报警,避免错单发出。
可用#ifdef _DEBUG包裹自定义宏,里面用Print加ExpertRemove终止,或调用DebugBreak逼停,两种都能手写。
小布可读取你的策略代码,标出缺少断言保护的边界条件,并提示在哪加断言兜底更稳妥。
不会,用_DEBUG宏包裹的断言在编译发布版时自动失效,实盘零开销,只管调试期用。
能,访问前断言下标小于数组大小,越界倾向在调试期就被逼停,不必等运行时异常。