解读经典与隐性背离的新途径·进阶篇
🔍

解读经典与隐性背离的新途径·进阶篇

(2/3)·多数背离策略卡在指标与价格的机械比对,本文给出供给需求视角的隐性识别路径

偏理论 第 2/3 篇

把价格新高和指标掉头划等号就开反向单,是背离交易里最容易被扫损的坏习惯。经典分类讲了十几年,但隐性背离为什么常在趋势延续里出现,很少被说清。这篇不重复教科书,直接从参与资金意愿切入看背离本质。

◍ 背离交易里那些容易踩的坑

背离形态只在趋势中存在,横盘阶段硬找背离基本是浪费时间。很多新手把震荡里的指标摆动当成信号,结果被来回扫损,这点必须先钉死。 除了指标层面的背离,入场还得靠价格行为或日本烛条确认。单看 MACD 或类似趋势指标的红绿柱背离就冲进去,胜率撑不住;尤其当价格靠近零轴交叉,信号往往被削弱甚至直接作废。 新闻行情里的蜡烛不能用来测背离。重大数据发布时波动骤增,烛条拉出极端影线,这类噪音生成的「背离」十有八九是假信号,回测里也经不起复盘。 背离要「明确」才有用——不光你自己看出来,其他市场参与者也得能认出同一结构,这种共识下决策正确的概率才会上移。另外只盯最近的波峰波谷,别拿半年前的老高点和现在比,那样只会把图表看乱。 外汇和贵金属杠杆高、滑点猛,背离出错是常态。任何信号都按常规仓位和止损规则走,别把概率优势当成确定性。

用加速器振荡指标挖非标准背离

标准背离规则之外,还有一条更靠前的路径:在比尔·威廉姆斯的加速器振荡指标(AO)上做文章。AO 的方向变化领先于驱动力,而驱动力又领先于价格,所以它天然是早一步的确认信号。代价是噪声会变多,但换来的是更密集的入场信号和更早的减速提示。 这种非标准背离仍沿用常用背离的框架,只是入场点的判定方式不按常规来。工具的核心目的就是抓背离,因此变量只留一个——用于判断背离的柱线数量,初始化成多色直方图。 可视化上,实线画经典背离,虚线画隐性背离;红色对应看跌、绿色对应看涨。粗线专门标出价格图上的最后隐性背离,以及指标窗内的经典背离。这样一眼能分清信号层级。 下面这段初始化代码里,indicator_buffers 设成 2,但 indicator_plots 只有 1——说明一个绘图层背后挂了数据和颜色两个缓冲区。DATA_LIMIT 宏定义为 37,意味着少于 37 根柱线直接不计算,避免边缘噪声。外汇与贵金属波动剧烈,这类早信号策略需先在 MT5 策略测试器里验证再上实盘。

