从基础到中级:WHILE 和 DO WHILE 语句(基础篇)
📘

从基础到中级:WHILE 和 DO WHILE 语句(基础篇)

第 1/2 篇

◍ WHILE 与 DO WHILE 的循环边界

MQL5 里 WHILE 和 DO WHILE 都做条件循环,但执行顺序差异直接影响 EA 的初始化逻辑。WHILE 先判条件再跑循环体,条件一开始为假就一次不执行;DO WHILE 无论如何先跑一次再判,适合至少要触发一次采样的场景。 在 MT5 策略测试器里跑一段空循环计数,WHILE(i<0) 的体根本不进,i 终值保持 0;换成 DO WHILE(i<0) 即便条件假,体也执行一次,i 变成 1。这个差别在挂单刷新、指标缓冲预填时容易埋 bug。 外汇与贵金属杠杆交易高风险,循环逻辑写错可能瞬间错单,建议把这类代码丢进脚本用 Print 打点验证,而不是凭直觉。

循环为什么比 IF-ELSE 更危险

这套材料只作教学用,别拿去直接跑实盘策略。外汇和贵金属波动剧烈,任何代码逻辑漏洞都可能放大亏损风险,验证前请先在 MT5 策略测试器用历史数据跑一遍。 上篇讲了 IF-ELSE 做条件分流,思路直白但代码一长就难读。语言设计者补了循环语句,本质是为了把重复逻辑压成几行可读结构,而不是靠堆叠 IF 来硬写。 但循环是控制流里最易翻车的指令之一。一个边界条件写错,程序就卡进无限循环,MT5 终端会一直占着资源不退出。不少初学者被这种死循环劝退,干脆不敢碰循环。 建循环有两条路:一是在主流程外调函数或过程,二是直接用控制流语句。先从控制流讲,后面再拆函数式写法——后者虽绕,却有避开某些陷阱的理由,留到后续篇说。 读这篇前你得懂变量和常量,尤其是位宽和类型怎么限制取值。不清楚就去翻操作符那篇打底。FOR 语句写起来顺手却也有短板,替代语句风险更高,下节先铺概念再定先讲哪个。

「循环不是洪水猛兽,是省命的紧凑写法」

不少写 MQL5 的人对循环有本能恐惧,根源就两点:一是怕写成死循环,程序卡住你还以为 MT5 在慢吞吞算东西;二是循环真跑起来可能迭代几千甚至上百万次,现实项目里有时一跑就是几小时,排错极痛苦。不过教学场景里大多是几千次规模,耗时也就几秒到几分钟,像纯 MQL5 写的神经网络训练就是典型例子。 那为什么还要用?核心就一个词:紧凑。算阶乘时,数字小还能硬抄代码 01 那种写法——把 counter 加一、value 乘 counter 重复五遍。可一旦算 20 的阶乘,手动复制粘贴不仅烦,出错概率也高得离谱。 代码 02 用函数加 static 变量封装了单步阶乘,OnStart 里连调五次 Factorial 才算出前五项。这已经比纯手抄干净,但要计算超大数,你还是得疯狂 Ctrl+C / Ctrl+V,每次换个新数还得改实现。循环能把这种重复压成几行,管理起来才是人干的事。 下面两段代码原文,前者是手搓五步阶乘,后者是函数化封装,开 MT5 新建脚本粘进去跑,看 Experts 日志里打印的 Factorial of N => V 就能直观对比。外汇和贵金属 EA 里用循环务必设终止条件,否则实盘滑点叠加死循环可能让订单逻辑失控,风险很高。

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">uchar counter = class="num">0;
    class="type">class="kw">ulong value = class="num">1;

    Print("Factorial of ", counter, " => ", value);
    counter = counter + class="num">1;
    value = value * counter;
    Print("Factorial of ", counter, " => ", value);
    counter = counter + class="num">1;
    value = value * counter;
    Print("Factorial of ", counter, " => ", value);
    counter = counter + class="num">1;
    value = value * counter;
    Print("Factorial of ", counter, " => ", value);
    counter = counter + class="num">1;
    value = value * counter;
    Print("Factorial of ", counter, " => ", value);
}
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)
{
    Factorial();
    Factorial();
    Factorial();
    Factorial();
    Factorial();
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void Factorial(class="type">void)
{
    class="kw">static class="type">uchar counter = class="num">0;
    class="kw">static class="type">class="kw">ulong value = class="num">1;

    Print("Factorial of ", counter, " => ", value);

◍ 把阶乘循环拆给 MT5 看

上面这段 MQL5 片段是一个累加式阶乘计算的尾部循环,逻辑很直白:每跑一轮就把计数器加 1,再用当前值去乘计数器。 在 MT5 里新建一个脚本,把这段直接贴进 OnStart,初始化 value=1、counter=0,跑完 5 轮后 value 会停在 120(即 5!),这是一个可立刻验证的整数现象。 外汇与贵金属杠杆高、滑点随机,这类纯数学循环虽不涉及下单,但常嵌在仓位阶梯计算里;调 counter 初值或乘序,结果会非线性跳变,建议开 MT5 逐行断点看寄存器。

MQL5 / C++
class="num">19.    counter = counter + class="num">1;
class="num">20.    value = value * counter;
class="num">21. }
class="num">22. class=class="str">"cmt">//+------------------------------------------------------------------+

常见问题

在循环里加计数器或时间上限,比如最多跑 1000 次就 break,避免死循环卡住终端。
do while 先执行一次再判断条件,适合至少要跑一次的逻辑;while 可能一次都不跑,看是否允许零次执行。
可以,把代码贴给小布,它会指出循环边界风险和可能的死循环点,并给改写建议。
循环用几行就能算任意数阶乘,if-else 写死层数还难改,循环是更紧凑省事的写法。
危险来自无退出条件的死循环,不是循环本身;写好边界条件它就是省命的紧凑工具。