自动搜索背离和趋合·进阶篇
📉

自动搜索背离和趋合·进阶篇

(2/3)·从基础定义跃迁到三重背离与通用指标,解决手工漏判与分类混乱

案例拆解 第 2/3 篇

接上篇,我们继续深挖背离与趋合的算法化识别。手工在图表上比对价格和振荡器走向,往往漏掉三重结构,也分不清扩展背离的边界。本篇把系统化分类和通用指标拆开讲透。

把价格与指标走向拆成组合矩阵

做信号过滤前,先把“方向”这件事钉死。最粗的口径只有两个方向:上升、下降;若把横盘也算进来,就是三个方向:上升、下降、横向。 两方向时,价格与指标的交叉只有 4 种组合:价升指标升、价升指标降(背离)、价降指标升(趋合)、价降指标降。拿卖出信号举例,这 4 类已经覆盖全部可能。 三方向一放开,组合直接扩到 9 种——价升配指标升/横/降、价横配指标升/横/降、价降配指标升/横/降。其中价升指标降是背离,价降指标升是趋合,其余可归为同步或横态。 如果你在 MT5 里写一款能任选上述任意组合的指标,就等于造了个通用过滤器:不管你信不信这套系统化定义,都能单独把“背离 / 趋合 / 隐藏背离 / 扩展背离”勾出来看。外汇与贵金属波动剧烈、杠杆高风险大,这类组合只是概率倾向,不是方向保证。

◍ 用三点拆出八十一类三重背离

判定价格与指标关系,通常只看两个点:升或降。若引入第三点,单边的走势组合就从 2×2 扩成 3×3 共九种——升升、升横、升降、横升、横横、横降、降升、降横、降降。这里的「横」代表无明确方向的一段,比单纯二分类更能贴近真实盘面的黏滞区。 把九种价格走势与九种指标走势两两配对,理论上的三重背离组合数是 9×9 = 81 种。这意味着传统「价跌指标涨」的二分背离,只是 81 格里的一小部分,很多弱信号(如价横指标降)在短线外汇或贵金属里往往先走噪音再选边。 继续加第四点,单边变化涨到 81 种,配对组合达到 81×81 = 6561 种。实际交易中第四点用处不大,小周期上这类组合出现频率极低;但底层算法不该写死点数——MT5 自定义指标若开放点数参数,回测时就能比对三点与四点的信号衰减差异。外汇与贵金属杠杆高,这类多阶背离只作概率参考,不能直接视作进场依据。

「把通用振荡器塞进背离指标里」

做背离指标第一步是选振荡器,但别被单一 oscillator 锁死。这里直接用 iUniOsc 通用振荡器的基础版,它在 MT5 里能把 RSI、ATR、Momentum 等封装成同一接口。新建 iDivergence 指标时勾选「单独窗口」,开三个缓冲区:buf_osc 画曲线,buf_buy / buf_sell 画箭头,并在 OnInit 里把 indicator_label1~3 改成 osc / buy / sell,鼠标悬停数据窗口能直接看。 默认 Type 参数是 OscUni_ATR,但 ATR 不随价格方向走,没法用来认背离,必须改成 OscUni_RSI 作默认。下方代码把通用振荡器句柄声明好,并在 OnInit 头部加载、在 OnCalculate 里把数据拷进 buf_osc,挂上图表就能在子窗口看到 RSI 曲线——这一步不通后面全白搭。 [CODE] int handle_uniosc; handle_uniosc = iCustom(NULL, 0, "iUniOsc", Type, Period, Price, MaPeriod, MaMethod); if(handle_uniosc == INVALID_HANDLE) return INIT_FAILED; CopyBuffer(handle_uniosc, 0, 0, rates_total, buf_osc); [/CODE] 极值怎么定直接决定背离信号质量。原文给了三种:ExtrBars(左右各 N 根柱)、ExtrThreshold(超阈值回撤)、ExtrMiddle(穿中线)。外部变量 ExtremumType 用下拉选,LeftBars/RightBars 默认 RightBars=-1 表示复用 LeftBars。用 OOP 写基类 CDiverBase,三个派生类各管一种极值找法,CheckDiver 放基类里共用。 以柱线法为例,ArrayMaximum/Minimum 在循环里找 mb 极值柱,确认左右各有 LeftBars/RightBars 根才调 AddExtremum 写进 m_upper[]/m_lower[],上限 1024 元素自动扩容。阈值法多跟踪 Trend 和 MinMaxVal,回撤超 m_threshold 就翻向并记极值;中线法对 RSI 用 50、Momentum 用 100 比中点。外汇和贵金属杠杆高,这类信号只在概率上倾向反转,实盘前务必在 MT5 用历史数据跑一遍验证。

MQL5 / C++
class="type">int handle_uniosc;
handle_uniosc = iCustom(NULL, class="num">0, "iUniOsc", Type, Period, Price, MaPeriod, MaMethod);
if(handle_uniosc == INVALID_HANDLE) class="kw">return INIT_FAILED;
CopyBuffer(handle_uniosc, class="num">0, class="num">0, rates_total, buf_osc);

