指标喷发整体特征的计算(基础篇)
📘

指标喷发整体特征的计算(基础篇)

第 1/3 篇

指标喷发强度的整体刻画

在 MT5 里做价格行为分析时,单看某一根 K 线的指标突变容易误判,更稳妥的做法是把「喷发」当作一段时间内的整体特征来算。所谓喷发,通常指指标值在短时间内偏离其近期均值达到统计显著的距离,这类现象在贵金属与外汇的跳空时段尤其密集。 以 Sergey Pavlov 在 2014-03-10 发布的公开示例为例,该指标累计被社区查看 4685 次、评论 9 条,说明这类「整体特征计算」的需求在实盘群体里一直有存在感。你可以在 MT5 自带的自定义指标编辑器里,把一段回看窗口内的指标极值差除以平均绝对偏差,得到一个无量纲的喷发系数。 外汇与贵金属杠杆高、滑点随机,喷发系数只描述「偏离强度」,不预示方向;系数超过 3 倍历史中位数的窗口,后续波动率倾向放大,但是否进场仍要看结构。

◍ 喷发到底是哪根线上的什么点

指标喷发把分析重心从指标线本身挪到了它向过去或未来“喷”出的点集上。一个喷发点,本质是所选指标特定线在某个交叉处生成的坐标;同类点有抱团倾向,密集簇可能吸引价格,也可能把价格推离,这是后续做支撑阻力预判的底层逻辑。 实际标绘时,线数和平均周期、方差都是随机挑的,只要两条线在空间有交叉就能出喷发。上面这段代码用 iMA 与 iEnvelopes 做底:ENV 数组列了 11 个包络偏差,从 0.01 到 1.5237;MA 数组是 7 条均线周期 4/7/11/19/31/51/85,ma_period 固定为 140。CEmission 实例 EnvMa(0,300) 负责两条线交叉点的计算与显示。 喷发点用 Text 这类图形对象画,锚点要对准 K 线中心,尺寸可大范围调,这给“复杂喷发”留了很大扩展空间。外汇和贵金属波动大、杠杆高,这类标绘只是概率层面的结构参考,不能直接当入场信号。

MQL5 / C++
class=class="str">"cmt">//--- external variable for storing averaging period of the iEnvelopes indicator
input class="type">int   ma_period=class="num">140; class=class="str">"cmt">// averaging period of the iEnvelopes indicator
class=class="str">"cmt">//--- array for storing deviations of the iEnvelopes indicator
class="type">class="kw">double      ENV[]={class="num">0.01,class="num">0.0165,class="num">0.0273,class="num">0.0452,class="num">0.0747,class="num">01234,class="num">0.204,class="num">0.3373,class="num">0.5576,class="num">0.9217,class="num">1.5237};
class=class="str">"cmt">//--- array for storing iMA indicator periods
class="type">int         MA[]={class="num">4,class="num">7,class="num">11,class="num">19,class="num">31,class="num">51,class="num">85};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                      emission_of_MA_envelope.mq5 |
class=class="str">"cmt">//|                     Copyright class="num">2013, DC2008 |
class=class="str">"cmt">//|             [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2013, DC2008"
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class=class="str">"cmt">//---
class="macro">#include <GetIndicatorBuffers.mqh>
class="macro">#include <Emission.mqh>
class=class="str">"cmt">//--- external variable for storing averaging period of the iEnvelopes indicator
input class="type">int   ma_period=class="num">140;      class=class="str">"cmt">// averaging period of the iEnvelopes indicator
class=class="str">"cmt">//--- array for storing deviations of the iEnvelopes indicator
class="type">class="kw">double      ENV[]={class="num">0.01,class="num">0.0165,class="num">0.0273,class="num">0.0452,class="num">0.0747,class="num">01234,class="num">0.204,class="num">0.3373,class="num">0.5576,class="num">0.9217,class="num">1.5237};
class=class="str">"cmt">//--- array for storing the iMA indicator periods
class="type">int         MA[]={class="num">4,class="num">7,class="num">11,class="num">19,class="num">31,class="num">51,class="num">85};
class=class="str">"cmt">//--- array for storing pointers to the iMA and iEnvelopes indicators
class="type">int         handle_MA[];
class="type">int         handle_Envelopes[];
class=class="str">"cmt">//--- market data
class="type">class="kw">datetime    T[],prevTimeBar=class="num">0;
class="type">class="kw">double      H[],L[];
class="macro">#define      HL(a, b) (a+b)/class="num">2
class=class="str">"cmt">//--- class instances
CEmission      EnvMa(class="num">0,class="num">300);
PointEmission  pEmission;
class=class="str">"cmt">//--- drawing styles for points of emission
class="macro">#define      COLOR_UPPER  C&class="macro">#x27;class="num">51,class="num">255,class="num">255&class="macro">#x27;

