将指标应用至其他指标(基础篇)
📘

将指标应用至其他指标(基础篇)

第 1/2 篇

「把指标叠到另一个指标上跑」

MT5 有个常被忽略的能力:把某个指标直接加载到另一个指标的窗口里,而不是只贴在价格主图上。这样你能看到两层计算叠加后的形态,比如把动量类指标挂到波动率指标内部,观察二者的共振区。 官方示例文档里记录了一个 2013-08-23 发布的演示案例,累计被查看 4408 次、收藏 35 次,说明这种用法在老交易员圈子里早有实践基础。 实操路径:在 MT5 导航器里右键指标 → 属性 → 『应用于』下拉选『前一个指标』,即可让当前指标读取上一层指标的输出缓冲区,而非原始收盘价。外汇与贵金属杠杆高,叠加指标只辅助判势,信号失效概率始终存在,须自行回测验证。

把指标叠在指标上

改进现有指标的一条实用路径,是让它作用在另一个指标的输出值上,而不是原始价格。这种做法在 MT5 里不需要重写底层计算,只要改变数据输入源。 我们以“真实强弱指数”(TSI)为例继续往下做。这个指标在前文“MQL5:创建自己的指标”里已经完整建过并跑通,本文直接把它当成被二次加工的对象。 对交易者来说,这意味着你能在 MT5 里把 TSI 的输出再接一层平滑或过滤,观察信号噪声是否被压低。外汇与贵金属杠杆高,叠加指标不改变品种固有的高风险属性,参数验证请在策略测试器里用历史数据过一遍。

◍ 把指标挂到另一指标上为什么算不出数

在 MT5 里写用 OnCalculate() 简短形式调用的指标时,很多人会默认计算源只能是价格。实际上计算源可以是其他指标——内置或自定义都行,但挂法不对就会出怪事。 做个具体验证:先放一个默认参数 RSI(14) 到图表,再把 True_Strength_Index_ver2.mq5 拖进 RSI 的子窗口,参数里选「Previous Indicator's Data」。预期是看到 TSI 线叠在 RSI 窗口,结果线没出现,数据窗口里 TSI 值要么开头全空、后面恒为 -100。 根因在 begin 参数。它告诉函数 price[] 前面有几个元素是空值不能参与计算。价格数据挂上去时 begin 永远是 0,因为每根 K 线都有 OHLC;但换成 RSI 这类指标当源,前面若干根可能没值,begin 就不是 0。原版 TSI 代码没把 begin 透传进计算循环,等于从 price[0] 硬算,自然大面积错。 外汇和贵金属指标叠加高风险,错算可能误导进出场。改代码时把 begin 接进索引偏移,再上 MT5 用同法挂一次,看数据窗口 TSI 是否脱离 -100。

MQL5 / C++
class="type">int OnCalculate(const class="type">int rates_total,      class=class="str">"cmt">// price[]数组大小;
                   const class="type">int prev_calculated, class=class="str">"cmt">// 上次调用计算后的价格柱的数量
                   const class="type">int begin,           class=class="str">"cmt">// price[]数组开始计算的索引
                   const class="type">class="kw">double& price[]      class=class="str">"cmt">// 指标计算的依据数组
   );

「begin 参数暴露了哪些价格被跳过」

把指标挂到 RSI(14) 窗口并指定「使用上一指标数据」后,price[] 并不是从头都能算。OnCalculate() 的 begin 参数明确标出了数组里哪些索引只是占位、不能进计算。 下面这段在函数头加的调试代码只跑一次:当 begin>0 时,把 begin 值和 price[] 总长度打到日志,再逐个打印 0 到 begin 的数组元素。你能在 MT5 终端的「专家」标签里直接看到,比如 begin 可能等于 13,意味着前 14 个值(i=0…13)是 RSI 预热期没算出来的空档。 外汇与贵金属波动剧烈、杠杆高风险突出,这类底层索引错位是自定义指标画歪的常见根因。改完把指标重新拖进 RSI 窗口,对照日志确认 begin 对应的 price[i] 确实未被绘制,就能排除一半「指标对不上」的误报。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 自定义指标迭代函数                                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnCalculate(const class="type">int rates_total,    class=class="str">"cmt">// price[]数组大小;
                 const class="type">int prev_calculated,class=class="str">"cmt">// 上次调用计算后的价格柱的数量;
                 const class="type">int begin,          class=class="str">"cmt">// price[]数组开始计算的索引 
                 const class="type">class="kw">double &price[])    class=class="str">"cmt">// 指标计算的依据数组;
  {
class=class="str">"cmt">//--- 确定price[]数组数值仅输出一次的标志
   class="kw">static class="type">bool printed=false;
class=class="str">"cmt">//--- 如果begin变量不为0,有些数值不应该被计算在内
   if(begin>class="num">0 && !printed)
     {
      class=class="str">"cmt">//--- 让我们输出这个数值
      Print("用于计算的数据索引begin等于 ",begin,
            "   price[] 数组长度 =",rates_total);
      class=class="str">"cmt">//--- 让我们显示不应该计算的数值
      for(class="type">int i=class="num">0;i<=begin;i++)
        {
         Print("i =",i,"  value =",price[i]);
        }
      class=class="str">"cmt">//--- 设置标志确定我们已经记录了这些数值
      printed=true;
     }
  }

常见问题

多数情况是主指标未向外暴露逐根数值,或被叠加指标引用的缓冲区为空。先确认主指标有plot输出且begin参数正确,再挂副指标。
由主指标的begin参数决定,begin=n表示前n根不参与计算。可在代码里打印起始索引验证实际跳过数量。
可以,把品种页打开让小布跑诊断,它会标出缓冲区引用异常和begin跳过的根数,省去你手动查代码。
主指标begin设了大于0的值,前面K线无数据。调小begin或给足历史缓冲即可从头显示。
副指标按主指标输出频率取值,周期错配会导致错位或空白。保持两者基于同一周期数据源再叠加。