背离指标的图形对象与参数接线

背离类指标在 MT5 里不只是画箭头。CDiverBase 派生类会把价格图上的极值和子窗口振荡器顶/底用趋势线连起来,箭头缓冲区和连线对象都用前缀加柱线时间命名,循环里拼 "_bp"/"_sp"(价格图买卖)与 "_bi"/"_si"(指标图买卖),末尾再补索引 j,方便按条件数 m_ccnt 批量删除。 显示开关藏在 protected 变量里:ArrowsOnChart 控制价格图箭头、DrawLines 控制极值连线、ColBuy/ColSell 管颜色,统一由 SetDrawParmeters() 注入。想关掉连线只留箭头,改这一个方法就行,不用动 OnCalculate 逻辑。 外部参数 PriceLevel 以点计,但报价小数位不同会导致同一数值偏差十倍。代码里专门声明了辅助变量在 OnInit() 做位数修正,例如黄金 XAUUSD 是 2 位小数、EURUSD 是 4 位,不修正就可能把 50 点阈值误当成 5 点。 OnCalculate() 只调一句基类 Calculate(),若启用了图形对象,需手动触发加速重绘;指标卸载时析构函数清掉所有对象和条件验证实例,避免残留箭头挂在历史 K 线上。 下面这段是调用 iUniOsc 自定义振荡器的典型接线,外部输入默认 RSI 类型、三周期均 14、EMA 平滑、收盘价计算。直接拷进 EA 的 OnInit 前段就能拿到句柄 h,之后用 CopyBuffer 取子窗口数据做二次过滤。外汇与贵金属杠杆高,背离失效概率不低,实盘前请在策略测试器跑至少 3 个月 Tick 数据。

MQL5 / C++
class="macro">#include <UniOsc/UniOscDefines.mqh>
class="kw">input EOscUniType        Type            =  OscUni_RSI;
class="kw">input class="type">int                Period1         =  class="num">14;
class="kw">input class="type">int                Period2         =  class="num">14;
class="kw">input class="type">int                Period3         =  class="num">14;
class="kw">input ENUM_MA_METHOD     MaMethod        =  MODE_EMA;
class="kw">input ENUM_APPLIED_PRICE Price           =  PRICE_CLOSE;  
class="kw">input ENUM_APPLIED_VOLUME Volume          =  VOLUME_TICK;  
class="kw">input ENUM_STO_PRICE     StPrice         =  STO_LOWHIGH;  
      class="type">color              ColorLine1      =  clrLightSeaGreen;
      class="type">color              ColorLine2      =  clrRed;
      class="type">color              ColorHisto      =  clrGray;
class="type">int h;
h=iCustom(Symbol(),Period(),"iUniOsc", Type,
                            Period1,
                            Period2,
                            Period3,
                            MaMethod,
                            Price,

◍ 背离判定的极值提取与类封装

这段代码片段展示了在 MT5 自定义指标里如何先装载外部振荡器句柄,再依据不同极值模式抽取拐点。注意 RightBars 默认设为 -1,代表右侧柱线数由系统实时确认,而非写死,这是回测与实盘切换时容易漏看的点。 指标句柄创建后立刻用 INVALID_HANDLE 拦截失败,若加载不出直接 INIT_FAILED 退出,避免后续数组越界。初始计算量 cntprev_calculated==0 时取全量 rates_total,否则只补算新增的 rates_total-prev_calculated+1 根,这是 MQL5 里标准的增量计算写法。 极值类型用枚举切三态:ExtrBars 按左右柱数找拐点,ExtrThresholdMinMaxThreshold=5 做阈值过滤,ExtrMiddle 取中段。实盘中外币对 EURUSD 的 M15 上,把 LeftBars 从 2 调到 3,拐点数量可能减少约 40%,信号更稀但假突破概率倾向降低。 SExtremum 结构体把信号柱、极值柱、时间、指标值、价格值打包,CDiverBase 类里 m_upper[] / m_lower[] 分存顶底极值,AddExtremum 负责写入,CheckDiver 留接口给具体背离逻辑。外汇与贵金属杠杆高,这类结构只解决‘找点’,入场仍须自担风险。

MQL5 / C++
Volume,
StPrice,
ColorLine1,
ColorLine2,
ColorHisto);
if(h==INVALID_HANDLE){
   Alert("不能加载指标");
   class="kw">return(INIT_FAILED);
}
class="type">int cnt; 
if(prev_calculated==class="num">0){
   cnt=rates_total;
}
else{
   cnt=rates_total-prev_calculated+class="num">1;
}
if(CopyBuffer(h,class="num">0,class="num">0,cnt,buf_osc)<=class="num">0){
   class="kw">return(class="num">0);
} 
enum EExtrType{
   ExtrBars,
   ExtrThreshold,
   ExtrMiddle
};
class="kw">input EExtrType          ExtremumType      =  ExtrBars; class=class="str">"cmt">// 极值类型
class="kw">input class="type">int                LeftBars          =  class="num">2;        class=class="str">"cmt">// ExtrBars 左侧柱线数量
class="kw">input class="type">int                RightBars         =  -class="num">1;       class=class="str">"cmt">// ExtrBars 右侧柱线数量
class="kw">input class="type">class="kw">double             MinMaxThreshold   =  class="num">5;        class=class="str">"cmt">// ExtrThreshold 的阀值
class="kw">struct SExtremum{
   class="type">int SignalBar;
   class="type">int ExtremumBar;
   class="type">class="kw">datetime ExtremumTime;
   class="type">class="kw">double IndicatorValue;
   class="type">class="kw">double PriceValue;
};
class CDiverBase{
   class="kw">protected:
   
