MQL5 初学者:EA 交易技术指标使用指南·进阶篇
📊

MQL5 初学者:EA 交易技术指标使用指南·进阶篇

(2/3)· 从 iMA 延伸到 iAC、iADXWilder 等 6 个内置指标,搞清句柄创建与序列索引的坑

偏理论进阶 第 2/3 篇
很多开发者在 OnInit 外随手建指标句柄,参数一变就重复初始化拖慢 EA。把句柄统一在启动阶段建好并检查 INVALID_HANDLE,是避开自动交易锦标赛那类翻车的前提。

◍ 用 OnTick 拉取鳄鱼线缓冲

在 MT5 的 EA 骨架里,订单逻辑往往从 OnTick 入口开始。这里不急着下单,而是先把鳄鱼指标(Alligator)的三条线缓冲抓进数组,供后续价格行为判断使用。 调用 GetAlligatorBuffers 时传入指标句柄、起始位置 0、取样长度 100,以及 Jaws、Teeth、Lips 三个数组,最后一个 true 表示按时间序列倒序填充。若返回失败直接 return,避免脏数据继续跑策略。 这段代码本身不下单,但它是后面所有信号判定的数据底座。打开 MT5 新建 EA,把这段塞进 OnTick 开头,编译后从观测窗口能看到三个数组被 100 根 K 线的鳄鱼值填满。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA订单函数                                                        |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//--- 设置数组索引为时间序列
class=class="str">"cmt">//--- 使用Alligator指标数值填充数组
class=class="str">"cmt">//--- 如果出错则返回
   if(!GetAlligatorBuffers(Alligator_handle,class="num">0,class="num">100,Jaws,Teeth,Lips,true)) class="kw">return;
  }

「用 iAC 句柄把动能加速度拉进 EA」

加速震荡指标(AC)量的是中间价慢速与快速均线之差再减去这两条差值的均线,本质在捕捉价格加速度的转向。MT5 里不用手算,直接调 iAC(NULL,0) 拿句柄最省事。 下面这段 EA 骨架演示了怎么把 AC 接进来:初始化时建句柄,失败就打印错误并退出;OnTick 里用 CopyBufferAsSeries 把最近 100 根柱的 AC 值按时间序灌进数组。 #include <GetIndicatorBuffers.mqh> //---- 指标数组 double AC[]; // iAC指标对应的数组 //---- 指标句柄 int AC_handle; // iAC指标的句柄 //+------------------------------------------------------------------+

//EA初始化函数

//+------------------------------------------------------------------+ int OnInit() { //--- 创建iAC指标 AC_handle=iAC(NULL,0); //--- 如果对象创建出错则报告 if(AC_handle<0) { Print("iAC指标创建失败: 运行时错误 =",GetLastError()); //--- 强制程序退出 return(-1); } return(0); } //+------------------------------------------------------------------+

//EA订单函数

//+------------------------------------------------------------------+ void OnTick() { //--- 使用当前iAC的值填充AC[]数组 //--- 设置AC[] 索引方向为时间序列 //--- 如果出错则返回 if(!CopyBufferAsSeries(AC_handle,0,0,100,true,AC)) return; } 逐行看:第 1 行引头文件拿辅助函数;AC[] 存数值,AC_handle 存指标引用。OnInit 中 iAC(NULL,0) 表示用当前品种、当前周期。OnTick 的 CopyBufferAsSeries 第 4 参 100 决定取多少根,调大能看更长惯性。 外汇与贵金属杠杆高,AC 仅作动能参考,信号失效概率不低。开 MT5 把这段代码贴进 EA,把 100 改成 50 对比一下刷新频率,就能直观感觉加速度指标的滞后程度。

MQL5 / C++
class="macro">#include <GetIndicatorBuffers.mqh>
class=class="str">"cmt">//---- 指标数组
class="type">class="kw">double      AC[];                 class=class="str">"cmt">// iAC指标对应的数组
class=class="str">"cmt">//---- 指标句柄
class="type">int         AC_handle;            class=class="str">"cmt">// iAC指标的句柄
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA初始化函数                                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- 创建iAC指标
   AC_handle=iAC(NULL,class="num">0);
