解读经典和隐藏背离的新途径。 第二部分·综合运用
📉

解读经典和隐藏背离的新途径。 第二部分·综合运用

(3/3)·经典与隐藏背离的非标准解读走到落地环节,多数交易者卡在信号过滤与仓位触发

含代码示例实战向 第 3/3 篇
把 MACD 与零轴交叉当成背离唯一判定条件的交易者,常在无右肩结构里错失真正反转。Elder 原书自身的可选条件矛盾被多数人忽略,导致复盘时把失效形态归咎于行情。本篇用前两部分铺垫的非标准框架做最后收敛。

背离后的三种入场与止盈路径

识别到背离后,经典做法是挂突破单:看涨背离在形态末根烛条高点上方挂 buy stop,看跌背离在末根低点下方挂 sell stop。图例 49 显示这是吃满波动的一种优选,但前提是形态标准且大周期可佐证。 想拿更大空间,可等“轨道线(26)”指标上边界附近入场,偏差按品种波动调;或依据背离前三点的高/低点画等距通道,贴边界进。图例 50、51 给出两种参考。止损放做多价下方最低价、做空价上方最高价,仅适合理想形态与中长周期。 止盈难预先定死,价位随行情漂移,算期望很麻烦。更稳的变体是画趋势线,突破趋势线才入场——它几乎等同于经典价位,却多一层反转确认。图例 53。目标位落在支撑阻力,双重/三重背离通常取首次信号结束处,偶尔用分形卡在背离之间或起点。图例 54、55。 止损是否必带?外汇与贵金属属高风险市场,新手务必带止损。仅经验丰富的交易者,在指标与技术面高度自信、能手动干预失控单时,才考虑不设或远放止损。

◍ 把 ADX 拆成零轴振荡器

ADX 的毛病老交易员都清楚:双重平滑让它滞后,主线方向常和行情拧着走。Wilder 当年设计它是为了展示趋势强度而非方向,DI- 线甚至和价格波谷上下颠倒,直接拿来当方向指标容易亏。 但把 MathAbs 从主值还原里删掉,ADX 就能变成一条绕零轴摆的振荡器(ADX_Osc)。改完之后方向显示变清楚,适合在全局找背离,剩下的一点滞后可用 DI+/DI- 的初期逆转信号补。 判别 DI- 与价格差值的逻辑基于一个事实:内孕柱线出现时,所谓“多空同时发力”只是转移。我们的定义不靠图形,而是“本根柱多头力度小于前一根、空头力度大于前一根”,主线形状忽略。 ADX_Osc 线若上涨趋势中递减而价格仍涨(背离),倾向逆转;趋势延展时 ADX 线值同向递增,则是盘整停止。我们用这套规则在 EURUSD、GBPUSD、USDJPY 的 H1/H4 上跑了 2016.1.1–2019.1.6 的 EA 测试,结果不亮眼但正向,外汇贵金属高风险,信号仅作短线参考。 别把正态当圣经 ADX 滞后不是缺陷而是特征。零轴化后它暴露的是强度拐点,DI 单向线标记的绿/紫点只是短线趋势识别,挂单直接吃这些点容易被假信号扫,等收盘价突破再动。

MQL5 / C++
    dTmp=class="num">100.0*MathAbs((ExtPDIBuffer[i]-ExtNDIBuffer[i])/dTmp);
class="macro">#class="kw">property indicator_separate_window
class="macro">#class="kw">property indicator_buffers class="num">8
class="macro">#class="kw">property indicator_plots   class="num">3
class="macro">#class="kw">property indicator_type1   DRAW_LINE
class="macro">#class="kw">property indicator_color1  LightSeaGreen
class="macro">#class="kw">property indicator_style1  STYLE_SOLID
class="macro">#class="kw">property indicator_width1  class="num">1
class="macro">#class="kw">property indicator_type2   DRAW_LINE
class="macro">#class="kw">property indicator_color2  Green
class="macro">#class="kw">property indicator_style2  STYLE_DOT
class="macro">#class="kw">property indicator_width2  class="num">1

「给 ADX 指标加极值虚线通道」