「初始化里把均线和轨道指针一次建好」

EA 启动阶段最该做干净的事,是把后续 tick 要反复调用的指标句柄先建好,而不是每次报价都去动态申请。下面这段代码在 OnInit 里同时挂了两组指标:一组是多条周期不同的 SMA(中位数价),一组是包络带(Envelopes)。 颜色宏先定调:上轨用 C'0,51,255'(蓝),下轨 C'0,51,255' 实际是蓝、品红 MA 用 C'255,51,255',三个颜色写进 colorPoint 数组,配合 styleUpper / styleLower / styleMA 里统一的 158 号箭头、SMALL 尺寸,图表上三类点一眼能分。 建句柄的循环很直白:先按 MA 数组长度 resize handle_MA,再 iMA(NULL,0,MA[i],0,MODE_SMA,PRICE_MEDIAN) 逐条拿句柄;任一返回负值就 Print 出错周期并打印 GetLastError(),直接 return(-1) 终止加载。ENV 数组同理走 iEnvelopes,参数里 ma_period 和 ENV[i] 偏移百分比是外部传进来的,没写死。 OnDeinit 这里是空壳,没做句柄释放——MT5 终端退出时会自动回收,但如果你打算热重载参数,得自己补清理。OnTick 函数体被截断,真正的信号判断在后面章节。外汇和贵金属杠杆高,这类多指标 EA 在滑点扩大时可能漏信号,上 MT5 用策略测试器跑历史段先验证句柄是否零报错。

MQL5 / C++
class="macro">#define     COLOR_LOWER   C&class="macro">#x27;class="num">0,class="num">51,class="num">255&class="macro">#x27;
class="macro">#define     COLOR_MA      C&class="macro">#x27;class="num">255,class="num">51,class="num">255&class="macro">#x27;
class="type">color       colorPoint[]={COLOR_UPPER,COLOR_LOWER,COLOR_MA};
CodeColor   styleUpper={class="num">158,COLOR_UPPER,SMALL};
CodeColor   styleLower={class="num">158,COLOR_LOWER,SMALL};
CodeColor   styleMA={class="num">158,COLOR_MA,SMALL};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                     |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
   ArraySetAsSeries(T,true);
   ArraySetAsSeries(H,true);
   ArraySetAsSeries(L,true);
class=class="str">"cmt">//---
   class="type">int size=ArraySize(MA);
   ArrayResize(handle_MA,size);
class=class="str">"cmt">//--- create a pointer to the object - the iMA indicator
   for(class="type">int i=class="num">0; i<size; i++)
     {
      handle_MA[i]=iMA(NULL,class="num">0,MA[i],class="num">0,MODE_SMA,PRICE_MEDIAN);
      class=class="str">"cmt">//--- if an error occurs when creating the object, print the message
      if(handle_MA[i]<class="num">0)
        {
         Print("The iMA object[",MA[i],"] has not been created: Error = ",GetLastError());
         class=class="str">"cmt">//--- forced program termination
         class="kw">return(-class="num">1);
        }
     }
class=class="str">"cmt">//---
   size=ArraySize(ENV);
   ArrayResize(handle_Envelopes,size);