MQL5 / C++
class="macro">#class="kw">property indicator_separate_window
class=class="str">"cmt">//---- 用于指标计算和绘制的一个缓冲区
class="macro">#class="kw">property indicator_buffers class="num">2
class=class="str">"cmt">//---- 只使用一个图形构造
class="macro">#class="kw">property indicator_plots class="num">1
class=class="str">"cmt">//---- 指标绘制为一条线
class="macro">#class="kw">property indicator_type1 DRAW_COLOR_HISTOGRAM
class=class="str">"cmt">//---- 指标线使用蓝色
class="macro">#class="kw">property indicator_color1 Green,Red
class=class="str">"cmt">//----
class="macro">#class="kw">property indicator_width1 class="num">2
class=class="str">"cmt">//---- 指标线是连续的曲线
class="macro">#class="kw">property indicator_style1 STYLE_SOLID
class=class="str">"cmt">//---- 显示指标标签
class="macro">#class="kw">property indicator_label1 "AC_Div"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="kw">input class="type">int Bars_Calculated=class="num">1000;
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">string shortname="";
class="type">class="kw">double AC_buff[];
class="type">class="kw">double Color_buff[];
class="type">int wid;
class="type">int Handle_AC;
class=class="str">"cmt">//---
class="macro">#define DATA_LIMIT class="num">37
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 自定义指标初始化函数                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
{
class=class="str">"cmt">//---- 设置动态数组作为指标缓冲区
SetIndexBuffer(class="num">0,AC_buff,INDICATOR_DATA);
SetIndexBuffer(class="num">1,Color_buff,INDICATOR_COLOR_INDEX);
class=class="str">"cmt">//---- 设置指标绘图开始位置
PlotIndexSetInteger(class="num">1,PLOT_DRAW_BEGIN,DATA_LIMIT);
class=class="str">"cmt">//---- 初始化指标简称的变量
shortname="Accelerator_Divergence";
class=class="str">"cmt">//---- 创建在单独子窗口和工具提示中显示的名称
IndicatorSetString(INDICATOR_SHORTNAME,shortname);
class=class="str">"cmt">//---- 定义指标值的显示精度
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
class=class="str">"cmt">//---- 禁用绘制空指标值
PlotIndexSetDouble(class="num">0, PLOT_EMPTY_VALUE, class="num">0.0);
PlotIndexSetDouble(class="num">1, PLOT_EMPTY_VALUE, class="num">0.0);
class=class="str">"cmt">//--- 加速器指标的句柄
Handle_AC=iAC(NULL,class="num">0);
class=class="str">"cmt">//--- 查找图表子窗口的索引
wid=ChartWindowFind(class="num">0,shortname);
class=class="str">"cmt">//---
class="kw">return(INIT_SUCCEEDED);
}
class=class="str">"cmt">//---- 声明局部变量 
class="type">int limit,bar,pos;
class=class="str">"cmt">//---- 检查柱线数量是否足够进行计算
if(rates_total<DATA_LIMIT)
class="kw">return(class="num">0);
class="type">int barsCalculated=MathMin(Bars_Calculated,rates_total);
class=class="str">"cmt">//+------- 设置数组索引方向 ---------------------+
ArraySetAsSeries(close,true);
ArraySetAsSeries(AC_buff,true);
ArraySetAsSeries(low,true);
ArraySetAsSeries(high,true);
ArraySetAsSeries(Color_buff,true);
ArraySetAsSeries(time,true);
class=class="str">"cmt">//+--- 确定计算所需的柱线数量 --------+
limit=rates_total-DATA_LIMIT-class="num">1;
if(prev_calculated>class="num">0) limit=rates_total-prev_calculated;
pos=limit;
if(pos>barsCalculated)pos=limit;
class="type">int to_copy;
if(prev_calculated>rates_total || prev_calculated<class="num">0) to_copy=rates_total;
else
{
to_copy=rates_total-prev_calculated;

「AC 背离的极值扫描与画线逻辑」

加速振荡器(AC)的背离识别,核心在于先定位局部极值,再比较价格与指标的斜率方向。下面这段实现用 Extremum() 判断三点形态:当 (a-b)*(b-c)<0 且 b 处于零轴下方、c 回抬时记为向下极值(返回 1),反之在零轴上方、c 走低时记为向上极值(返回 -1),其余情况返回 0。 LastPeak() 与 LastTrough() 从当前棒 l 向后跳 5 根再搜索,直到 bar-2 为止,分别抓第二个向上/向下极值;若找不到返回 -1。这种 +5 的偏移是为了避开邻近噪声棒,实盘里你可以把 5 改成 3 或 8 来适配不同周期波动。 主循环里,对向上极值 l 调用 LastPeak 拿到 counted:若 AC[i]<AC[counted] 而 high[i]>high[counted],就是价格新高、动能走弱的典型看跌背离,用红色实线连价格与指标;若反过来 AC 走高、高点降低,则画红色点线。向下背离对称处理,用绿色标记。外汇与贵金属杠杆高,背离仅提示概率转折,须配合止损。 CopyBuffer 取数前用 IsStopped() 拦截终止信号,避免 MT5 卸载指标时崩线程;着色循环里 Color_buff 默认 0,仅当 AC[bar]<AC[bar+1] 时置 1,方便前端做直方图红绿切换。

MQL5 / C++
if(prev_calculated>class="num">0) to_copy++;
class=class="str">"cmt">//---
if(IsStopped()) class="kw">return(class="num">0); class=class="str">"cmt">//Checking for stop flag
class=class="str">"cmt">//+----- 主要数组 -------------------------------------+
if(CopyBuffer(Handle_AC,class="num">0,class="num">0,to_copy,AC_buff)<=class="num">0)
{
   Print("getting Accelerator Handle is failed! Error",GetLastError());
   class="kw">return(class="num">0);
}
class=class="str">"cmt">//+---------- 直方图着色 --------------------------------+
for(bar=limit; bar>=class="num">0 && !IsStopped(); bar--)
{
   Color_buff[bar]=class="num">0.0;
   if(AC_buff[bar]<AC_buff[bar+class="num">1])Color_buff[bar] =class="num">1.0;
   if(AC_buff[bar]>AC_buff[bar+class="num">1])Color_buff[bar] =class="num">0.0;
}
class=class="str">"cmt">//+----------- 检测向上背离 ------------------------------+
class="type">int bars=barsCalculated;
for(bar=pos; bar>=class="num">0 && !IsStopped(); bar--)
{
   class="type">int l=bar+class="num">2;
   if(Extremum(AC_buff[l+class="num">1],AC_buff[l],AC_buff[l-class="num">1])<class="num">0)
   {
      class="type">int i=l;
      class="type">int counted=LastPeak(l,bars,AC_buff);
      if(counted!=-class="num">1)
      {
         if(AC_buff[i]<AC_buff[counted] && high[i]>high[counted])
         {
            DrawPriceTrendLine(time[i],time[counted],high[i],high[counted],Red,STYLE_SOLID);
            DrawIndicatorTrendLine(time[i],time[counted],AC_buff[i],AC_buff[counted],Red,STYLE_SOLID);
         }
         if(AC_buff[i]>AC_buff[counted] && high[i]<high[counted])
         {
            DrawPriceTrendLine(time[i],time[counted],high[i],high[counted],Red,STYLE_DOT);
            DrawIndicatorTrendLine(time[i],time[counted],AC_buff[i],AC_buff[counted],Red,STYLE_DOT);
         }
      }
   }
class=class="str">"cmt">//+----------- 检测向下背离 ------------------------------+
   if(Extremum(AC_buff[l+class="num">1],AC_buff[l],AC_buff[l-class="num">1])>class="num">0)
   {
      class="type">int i=l;
      class="type">int counted=LastTrough(l,bars,AC_buff);
      if(counted!=-class="num">1)
      {
         if(AC_buff[i]>AC_buff[counted] && low[i]<low[counted])
         {
            DrawPriceTrendLine(time[i],time[counted],low[i],low[counted],Green,STYLE_SOLID);
            DrawIndicatorTrendLine(time[i],time[counted],AC_buff[i],AC_buff[counted],Green,STYLE_SOLID);
         }
         if(AC_buff[i]<AC_buff[counted] && low[i]>low[counted])
         {
            DrawPriceTrendLine(time[i],time[counted],low[i],low[counted],Green,STYLE_DOT);
            DrawIndicatorTrendLine(time[i],time[counted],AC_buff[i],AC_buff[counted],Green,STYLE_DOT);
         }
      }
   }
}
class=class="str">"cmt">//+----- 搜索第二个向上极值 --------------------------+
class="type">int LastPeak(class="type">int l,class="type">int bar,class="type">class="kw">double &buf[])
{
   for(class="type">int i=l+class="num">5; i<bar-class="num">2; i++)
   if(Extremum(buf[i+class="num">1],buf[i],buf[i-class="num">1])<class="num">0)class="kw">return (i);
   class="kw">return (-class="num">1);
}
class=class="str">"cmt">//+----- 搜索第二个向下极值 --------------------------+
class="type">int LastTrough(class="type">int l,class="type">int bar,class="type">class="kw">double &buf[])
{
   for(class="type">int i=l+class="num">5; i<bar-class="num">2; i++)
   if(Extremum(buf[i+class="num">1],buf[i],buf[i-class="num">1])> class="num">0)class="kw">return (i);
   class="kw">return (-class="num">1);
}
class=class="str">"cmt">//+-- 搜索极值 -------------------------------------------+
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 && b<class="num">0) class="kw">return(class="num">1); class=class="str">"cmt">//DN extremum
      if(c<b && b>class="num">0) class="kw">return(-class="num">1);class=class="str">"cmt">//UP extremum
   }
   class="kw">return(class="num">0);
}
class=class="str">"cmt">//+------ 在价格图表上创建对象 -----------------------+

