您应当知道的 MQL5 向导技术(第 56 部分):比尔·威廉姆斯(Bill Williams)分形·进阶篇
(2/3)·只懂基础分形识别不够,这 5 类 MQL5 向导形态才能把假突破和趋势延续看清
分形点怎么暴露背离结构
价格动作背离在我们的体系里归为形态-3。当价格打出更低的低点(持续下压的信号),但对应的看涨分形——也就是波段低点——反而高于前一个波段低点时,看涨背离就出现了。这种组合说明下方承接在变厚,价格虽在跌,底部支撑却在增强,反转向上倾向发生。 反过来看,价格创出更高的高点,而看跌分形高点却低于前高,就是看跌背离。它通常意味着上方抛压在收口,买盘力量可能衰减,转向下的概率上升。外汇与贵金属波动剧烈,此类信号仅作概率参考,不构成方向保证。 代码实现只抓两个分形点,不像形态-2那样扫完整个 m_periods 区间的集合,而是结合这两个分形与两个价格极值来确认信号。下面这段可直接贴进 MT5 的 CSignalFractals 类里验证: //+------------------------------------------------------------------+
| // | Check for Pattern 3. |
|---|
//+------------------------------------------------------------------+ bool CSignalFractals::IsPattern_3(ENUM_POSITION_TYPE T) { CArrayDouble _buffer; if(T == POSITION_TYPE_BUY) { for(int i = 0; i < m_periods; i++) { if(FractalLow(X() + i) != 0.0) { _buffer.Add(FractalLow(X() + i)); } if(_buffer.Total() >= 2) { break; } } if(_buffer[0] > _buffer[1] && Low(X()) < Low(X() + 1)) { return(true); } } else if(T == POSITION_TYPE_SELL) { for(int i = 0; i < m_periods; i++) { if(FractalHigh(X() + i) != 0.0) { _buffer.Add(FractalHigh(X() + i)); } if(_buffer.Total() >= 2) { break; } } if(_buffer[0] < _buffer[1] && High(X()) > High(X() + 1)) { return(true); } } return(false); } 逐行拆解:函数接收持仓方向 T;买侧先用循环从 X() 往前找非零的 FractalLow,塞进 _buffer,凑满 2 个分形就 break。判定条件是 _buffer[0](较近分形低)大于 _buffer[1](较远分形低),且当前 Low 低于前一根 Low,满足即返回 true。卖侧逻辑镜像:抓 FractalHigh,要求近高低于远高,且 High 创新高,才确认看跌背离。 前向漫游测试用同类品种、周期与帧,报告里形态-3 的信号触发频次明显少于形态-2,说明分形背离本身偏稀有的特性。你可在策略测试器里把 m_periods 从默认调小到 20,看信号密度是否更符合自己的盯盘节奏。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">3. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalFractals::IsPattern_3(class="type">ENUM_POSITION_TYPE T) { CArrayDouble _buffer; if(T == POSITION_TYPE_BUY) { for(class="type">int i = class="num">0; i < m_periods; i++) { if(FractalLow(X() + i) != class="num">0.0) { _buffer.Add(FractalLow(X() + i)); } if(_buffer.Total() >= class="num">2) { break; } } if(_buffer[class="num">0] > _buffer[class="num">1] && Low(X()) < Low(X() + class="num">1)) { class="kw">return(true); } } else if(T == POSITION_TYPE_SELL) { for(class="type">int i = class="num">0; i < m_periods; i++) { if(FractalHigh(X() + i) != class="num">0.0) { _buffer.Add(FractalHigh(X() + i)); } if(_buffer.Total() >= class="num">2) { break; } } if(_buffer[class="num">0] < _buffer[class="num">1] && High(X()) > High(X() + class="num">1)) { class="kw">return(true); } } class="kw">return(false); }
◍ 双胞分形框出的犹豫区怎么破
形态-4 的本质是在图表上叠一对同周期的分形:低位看涨分形配高位看跌分形,两者把价格夹在一个犹豫区间内。当价格从低位分形弹起并站上高位分形,看涨倾向确认;反过来看跌序列里,价格自高位分形回落并跌破低位分形,卖出信号才触发。 代码里用两个布尔值 _1、_2 去查当前根的前一根(X()+1)和前两根(X()+2)是否同时具备顶底分形。之所以查两根而不是一根,是因为这种双胞结构的影响可能略微延后,只盯最后完整柱容易漏掉刚成型的形态。 确认形态后,逻辑不复杂:买单看收盘价是否高于对应分形的高点,卖单看是否低于对应分形的低点。优化后的前向漫游测试报告显示,连续出现的看涨与看跌分形本身也是市场犹豫的佐证,因此两侧突破都可当作形态-4 的触发依据。外汇与贵金属波动剧烈,此类突破在震荡市可能反复打脸,上 MT5 用策略测试器跑一遍 EURUSD 15M 再决定参数。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">4. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalFractals::IsPattern_4(class="type">ENUM_POSITION_TYPE T) { class="type">bool _1 = (FractalHigh(X() + class="num">1) != class="num">0.0 && FractalLow(X() + class="num">1) != class="num">0.0); class="type">bool _2 = (FractalHigh(X() + class="num">2) != class="num">0.0 && FractalLow(X() + class="num">2) != class="num">0.0); if(_1 || _2) { if(T == POSITION_TYPE_BUY) { if((_1 && Close(X()) > FractalHigh(X() + class="num">1)) || (_2 && Close(X()) > FractalHigh(X() + class="num">2))) { class="kw">return(true); } } else if(T == POSITION_TYPE_SELL) { if((_1 && Close(X()) < FractalLow(X() + class="num">1)) || (_2 && Close(X()) < FractalLow(X() + class="num">2))) { class="kw">return(true); } } } class="kw">return(false); }
「用分形基准卡住波段反转的边界」
形态-5 的核心,是拿分形低点当潜在支撑、分形高点当潜在阻力,再去观察后续价格动作有没有真正越界。看涨情形里,先出现一个看涨分形(低点基准),之后价格没显著跌破它,还从该位反弹,支撑区的可信度就上来了;看跌情形则反过来,分形高点立住后,后续动作始终摸不到更高的基准位,阻力角色被强化,情绪偏空。 代码里顺手把汇率缓冲区的标准差也算了出来,拿它和收盘价偏离盛行趋势的幅度做比对——这一步和形态-2 的判据同构,所以形态-2 里提到的样本偏差、窗口敏感等坑,在这里同样要留心。读者可以直接改附带的 buffer 长度和 Std 阈值来适配自己的品种。 按品种、窗口、时间帧调过参数后,我们跑了一次向前测试(本系列前面没做,因为这次测试窗口很小,纳入不算负担;训练期优化和前向同时铺开会让篇幅太挤,所以略去)。报告指向:该判据在窄幅震荡品种上触发频率偏高,趋势段则容易漏掉晚到的分形确认。 别把分形当绝对墙 分形只是 N 根 K 线的局部极值,外汇和贵金属的高波动特性下,假突破后快速收回是常态,单看分形容易在数据噪音里反复止损。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">5. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalFractals::IsPattern_5(class="type">ENUM_POSITION_TYPE T) { vector _std; _std.Init(class="num">5); _std.Fill(class="num">0.0); if(T == POSITION_TYPE_BUY && FractalLow(X() + m_periods) != class="num">0.0) { if(_std.CopyRates(m_symbol.Name(), m_period, class="num">4, class="num">0, m_periods) && _std.Std() <= fabs(Close(X()) - Close(X() + m_periods))) { class="kw">return(true); } } else if(T == POSITION_TYPE_SELL && FractalHigh(X() + m_periods)) { if(_std.CopyRates(m_symbol.Name(), m_period, class="num">2, class="num">0, m_periods) && _std.Std() <= fabs(Close(X()) - Close(X() + m_periods))) { class="kw">return(true); } } class="kw">return(false); }
分形位被碰穿又收回的失效波段
牛市分形之后,价格若向下试探前分形低点却没守住跌势,反而拒创新低并快速拉回,通常意味着抛压短期耗尽,买方有概率接手。反过来,分形高点形成后向上刺穿却收不上去,这种“波段失败”更倾向于是卖方夺回主导、价格转弱的前兆。 这段代码把判断压到极简:以 X() 为当前柱,X()+2 是前两根处的分形低点/高点,X()+1 是上一根。看涨时要求上一根最低 ≤ 前分形低,且当前收盘 ≥ 前分形对应两根高点;看跌对称处理。回测沿用形态0-5 相同的开平仓阈值,前向测试里若后续蜡烛始终未越过分形高位(或低位),往往被视为抵触信号,是趋势动能枯竭的较强提示。 外汇与贵金属杠杆高、滑点大,这类失效信号只是概率倾向,实盘前请在 MT5 用历史数据自测分形回溯窗长。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">6. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalFractals::IsPattern_6(class="type">ENUM_POSITION_TYPE T) { if(T == POSITION_TYPE_BUY && FractalLow(X() + class="num">2) != class="num">0.0) { if(Low(X() + class="num">1) <= FractalLow(X() + class="num">2) && Close(X()) >= High(X() + class="num">2)) { class="kw">return(true); } } else if(T == POSITION_TYPE_SELL && FractalHigh(X() + class="num">2) != class="num">0.0) { if(High(X() + class="num">1) >= FractalHigh(X() + class="num">2) && Close(X()) <= Low(X() + class="num">2)) { class="kw">return(true); } } class="kw">return(false); }
◍ 分形点贴着均线堆出来的枢轴区
把分形指标和一条 50-周期均线叠在一起看,会出现一种值得盯的形态:一连串分形低位全挤在均线附近,说明均线在这里充当了强支撑。此时买方倾向在回踩分形低位时找机会,等价格决定性突破最近阻力甚至站上均线,看涨观点才被确认。反过来,多个分形高位贴着均线排布,均线变成阻力,价格反复被压回、最后明显跌破支撑或均线,看跌倾向随之成立。 这套逻辑在 MT5 里用数组记录「分形点到均线的缝隙」来实现。代码取缓冲区内所有缝隙的最大值,目的是筛出缝隙尽可能小的聚集状态——也就是分形和均线几乎黏在一起。该最大值还要和近期收盘价波幅比大小,确保聚集发生在有意义的趋势背景里,具体阈值可参照同系列其他形态的输入调节。 按前文优化过的品种与参数做前向漫游测试,结论很直接:分形在均线旁固定成簇,往往暗示一个枢轴区域正在形成,后续依突破方向确认延续或逆转。外汇与贵金属这种高杠杆品种,枢轴被破只是概率倾斜,实盘必须带止损。 下面这段是形态-7 的判断函数,逐行拆一下关键处: // 函数入口,按多空类型分支 bool CSignalFractals::IsPattern_7(ENUM_POSITION_TYPE T) // 声明双精度数组存缝隙 CArrayDouble _buffer; // 看涨分支:遍历前 m_periods 根 K 线 if(T == POSITION_TYPE_BUY) { for(int i = 1; i < m_periods; i++) // 若有分形低位,把「分形低位与均线差的绝对值」塞进数组 { if(FractalLow(X() + i) != 0.0) { _buffer.Add(fabs(FractalLow(X() + i) - MA(X() + i))); } } // 最大缝隙小于等于近期收盘波幅,且前一根收在均线下方、当前根站上均线,才返回 true if(_buffer[_buffer.Maximum(0, _buffer.Total())] <= fabs(Close(X() + 1) - Close(X() + m_periods)) && Close(X() + 1) <= MA(X() + 1) && Close(X()) > MA(X())) { return(true); } } // 看跌分支对称:用分形高位、收盘价在均线上方转下方 else if(T == POSITION_TYPE_SELL) { for(int i = 1; i < m_periods; i++) { if(FractalHigh(X() + i) != 0.0) { _buffer.Add(fabs(FractalHigh(X() + i) - MA(X() + i))); } } if(_buffer[_buffer.Maximum(0, _buffer.Total())] <= fabs(Close(X() + 1) - Close(X() + m_periods)) && Close(X() + 1) >= MA(X() + 1) && Close(X()) < MA(X())) { return(true); } } // 都不满足返回 false return(false); 开盘前把 m_periods 调到 20~30 之间跑一遍 EURUSD 的 M15,能直观看到分形簇黏均线的触发频率。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">7. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalFractals::IsPattern_7(class="type">ENUM_POSITION_TYPE T) { CArrayDouble _buffer; if(T == POSITION_TYPE_BUY) { for(class="type">int i = class="num">1; i < m_periods; i++) { if(FractalLow(X() + i) != class="num">0.0) { _buffer.Add(fabs(FractalLow(X() + i) - MA(X() + i))); } } if(_buffer[_buffer.Maximum(class="num">0, _buffer.Total())] <= fabs(Close(X() + class="num">1) - Close(X() + m_periods)) && Close(X() + class="num">1) <= MA(X() + class="num">1) && Close(X()) > MA(X())) { class="kw">return(true); } } else if(T == POSITION_TYPE_SELL) { for(class="type">int i = class="num">1; i < m_periods; i++) { if(FractalHigh(X() + i) != class="num">0.0) { _buffer.Add(fabs(FractalHigh(X() + i) - MA(X() + i))); } } if(_buffer[_buffer.Maximum(class="num">0, _buffer.Total())] <= fabs(Close(X() + class="num">1) - Close(X() + m_periods)) && Close(X() + class="num">1) >= MA(X() + class="num">1) && Close(X()) < MA(X())) { class="kw">return(true); } } class="kw">return(false); }