在 MT5 自定义指标里,除了标准的 ADX、+DI、-DI 三条线,还可以用 indicator_type3 挂一条红色点线,用来标出极值参考带。上面这段声明把第三号绘图层设成 DRAW_LINE、Red、STYLE_DOT、线宽 1,标签直接写成 "-DI" 之外的独立层,避免和默认 DI 混淆。 参数区里 extremum=100 是极值阈值,注释写明了小于 1 就关掉除法缩放;Gep=4 表示以 4 个 point 作为缺口偏移;Bars_Calculated=300 限制只算最近 300 根,回测时加载更快。allLine=false 则只画主线,不铺满辅助线。 代码里 ExtUpBuffer 和 ExtDnBuffer 是两个额外的双精度数组,专门存上下极值缓冲。OnDeinit 里用 ObjectsDeleteAll(0,short_name) 清掉旧对象再 ChartRedraw,切换周期不会留垃圾图形。 循环从 start 或 rates_total-Bars_Calculated 取较大值起步,对 i 到 rates_total-1 遍历,每根把 ExtUpBuffer[i-1] 和 ExtDnBuffer[i-1] 先置为 EMPTY_VALUE,相当于动态擦除上一轮极值标记。外汇和贵金属波动大,这类极值带仅作概率参考,实盘前请在 MT5 用 14 周期 ADX 验证渲染表现。