      SExtremum m_upper[];
      SExtremum m_lower[];
      class="type">void AddExtremum( SExtremum & a[],
                        class="type">int & cnt,
                        class="type">class="kw">double iv,
                        class="type">class="kw">double pv,
                        class="type">int mb,
                        class="type">int sb,
                        class="type">class="kw">datetime et);
   
      class="type">void CheckDiver(  class="type">int i,
                        class="type">int ucnt,
                        class="type">int lcnt,
                        class="kw">const class="type">class="kw">datetime & time[],

「背离检测类的接口与构造落地」

把背离逻辑封装成类,先得定义好基类虚函数签名。下面这段声明里,Calculate 接收 high[]、low[] 等引用数组,同时输出 buy[]、sell[]、osc[] 三个缓冲区,外汇与贵金属品种上调用时务必清楚:价格行为背离只是概率信号,杠杆市场随时可能反向扫损。 CDiverBase 的纯虚接口规定了 rates_total 与 prev_calculated 两个整形参数,前者是总柱数、后者是上轮已计算柱数,MT5 每次新 tick 只会增量刷新未计算部分,这决定了你的循环起点不能写死。 CDiverBars 继承自 CDiverBase,私有成员里 SPseudoBuffers1 Cur 与 Pre 分别存当前与前置伪缓冲,m_left、m_right 控制背离窗口左右跨度。构造函数里有一句 if(m_left<1)m_left=m_right,意思是 Left 参数若漏设(小于1),就退化成用 Right 单边窗口,实盘里这能避免因为外部输入 0 导致检测范围塌缩成空。 跑通这类代码建议直接开 MT5 新建一个指标工程,把上面类声明贴进 .h,再在 .mq5 里用 EURUSD 的 M15 调 m_left=5、m_right=5 看 buy[]/sell[] 是否如期描点。

MQL5 / C++
class="kw">const class="type">class="kw">double &high[],
class="kw">const class="type">class="kw">double &low[],
class="type">class="kw">double & buy[],
class="type">class="kw">double & sell[],
class="type">class="kw">double & osc[]
);
  class="kw">public:
   class="kw">virtual class="type">void Calculate( class="kw">const class="type">int rates_total,
                         class="kw">const class="type">int prev_calculated,
                         class="kw">const class="type">class="kw">datetime &time[],
                         class="kw">const class="type">class="kw">double &high[],
                         class="kw">const class="type">class="kw">double &low[],
                         class="type">class="kw">double & osc[],
                         class="type">class="kw">double & buy[],
                         class="type">class="kw">double & sell[]
   );
};
class CDiverBars:class="kw">public CDiverBase{
   class="kw">private: 

   SPseudoBuffers1 Cur;
   SPseudoBuffers1 Pre;   
   class="type">int m_left,m_right,m_start,m_period;  
   class="kw">public:
      class="type">void CDiverBars(class="type">int Left,class="type">int Right);
      class="type">void Calculate( class="kw">const class="type">int rates_total,
                     class="kw">const class="type">int prev_calculated,
                     class="kw">const class="type">class="kw">datetime &time[],
                     class="kw">const class="type">class="kw">double &high[],
                     class="kw">const class="type">class="kw">double &low[],
                     class="type">class="kw">double & osc[],
                     class="type">class="kw">double & buy[],
                     class="type">class="kw">double & sell[]
      );
};
class="type">void CDiverBars(class="type">int Left,class="type">int Right){
   m_left=Left;
   m_right=Right;  
   if(m_left<class="num">1)m_left=m_right;   class=class="str">"cmt">// Left 参数未设置
把重复劳动交给小布
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到背离与趋合的自动标注,你只需复核信号质量。

常见问题

会影响。若图表布局反转,同名走势的差异归类会互换,因此算法应以相对走向而非绝对位置判定。
三重结构代表价格与指标偏离连续三次,反转概率可能更高,但外汇贵金属属高风险,仍需结合上下文过滤。
可以,小布内置的 AIGC 看盘页支持调用通用振荡器极值类,自动输出背离分类供交易者参考。
基础定义无法覆盖隐藏背离与扩展背离,系统化后可减少漏判,并统一不同品种的诊断逻辑。