class=class="str">"cmt">//--- create a pointer to the object - the iEnvelopes indicator
   for(class="type">int i=class="num">0; i<size; i++)
     {
      handle_Envelopes[i]=iEnvelopes(NULL,class="num">0,ma_period,class="num">0,MODE_SMA,PRICE_MEDIAN,ENV[i]);
      class=class="str">"cmt">//--- if an error occurs when creating the object, print the message
      if(handle_Envelopes[i]<class="num">0)
        {
         Print("The iEnvelopes object[",ENV[i],"] has not been created: Error = ",GetLastError());
         class=class="str">"cmt">//--- forced program termination
         class="kw">return(-class="num">1);
        }
     }
class=class="str">"cmt">//---
   class="kw">return(class="num">0);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert deinitialization function                                   |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(const class="type">int reason)
  {
class=class="str">"cmt">//---
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert tick function                                               |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnTick()

抓取轨道与均线交叠的坐标

在 MT5 的 EA 或脚本里,先把当前品种、当前周期最近两根 K 线的时间、最高、最低抓进数组,这是后续所有几何计算的坐标基准。 CopyTime(NULL,0,0,2,T) 取 2 根 Bar 的时间戳,CopyHigh / CopyLow 同理取高低价;只用 2 根是因为交叠检测只依赖相邻两根的线性插值,数据量越小重绘越快。 下面这段把 iMA 与 iEnvelopes 的上下轨缓冲分别读入 ibMA[] 和 ibEnvelopesUpper[] / ibEnvelopesLower[],注意 CopyBufferAsSeries 最后一个参数 true 表示按时间序列正序填充,避免和 T[0] 对位错乱。 双重循环里对每一对 (均线 i, 轨道 j) 调用 EnvMa.CalcPoint,用上轨或下轨的两根值加均线两根值去解交点;若 pEmission.real 为真,就用含 GTC 毫秒数的 name 把点画到图上,保证同帧多次绘制不重名。 外汇与贵金属杠杆高,这类交点只是价格行为的几何标记,不代表方向确认,实盘前请在策略测试器用历史数据验证命中率。

MQL5 / C++
  {
class=class="str">"cmt">//--- market data
  CopyTime(NULL,class="num">0,class="num">0,class="num">2,T);
  CopyHigh(NULL,class="num">0,class="num">0,class="num">2,H);
  CopyLow(NULL,class="num">0,class="num">0,class="num">2,L);
class=class="str">"cmt">//--- fill the declared arrays with current values from all indicator buffers
  class="type">class="kw">string name;
  class="type">uint GTC=GetTickCount();
class=class="str">"cmt">//---- indicator buffers
  class="type">class="kw">double   ibMA[],ibMA1[];       class=class="str">"cmt">// arrays for the iMA indicator
  class="type">class="kw">double   ibEnvelopesUpper[];   class=class="str">"cmt">// array for the iEnvelopes indicator(UPPER_LINE)
  class="type">class="kw">double   ibEnvelopesLower[];   class=class="str">"cmt">// array for the iEnvelopes indicator(LOWER_LINE)
  for(class="type">int i=ArraySize(handle_MA)-class="num">1; i>=class="num">0; i--)
   {
    if(!CopyBufferAsSeries(handle_MA[i],class="num">0,class="num">0,class="num">2,true,ibMA))
      class="kw">return;
    class=class="str">"cmt">//---
    for(class="type">int j=ArraySize(handle_Envelopes)-class="num">1; j>=class="num">0; j--)
     {
      if(!GetEnvelopesBuffers(handle_Envelopes[j],class="num">0,class="num">2,ibEnvelopesUpper,ibEnvelopesLower,true))
        class="kw">return;
      class=class="str">"cmt">//--- find the intersection point of the iEnvelopes(UPPER_LINE) and iMA indicators
      pEmission=EnvMa.CalcPoint(ibEnvelopesUpper[class="num">1],ibEnvelopesUpper[class="num">0],ibMA[class="num">1],ibMA[class="num">0],T[class="num">0]);
      if(pEmission.real) class=class="str">"cmt">// if the intersection point is found, draw it in the chart
       {
        name="iEnvelopes(UPPER_LINE)"+(class="type">class="kw">string)j+"=iMA"+(class="type">class="kw">string)i+(class="type">class="kw">string)GTC;
        EnvMa.CreatePoint(name,pEmission,styleUpper);
       }
      class=class="str">"cmt">//--- find the intersection point of the iEnvelopes(LOWER_LINE) and iMA indicators
      pEmission=EnvMa.CalcPoint(ibEnvelopesLower[class="num">1],ibEnvelopesLower[class="num">0],ibMA[class="num">1],ibMA[class="num">0],T[class="num">0]);
      if(pEmission.real) class=class="str">"cmt">// if the intersection point is found, draw it in the chart
       {
        name="iEnvelopes(LOWER_LINE)"+(class="type">class="kw">string)j+"=iMA"+(class="type">class="kw">string)i+(class="type">class="kw">string)GTC;
        EnvMa.CreatePoint(name,pEmission,styleLower);
       }
     }
    class=class="str">"cmt">//---
    for(class="type">int j=ArraySize(handle_MA)-class="num">1; j>=class="num">0; j--)
     {
      if(i!=j)
       {
        if(!CopyBufferAsSeries(handle_MA[j],class="num">0,class="num">0,class="num">2,true,ibMA1))
          class="kw">return;

◍ 双均线交点落点与图表清理

这段逻辑干两件事:先算两条 iMA 指标在当前与上一根 K 线的交点,命中就在图上画点;再每根 K 线清一次旧对象,避免文本堆满画布。 交点计算靠 EnvMa.CalcPoint,喂入的是两条均线在 [1](前一根)和 [0](当前根)的报价,以及当前时间 T[0]。返回结构体里 real 为 true 才说明真交上了,此时拼一个带计数后缀的 name,调 CreatePoint 把标记钉在图上去。 清理段用 ObjectsTotal(0,0,-1) 拿全量对象数,只在 T[0] 大于 prevTimeBar(即新 BAR 成型)时跑一次。倒序遍历所有 OBJ_TEXT,凡时间早于当前 BAR 时间的直接 ObjectDelete 抹掉,最后 Comment 把残留对象数打印在左上角。 BIG 与 SMALL 两个宏分别定成 7 和 3,是交点标记两种尺寸,后面画点风格会按信号强弱二选一。外汇与贵金属杠杆高,这类辅助标记只帮你定位,不等于方向确认,实盘前请在 MT5 策略测试器里先跑一遍看对象数是否随 BAR 归零。

MQL5 / C++
class=class="str">"cmt">//--- find the intersection point of the iMA and iMA indicators
   pEmission=EnvMa.CalcPoint(ibMA1[class="num">1],ibMA1[class="num">0],ibMA[class="num">1],ibMA[class="num">0],T[class="num">0]);
   if(pEmission.real) class=class="str">"cmt">// if the intersection point is found, draw it in the chart
     {
      name="iMA"+(class="type">class="kw">string)j+"=iMA"+(class="type">class="kw">string)i+(class="type">class="kw">string)GTC;
      EnvMa.CreatePoint(name,pEmission,styleMA);
     }
   }
  }
 }
class=class="str">"cmt">//--- deletion of the graphical objects of emission not to stuff the chart
  if(T[class="num">0]>prevTimeBar) class=class="str">"cmt">// class="kw">delete once per bar
   {
    class="type">int  total=ObjectsTotal(class="num">0,class="num">0,-class="num">1);
    prevTimeBar=T[class="num">0];
    for(class="type">int obj=total-class="num">1;obj>=class="num">0;obj--)
     {
      class="type">class="kw">string obj_name=ObjectName(class="num">0,obj,class="num">0,OBJ_TEXT);
      class="type">class="kw">datetime obj_time=(class="type">class="kw">datetime)ObjectGetInteger(class="num">0,obj_name,OBJPROP_TIME);
      if(obj_time<T[class="num">0])
         ObjectDelete(class="num">0,obj_name);
     }
    Comment("Emission © DC2008      Objects = ",total);
   }
class=class="str">"cmt">//---
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                Emission.mqh |
class=class="str">"cmt">//|                     Copyright class="num">2013, DC2008 |
class=class="str">"cmt">//|             [MQL5官方文档] |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Copyright class="num">2013, DC2008"
class="macro">#class="kw">property link      "[MQL5官方文档]
class="macro">#class="kw">property version   "class="num">1.00"
class="macro">#define   BIG   class="num">7     class=class="str">"cmt">// point size
class="macro">#define   SMALL class="num">3     class=class="str">"cmt">// point size
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| pMABB structure                                                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">struct PointEmission
  {
   class="type">class="kw">double            x;    class=class="str">"cmt">// X-coordinate of the time point

「射线交点的结构体与基类实现」

把两条射线在相邻两根 bar 上的端点坐标喂进去,就能算出它们的理论交点。下面这套结构体先把「点」和「样式」拆开存,避免绘图逻辑和坐标计算耦合。 PointEmission 里 y 是价格坐标、t 是时间坐标、real 标记该点是否真实存在(比如平行线永不相交时 real=false)。CodeColor 则绑定了符号代码、颜色和线宽,方便同一类信号复用视觉风格。 CEmission 作为基类,用 lim_Left / lim_Right 限制信号只在最近若干根 bar 内可见,防止历史图形堆积拖慢 MT5 图表刷新。CalcPoint 接收 y1,y0(线1在[1]、[0]的Y值)与 yy1,yy0(线2对应值)及当前 bar 时间 t0,返回交点;CreatePoint 负责按 name 和 style 真正画到图上。 开 MT5 新建 EA 把这段直接贴进头文件,改 lim_Left=50、lim_Right=0,就能只显示最近 50 根 bar 内的射线交点,外汇与贵金属波动剧烈,这类信号仅作辅助、实战需自担高风险。

MQL5 / C++
class="type">class="kw">double y; class=class="str">"cmt">// Y-coordinate of the price point
class="type">class="kw">datetime t; class=class="str">"cmt">// t-coordinate of the point&class="macro">#x27;s time
class="type">bool real; class=class="str">"cmt">// whether the point exists
};
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| CodeColor structure |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">struct CodeColor
 {
 class="type">long Code; class=class="str">"cmt">// point symbol code
 class="type">color Color; class=class="str">"cmt">// point class="type">color
 class="type">int Width; class=class="str">"cmt">// point size
 };
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Base class for emissions |
class=class="str">"cmt">//+------------------------------------------------------------------+
class CEmission
 {
class="kw">private:
 class="type">int sec;
 class="type">int lim_Left; class=class="str">"cmt">// limiting range of visibility in bars
 class="type">int lim_Right; class=class="str">"cmt">// limiting range of visibility in bars
class="kw">public:
 PointEmission CalcPoint(class="type">class="kw">double y1, class=class="str">"cmt">// Y-coordinate of straight line class="num">1 on bar [class="num">1]
 class="type">class="kw">double y0, class=class="str">"cmt">// Y-coordinate of straight line class="num">1 on bar [class="num">0]
 class="type">class="kw">double yy1, class=class="str">"cmt">// Y-coordinate of straight line class="num">2 on bar [class="num">1]
 class="type">class="kw">double yy0, class=class="str">"cmt">// Y-coordinate of straight line class="num">2 on bar [class="num">0]
 class="type">class="kw">datetime t0 class=class="str">"cmt">// t-coordinate of the current bar Time[class="num">0]
 );
 class="type">bool CreatePoint(class="type">class="kw">string name, class=class="str">"cmt">// point name
 PointEmission &point, class=class="str">"cmt">// coordinates of the point
 CodeColor &style); class=class="str">"cmt">// point drawing style
 CEmission(class="type">int limitLeft,class="type">int limitRight);
 ~CEmission();
 };

常见问题

看指标线是否突破预设轨道并且与均线出现交叠点,交叠坐标越密集、偏离越大,喷发强度越高,可用代码抓取这些点来量化。
在 OnInit 里用 iMA 和轨道类各 new 一次指针并存入数组,后续直接用数组下标访问,避免每根 K 线重复创建拖慢运行。
可以,小布盯盘的 AIGC 已内置这类叠加诊断,打开对应品种页就能直接看到交叠坐标和喷发强度提示,不用自己写代码。
用结构体记录每根射线对象名,在新交点生成前遍历删除上一批同名对象,保持图表只留当前周期的落点。
基类统一管坐标计算和绘制,结构体存具体交点数据,后续加新指标类型只继承不改原逻辑,扩展喷发诊断更干净。