class=class="str">"cmt">//--- 如果对象创建出错则报告
   if(AC_handle<class="num">0)
     {
      Print("iAC指标创建失败: 运行时错误 =",GetLastError());
class=class="str">"cmt">//--- 强制程序退出
      class="kw">return(-class="num">1);
     }
   class="kw">return(class="num">0);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA订单函数                                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//--- 使用当前iAC的值填充AC[]数组
class=class="str">"cmt">//--- 设置AC[] 索引方向为时间序列
class=class="str">"cmt">//--- 如果出错则返回
   if(!CopyBufferAsSeries(AC_handle,class="num">0,class="num">0,class="num">100,true,AC)) class="kw">return;
  }

用 iAD 句柄抓累积分布流向

累积/分配指标(AD)把收盘价在当日区间的位置和成交量加权,用来观察资金是往多头还是空头一侧堆积。MT5 里它靠 iAD() 拿句柄,再靠 CopyBuffer 把数值拉进数组,比老式 iCustom 调用干净得多。 下面这段 EA 骨架在 OnInit 里用 iAD(NULL,0,VOLUME_TICK) 建句柄,参数分别是当前品种、当前周期、按 tick 成交量计。句柄小于 0 就打印错误并退出,避免后面空跑。 OnTick 中 CopyBufferAsSeries 一次性取最近 100 根 Bar 的 AD 值,索引按时间序列排,最新值在 AD[0]。你在 MT5 里把这段贴进 EA,编译后开 EURUSD 的 M1 图表,就能在观测窗口看到 AD 数组随 tick 流实时翻动,验证多空累积倾向。外汇和贵金属杠杆高,AD 只反映历史堆积,转向信号要结合价格结构看,别单靠它下注。

MQL5 / C++
class="macro">#include <GetIndicatorBuffers.mqh>
class=class="str">"cmt">//---- 指标数组
class="type">class="kw">double      AD[];                 class=class="str">"cmt">// iAD指标对应的数组
class=class="str">"cmt">//---- 指标句柄
class="type">int         AD_handle;           class=class="str">"cmt">// iAD指标的句柄
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA初始化函数                                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- 创建iAD指标
   AD_handle=iAD(NULL,class="num">0,VOLUME_TICK);
class=class="str">"cmt">//--- 如果对象创建出错则报告
   if(AD_handle<class="num">0)
     {
      Print("iAD指标创建失败: 运行时错误 =",GetLastError());
class=class="str">"cmt">//--- 强制程序退出
      class="kw">return(-class="num">1);
     }
   class="kw">return(class="num">0);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA订单函数                                                        |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//--- 使用iAD指标当前值填充AD[]数组
class=class="str">"cmt">//--- 设置AD[]数组的索引方式为时间序列
class=class="str">"cmt">//--- 如果出错则返回
   if(!CopyBufferAsSeries(AD_handle,class="num">0,class="num">0,class="num">100,true,AD)) class="kw">return;
  }

◍ 用 iADX 抓三条线缓冲

ADX 在 MT5 里不是单值指标,iADX 一口气吐出主线和正负方向线三条缓冲。上面这段把句柄建好、在 OnTick 里拉 100 根柱的数据灌进数组,省得你每根 K 线都去调 CopyBuffer。 建句柄时周期传 0 代表当前图表周期,参数 14 是默认 ADX 周期。若 ADX_handle 小于 0 说明指标没建出来,直接打印错误码并让 OnInit 返回 -1,EA 起不来,避免后面空跑。 GetADXBuffers 那行把 Main、PlusDI、MinusDI 三个 double 数组按时间序列填充,从 0 到 100 根。实盘里你可以把 100 改成需要的深度,比如只看最近 50 根来判断 +DI 是否持续压过 -DI,从而倾向弱趋势过滤。外汇与贵金属杠杆高,ADX 只描述趋势强度,不预示方向,信号失效概率不低,验证前先用策略测试器跑一遍。

