MQL5 中如何调用指标·进阶篇
📘

MQL5 中如何调用指标·进阶篇

第 2/2 篇

用 IndicatorCreate 拿指标句柄的坑与写法

在 MT5 里用 IndicatorCreate() 拿指标句柄,成功就返回一个正数句柄,失败直接给 -1。凡是带参数的指标,调用前都得先填一个 MqlParam 结构数组,每个元素有 4 个字段,第一个 type 字段决定后面三个里哪个字段真正被当作参数用。 把创建逻辑塞进 OnInit() 而不是每笔订单都调一次,是基本常识——指标句柄只需在程序启动那一下建好。动态数组 params[] 声明时不写大小,所以必须用 ArrayResize() 先定长,移动平均线要传 4 个参数就 resize 成 4。 以快速 MA 为例:周期 5、偏移 0、MODE_SMA 简单平均、PRICE_CLOSE 收盘价,四个全是 int 类型,所以每一项的 type 都写 TYPE_INT,值进 integer_value。IndicatorCreate() 五个实参依次是 Symbol()、0(当前周期)、IND_MA、4、params,返回的句柄存进 MA1。 慢线只需把周期从 5 改成 21 重新建一次;ParabolicSAR 则不同,它的参数是 double,数组 type 要写 TYPE_DOUBLE、值进 double_value,且只要 2 个参数所以 ArrayResize(params,2)。外汇和贵金属波动大、杠杆高,句柄建错会导致指标读取失效,实盘前务必在策略测试器里先跑一遍确认返回值不为 -1。

MQL5 / C++
class="type">int MA1 = class="num">0,              class=class="str">"cmt">// 声明变量存储快速MA指标的句柄
    MA2 = class="num">0,              class=class="str">"cmt">// 声明变量存储慢速MA指标的句柄
    SAR = class="num">0;              class=class="str">"cmt">// 声明变量存储SAR指标的句柄
    
class="type">MqlParam params[];       class=class="str">"cmt">// 存储指标参数的数组
class="type">int OnInit()
{
class=class="str">"cmt">//---
class=class="str">"cmt">// 设置params的大小和被调用指标参数数量一致
  ArrayResize(params,class="num">4);
  class=class="str">"cmt">// 设置快速MA的周期
  params[class="num">0].type        =TYPE_INT;
  params[class="num">0].integer_value=class="num">5;
  class=class="str">"cmt">// 偏移
  params[class="num">1].type        =TYPE_INT;
  params[class="num">1].integer_value=class="num">0;
  class=class="str">"cmt">// 计算方法:简单平均
  params[class="num">2].type        =TYPE_INT;
  params[class="num">2].integer_value=MODE_SMA;
  class=class="str">"cmt">// 用于计算的价格类型:收盘价
  params[class="num">3].type        =TYPE_INT;
  params[class="num">3].integer_value=PRICE_CLOSE;
  
  MA1 = IndicatorCreate(Symbol(), class=class="str">"cmt">// 用于计算指标的交易品种
                        class="num">0,       class=class="str">"cmt">// 时间框架。class="num">0 代表当前时间框架
                        IND_MA,  class=class="str">"cmt">// ENUM_INDICATOR枚举值定义的指标类型
                        class="num">4,       class=class="str">"cmt">// 数组传递的参数数量
                        params   class=class="str">"cmt">// 参数数组
                        );
class=class="str">"cmt">//---
class="kw">return(class="num">0);
}

◍ 用 IndicatorCreate 拼出双均线加 SAR

在 MT5 里用 IndicatorCreate 动态挂指标,比直接调 iMA、iSAR 更底层,也更适合做多品种批量扫描。下面这段把快线、慢线和 SAR 一次性建出来,参数全走 MqlParam 结构体数组。 快线用了 8 周期简单平均,慢线用 21 周期,都是基于收盘价(PRICE_CLOSE)计算;注意 params 数组在创建慢线前不用重新 resize,因为还是 4 个整型参数。 SAR 部分先把 params 用 ArrayResize 砍到 2 个元素,步长 0.02、最大值 0.2,这是 MT5 里抛物线转向指标的默认区间。外汇和贵金属波动大,SAR 在单边市里可能反应滞后,实盘前务必在策略测试器里跑一遍。 代码里 Symbol() 和 0 分别代表当前品种和当期图表周期,换品种扫描时把 Symbol() 替成具体符号即可。

MQL5 / C++
  params[class="num">3].type        =TYPE_INT;
  params[class="num">3].integer_value=PRICE_CLOSE;

  MA1 = IndicatorCreate(Symbol(), class="num">0, IND_MA, class="num">4, params);

  class=class="str">"cmt">// 设置慢速MA的周期
  params[class="num">0].type        =TYPE_INT;
  params[class="num">0].integer_value=class="num">21;
  class=class="str">"cmt">// 偏移   
  params[class="num">1].type        =TYPE_INT;
  params[class="num">1].integer_value=class="num">0;
  class=class="str">"cmt">// 计算方法:简单平均
  params[class="num">2].type        =TYPE_INT;
  params[class="num">2].integer_value=MODE_SMA;
  class=class="str">"cmt">// 用于计算的价格类型:收盘价
  params[class="num">3].type        =TYPE_INT;
  params[class="num">3].integer_value=PRICE_CLOSE;

  MA2 = IndicatorCreate(Symbol(), class="num">0, IND_MA, class="num">4, params);


  class=class="str">"cmt">// 改变数组的大小来存储SAR指标的参数
  ArrayResize(params,class="num">2);
  class=class="str">"cmt">// 步长
  params[class="num">0].type        =TYPE_DOUBLE;
  params[class="num">0].double_value = class="num">0.02;
  class=class="str">"cmt">// 最大值
  params[class="num">1].type        =TYPE_DOUBLE;
  params[class="num">1].double_value = class="num">0.2;

  SAR = IndicatorCreate(Symbol(), class="num">0, IND_SAR, class="num">2, params);

