解读经典与隐性背离的新途径·综合运用
📉

解读经典与隐性背离的新途径·综合运用

(3/3)·从定义到实战,把经典与隐性背离揉进一套能跑的策略,而不是停留在看图说话

含代码示例实战向 第 3/3 篇
不少人把指标和价格方向相反就当反转信号直接开仓,结果在隐性背离确认的顺势行情里反复被扫。背离类型混用、不区分经典与隐性,是账户回撤的常见源头。本文收尾篇把前面拆开的概念拼成完整打法。

挂单怎么吃突破信号

这套打法不挑时间帧,挂单和市价单都能用,核心只有一条:指示线被突破才算数。做挂单时把单子挂在正在突破的烛条高点或低点,烛条收盘方向必须和突破方向一致——线向上破就等阳线收,向下破就等阴线收。 止损放在最近局部极值外侧,止盈看支撑阻力;逆势单的支撑阻力也可以直接画在指示线上,但得留神,行情可能急转,止盈位得跟着调。M1 到 M15 小周期里,价格突破后常回踩指示线走出 1-2-3 形态,等于给信号加保险,所以不够活跃时不妨等破烛条高低点后再进。 AO 振荡器在这套里主要干图形确认的活,不似别的系统那么重,但配合 AO 能明显抬升策略有效率。需要提醒,外汇和贵金属杠杆高,回踩失效或假突破都可能直接扫损,仓位别重。 为了验证,把指标代码嵌进 EA 而不是普通调用(否则指标窗口不画东西),除了 Lots、TP、SL、TrailingStop,还加了 InpOffset 和 InpDellOorder:前者是突破烛条到挂单的距离(点),后者是订单未触发且反向走动超过该点值就删单。 回测选 GBPUSD H1,从 2017 年初跑默认参数,结果偏向「有潜力」而非「已成型」。图形构造类策略只能可视模式人工评估,自动优化做不到,这个过程很耗时间。