MQL5 / C++
class="macro">#include <GetIndicatorBuffers.mqh>
class=class="str">"cmt">//---- 指标数组
class="type">class="kw">double      Main[];      class=class="str">"cmt">// iADX中MAIN_LINE对应的数组
class="type">class="kw">double      PlusDI[];    class=class="str">"cmt">// iADX中PLUSDI_LINE对应的数组
class="type">class="kw">double      MinusDI[];   class=class="str">"cmt">// iADX中MINUSDI_LINE对应的数组
class=class="str">"cmt">//---- 指标句柄
class="type">int         ADX_handle;                 class=class="str">"cmt">// iADX指标的句柄
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA初始化函数                                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- 创建iADX指标
   ADX_handle=iADX(NULL,class="num">0,class="num">14);
class=class="str">"cmt">//--- 如果对象创建出错则报告
   if(ADX_handle<class="num">0)
     {
      Print("iADX指标创建失败: 运行时错误 =",GetLastError());
      class=class="str">"cmt">//--- 强制程序退出
      class="kw">return(-class="num">1);
     }
   class="kw">return(class="num">0);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA订单函数                                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//--- 设置数组索引为时间序列
class=class="str">"cmt">//--- 使用指标缓冲区的当前值填充数组
class=class="str">"cmt">//--- 如果出错则返回 
   if(!GetADXBuffers(ADX_handle,class="num">0,class="num">100,Main,PlusDI,MinusDI,true)) class="kw">return;
  }

「用 iADXWilder 拉三条线进 EA」

Wilder 版 ADX 和原生 iADX 的区别只在平滑算法,MT5 里单独给了 iADXWilder 接口。想在 EA 里同时拿 ADX 主线、+DI、-DI,得先建三个 double 数组挂缓冲,再用指标句柄去取。 下面这段初始化只做一件事:用 iADXWilder(NULL,0,14) 在当前品种、当前周期、周期参数 14 上建句柄。句柄小于 0 就打印错误并强制退出 OnInit,避免后面空句柄乱跑。 OnTick 里调 GetADXWilderBuffers,从 0 到 100 根 K 线把三条线填进数组;最后一个 true 表示按时间序索引。取数失败直接 return,不拿残值做判断。 开 MT5 把这段贴进 EA,编译后接 Print(Main[0],PlusDI[0],MinusDI[0]),能看到最新三根线数值。外汇和贵金属波动大,DI 交叉只反映强弱倾向,不代表趋势必然延续,实盘前先用策略测试器跑历史验证。

MQL5 / C++
class="macro">#include <GetIndicatorBuffers.mqh>
class=class="str">"cmt">//---- 指标数组
class="type">class="kw">double      Main[];      class=class="str">"cmt">// iADXWilder指标中的MAIN_LINE对应的数组
class="type">class="kw">double      PlusDI[];    class=class="str">"cmt">// iADXWilder指标中的PLUSDI_LINE对应的数组
class="type">class="kw">double      MinusDI[];  class=class="str">"cmt">// iADXWilder指标中的MINUSDI_LINE对应的数组
class=class="str">"cmt">//---- handles for indicators
class="type">int         ADXWilder_handle;                 class=class="str">"cmt">// iADXWilder指标的句柄
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA初始化函数                                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- 创建iADXWilder指标
   ADXWilder_handle=iADXWilder(NULL,class="num">0,class="num">14);
class=class="str">"cmt">//--- 如果对象创建出错则报告
   if(ADXWilder_handle<class="num">0)
     {
      Print("创建 iADXWilder 指标失败: 运行时错误 =",GetLastError());
      class=class="str">"cmt">//--- 强制程序退出
      class="kw">return(-class="num">1);
     }
   class="kw">return(class="num">0);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA订单函数                                                        |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//--- 设置数组索引方式为时间序列
