MQL5 编程基础:数组(基础篇)
📘

MQL5 编程基础:数组(基础篇)

第 1/3 篇

「MQL5 里数组到底怎么排」

MQL5 的数组分一维和多维,索引默认从 0 开始,这一点和 C 系语言一致,但 MT5 在运行时会对越界访问直接抛错而非静默截断。写 EA 或指标时,若用 ArrayResize() 动态扩容量,旧数据默认保留在低位,新元素补到尾部。 静态数组在声明时就要给定长度,例如 double a[10]; 表示 10 个双精度浮点,占用连续内存。实测在 64 位 MT5 终端里,这类数组的随机读写延迟通常在纳秒级,但跨周期拷贝大数组(超过 10 万元素)会明显拖慢 OnCalculate 的 tick 响应。 动态数组更灵活,配合 ArraySetAsSeries() 可把时间序翻转,让最新价落在索引 0,老数据往后排。做价格行为分析时,这种倒置能少写不少偏移计算,但也容易在循环里搞反方向,建议开 MT5 用下面代码自测一遍。

MQL5 / C++
class="type">class="kw">double price[];
ArraySetAsSeries(price, true);
CopyClose(_Symbol, _Period, class="num">0, class="num">100, price);
class=class="str">"cmt">// price[class="num">0] 为最新收盘价,price[class="num">99] 为 class="num">100 根 K 线前

◍ 数组和变量到底差在哪

不少写 EA 的新手对数组有本能的抵触,其实它和普通变量本质是一类东西。抛开符号细节,写法和声明逻辑差别很小,只是数组名后面带了一对中括号。 声明时最能看出分野:普通变量得一个一个起名,数组只要写一次名字,在括号里填元素个数就行。当你要处理几十个价格样本时,用数组比堆 Variable0、Variable1…… 要干净太多。 有人怕数组,纯粹是怕那两个方括号 [ ] 找不着键位。它们就贴在 Enter 键两侧,左开右合,记住一次就不再别扭。 下面这段对照很直接:左边三个独立 double 变量做加法,右边用长度为 3 的数组做完全一样的计算。差异只在方括号里的下标,从 0 开始数。

MQL5 / C++
Variable0=class="num">1;
Variable1=class="num">2;
Variable2=Variable0+Variable1;
class="type">class="kw">double Variable[class="num">3];
Variable[class="num">0]=class="num">1;
Variable[class="num">1]=class="num">2;
Variable[class="num">2]=Variable[class="num">0]+Variable[class="num">1];

从 0 开始计数的数组索引

MQL5 里的数组是一组共用同一个名字、按编号排列的变量,所有元素必须同类型(int、double 等),数组大小就是实际元素个数。容易踩坑的是:元素索引从 0 起算,所以最后一个元素的索引比数组长度小 1。 比如声明 double Variable[3],真实元素是 Variable[0]、Variable[1]、Variable[2],肉眼看「长度 3」和「最大下标 2」对不上,但相比那些下标从 1 开始、或用末位下标代表长度的语言,这种 0-based 设计在指针寻址和循环处理上更干净。 要拿到数组实际长度,别手算,直接调 ArraySize()。下面这段代码跑完,Size 会被赋值为 3,你可以在 MT5 里建个脚本粘进去验证。

MQL5 / C++
class="type">class="kw">double Variable[class="num">3];
class="type">class="kw">double Variable[class="num">3];
class="type">int Size=ArraySize(Variable);
逐行拆解:第 1、2 行重复声明了同尺寸 double 数组 Variable[3](实际写脚本留一行即可,这里只是原文示例);第 3 行用 ArraySize(Variable) 取元素总数赋给 int 型 Size,结果恒为 3。外汇与贵金属 EA 开发中滥用全局数组需注意内存与越界风险,下标写错可能静默崩单。

MQL5 / C++
class="type">class="kw">double Variable[class="num">3];
class="type">class="kw">double Variable[class="num">3];
class="type">int Size=ArraySize(Variable);

「静态与动态数组的边界怎么划」

MQL5 里数组分两种:声明时直接给定长度的就是静态数组,比如 double Variable[3] 或用 #define SIZE 3double Variable[SIZE],这两种写法长度在运行期都锁死,程序里改不了。 声明时只写 double Variable[]、不填长度的,是动态数组。用之前必须先用 ArrayResize(Variable,3) 把大小撑开,否则就是个空壳。动态数组的核心好处是执行期间能反复 ArrayResize 改尺寸,这是和静态最本质的区别。 不再需要的时候,调 ArrayFree(Variable) 把数组释放掉,效果等同于 ArrayResize(Variable,0),大小归零、内存交还。常见用法是在函数开头清一遍,或者确认后续逻辑不再采集数据时释放,减少 MT5 终端的内存占用。 想确认某个数组到底是什么类型,用 ArrayIsDynamic(Variable) 即可:动态返回 true,静态返回 false。开 MT5 随便建个脚本把下面代码贴进去跑一下,能在观测窗口直接看到 dynamicArray 的取值差异。