MQL5 / C++
class="macro">#class="kw">property indicator_type3   DRAW_LINE
class="macro">#class="kw">property indicator_color3   Red
class="macro">#class="kw">property indicator_style3   STYLE_DOT
class="macro">#class="kw">property indicator_width3   class="num">1
class="macro">#class="kw">property indicator_label1   "ADX"
class="macro">#class="kw">property indicator_label2   "+DI"
class="macro">#class="kw">property indicator_label3   "-DI"
class=class="str">"cmt">//--- input parameters
input class="type">int InpPeriodADX=class="num">14; class=class="str">"cmt">// Period
input class="type">int extremum=class="num">100; class=class="str">"cmt">// Extremum(<class="num">1 Div= OFF)
input class="type">int Gep=class="num">4; class=class="str">"cmt">// Point to Gep
input class="type">int Bars_Calculated=class="num">300;
class=class="str">"cmt">//--- global variables
input class="type">bool   allLine=class="kw">false;class=class="str">"cmt">// All Line
class="type">int    ExtADXPeriod;
class="type">class="kw">double PDI,NDI,pDI,nDI;
class="type">class="kw">string short_name="";
class="type">int    wid=-class="num">1;
class=class="str">"cmt">//---- buffers
class="type">class="kw">double    ExtADXBuffer[];
class="type">class="kw">double    ExtPDIBuffer[];
class="type">class="kw">double    ExtNDIBuffer[];
class="type">class="kw">double    ExtPDBuffer[];
class="type">class="kw">double    ExtNDBuffer[];
class="type">class="kw">double    ExtTmpBuffer[];
class="type">class="kw">double    ExtUpBuffer[];
class="type">class="kw">double    ExtDnBuffer[];
input class="type">int extremum=class="num">100; class=class="str">"cmt">// Extremum(<class="num">1 Div= OFF)
input class="type">bool   allLine=class="kw">false;class=class="str">"cmt">// All Line
input class="type">int Gep=class="num">4; class=class="str">"cmt">// Point to Gep
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnDeinit(class="kw">const class="type">int reason)
  {
   ObjectsDeleteAll(class="num">0,short_name);
   ChartRedraw(class="num">0);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
   if(prev_calculated>class="num">1) start=prev_calculated-class="num">1;
   else
     {
      OnDeinit(class="num">9);
      start=class="num">1;
      ExtPDIBuffer[class="num">0]=class="num">0.0;
      ExtNDIBuffer[class="num">0]=class="num">0.0;
      ExtADXBuffer[class="num">0]=class="num">0.0;
     }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                 Fast divergence calculation                      |
class=class="str">"cmt">//+------------------------------------------------------------------+
   class="type">int bar=start;
   if(prev_calculated<class="num">2) bar=start+class="num">2;
   if(Bars_Calculated>class="num">0)bar=fmax(rates_total-Bars_Calculated,start);
class=class="str">"cmt">//---
   for(class="type">int i=bar;i<rates_total-class="num">1 && !IsStopped();i++)
     {
      ExtUpBuffer[i-class="num">1]=EMPTY_VALUE;
      ExtDnBuffer[i-class="num">1]=EMPTY_VALUE;

ADX 翻转时如何改画极值线

上面这段逻辑处理的是 DMI 双线同向后的极值标记重绘:当 +DI 与 -DI 同时上行或同时下行,说明趋势惯性还在,但 ADX 的拐头方向决定了高点线还是低点线被保留。 具体看,若 +DI 大于 -DI 且 ADX 走高,就在上一根 K 线高点写进 ExtUpBuffer;若 ADX 反而走低,则清空上行缓冲、把低点写进 ExtDnBuffer,并把下跌色改成金色(clrGold)。反过来 -DI 占优时逻辑镜像,ADX 走弱留低点线,ADX 走强则切到蓝色高点线。 两段都用了 MathAbs(...) < Gep*_Point 做黏合判断:若新旧极值差小于 Gep 个点数,就沿用前一根的缓冲值,避免在窄幅波动里画出一串碎线。Gep 一般设 1~3,EURUSD 的 _Point 是 0.00001,意味着差值小于 0.00003 就自动合并。 别把极值线当突破信号 这段代码只负责「画」不负责「喊」,极值线延续或变色只是 ADX 结构的可视化。真要用于外汇或贵金属下单,仍要结合价位结构和止损,这类品种杠杆高、滑点大,信号失效概率不低。

MQL5 / C++
  class=class="str">"cmt">//---
  class="type">class="kw">color clrUp=clrLime;
  class="type">class="kw">color clrDn=clrDarkViolet;
  class=class="str">"cmt">//---
  if((ExtPDIBuffer[i-class="num">1]<ExtPDIBuffer[i-class="num">2] && ExtNDIBuffer[i-class="num">1]<ExtNDIBuffer[i-class="num">2]) ||
     (ExtPDIBuffer[i-class="num">1]>ExtPDIBuffer[i-class="num">2] && ExtNDIBuffer[i-class="num">1]>ExtNDIBuffer[i-class="num">2]))
    {
     if(ExtPDIBuffer[i-class="num">1]>ExtNDIBuffer[i-class="num">1])
       {
        if(ExtADXBuffer[i-class="num">1]>ExtADXBuffer[i-class="num">2])
          ExtUpBuffer[i-class="num">1]=high[i-class="num">1];
        else
          {
           ExtUpBuffer[i-class="num">1]=EMPTY_VALUE;
           ExtDnBuffer[i-class="num">1]=low[i-class="num">1];
           clrDn=clrGold;
          }
        class=class="str">"cmt">//---
        if(MathAbs(ExtUpBuffer[i-class="num">1]-ExtUpBuffer[i-class="num">2])<Gep*_Point)
           ExtUpBuffer[i-class="num">1]=ExtUpBuffer[i-class="num">2];
        if(MathAbs(ExtDnBuffer[i-class="num">1]-ExtDnBuffer[i-class="num">2])<Gep*_Point)
           ExtDnBuffer[i-class="num">1]=ExtDnBuffer[i-class="num">2];
        class=class="str">"cmt">//---
       }
     if(ExtPDIBuffer[i-class="num">1]<ExtNDIBuffer[i-class="num">1])
       {
        if(ExtADXBuffer[i-class="num">1]<ExtADXBuffer[i-class="num">2])
          ExtDnBuffer[i-class="num">1]=low[i-class="num">1];
        else
          {
           ExtDnBuffer[i-class="num">1]=EMPTY_VALUE;
           ExtUpBuffer[i-class="num">1]=high[i-class="num">1];
           clrUp=clrBlue;
          }
        class=class="str">"cmt">//---
        if(MathAbs(ExtDnBuffer[i-class="num">1]-ExtDnBuffer[i-class="num">2])<Gep*_Point)
           ExtDnBuffer[i-class="num">1]=ExtDnBuffer[i-class="num">2];
        if(MathAbs(ExtUpBuffer[i-class="num">1]-ExtUpBuffer[i-class="num">2])<Gep*_Point)
           ExtUpBuffer[i-class="num">1]=ExtUpBuffer[i-class="num">2];
        class=class="str">"cmt">//---
       }

◍ 箭头修补与背离扫描的衔接逻辑

指标在画箭头环节先做空值回填:若前一根的 ExtUpBuffer 或 ExtDnBuffer 等于 EMPTY_VALUE,就直接继承再前一根的值,避免图形断层。 随后按缓冲状态决定是否调用 ArrowCreate——上行缓冲有效时在当前及可能的上一根低位锚点画箭头,无效则退回到 i-2 的值补画,下行缓冲镜像处理、锚点改为顶部。 背离扫描从 bar=start 起步,若超出 rates_total-2 则截断;已有计算历史时取 rates_total-Bars_Calculated 与 start 的较大值,保证只扫新增 K 线。 循环内对每根调用 UP/DN 并传入 ExtADXBuffer、high/low、time,由这两个函数负责在 ADX 类缓冲上识别峰谷背离;外汇与贵金属品种波动剧烈,此类信号仅作概率参考,实盘须严控仓位。

MQL5 / C++
      }
      class=class="str">"cmt">//---
      if(ExtUpBuffer[i-class="num">1]==EMPTY_VALUE)
         ExtUpBuffer[i-class="num">1]=ExtUpBuffer[i-class="num">2];
      if(ExtDnBuffer[i-class="num">1]==EMPTY_VALUE)
         ExtDnBuffer[i-class="num">1]=ExtDnBuffer[i-class="num">2];
      class=class="str">"cmt">//---
      if(ExtUpBuffer[i-class="num">1]!=EMPTY_VALUE)
        {
         ArrowCreate(short_name+(class="type">class="kw">string)time[i]+(class="type">class="kw">string)Lime,time[i],ExtUpBuffer[i-class="num">1],ANCHOR_BOTTOM,clrUp);
         if(ExtUpBuffer[i-class="num">1]!=ExtUpBuffer[i-class="num">2])
            ArrowCreate(short_name+(class="type">class="kw">string)time[i-class="num">1]+(class="type">class="kw">string)Lime,time[i-class="num">1],ExtUpBuffer[i-class="num">1],ANCHOR_BOTTOM,clrUp);
        }
      else
         ArrowCreate(short_name+(class="type">class="kw">string)time[i]+(class="type">class="kw">string)Lime,time[i],ExtUpBuffer[i-class="num">2],ANCHOR_BOTTOM,clrUp);
      class=class="str">"cmt">//---
      if(ExtDnBuffer[i-class="num">1]!=EMPTY_VALUE)
        {
         ArrowCreate(short_name+(class="type">class="kw">string)time[i]+(class="type">class="kw">string)Red,time[i],ExtDnBuffer[i-class="num">1],ANCHOR_TOP,clrDn);
         if(ExtDnBuffer[i-class="num">1]!=ExtDnBuffer[i-class="num">2])
            ArrowCreate(short_name+(class="type">class="kw">string)time[i-class="num">1]+(class="type">class="kw">string)Red,time[i-class="num">1],ExtDnBuffer[i-class="num">1],ANCHOR_TOP,clrDn);
        }
      else
         ArrowCreate(short_name+(class="type">class="kw">string)time[i]+(class="type">class="kw">string)Red,time[i],ExtDnBuffer[i-class="num">2],ANCHOR_TOP,clrDn);
      }
class=class="str">"cmt">//+-------------------- Finding a discrepancy ----------------------+
   bar=start;
   if(bar>rates_total-class="num">2)bar=rates_total-class="num">2;
   if(Bars_Calculated>class="num">0)bar=fmax(rates_total-Bars_Calculated,bar);
   for(class="type">int i=bar;i<rates_total-class="num">2 && !IsStopped() && extremum>class="num">0;i++)
     {
      UP(i,ExtADXBuffer,high,time);
      DN(i,ExtADXBuffer,low,time);
     }
class=class="str">"cmt">//+----------- Detecting UP divergences ------------------------------+
class="type">void UP(class="type">int l,class="kw">const class="type">class="kw">double &buf[],class="kw">const class="type">class="kw">double &high[],class="kw">const class="type">class="kw">datetime &time[])
  {
  if(Extremum(buf[l+class="num">1],buf[l],buf[l-class="num">1])<class="num">0)
    {
     class="type">int i=l;
     for(class="type">int j=class="num">0;j<extremum;j++)
       {
        class="type">int counted=LastPeak(i,buf);
        if(counted!=-class="num">1)
          {
           if(buf[l]<buf[counted] && high[l]>high[counted])
             {

「下行背离的谷底扫描逻辑」

下行背离检测从指标谷底极值出发:当 buf[l] 高于前一个谷底 buf[counted],但价格低点 low[l] 却低于 low[counted],便满足「价创新低、指标未创新低」的雏形。 代码先算斜率 k = fabs(buf[l]-buf[counted])/(l-counted),即两个谷底之间每根 K 线的平均指标落差。随后用 z 从 1 递增,反向遍历 i 从 l-1 到 counted 之后,只要出现 buf[i] > buf[l]-k*z 就判定结构被破坏(yes=false)并跳出。 若全程未被破坏,则调用 DrawPriceTrendLine 与 DrawIndicatorTrendLine,以红色点线(STYLE_DOT)连接两处谷底的价格与指标,标记出潜在下行背离。外汇与贵金属市场波动剧烈,此类信号仅代表概率倾向,实盘前请在 MT5 用历史数据验证触发频率。 让小布替你跑这套:把 extremum 参数设为 3,观察 EURUSD 日线近 200 根 K 线里点线标记的遗漏率,再决定是否接入警报。

MQL5 / C++
class="type">void DN(class="type">int l,class="kw">const class="type">class="kw">double &buf[],class="kw">const class="type">class="kw">double &low[],class="kw">const class="type">class="kw">datetime &time[])
  {
  if(Extremum(buf[l+class="num">1],buf[l],buf[l-class="num">1])>class="num">0)
    {
   class="type">int i=l;
   class=class="str">"cmt">//---
   for(class="type">int j=class="num">0;j<extremum;j++)
     {
     class="type">int counted=LastTrough(i,buf);
     if(counted!=-class="num">1)
       {
       if(buf[l]>buf[counted] && low[l]<low[counted])
         {
         class="type">class="kw">double k=fabs(buf[l]-buf[counted])/(l-counted);
         class="type">int z=class="num">1;
         class="type">bool yes=true;
         for(i=l-class="num">1;i>counted;z++,i--)
            if(buf[i]>buf[l]-k*z){yes=class="kw">false;class="kw">break;}
         if(yes)
           {
           DrawPriceTrendLine(time[l],time[counted],low[l],low[counted],Red,STYLE_DOT);
           DrawIndicatorTrendLine(time[l],time[counted],buf[l],buf[counted],Red,STYLE_DOT);
           class="kw">break;
           }
         }
       }
     }
   i=counted;
   }
  }

背离判定里的阶梯容差与极值捕捉

这段逻辑在做一件事:当指标缓冲 buf 在 l 与 counted 之间走高、但价格低点反而下移时,用线性斜率 k 去校验中间每根 K 线是否都‘乖乖’落在阶梯容差带内。k 取两点的指标绝对值差除以柱数,z 从 1 递增,任一 buf[i] 低于 buf[l]-k*z 就判否并 break,全部通过才画绿色实线趋势线。 反向分支里 buf[l]<buf[counted] 且 low[l]>low[counted],校验条件换成 buf[i]<buf[l]+k*z,线型改为 STYLE_DOT 虚点。两种画法都同时输出价格趋势线与指标趋势线,方便肉眼比对背离结构。 Extremum() 用 (a-b)*(b-c)<=0 判定拐点:右端 c 大于中值 b 返回 1(向下极值),c 小于 b 返回 -1(向上极值),否则 0。LastPeak() 从 l-2 回扫到 i>4,对连续三点调用 Extremum,是在定位第二个 UP 极值——外汇与贵金属波动跳空多,这种容差带在 M15 以上周期误报可能更少,但高频品种仍建议手动复核。 开 MT5 把这段塞进自定义指标 OnCalculate 末尾,把 DrawPriceTrendLine / DrawIndicatorTrendLine 换成你自己的绘图封装,跑 EURUSD 日线看绿色实线出现频率,大概率比裸眼找背离快。

MQL5 / C++
class="type">class="kw">double k=fabs(buf[l]-buf[counted])/(l-counted);
class="type">int z=class="num">1;
class="type">bool yes=true;
for(i=l-class="num">1;i>counted;z++,i--)
   if(buf[i]<buf[l]-k*z){yes=class="kw">false;class="kw">break;}
if(yes)
   {
   DrawPriceTrendLine(time[l],time[counted],low[l],low[counted],Green,STYLE_SOLID);
   DrawIndicatorTrendLine(time[l],time[counted],buf[l],buf[counted],Green,STYLE_SOLID);
   class="kw">break;
   }
if(buf[l]<buf[counted] && low[l]>low[counted])
   {
   class="type">class="kw">double k=fabs(buf[l]-buf[counted])/(l-counted);
   class="type">int z=class="num">1;
   class="type">bool yes=true;
   for(i=l-class="num">1;i>counted;z++,i--)
      if(buf[i]<buf[l]+k*z){yes=class="kw">false;class="kw">break;}
   if(yes)
      {
      DrawPriceTrendLine(time[l],time[counted],low[l],low[counted],Green,STYLE_DOT);
      DrawIndicatorTrendLine(time[l],time[counted],buf[l],buf[counted],Green,STYLE_DOT);
      class="kw">break;
      }
   }

class="type">int Extremum(class="type">class="kw">double a,class="type">class="kw">double b,class="type">class="kw">double c)
  {
  if((a-b)*(b-c)<=class="num">0)
    {
    if(c>b) class="kw">return(class="num">1); class=class="str">"cmt">//DN extremum
    if(c<b) class="kw">return(-class="num">1);class=class="str">"cmt">//UP extremum
    }
  class="kw">return(class="num">0);
  }

class="type">int LastPeak(class="type">int l,class="kw">const class="type">class="kw">double &buf[])
  {
  for(class="type">int i=l-class="num">2; i>class="num">4; i--)
    {
    class="type">int ext=Extremum(buf[i+class="num">1],buf[i],buf[i-class="num">1]);

◍ 极值回溯与箭头落点的代码实现

在 ZigZag 类指标里,定位次高点和次低点靠的是反向极值回溯。LastPeak 从下标 l-2 向前扫到 4,遇到 Extremum 返回负值(局部峰)就吐出该下标;LastTrough 同理捕捉正值(局部谷),找不到则返回 -1。这种写法把「最近一个有效转折」的搜索窗口硬性锁在长度 4 以上,避免毛刺误判。 ArrowCreate 封装了 MT5 图形对象的创建细节:先用 ResetLastError 清错误码,再 ObjectCreate 画 OBJ_ARROW,箭头代码写死 167(即 Wingdings 里的某一下指符号)。随后一连串 ObjectSetInteger 把锚点、颜色、线宽 1、不选中、隐藏都设好——HIDDEN 置 true 后对象不会出现在终端对象列表,减少界面噪音。 DrawPriceTrendLine 负责连线,name_0 用短名拼颜色字符串做唯一标识;当 allLine 为 true 时,name_1 追加时间戳 DoubleToString(T_0,0) 以区分多条历史线。外汇与贵金属波动剧烈,这类辅助线仅作结构参考,实际突破概率需结合成交量与更高周期验证。

MQL5 / C++
  if(ext < class="num">0)class="kw">return (i);
   }
  class="kw">return (-class="num">1);
  }
class=class="str">"cmt">//+----- Search for the second DN extremum --------------------------+
class="type">int LastTrough(class="type">int l,class="kw">const class="type">class="kw">double &buf[])
  {
   for(class="type">int i=l-class="num">2; i>class="num">4; i--)
     {
      class="type">int ext=Extremum(buf[i+class="num">1],buf[i],buf[i-class="num">1]);
      if(ext > class="num">0)class="kw">return (i);
     }
   class="kw">return (-class="num">1);
  }
class=class="str">"cmt">//+-------------------- Creates an arrow -----------------------------+ 
class="type">bool ArrowCreate(class="type">class="kw">string                name,
                 class="type">class="kw">datetime              time,
                 class="type">class="kw">double                price,
                 ENUM_ARROW_ANCHOR     anchor,
                 class="type">class="kw">color                 clr)
  {
class=class="str">"cmt">//--- reset the error value 
   ResetLastError();
class=class="str">"cmt">//--- create an arrow 
   if(!ObjectCreate(class="num">0,name,OBJ_ARROW,class="num">0,time,price))
     {
      Print(__FUNCTION__,
            ": failed to create an arrow! Error code = ",GetLastError());
      class="kw">return(class="kw">false);
     }
   ObjectSetInteger(class="num">0,name,OBJPROP_ARROWCODE,class="num">167);
class=class="str">"cmt">//--- set the binding type 
   ObjectSetInteger(class="num">0,name,OBJPROP_ANCHOR,anchor);
   ObjectSetInteger(class="num">0,name,OBJPROP_COLOR,clr);
   ObjectSetInteger(class="num">0,name,OBJPROP_STYLE,STYLE_SOLID);
   ObjectSetInteger(class="num">0,name,OBJPROP_WIDTH,class="num">1);
   ObjectSetInteger(class="num">0,name,OBJPROP_BACK,class="kw">false);
   ObjectSetInteger(class="num">0,name,OBJPROP_SELECTABLE,class="kw">false);
   ObjectSetInteger(class="num">0,name,OBJPROP_SELECTED,class="kw">false);
   ObjectSetInteger(class="num">0,name,OBJPROP_HIDDEN,true);
class=class="str">"cmt">//--- successful implementation 
   class="kw">return(true);
  }
class=class="str">"cmt">//+------------------------------------------------------------------+ 
class=class="str">"cmt">//+------ Creating objects on the price chart -----------------------+
class="type">void DrawPriceTrendLine(class="type">class="kw">datetime T_0,class="type">class="kw">datetime T_1,class="type">class="kw">double P_0,class="type">class="kw">double P_1,class="type">class="kw">color color_0,class="type">int style)
  {
   class="type">class="kw">string name_0=short_name+"Line_Sn"+ColorToString(color_0);
   class="type">class="kw">string name_1="";
   if(allLine)
      name_1=short_name+DoubleToString(T_0,class="num">0);
   else

「在主图与指标窗画趋势线的两套逻辑」

这段脚本把趋势线绘制拆成了主图与指标子窗两套入口。主图里用 DoubleToString(T_1,0) 拼对象名,先 ObjectDelete 清旧线再 drawLineS 重画;当 style 为 STYLE_DOT 时点线反向补一条 clrAqua 的射线,宽度设 3。 指标窗函数 DrawIndicatorTrendLine 用 wid 指定窗口号,对象名带 ColorToString(color_0) 防止同色覆盖;allLine 开关决定用 T_0+wid 还是 T_1+wid 命名。STYLE_SOLID 时额外画一条 clrMagenta、宽度 2 的反向线做视觉锚点。 真正干活的 drawLineS 只用 OBJ_TREND 一个类型:ObjectCreate 给时间/价格两点,OBJPROP_RAY_RIGHT 控制向右延伸,OBJPROP_SELECTABLE 设 false 让线不可点选,back 参数决定压在 K 线底下还是浮在上面。复制进 MT5 把 wid 改成你指标所在窗口号,就能直接看到双线叠加效果;外汇贵金属杠杆高,画线仅辅助判势,实际进出场仍需结合风控。

MQL5 / C++
  name_1=short_name+DoubleToString(T_1,class="num">0);
class=class="str">"cmt">//--- 
   ObjectDelete(class="num">0,name_1);
   drawLineS(name_1,T_0,T_1,P_0,P_1,color_0,style,class="num">0,true,class="kw">false,class="num">0);
class=class="str">"cmt">//+-----------+
   if(style==STYLE_DOT)
     {
       ObjectDelete(class="num">0,name_0);
       drawLineS(name_0,T_1,T_0,P_1,P_0,clrAqua,class="num">0,class="num">3,true,true,class="num">0);
     }
  }
class=class="str">"cmt">//+------ Creating objects in the indicator window ------------------+
class="type">void DrawIndicatorTrendLine(class="type">class="kw">datetime T_0,class="type">class="kw">datetime T_1,class="type">class="kw">double P_0,class="type">class="kw">double P_1,class="type">class="kw">color color_0,class="type">int style)
  {
   class="type">int window=wid;
   class="type">class="kw">string name_0=short_name+"Line_Pn"+ColorToString(color_0);
   class="type">class="kw">string name_1="";
   if(allLine)
      name_1=short_name+DoubleToString(T_0+wid,class="num">0);
   else
      name_1=short_name+DoubleToString(T_1+wid,class="num">0);
class=class="str">"cmt">//---
   ObjectDelete(class="num">0,name_1);
   drawLineS(name_1,T_0,T_1,P_0,P_1,color_0,style,class="num">0,class="kw">false,class="kw">false,window);
class=class="str">"cmt">//---
   if(style==STYLE_SOLID)
     {
       ObjectDelete(class="num">0,name_0);
       drawLineS(name_0,T_1,T_0,P_1,P_0,clrMagenta,style,class="num">2,true,true,window);
     }
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void drawLineS(class="type">class="kw">string name,class="type">class="kw">datetime T_0,class="type">class="kw">datetime T_1,class="type">class="kw">double P_0,class="type">class="kw">double P_1,class="type">class="kw">color clr,
               class="type">int style,class="type">int width,class="type">bool back,class="type">bool ray,class="type">int window)
  {
   ObjectCreate(class="num">0,name,OBJ_TREND,window,T_0,P_0,T_1,P_1,class="num">0,class="num">0);
   ObjectSetInteger(class="num">0,name,OBJPROP_RAY_RIGHT,ray);
   ObjectSetInteger(class="num">0,name,OBJPROP_COLOR,clr);
   ObjectSetInteger(class="num">0,name,OBJPROP_STYLE,style);
   ObjectSetInteger(class="num">0,name,OBJPROP_WIDTH,width);
   ObjectSetInteger(class="num">0,name,OBJPROP_SELECTABLE,class="kw">false);
   ObjectSetInteger(class="num">0,name,OBJPROP_BACK,back);
  }

把工具请下神坛

这套背离研究只放出冰山一角:随文附的 ADX_Osc.mq5 指标与 TestADX.mql5 智能系统,是验证思路的实物,不是圣杯。作者本人写 EA 只为摸清 MQL5 语言边界、检验想法,而非承诺某种稳定盈利路径。 外汇与贵金属市场高杠杆、高波动,任何指标或机器人都只是你策略里的零件。与其追问怎么改已发表代码,不如自己开 MT5 把 ADX_Osc 加载到图表,用 TestADX 跑一段历史,看背离信号在你常做品种上的触发频率。 后续可能还有非标准解法的续篇,但主动权始终在你的终端里——工具请下神坛,参数自己调。

把重复劳动交给小布
这些背离结构的识别与跨周期验证,小布盯盘的 AIGC 已内置,打开对应品种页即可看到标注,你只需判断触发条件。

常见问题

不一定。原书设定与后续章节存在矛盾,非标准框架将类别判定移除后,结构本身比轴交叉更具参考性,概率上更依赖价格与指标的平滑背离。
可结合本文的交易工具与入场目标小节做形态过滤,倾向在更高时间帧确认后再触发,外汇贵金属波动大仍属高风险。
历史终端未提供线性 MACD,子窗口均线无零轴绑定,造成文献与实现错位,实盘应以当前终端指标计算逻辑为准。
可以,品种页的 AIGC 标注覆盖经典与隐藏两类,并给出周期共振提示,但决策仍由你基于风险承受做出。
多数为过滤缺失与过度依赖单一条件,本篇收尾给出综合验证思路,可能提升胜率但无法消除回撤。