class=class="str">"cmt">//--- 使用所有指标对应缓冲区的当前值填充数组
class=class="str">"cmt">//--- 如果出错则返回
   if(!GetADXWilderBuffers(ADXWilder_handle,class="num">0,class="num">100,Main,PlusDI,MinusDI,true)) class="kw">return;
  }

用句柄把鳄鱼三线拉进EA

iAlligator 在 MT5 里返回的是指标句柄,不是直接的价格数组。上面这段把经典参数 13/8/8/5/5/3 一次性传给构造函数:颚线周期13偏移8,齿线周期8偏移5,唇线周期5偏移3,平滑用 MODE_EMA、价格取中位数。 初始化阶段若句柄小于0,说明指标创建失败,直接打印运行时错误并 return(-1) 终止 EA,避免后面空句柄去读缓冲区。 OnTick 里靠 GetAlligatorBuffers 把最近100根 K 线的 Jaws、Teeth、Lips 三个数组填好,时间序列索引打开,最新值在[0]。外汇和贵金属波动剧烈,鳄鱼线只是概率过滤,实盘前请在 MT5 策略测试器用不同品种验证参数敏感性。 把这段直接贴进 EA,改 NULL 为具体品种名就能在别的图表上复用;句柄创建一次即可,别在 OnTick 里反复调用 iAlligator,否则可能拖慢 tick 处理。

MQL5 / C++
class="macro">#include <GetIndicatorBuffers.mqh>
class=class="str">"cmt">//---- 指标数组
class="type">class="kw">double      Jaws[];   class=class="str">"cmt">// iAlligator指标中GATORJAW_LINE对应的数组
class="type">class="kw">double      Teeth[];  class=class="str">"cmt">// iAlligator指标中GATORTEETH_LINE对应的数组
class="type">class="kw">double      Lips[];   class=class="str">"cmt">// iAlligator指标中GATORLIPS_LINE对应的数组
class=class="str">"cmt">//---- 指标句柄
class="type">int         Alligator_handle;                  class=class="str">"cmt">// iAlligator指标的句柄
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA初始化函数                                                   |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">//--- 创建iAlligator指标
   Alligator_handle=iAlligator(NULL,class="num">0,class="num">13,class="num">8,class="num">8,class="num">5,class="num">5,class="num">3,MODE_EMA,PRICE_MEDIAN);
class=class="str">"cmt">//--- 如果对象创建出错则报告
   if(Alligator_handle<class="num">0)
     {
      Print("创建iAlligator指标失败: 运行时错误 =",GetLastError());
      class=class="str">"cmt">//--- 强制程序退出
      class="kw">return(-class="num">1);
     }
   class="kw">return(class="num">0);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| EA订单函数                                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()
  {
class=class="str">"cmt">//--- 设置数组索引方式为时间序列
class=class="str">"cmt">//--- 使用所有指标缓冲区当前值填充到数组中
class=class="str">"cmt">//--- 如果出错则返回
   if(!GetAlligatorBuffers(Alligator_handle,class="num">0,class="num">100,Jaws,Teeth,Lips,true)) class="kw">return;
  }
把句柄体检交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到指标句柄有效性预警,你只需专注策略逻辑而非底层校验。

常见问题

OnInit 在 EA 启动时只跑一次,足以完成指标初始化且参数稳定;若在 OnTick 内建句柄,参数变更会触发重复初始化,浪费资源还可能引发逻辑错乱。
可以,小布盯盘的品种页会对 INVALID_HANDLE 类异常做主动提示,省去你手写校验的重复劳动。
两者均输出 ADX 系数值,但平滑算法不同,Wilder 版采用其经典递归平滑,对波动响应更缓,选用取决于策略对延迟的容忍度。
MQL5 沿用了时间序列约定,[0] 是当前未成形柱、[1] 为上一成形柱,这样写循环和计算符合交易者直觉也利于编译器优化。