从基础到中级:IF ELSE(基础篇)
📘

从基础到中级:IF ELSE(基础篇)

第 1/2 篇

用 IF ELSE 搭出 MT5 条件分支

MQL5 里 IF ELSE 是写 EA 和指标时最基础的控制流,决定某段逻辑在何种行情状态下才执行。很多新手把判断写死在 OnTick 里,导致每次报价都重复运算,其实用 IF ELSE 把「该不该算」先拦一层,回测负载能降一截。 下面这段示例演示了当短期均线高于长期均线时做多倾向判断,否则走空方分支。注意条件里用的是 iMA 句柄取得的缓冲区值,而非直接读 Price。 在 MT5 里新建脚本粘入即可编译运行;把 FastPeriod 从 12 改成 5,能明显看到信号翻转更频繁,适合用来验证参数敏感度。外汇与贵金属杠杆高,这类分支仅作逻辑骨架,实盘须自行加风控。

MQL5 / C++
class="type">int fastHandle = iMA(_Symbol, PERIOD_CURRENT, class="num">12, class="num">0, MODE_SMA, PRICE_CLOSE);
class="type">int slowHandle = iMA(_Symbol, PERIOD_CURRENT, class="num">26, class="num">0, MODE_SMA, PRICE_CLOSE);
class="type">class="kw">double fastVal, slowVal;
if(CopyBuffer(fastHandle, class="num">0, class="num">0, class="num">1, fastVal) > class="num">0 && CopyBuffer(slowHandle, class="num">0, class="num">0, class="num">1, slowVal) > class="num">0)
{
   if(fastVal > slowVal)
   {
      class=class="str">"cmt">// 多头倾向分支
      Comment("Bias: Long");
   }
   else
   {
      class=class="str">"cmt">// 空方分支
      Comment("Bias: Short");
   }
}

「进阶前先把传递机制焊死」

这套材料只服务于一个目标:弄懂概念本身。除了在 MT5 里做学习和验证,别把它当信号工具直接上实盘——外汇和贵金属杠杆交易的高风险不会因为代码高级就消失。 上一节我们拆过「按值传递」和「按引用传递」在跨程序搬数据时的坑,那里讲的风险和预防措施不是铺垫废话,而是后面所有高级写法的地基。 如果你现在写 EA 还只会堆数学表达式,等于白白浪费终端的并行和计算拆解能力,能实现的逻辑上限也被自己锁死。所以从这节往后的内容,默认你已经吃透了前几篇的传递语义。 哪个环节突然看不懂为什么变量被改、为什么数组越界,就回去重读对应篇章,别赶进度。基础没焊死就去碰复杂结构,调试成本会指数级反弹。 在正式进入本篇第一个技术主题前,得先统一一个术语口径:后面讲语句结构时反复出现的某个词,必须先定义清楚,否则容易和 MQL5 文档里的歧义用法混掉。

◍ 把一段花括号区块看成单一执行单元