MQL5 / C++
<span class="keyword">class="type">class="kw">double</span> Variable[<span class="number">class="num">3</span>];
<span class="preprocessor">class="macro">#define SIZE <span class="number">class="num">3</span></span>
<span class="keyword">class="type">class="kw">double</span> Variable[SIZE];
<span class="keyword">class="type">class="kw">double</span> Variable[];
<span class="functions">ArrayResize</span>(Variable,<span class="number">class="num">3</span>);
<span class="functions">ArrayFree</span>(Variable);
<span class="functions">ArrayResize</span>(Variable,<span class="number">class="num">0</span>);
<span class="keyword">class="type">bool</span> dynamicArray=<span class="functions">ArrayIsDynamic</span>(Variable);

◍ 声明即赋值:静态数组的初始化套路

做 MT5 面板时,常要一次性排一排同类型按钮,每个按钮文字不同。与其复制几十行 ObjectCreate,不如直接把字符串塞进数组,再让循环去迭代——声明和赋值的活可以在同一行干完。 下面这种写法里,数组大小不用手写:花括号里有几个值,编译器就定多大。它本质还是静态数组,只是尺寸由值列表隐式决定。 string Variable[] = {"Button 1", "Button 2", "Button 3"}; 你也可以显式写 Variable[3],不会报错。但后面要加按钮或减按钮时,得同时改两处;更稳的做法是用 ArraySize() 拿长度,主逻辑里只认这个函数返回的值,值列表随便增删。 如果所有元素都要同一个初值,ArrayInitialize() 一行搞定。比如对 double 数组执行后,四个元素全是 1。只填部分元素就用 ArrayFill(),从下标 0 开始填 2 个 1、再从下标 2 填 2 个 2,跑完得到 [1,1,2,2] 这种分段初值。 别把数组大小硬编码进循环边界,外汇和贵金属 EA 面板迭代快,改一处值列表却漏改尺寸常量,轻则按钮缺失重则数组越界报错。

MQL5 / C++
class="type">class="kw">string Variable[] = {"Button class="num">1", "Button class="num">2", "Button class="num">3"};
class="type">class="kw">string Variable[class="num">3] = {"Button class="num">1", "Button class="num">2", "Button class="num">3"};
ArrayInitialize(Variable,class="num">1);
class="type">class="kw">double Variable[class="num">4];
ArrayFill(Variable,class="num">0,class="num">2,class="num">1);
ArrayFill(Variable,class="num">2,class="num">2,class="num">2);

循环里别让 ArraySize 反复拖后腿

处理静态数组时,按任务需求决定正向还是反向跑 for 循环即可,编译期大小已知,没什么额外开销。 动态数组才容易踩坑。正确做法是先取一次 ArraySize 存进变量,再拿变量当循环上限;这样函数只调用一次。 若把 ArraySize() 直接写进循环条件,每次迭代都会重新调用,循环耗时显著拉长——调用函数比读变量贵得多,这种写法不建议留着。 算法允许的话,反向循环从 ArraySize(Variable)-1 跑到 0,函数同样只在开头算一次,速度就回来了。外汇与贵金属 EA 高频跑数组时,这类细节可能直接影响 tick 处理延迟,属于高风险环境下的隐性损耗。

MQL5 / C++
class=class="str">"cmt">//--- forwards
for(class="type">int i=class="num">0; i<SIZE; i++){ 
  class=class="str">"cmt">// some manipulations on the Variable[i] element
}
class=class="str">"cmt">//--- backwards
for(class="type">int i=SIZE-class="num">1; i>=class="num">0; i--){
  class=class="str">"cmt">// some manipulations on the Variable[i] element
}
class="type">int Size=ArraySize(Var);
for(class="type">int i=class="num">0; i<Size; i++){
  class=class="str">"cmt">// some manipulations on the Variable[i] element
}
for(class="type">int i=class="num">0; i<ArraySize(Variable); i++){
   class=class="str">"cmt">// some manipulations on the Variable[i] element
}
for(class="type">int i=ArraySize(Variable)-class="num">1; i>=class="num">0; i--){
  class=class="str">"cmt">// some manipulations on the Variable[i] element
}

常见问题

MQL5数组索引从0开始,第一个元素是arr[0],最后一个为arr[ArraySize(arr)-1]。循环时条件写i<ArraySize(arr)就不会越界。
单个数值用普通变量,同类型多个数值用数组。存10个收盘价直接声明double close[10],比建10个变量清爽且能用循环批量处理。
可以。把代码贴给小布,它能指出数组越界、静态数组未初始化、动态数组未Resize等常见坑,并给修改建议。
静态数组声明时定长不可改,越界即报错;动态数组用ArrayResize扩长度,不扩就写超原大小会运行时错。
会。循环前把int n=ArraySize(arr)存好,循环里用n判断,避免每次迭代重复调用函数。