◍ 趋势线对象的创建与窗口分发

在 MT5 指标里画趋势线,核心不是算点,而是把点塞进正确的窗口并避免重名覆盖。上面这组函数把主图线和指标副图线拆成了两套入口,主图用 DrawPriceTrendLine,副图用 DrawIndicatorTrendLine,底层都交给 drawLineS 统一建对象。 DrawPriceTrendLine 先用 ObjectFind 查 name_2 是否存在,不存在才调 drawLineS 画实线;当 style 传 STYLE_DOT 时,额外画一条 clrAqua 的虚点线,宽度 3、向右射线开启。注意它用 shortname+DoubleToString(T_0,0) 当唯一名,靠时间戳避免重复。 DrawIndicatorTrendLine 多了一个 window=wid 参数,把线发到指标窗口。若 style==STYLE_SOLID,还会补一条 clrMagenta、宽度 2 的线,同样向右延伸。副图线的命名加了 wid 偏移,防止和主图同名冲突。 drawLineS 每次先 ObjectDelete 再 ObjectCreate,等于强制重画;OBJ_TREND 类型用 t0,p0 到 t1,p1 两点定位,OBJPROP_RAY_RIGHT 控制是否向右射线,OBJPROP_SELECTABLE 设 false 让线不可选中,back 决定压在主图下方还是上方。 开 MT5 新建指标把这段贴进 OnCalculate,把 wid 设成你指标窗口号,就能直接看到主副图双线联动;外汇和贵金属波动快,这类自动线在高波动时段可能频繁重绘,属正常现象,交易决策请自担高风险。