在 MQL5 里先立一个地基概念:凡是被一对大括号 { } 包住的内容,不论里面几行、塞了什么,都该当成一个有凝聚力的整体去理解。这个整体,我们叫它例程。 例程不只是成块的代码。它也可以是一行表达式,甚至是一次函数或过程的调用。只要你看到「要执行某个例程」,脑子里要覆盖从单条调用到整段嵌套代码块的全部可能。 下面这段就是个真实例程,算的是加速震荡指标(AC)的缓冲赋值。注意它内部还嵌套了 for 循环和 if 分支,但对外仍是一个单元: [CODE] { ExtAOBuffer[i] = ExtFastBuffer[i] - ExtSlowBuffer[i]; double sumAO = 0.0; for(int j = 0; j < FAST_PERIOD; j++) sumAO+=ExtAOBuffer[i - j]; ExtSMABuffer[i] = sumAO / FAST_PERIOD; ExtACBuffer[i] = ExtAOBuffer[i] - ExtSMABuffer[i]; if ( ExtACBuffer[i] >= ExtACBuffer[i - 1]) ExtColorBuffer[i] = 0.0; // set color Green else ExtColorBuffer[i] = 1.0; // set color Red } ExtACBuffer[i] = ExtAOBuffer[i] - ExtSMABuffer[i]; [/CODE] 逐行拆一下:第 1 行开括号标志例程起点;第 2 行用快线减慢线缓冲得到 AO 原始值;第 3~4 行声明累加变量;第 5~6 行用 for 把前 FAST_PERIOD 根 AO 求和;第 7 行除以周期数得到 SMA 缓冲;第 8 行用 AO 减 SMA 得出 AC 值;第 9~12 行按 AC 是否不小于前一根来写颜色标记缓冲(0 绿 / 1 红);闭括号收束例程,末尾那行则是例程外的同级赋值。 开 MT5 建个指标把这段贴进 OnCalculate,改 FAST_PERIOD 看颜色翻转频率,就能直观抓到「例程=最小可执行整体」的分界。外汇与贵金属波动剧烈,指标仅辅助,实际信号概率随周期与品种而异。

MQL5 / C++
  {
      ExtAOBuffer[i] = ExtFastBuffer[i] - ExtSlowBuffer[i];
      class="type">class="kw">double sumAO = class="num">0.0;
      for(class="type">int j = class="num">0; j < FAST_PERIOD; j++)
         sumAO+=ExtAOBuffer[i - j];
      ExtSMABuffer[i] = sumAO / FAST_PERIOD;
      ExtACBuffer[i] = ExtAOBuffer[i] - ExtSMABuffer[i];
      if ( ExtACBuffer[i] >= ExtACBuffer[i - class="num">1])
         ExtColorBuffer[i] = class="num">0.0; class=class="str">"cmt">// set class="type">class="kw">color Green
      else
         ExtColorBuffer[i] = class="num">1.0; class=class="str">"cmt">// set class="type">class="kw">color Red
  }
ExtACBuffer[i] = ExtAOBuffer[i] - ExtSMABuffer[i];

IF 是控制流的地基

把 IF 读成「如果」就够了。它的唯一职责是判断括号里的条件为真(非零)还是为假(零),再决定要不要跑花括号内的例程。很多新手以为必须写大于小于这种比较符,其实 IF 只认真/假,零即假、非零即真,这是 MT5 里所有分支逻辑的起点。 下面这段是最朴素的演示:变量 info 赋值为 10,第 10 行直接拿 info 当条件。因为 10 不是零,条件为真,第 11 行才会打印「True condition...」,而第 13 行不管 IF 结果如何都会执行。 [CODE] //+------------------------------------------------------------------+ #property copyright "Daniel Jose" //+------------------------------------------------------------------+ void OnStart(void) { char info = 10; Print(__FUNCTION__, " : #1 => ", info); if (info) Print("True condition..."); Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway..."); } //+------------------------------------------------------------------+ [/CODE] 逐行拆解:06 行定义 char 型变量 info 并赋 10;08 行先打印当前值便于观察;10 行 if(info) 等价于测试 info!=0;11 行仅在真时执行;13 行是无条件执行的后继例程。跑完你会在终端看到两行输出,缺任何一行都说明环境异常。 故意把条件写成常量 true,例程就永远跑。下面代码第 08 行 if(true) 恒真,第 09 行必然执行,跟前面变量无关。 [CODE] //+------------------------------------------------------------------+ #property copyright "Daniel Jose" //+------------------------------------------------------------------+ void OnStart(void) { Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway..."); if (true) Print("True condition..."); Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway..."); } //+------------------------------------------------------------------+ [/CODE] 把 true 改成 false 再跑,第 09 行直接消失——不是隐藏,是根本没进执行流。很多人「见过 false 也触发」的错觉,来自逻辑反写:在 false 前加 ! 或用 !=0 反转,表达式就变真了。这种坑多出自运算符优先级,文档里叫「优先规则」,现在先记住手改一下就能验证。 开 MT5 新建脚本,把上面两段分别编译跑一遍,终端输出差一行就是 IF 语义生效的证据。外汇和贵金属行情受杠杆影响大、滑点随机,用 IF 做信号过滤时别把真/假边界写反,否则策略可能在高波动段频繁误触发。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Daniel Jose"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart(class="type">void)
{
    class="type">char info = class="num">10;

    Print(__FUNCTION__, " : #class="num">1 => ", info);

    if (info)
        Print("True condition...");

    Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Daniel Jose"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart(class="type">void)
{
    Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");

    if (true)
        Print("True condition...");

    Print(__FUNCTION__, " ", __LINE__, " It will be executed anyway...");
}

常见问题

用 if(iMA(...)>iMA(...)) 判断金叉,else 处理死叉;把判断和下单逻辑分别放进对应花括号区块即可。
多半是没搞清传递机制:基础类型直接拷贝,改的是副本;想影响外部就把变量声明在块外或用引用传递。
可以,把你的策略逻辑发给小布,它能逐段指出 IF ELSE 覆盖不全或顺序写反的地方,省去手动排查。
只要 IF 条件成立,花括号内整段被视为单一单元一次性顺序执行;不成立则整段跳过。
是的,IF 是控制流地基;不先焊死分支与区块概念,后面写嵌套和循环很容易出不可控bug。