MQL5 / C++
<span class="keyword">class="kw">input</span> <span class="keyword">class="type">class="kw">double</span> InpLots =<span class="number">class="num">0.1</span>;           <span class="comment">class=class="str">"cmt">// 手数</span>
<span class="keyword">class="kw">input</span> <span class="keyword">class="type">int</span> InpTakeProfit =<span class="number">class="num">150</span>;        <span class="comment">class=class="str">"cmt">// 止盈 (点值)</span>
<span class="keyword">class="kw">input</span> <span class="keyword">class="type">int</span> InpStopLoss =<span class="number">class="num">60</span>;           <span class="comment">class=class="str">"cmt">// 止损 (点值)</span>
<span class="keyword">class="kw">input</span> <span class="keyword">class="type">int</span> InpTrailingStop =<span class="number">class="num">25</span>;       <span class="comment">class=class="str">"cmt">// 尾随停止价位 (点值)</span>
<span class="keyword">class="kw">input</span> <span class="keyword">class="type">int</span> InpOffset =<span class="number">class="num">5</span>; <span class="comment">             class=class="str">"cmt">// 自价格距离 (点值)</span>
<span class="keyword">class="kw">input</span> <span class="keyword">class="type">int</span> InpDellOorder =<span class="number">class="num">30</span>; <span class="comment">        class=class="str">"cmt">// 订单删除距离 (点值)</span>
<span class="comment">class=class="str">"cmt">//---</span>
<span class="keyword">class="type">int</span> ExtTimeOut=<span class="number">class="num">10</span>;                   <span class="comment">class=class="str">"cmt">// 交易操作之间的间隔时间</span>
<span class="keyword">class="type">int</span> barsCalculated=<span class="number">class="num">1000</span>;
<span class="keyword">class="type">class="kw">datetime</span> t=<span class="number">class="num">0</span>;
<span class="keyword">class="type">class="kw">datetime</span> time[];
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="comment">class=class="str">"cmt">//| 基本计算                                                          |</span>
<span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="keyword">for</span>(<span class="keyword">class="type">int</span> bar=<span class="number">class="num">1</span>; bar&gt;<span class="number">class="num">0</span> &amp;&amp; !<span class="functions">IsStopped</span>() &amp;&amp; t!=time[<span class="number">class="num">0</span>]; bar--)
{
<span class="keyword">class="type">int</span> l=bar+<span class="number">class="num">1</span>;
<span class="keyword">class="type">int</span> p1=<span class="number">class="num">0</span>,p2=<span class="number">class="num">0</span>;
<span class="comment">class=class="str">"cmt">//+----------- 检测向上背离 ------------------------------+</span>
<span class="keyword">if</span>(Extremum(m_buff_ind[l+<span class="number">class="num">1</span>],m_buff_ind[l],m_buff_ind[l-<span class="number">class="num">1</span>])&lt;<span class="number">class="num">0</span>)
{
<span class="keyword">class="type">int</span> i=l;
<span class="keyword">class="type">int</span> counted=LastPeak(l,bars,m_buff_ind);
<span class="keyword">if</span>(counted!=-<span class="number">class="num">1</span>)
{
<span class="keyword">if</span>(m_buff_ind[i]&lt;m_buff_ind[counted] &amp;&amp; high[i]&gt;high[counted] &amp;&amp; !d1)
{ drawLine(<span class="class="type">class="kw">string">"Buy_1"</span>,time[i],time[counted],m_buff_ind[i],m_buff_ind[counted],Red,<span class="number">class="num">1</span>); d1=<span class="macro">true</span>;}
<span class="comment">class=class="str">"cmt">//---</span>
<span class="keyword">if</span>(m_buff_ind[i]&gt;m_buff_ind[counted] &amp;&amp; high[i]&lt;high[counted] &amp;&amp; !d2)
{
<span style="background-class="type">class="kw">color:rgb(class="num">255, class="num">235, class="num">85);">p1=<span class="functions">ArrayMaximum</span>(high,i-<span class="number">class="num">1</span>,<span class="number">class="num">5</span>);p2=<span class="functions">ArrayMaximum</span>(high,counted-<span class="number">class="num">2</span>,<span class="number">class="num">5</span>);</span>
drawLine(<span class="class="type">class="kw">string">"Buy_2"</span>,time[p1],time[p2],high[p1],high[p2],Red,<span class="number">class="num">0</span>);d2=<span class="macro">true</span>;
}
}
}
<span class="comment">class=class="str">"cmt">//+----------- 检测向下背离 ------------------------------+</span>
<span class="keyword">if</span>(Extremum(m_buff_ind[l+<span class="number">class="num">1</span>],m_buff_ind[l],m_buff_ind[l-<span class="number">class="num">1</span>])&gt;<span class="number">class="num">0</span>)
{
<span class="keyword">class="type">int</span> i=l;
<span class="keyword">class="type">int</span> counted=LastTrough(l,bars,m_buff_ind);
<span class="keyword">if</span>(counted!=-<span class="number">class="num">1</span>)
{
<span class="keyword">if</span>(m_buff_ind[i]&gt;m_buff_ind[counted] &amp;&amp; low[i]&lt;low[counted] &amp;&amp; !d3)
{ drawLine(<span class="class="type">class="kw">string">"Sell_1"</span>,time[i],time[counted],m_buff_ind[i],m_buff_ind[counted],Green,<span class="number">class="num">1</span>);d3=<span class="macro">true</span>;}
<span class="comment">class=class="str">"cmt">//---</span>

「空头触发与极值判定的代码骨架」

这段逻辑把「画线下破」和「极值识别」拆成了可复用的成员函数。先说极值函数 Extremum:它要求 a、b、c 三者同号,且 (a-b)*(b-c)<0,也就是中间点 b 是局部拐点;若 c>b 且 b<0 返回 1 判为向下极值,c<b 且 b>0 返回 -1 判为向上极值。 空头开仓检查 ShortOpened 里,先通过 ObjectFind 找 "Sell_2" 和 "Sell_1" 两条趋势线,再用 ValueByTime 取最近 3 根 K 线对应时间点的线价。只要 close[1] 跌破 Sell_2 且前一根收在线上方,或者指标 m_ind_1>m_ind_0 且指标与 Sell_1 线发生穿越,就返回 true,倾向认为空单触发概率升高。 OpenSellStop 中用 ArrayMinimum(low,0,3) 在最近 3 根里抓最低价挂 sell stop。外汇与贵金属杠杆高,这类下破单在震荡市可能被反复扫损,实盘前务必在 MT5 策略测试器用 2020—2023 年 XAUUSD 数据跑一遍。

MQL5 / C++
if(m_buff_ind[i]<m_buff_ind[counted] && low[i]>low[counted] && !d4)
{
p1=ArrayMinimum(low,i-class="num">1,class="num">5);p2=ArrayMinimum(low,counted-class="num">2,class="num">5);
drawLine("Sell_2",time[p1],time[p2],low[p1],low[p2],Green,class="num">0);d4=true;
}
}
}
if(d1 && d2 && d3 && d4)break;
t=time[class="num">0];
}
class=class="str">"cmt">//---
}
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) && ((a>class="num">0 && b>class="num">0 && c>class="num">0) || (a<class="num">0 && b<class="num">0 && 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">//+------
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|返回指定对象指定时间处的价格数值                                        |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double CSampleExpert::ValueByTime(class="type">class="kw">string label,class="type">int i)
{
class="type">class="kw">double p=class="num">0.0;
class=class="str">"cmt">//---
p=ObjectGetValueByTime(class="num">0,label,time[i],class="num">0);
class="kw">return(p);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 检查开空单的条件                                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool CSampleExpert::ShortOpened(class="type">void)
{
class="type">bool res=false;
class=class="str">"cmt">//---
class="type">class="kw">double pp1=EMPTY_VALUE,pp2=EMPTY_VALUE,pp3=EMPTY_VALUE,
pp4=EMPTY_VALUE,pp5=EMPTY_VALUE,pp6=EMPTY_VALUE;
class=class="str">"cmt">//---
if(ObjectFind(class="num">0,"Sell_2")!=-class="num">1)
{
pp1=ValueByTime("Sell_2",class="num">1);
pp2=ValueByTime("Sell_2",class="num">2);
pp3=ValueByTime("Sell_2",class="num">3);
}
if(ObjectFind(class="num">0,"Sell_1")!=-class="num">1)
{
pp4=ValueByTime("Sell_1",class="num">1);
pp5=ValueByTime("Sell_1",class="num">2);
pp6=ValueByTime("Sell_1",class="num">3);
}
class=class="str">"cmt">//--- 检查空头仓位的可能性 (卖出) 
if((pp1!=EMPTY_VALUE && close[class="num">1]<pp1 && close[class="num">2]>pp2&&close[class="num">0]<close[class="num">1])||
(pp4!=EMPTY_VALUE && m_ind_1>m_ind_0 && ((m_ind_1<pp4 && m_ind_2>pp5) ||(m_ind_2<pp5 && m_ind_3>pp6))))
{
class=class="str">"cmt">//--- 任何情况下, 我们都需要退出智能交易系统
res=true;
}
class=class="str">"cmt">//--- 结果
class="kw">return(res);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 开一笔向下突破卖出单                                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool CSampleExpert::OpenSellStop(class="type">void)
{
class="type">bool res=false;
class=class="str">"cmt">//--- 搜索最近烛条中的最低柱线
class="type">int i=ArrayMinimum(low,class="num">0,class="num">3);
class=class="str">"cmt">//---
if(ShortOpened())
{

◍ 挂单前先卡住保证金红线

这段逻辑干的事很直接:在挂 SELL STOP 之前,先用 FreeMarginCheck 探一下账户扛不扛得住。若返回值小于 0.0,说明保证金不够,直接 printf 打出当前可用保证金,不再往下走,避免盲目挂单把账户拖进强平区。外汇和贵金属杠杆高,这种前置检查不是可选项,是风控底线。 订单参数里,limit_price 取当前 Bid,price 则是前一根低点减去 offset 个点值,止盈在 price 下方、止损在 price 上方,典型的逆势接刀结构。开仓成功打印品种名,失败则把错误描述和价格参数都吐出来,方便你回 MT5 日志里对照。 DelOrder 这块有个反直觉的坑:删除成功时没置 res=true,失败反而 res=true 表示“还没删掉”。如果你拿这个函数写批量清理,得反过来读返回值,否则会以为删失败了。 [CODE]double offset=InpOffset; // 距烛台低点放置订单的距离点值 double limit_price=m_symbol.Bid(); double price=low[i]-offset*m_adjusted_point;; double tp =price-m_take_profit; double sl =price+m_stop_losse; //--- check the account balance if(m_account.FreeMarginCheck(Symbol(),ORDER_TYPE_SELL_STOP,InpLots,price)<0.0) printf("资金不足。可用保证金 = %f",m_account.FreeMargin()); else { //--- 开仓 if(m_trade.OrderOpen(Symbol(),ORDER_TYPE_SELL_STOP,InpLots,limit_price,price,sl,tp)) {res=true; printf("已开仓品种 %s",Symbol());} else { printf("SELL STOP %s 开仓错误: '%s'",Symbol(),m_trade.ResultComment()); printf("开仓参数: 价格=%f, 止盈=%f",price,tp); } } } //--- 结果 return(res); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+

//删除不必要的订单

//+------------------------------------------------------------------+ bool CSampleExpert::DelOrder(ulong ticket,string type) { bool res=false; if(m_trade.OrderDelete(ticket)) printf("已开仓品种 %s",Symbol()); else { res=true;// 设置标志, 表示订单尚未被删除 printf("删除订单错误"+type+" %s : '%s'",Symbol(),m_trade.ResultComment()); } return(res); } //+------------------------------------------------------------------+[/CODE]

MQL5 / C++
class="type">class="kw">double offset=InpOffset;                          class=class="str">"cmt">// 距烛台低点放置订单的距离点值
class="type">class="kw">double limit_price=m_symbol.Bid();
class="type">class="kw">double price=low[i]-offset*m_adjusted_point;;
class="type">class="kw">double tp =price-m_take_profit;
class="type">class="kw">double sl =price+m_stop_losse;
class=class="str">"cmt">//--- check the account balance
if(m_account.FreeMarginCheck(Symbol(),ORDER_TYPE_SELL_STOP,InpLots,price)<class="num">0.0)
printf("资金不足。可用保证金 = %f",m_account.FreeMargin());
else
{
class=class="str">"cmt">//--- 开仓
if(m_trade.OrderOpen(Symbol(),ORDER_TYPE_SELL_STOP,InpLots,limit_price,price,sl,tp))
{res=true; printf("已开仓品种 %s",Symbol());}
else
{
printf("SELL STOP %s 开仓错误: &class="macro">#x27;%s&class="macro">#x27;",Symbol(),m_trade.ResultComment());
printf("开仓参数: 价格=%f, 止盈=%f",price,tp);
}
}
}
class=class="str">"cmt">//--- 结果
class="kw">return(res);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 删除不必要的订单                                                    |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool CSampleExpert::DelOrder(class="type">class="kw">ulong ticket,class="type">class="kw">string type)
{
class="type">bool res=false;
if(m_trade.OrderDelete(ticket))
printf("已开仓品种 %s",Symbol());
else
{
res=true;class=class="str">"cmt">// 设置标志, 表示订单尚未被删除
printf("删除订单错误"+type+" %s : &class="macro">#x27;%s&class="macro">#x27;",Symbol(),m_trade.ResultComment());
}
class="kw">return(res);
}
class=class="str">"cmt">//+------------------------------------------------------------------+

策略能跑通但别指望全自动

这套基于加速器指标识别显性与隐性背离/趋合的思路,实测能拼出一个可上 MT5 跑的策略骨架,且留了口子接别的工具。但它有个硬伤:指标线偶尔会画错,得人工去修,直接导致难以全自动,回测统计也因此不好做干净。 附带的两个程序里,Accelerator_Div 指标负责背离判定,TestExpert 智能交易系统只用来跑策略测试,不是实盘 EA。外汇和贵金属波动大、滑点凶,手工干预环节多意味着实盘风险偏高,信号错过或画错都可能发生。 研究价值在于证明了经典战略之外还有活路,但别把它当免维护系统。真要验证,先把 ZIP 里的指标拖进 MT5 看画线错误频率,再决定值不值得自己写自动化外层。

让小布替你扫全市场背离
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到经典与隐性背离的标记,你只需在信号出现时判断趋势背景。把重复劳动交给小布,你专注决策。

常见问题

没有绝对强弱排序,需结合出现频次与趋势背景分别分析;C 类常伴双顶双底形态,确认度相对直观但出现少。
隐性背离倾向确认现有趋势延续,但外汇贵金属高风险,只能作为顺势参考而非加仓唯一依据。
可以,小布盯盘品种页已内置背离扫描,包含经典与隐性分类,并支持自定义振荡器参数过滤噪音。
默认参数在快周期可能过度敏感,建议按品种波动调整,并在代码层比对价格极值与振荡器极值的偏移量。
可在 EA 中维护一个背离序列数组,记录每笔类别与方向,当连续异构组合达到设定长度再触发评估。