MQL5 / C++
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_2=shortname+DoubleToString(T_0,class="num">0);
class="type">class="kw">string name_0;
name_0=shortname+"Line_Sn"+ColorToString(color_0);
class=class="str">"cmt">//--- 
if(ObjectFind(class="num">0,name_2)<class="num">0)
drawLineS(name_2,T_0,T_1,P_0,P_1,color_0,style,class="num">0,true,false,class="num">0);
class=class="str">"cmt">//+-----------+
if(style==STYLE_DOT)
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">//+------ 在指标窗口中创建对象 ------------------+
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">class="kw">string name_1,name_0;
class="type">int window= wid;
name_1 = shortname+DoubleToString(T_0+wid,class="num">0);
if(ObjectFind(class="num">0,name_1)<class="num">0)
drawLineS(name_1,T_0,T_1,P_0,P_1,color_0,style,class="num">0,false,false,window);
class=class="str">"cmt">//---
if(style==STYLE_SOLID)
{
name_0=shortname+"Line_Pn"+ColorToString(color_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 t0,
class="type">class="kw">datetime t1,
class="type">class="kw">double p0,
class="type">class="kw">double p1,
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)
{
ObjectDelete(class="num">0,name);
ObjectCreate(class="num">0,name,OBJ_TREND,window,t0,p0,t1,p1,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,false);
ObjectSetInteger(class="num">0,name,OBJPROP_BACK,back);
}
class=class="str">"cmt">//+------------------------------------------------------------------+

背离延长线被突破后的角色互换

对价格图表与指标图形的实测观察显示,价格图上逆转背离的延长线,与指标图上经典背离的延长线,会自然形成倾斜的支撑与阻力带。当价格或柱状线有力突破这些倾斜线,往往意味着短线与长线走势可能出现方向延续。 一个具体现象是:价格图表中由隐性背离生成的支撑线被跌破后,后续反弹常在该线下方受阻;另一例中,MACD 直方图柱体直接击穿指标窗内的经典背离指示线,突破后该指示线由支撑转为反压。 这类线被有效突破后,原支撑变阻力、原阻力变支撑的概率偏高,外汇与贵金属市场因杠杆高、波动剧烈,此类互换失效也常见,需结合实时成交量验证。 基于这种角色互换特征,可把‘突破倾斜背离线+回踩不回破’作为开仓触发条件之一,具体参数留给下一阶段策略细化。

让小布替你跑这套映射
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到隐性背离与经典背离的实时标注,你只需判断供需级别是否耗尽。

常见问题

没有固定强弱排序,三类常组合出现形成复合模型,需结合超买超卖级别与成交量结构分别分析,趋势反转可能而非必然。
价格未破前低而振荡器走低,说明抛压在指标层被放大但真实供需仍偏多,矛盾指向趋势延续倾向,外汇贵金属市场此类结构高风险高回撤。
可以,小布盯盘在品种页内置了非标准背离映射,将价格波浪与振荡器动量分层比对,直接标出隐性结构,省去手动翻图。
RSI 更敏感于短线超买超卖,MACD 含趋势与振荡双重元素,隐性背离用 MACD 更易暴露动量矛盾,但均需配合走势波浪验证。