class=class="str">"cmt">//---
  class="kw">return(class="num">0);
}

「用 iCustom 在启动阶段拿指标句柄」

获取指标句柄的第二类路子,是直接调技术指标函数。这类函数每个都对应 MT5 自带的一个标准指标,参数组合随目标指标而定。比如 iCCI() 拿 CCI 句柄时,要传品种、周期、平滑周期和价格类型——把最后一项换成另一个指标句柄,就能让该指标基于前级输出算,而不是裸价格。 iCustom() 比专函更灵活,能挂任何自定义指标。它前三个参数固定:品种填 NULL 即用当前品种(Symbol() 也行,差异极小)、周期填 0 表示当前图表周期、指标名必须已在 MQL5/Indicators/ 下编译好。后面跟着的才是被调指标的输入,类型顺序要对上,缺省就走默认。 句柄最好在 EA 初始化时一次性拿完,别放进 OnTick 反复申请。下面这段代码在 OnInit 里同时挂了两条均线(5 与 21 周期 SMA)和 ParabolicSAR,返回 0 即初始化成功。外汇与贵金属杠杆高,句柄失效或参数错配可能导致信号中断,实盘前务必在策略测试器跑一遍。 别把 NULL 和 0 当万能填法 若切换品种交易,NULL 不会自动跟票,跨品种 EA 里显式写 Symbol() 更稳;周期写 0 在加载多周期逻辑时容易踩坑,明确时段常量更不易误判。

MQL5 / C++
  CCI = iCCI(
                      Symbol(),            class=class="str">"cmt">// 交易品种
                      PERIOD_CURRENT,      class=class="str">"cmt">// 周期
                      class="num">20,                  class=class="str">"cmt">// 平滑周期
                      PRICE_CLOSE          class=class="str">"cmt">// 价格类型或者句柄
                      );
class="type">int OnInit()
  {
class=class="str">"cmt">//---
   MA1 = iCustom(NULL,class="num">0,"Custom Moving Average",
                                class="num">5,        class=class="str">"cmt">// 周期
                                class="num">0,        class=class="str">"cmt">// 偏移
                                MODE_SMA,  class=class="str">"cmt">// 计算方式
                                PRICE_CLOSE class=class="str">"cmt">// 在收盘价上进行计算
                   );
   MA2 = iCustom(NULL,class="num">0,"Custom Moving Average",
                                class="num">21,       class=class="str">"cmt">// 周期
                                class="num">0,        class=class="str">"cmt">// 偏移
                                MODE_SMA,  class=class="str">"cmt">// 计算方式
                                PRICE_CLOSE class=class="str">"cmt">// 在收盘价上进行计算
                   );
   SAR = iCustom(NULL,class="num">0,"ParabolicSAR",
                                class="num">0.02,     class=class="str">"cmt">// 步长
                                class="num">0.2       class=class="str">"cmt">// 最大值
                   );
class=class="str">"cmt">//---
   class="kw">return(class="num">0);
  }

收束

把指标句柄交给 CopyBuffer() 之后,真正干活的地方就在 OnTick() 里。上面那段代码每跳一次价就重拉最近 20 根柱的 MA 与 SAR 缓冲,复制失败立刻把错误码打进日志,思路直接能抄进自己的 EA。 外汇和贵金属杠杆高、滑点随机,这类轮询式取数在极端行情可能漏掉瞬时穿透,实盘前务必在 MT5 策略测试器用历史数据跑一遍。 MQL5 的指标调用远不止本文说的几种基础手法,用类封装句柄和缓冲会省掉大量重复代码,留着这个方向自己往后挖。

MQL5 / C++
class="type">void OnTick()
  {
class=class="str">"cmt">//---
class=class="str">"cmt">// 存储指标变量值的动态数组
class="type">class="kw">double _ma1[],
      _ma2[],
      _sar[];
class=class="str">"cmt">// 将数组设置成和时间序列一样,例如数组索引为0的元素
class=class="str">"cmt">// 存储最近一个柱形的值,索引为1的元素存储第二近柱形的值,等等。
  ArraySetAsSeries(_ma1, true);
  ArraySetAsSeries(_ma2, true);
  ArraySetAsSeries(_sar, true);
class=class="str">"cmt">// 使用指标句柄将指标的缓存值,复制到数组中,
class=class="str">"cmt">//这些数组正是用于这个目的
  if (CopyBuffer(MA1,class="num">0,class="num">0,class="num">20,_ma1) < class="num">0){Print("CopyBufferMA1 error =",GetLastError());}
  if (CopyBuffer(MA2,class="num">0,class="num">0,class="num">20,_ma2) < class="num">0){Print("CopyBufferMA2 error =",GetLastError());}
  if (CopyBuffer(SAR,class="num">0,class="num">0,class="num">20,_sar) < class="num">0){Print("CopyBufferSAR error =",GetLastError());}
class=class="str">"cmt">//---
  }

常见问题

先检查 symbol/period 是否与当前图表一致,再确认指标参数顺序和类型匹配;若仍失败多为指标名拼写或指标未编译进终端。
放在 OnInit 里用 iCustom 调用并保存句柄到全局变量,OnDeinit 里用 IndicatorRelease 释放,避免重复创建拖慢运行。
可以,小布能读取你的指标调用日志并提示参数不匹配或名称错误,省去手动逐行核对终端报错的麻烦。
用 IndicatorParameters 回读参数,并在前几根 K 线打印句柄值与缓冲长度,非空且长度匹配即加载成功。
句柄绑定了特定 period,切换周期后原句柄失效;需在周期变更时重新创建或改用随图表周期的参数。