您应当知道的 MQL5 向导技术(第 40 部分):抛物线止损和反转(PSAR)·进阶篇
(2/3)· 接上篇基础指标测试,本文在向导中跑通抛物线SAR的孤立与组合形态,省去手搓系统的重复劳动
接上篇,我们继续深挖MQL5向导里的交易设置思路。许多交易者把PSAR只当成一个画点的趋势线,却没意识到它在每根新柱线重算的特性,正好适合拆成多种形态分别回测。直接用向导类组装,比从零写EA更快看清哪些形态组合真有边缘。
◍ 压缩幅度过滤假突破
上面这段逻辑干的事很直接:先算一段 K 线里的「压缩值」_compression,也就是首末价差绝对值除以同向计数 _c;若 _c 为 0 直接返回 false,避免除零。 真正拿来筛形态的是 IsPattern_1:对多单要求压缩值小于基准与最低价差值的 2%(0.02 倍),空单则对照基准与最高价差值的 2%。这意味着只有价格波动被压到极窄的区间,才可能被判定为 Pattern 1 雏形。 在 MT5 里把 0.02 改成 0.05,回测 EURUSD H1 会看到信号数明显增多但假突破概率倾向上升;外汇与贵金属杠杆高,这类参数微调必须用小资金验证。
_i++;
_c++;
}
if(_c > class="num">0)
{ Out = fabs(_first - _last)/_c;
class="kw">return(true);
}
}
class="kw">return(class="kw">false);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Check for Pattern class="num">1. |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool CSignalSAR::IsPattern_1(class="type">ENUM_POSITION_TYPE T)
{ class="type">class="kw">double _compression = class="num">0.0;
if(Compression(T, _compression))
{ if(T == POSITION_TYPE_BUY && _compression < class="num">0.02*fabs(Base(StartIndex())-Low(StartIndex())))
{ class="kw">return(true);
}
else if(T == POSITION_TYPE_SELL && _compression < class="num">0.02*fabs(Base(StartIndex())-High(StartIndex())))
{ class="kw">return(true);
}
}
class="kw">return(class="kw">false);
}「敞口扩张时的 SAR 延续判定」
扩展趋势 SAR 属于趋势延续形态,出现在初始趋势折返被压制的场景,比如开局时 SAR 与价格距离极窄。多头侧 SAR 点间距持续放大、指标稳守在低点下方,倾向看涨;反过来点距也扩大但 SAR 悬在高点上方,则释放看跌信号。有人把它叫“落后者”,但下结论前最好先跑一遍回测。 我们只抽取形态 2 做隔离验证,把形态输入映射设为 4,其余参数沿用前篇设置。下面这段 MQL5 是形态 2 的识别核心,逻辑只看最近 5 根 SAR 基值的逐级差值方向。 代码逐行拆解:函数 IsPattern_2 接收持仓方向 T;买权分支要求连续四阶差值递减(Base(StartIndex())-Base(StartIndex()+1) 大于下一阶,依此类推),即 SAR 与价距离逐根拉开;卖权分支对称,要求反向差值逐级放大;不满足则返回 false。该写法不含任何未来函数,可直接挂 MT5 策略测试器验证。 外汇与贵金属杠杆高、滑点大,SAR 敞口扩张只代表概率倾斜,实盘前请用历史数据核对胜率与最大回撤。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">2. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalSAR::IsPattern_2(class="type">ENUM_POSITION_TYPE T) { if(T == POSITION_TYPE_BUY && Base(StartIndex()) - Base(StartIndex() + class="num">1) > Base(StartIndex() + class="num">1) - Base(StartIndex() + class="num">2) && Base(StartIndex() + class="num">1) - Base(StartIndex() + class="num">2) > Base(StartIndex() + class="num">2) - Base(StartIndex() + class="num">3) && Base(StartIndex() + class="num">2) - Base(StartIndex() + class="num">3) > Base(StartIndex() + class="num">3) - Base(StartIndex() + class="num">4) ) { class="kw">return(true); } else if(T == POSITION_TYPE_SELL && Base(StartIndex() + class="num">1) - Base(StartIndex()) > Base(StartIndex() + class="num">2) - Base(StartIndex() + class="num">1) && Base(StartIndex() + class="num">2) - Base(StartIndex() + class="num">1) > Base(StartIndex() + class="num">3) - Base(StartIndex() + class="num">2) && Base(StartIndex() + class="num">3) - Base(StartIndex() + class="num">2) > Base(StartIndex() + class="num">4) - Base(StartIndex() + class="num">3) ) { class="kw">return(true); } class="kw">return(class="kw">false); }
SAR 折返假信号的代码判定
SAR 折返假输出,指的是新趋势刚被 SAR 点翻出来,价格柱线只走了 1~2 根就回到原方向。图表上表现为同向 SAR 点出现后紧接反向一两个点,提示交易者这波信号可能不持续。 看涨情形里,先有常规多头 SAR 排列,随后 1~2 根柱线价格短暂跌破 SAR 又拉回,恢复上涨才算信号成立;看跌则反过来,下跌途中一两根柱线翻多后继续下破。原文把这种形态编为索引 3,单独用作交易信号时形态输入映射须置为 8,但那次测试没下单,所以没有可分享的盈亏数据。 这类假输出常见诱因就三类:行情波动或横盘、低波动性、纯市场噪音。对外汇和贵金属这种高杠杆品种,噪音引发的假信号可能造成较大回撤,靠 SAR 单指标硬吃风险偏高。 建议叠加 MACD 或支撑阻力做过滤,有量能数据也一并参考。相比形态 0 的单纯折返,带恢复确认的形态 3 可靠性倾向更好。 下面这段是形态 3 的判定函数,逐行看逻辑: //+------------------------------------------------------------------+
| // | Check for Pattern 3. |
|---|
//+------------------------------------------------------------------+ // 函数声明:返回布尔值,入参 T 为持仓方向枚举 bool CSignalSAR::IsPattern_3(ENUM_POSITION_TYPE T) { // 若方向为买,且起始根 SAR 在最低价下方(多头排列) if(T == POSITION_TYPE_BUY && Base(StartIndex()) < Low(StartIndex()) // 下一根 SAR 翻到最高价上方(折返) && Base(StartIndex() + 1) > High(StartIndex() + 1) // 再下一根 SAR 回最低价下方(恢复多头),判为形态 3 && Base(StartIndex() + 2) < Low(StartIndex() + 2)) { return(true); // 满足条件返回真 } // 卖向对称:起始 SAR 在最高价上,次根翻下,第三根回上 else if(T == POSITION_TYPE_SELL && Base(StartIndex()) > High(StartIndex()) && Base(StartIndex() + 1) < Low(StartIndex() + 1) && Base(StartIndex() + 2) > High(StartIndex() + 2)) { return(true); // 满足返回真 } return(false); // 都不符返回假 }
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">3. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalSAR::IsPattern_3(class="type">ENUM_POSITION_TYPE T) { if(T == POSITION_TYPE_BUY && Base(StartIndex()) < Low(StartIndex()) && Base(StartIndex() + class="num">1) > High(StartIndex() + class="num">1) && Base(StartIndex() + class="num">2) < Low(StartIndex() + class="num">2)) { class="kw">return(true); } else if(T == POSITION_TYPE_SELL && Base(StartIndex()) > High(StartIndex()) && Base(StartIndex() + class="num">1) < Low(StartIndex() + class="num">1) && Base(StartIndex() + class="num">2) > High(StartIndex() + class="num">2)) { class="kw">return(true); } class="kw">return(class="kw">false); }
◍ 双SAR折返叠加后的趋势延续判定
在基础折返形态(形态3)之上再叠加两次以上SAR与价格的来回穿越,就构成更强的延续结构。逻辑上它比形态3更可靠,因为多轮折返过滤了部分假突破,趋势延续的概率倾向更高。 原文作者在EURJPY的2023年日线周期上观察到:形态3全年无交易信号,因此同周期下该叠加形态也大概率不会产生任何信号与成交。这并不代表形态失效,而是样本期与品种波动特性使然,建议自行拉长测试窗口。 下面这段MT5代码给出了买方与卖方的判定函数,注意它仅做形态识别,未附任何回测结果。 //+------------------------------------------------------------------+
| // | Check for Pattern 4. |
|---|
//+------------------------------------------------------------------+ bool CSignalSAR::IsPattern_4(ENUM_POSITION_TYPE T) { if(T == POSITION_TYPE_BUY && Base(StartIndex()) < Low(StartIndex()) && Base(StartIndex() + 1) > High(StartIndex() + 1) && Base(StartIndex() + 2) < Low(StartIndex() + 2) && Base(StartIndex() + 3) > High(StartIndex() + 4) && Base(StartIndex() + 4) < Low(StartIndex() + 5) ) { return(true); } else if(T == POSITION_TYPE_SELL && Base(StartIndex()) > High(StartIndex()) && Base(StartIndex() + 1) < Low(StartIndex() + 1) && Base(StartIndex() + 2) > High(StartIndex() + 2) && Base(StartIndex() + 3) < Low(StartIndex() + 4) && Base(StartIndex() + 4) > High(StartIndex() + 5) ) { return(true); } return(false); } 逐行拆解:函数接收持仓方向T;买方向要求起始根SAR在最低价下方,其后第1根SAR翻到最高价上方,第2根又落回最低下方,第3根跃过第4根最高价,第4根再跌破第5根最低——五根内完成三次穿越;卖方向对称反转。外汇与贵金属属高风险品种,实盘前请在MT5策略测试器用超出一年的样本验证。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">4. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalSAR::IsPattern_4(class="type">ENUM_POSITION_TYPE T) { if(T == POSITION_TYPE_BUY && Base(StartIndex()) < Low(StartIndex()) && Base(StartIndex() + class="num">1) > High(StartIndex() + class="num">1) && Base(StartIndex() + class="num">2) < Low(StartIndex() + class="num">2) && Base(StartIndex() + class="num">3) > High(StartIndex() + class="num">4) && Base(StartIndex() + class="num">4) < Low(StartIndex() + class="num">5) ) { class="kw">return(true); } else if(T == POSITION_TYPE_SELL && Base(StartIndex()) > High(StartIndex()) && Base(StartIndex() + class="num">1) < Low(StartIndex() + class="num">1) && Base(StartIndex() + class="num">2) > High(StartIndex() + class="num">2) && Base(StartIndex() + class="num">3) < Low(StartIndex() + class="num">4) && Base(StartIndex() + class="num">4) > High(StartIndex() + class="num">5) ) { class="kw">return(true); } class="kw">return(class="kw">false); }
「用均线给 SAR 背离加一道滤网」
价格与 SAR 的背离在图表上太常见,单独看容易骗线。把移动平均线拉进来当确认层,信号质量会干净一些:看涨时价格连跌、SAR 连涨,且均线位于 SAR 下方或持平;看跌则反过来,价格连涨、SAR 连跌,均线压在两者之上。 步数窗口自己定,回测里我们取了 3 根 K 线做判定。智能系统只跑这一形态时,输入参数设为 32,缓冲区同时挂了价格、均线和 SAR 三条线,逻辑不复杂但足够直接。 价格和 SAR 的背离是主参考,均线-SAR 背离也能用。均线有滞后,所以那种组合信号会慢半拍,但短期噪音也少——长期看未必差,值得自己开 MT5 换周期试。 下面这段是形态 5 的判定函数,买/卖分支对称写死,StartIndex 起连续三根的比较一目了然。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Check for Pattern class="num">5. | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalSAR::IsPattern_5(class="type">ENUM_POSITION_TYPE T) { if(T == POSITION_TYPE_BUY && MA(StartIndex()) <= Base(StartIndex()) && Base(StartIndex()) > Base(StartIndex() + class="num">1) && Base(StartIndex() + class="num">1) > Base(StartIndex() + class="num">2) && Close(StartIndex()) < Close(StartIndex() + class="num">1) && Close(StartIndex() + class="num">1) < Close(StartIndex() + class="num">2) ) { class="kw">return(true); } else if(T == POSITION_TYPE_SELL && MA(StartIndex()) >= Base(StartIndex()) && Base(StartIndex()) < Base(StartIndex() + class="num">1) && Base(StartIndex() + class="num">1) < Base(StartIndex() + class="num">2) && Close(StartIndex()) > Close(StartIndex() + class="num">1) && Close(StartIndex() + class="num">1) > Close(StartIndex() + class="num">2) ) { class="kw">return(true); } class="kw">return(class="kw">false); }