您应该了解的MQL5向导技巧(第 75 部分):动量震荡指标与包络线的应用
「AO 与包络线:趋势和区间的两套语言」
动量震荡指标(AO)由比尔·威廉姆斯提出,本质是用中间价的快慢均线差刻画趋势动量。其数值为 5 周期与 34 周期简单移动平均之差,以零轴为界区分多空动能:上穿零轴倾向看涨,下穿则倾向看跌;零轴同侧出现后峰更贴零轴的双峰,往往预示动能在衰减。 AO 在趋势行情里更顺手,可辅助确认突破与背离;但它对区间震荡容易反复打脸。我们后续在 USDJPY 30 分钟框架用 2023 年回测、2024 年前瞻验证了一套 AO+包络线的 10 模式信号组合,先在这里把两个部件拆清楚。 包络线通道是在一条移动平均线上下按固定百分比(如 2%)拉开两条轨。价格触上轨偏超买、触下轨偏超卖,逻辑上服务均值回归;波动大时通道自动扩、平静时自动缩。它和 AO 互补——AO 滞后确认趋势,包络线边界自带前瞻预警,两者叠在一起能把纯趋势信号的延迟压下来,也更容易在边界捕捉动量背离。外汇与贵金属杠杆高、假突破频繁,这类组合只降低盲区,不消除风险。
◍ 包络线轨道外的 AO 陷阱
价格瞬间刺穿包络线下轨又弹回通道内,往往是空头动能枯竭的征兆。此时 AO 多半压在零轴下方,红色直方图柱体收窄,或假跌破当口出现轻微看涨背离——多重细节叠在一起,说明下跌推力在极端位附近开始松动。 对应的上方假突破则是刺穿上轨后迅速跌回,AO 居零轴上方,绿色柱体渐弱或走出圆弧顶,暗示买盘后劲不足。这类形态本质属于均值回归:轨道框定了价格预期波动带,冲出去又回来,基本是给滞后追单者挖的坑。 AO 在这里只做一件事——确认趋势并不站在突破那一边。下破时 AO 极低或红柱持续缩小,超卖概率上升,看涨反转可能性增加;上破时 AO 极高或绿柱转弱,则超买迹象明显,回落倾向加大。 把 AO 当作过滤层,能压低假信号比率。入场选在价格重回轨道的极端位附近,止损只需放在近期高低点稍外侧即包络线轨道外缘,风险收益比更合理。USDJPY 30 分钟周期两年测试(仅 2023 年作训练)显示,该形态前瞻阶段落在小幅盈利与基本持平之间,外汇品种波动剧烈,实盘前务必自测。 下面这段逻辑捕捉的是上述看涨分支:前两根 K 线收在轨内,上一根假跌破下轨,当前价回到轨上且 AO 由负翻正。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">0. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalAO_Envelopes::IsPattern_0(class="type">ENUM_POSITION_TYPE T) { if ( T == POSITION_TYPE_BUY && AO(X()) > class="num">0.0 && AO(X() + class="num">1) < class="num">0.0 && Close(X() + class="num">2) > Envelopes_Lo(X() + class="num">2) && Close(X() + class="num">1) <= Envelopes_Lo(X() + class="num">1) && Close(X()) > Envelopes_Lo(X()) class=class="str">"cmt">//m_symbol.Bid() ) { class="kw">return(true); } else if ( T == POSITION_TYPE_SELL && AO(X()) < class="num">0.0 && AO(X() + class="num">1) > class="num">0.0 && Close(X() + class="num">2) < Envelopes_Up(X() + class="num">2) && Close(X() + class="num">1) >= Envelopes_Up(X() + class="num">1) && Close(X()) < Envelopes_Up(X()) ) { class="kw">return(true); } class="kw">return(class="kw">false); }
AO 给突破续命的判定逻辑
形态 1 与假突破反向:它抓的是价格冲出包络线后还能延续的真突破。条件是价格至少连续两根 K 线收在包络线上轨之上,同时 AO 录得较大正值或处于近期超买区,说明买盘压力足以把价位钉在近期高位附近。 若 AO 远高于零轴、甚至刷出多周期新高或持续高位的绿色柱,则趋势延续的概率进一步抬升;此时价格不是试探上冲,而是波动率沿原方向放大的开端。包络线在这里变成动态通道——价格能连多根 K 线待在通道外,往往意味着旧区间已破、新趋势启动。 反向同理:连续两根以上收在下轨下方且 AO 深度负值,才是有效破位。若价格两次收上轨外但 AO 仅勉强过零轴,动能不足,仍可能是假突破;AO 持续高于中位且柱体高耸,才坐实突破。同条件回测下,形态 1 的前瞻测试表现居前。 下方 MQL5 片段用最近 3 根 AO 值与包络中轨交叉结构过滤信号: // 取最近3根AO值 vector _last = AO_Last3(X()); // 多单:AO均为负且当前负值为更浅(动量回暖) T == POSITION_TYPE_BUY && _last[0] < 0.0 && _last[2] < 0.0 && _last[0] > _last[2] // 价格两跨中轨:前前根在上方,前根回踩至下,当前再破上 Close(X()+2) > Envelopes_Mid(X()+2) && Close(X()+1) <= Envelopes_Mid(X()+1) && Close(X()) > Envelopes_Mid(X()) // 空单镜像:AO双正且现值更负,价格中轨下穿 T == POSITION_TYPE_SELL && _last[0] > 0.0 && _last[2] > 0.0 && _last[0] < _last[2] && Close(X()+2) < Envelopes_Mid(X()+2) && Close(X()+1) >= Envelopes_Mid(X()+1) && Close(X()) < Envelopes_Mid(X()) 外汇与贵金属杠杆高,上述信号仅作过滤参考,实盘须自验。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">1. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalAO_Envelopes::IsPattern_1(class="type">ENUM_POSITION_TYPE T) { vector _last = AO_Last3(X()); if ( T == POSITION_TYPE_BUY && _last[class="num">0] < class="num">0.0 && _last[class="num">2] < class="num">0.0 && _last[class="num">0] > _last[class="num">2] && Close(X() + class="num">2) > Envelopes_Mid(X() + class="num">2) && Close(X() + class="num">1) <= Envelopes_Mid(X() + class="num">1) && Close(X()) > Envelopes_Mid(X()) ) { class="kw">return(true); } else if ( T == POSITION_TYPE_SELL && _last[class="num">0] > class="num">0.0 && _last[class="num">2] > class="num">0.0 && _last[class="num">0] < _last[class="num">2] && Close(X() + class="num">2) < Envelopes_Mid(X() + class="num">2) && Close(X() + class="num">1) >= Envelopes_Mid(X() + class="num">1) && Close(X()) < Envelopes_Mid(X()) ) { class="kw">return(true); } class="kw">return(class="kw">false); }
「轨道边界上的 AO 背离怎么抓反转」
第三个可量化形态(形态2)把包络线轨道当支撑阻力过滤器,只在价格触到上轨或下轨附近时出现 AO 背离才算信号。下轨处的看涨背离表现为:价格刺穿或触及下轨创出新低,但 AO 直方图谷底反而比前一次更浅,说明空头推价动能衰减。 上轨处的看跌背离是镜像:价格略破上轨新高,AO 峰值却形成更低的高点,买盘二次上冲乏力,倾向见顶回落。包络线把价格框在统计通道里,轨道未被有效突破本身就意味着原支撑阻力仍有效。 市场心理层面也说得通——超卖区里价格新低但动量不再跟跌,空头力量枯竭;常出现 AO 已拐头而价格还在横盘的现象,可作为转向佐证。前瞻性测试里该形态能实现盈利,但 Equity 曲线震荡明显,外汇与贵金属品种须警惕假突破带来的连续止损风险。 MQL5 里这段判定函数把逻辑写得很死:以两bar前、前一bar、当前bar三组关系锁定时序。下面逐行拆一下关键约束。 bool CSignalAO_Envelopes::IsPattern_2(ENUM_POSITION_TYPE T) // 定义形态2检查函数,入参为持仓方向枚举 if(T == POSITION_TYPE_BUY && // 仅当检查买入(看涨背离)分支 AO(X()+2) > AO(X()+1) && // 两bar前AO大于前一bar,即AO自更前开始走低 AO(X()+1) < AO(X()) && // 前一bar AO小于当前bar,即AO当前回升,构成更高低点 Close(X()+2) > Envelopes_Lo(X()+2) && // 两bar前收盘价在下行包络线上方 Close(X()+1) <= Envelopes_Lo(X()+1) && // 前一bar收盘价触碰或刺穿下轨 Close(X()) > Envelopes_Lo(X())) // 当前bar收回下轨上方,确认支撑有效 { return(true); } // 满足则返回真,触发买信号 else if(T == POSITION_TYPE_SELL && // 对称处理卖出(看跌背离) AO(X()+2) < AO(X()+1) && // 两bar前AO小于前一bar,AO走高 AO(X()+1) > AO(X()) && // 前一bar AO大于当前bar,AO回落成更低高点 Close(X()+2) < Envelopes_Up(X()+2) && // 两bar前收在下轨上方(上轨分支用上轨线) Close(X()+1) >= Envelopes_Up(X()+1) && // 前一bar触或破上轨 Close(X()) < Envelopes_Up(X())) // 当前bar退回上轨下,阻力确认 { return(true); } return(false); // 都不满足返回假,不开仓
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">2. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalAO_Envelopes::IsPattern_2(class="type">ENUM_POSITION_TYPE T) { if ( T == POSITION_TYPE_BUY && AO(X() + class="num">2) > AO(X() + class="num">1) && AO(X() + class="num">1) < AO(X()) && Close(X() + class="num">2) > Envelopes_Lo(X() + class="num">2) && Close(X() + class="num">1) <= Envelopes_Lo(X() + class="num">1) && Close(X()) > Envelopes_Lo(X()) ) { class="kw">return(true); } else if ( T == POSITION_TYPE_SELL && AO(X() + class="num">2) < AO(X() + class="num">1) && AO(X() + class="num">1) > AO(X()) && Close(X() + class="num">2) < Envelopes_Up(X() + class="num">2) && Close(X() + class="num">1) >= Envelopes_Up(X() + class="num">1) && Close(X()) < Envelopes_Up(X()) ) { class="kw">return(true); } class="kw">return(class="kw">false); }