价格行为分析工具包开发(第十四部分):抛物线转向与反转工具·综合运用
(3/3)· 从指标原理到回测结果,手把手把 PSAR 反转逻辑封装进自动交易系统
假信号的三根蜡烛防线
这段代码处理的是反转信号落地前的最后过滤:当挂起的 BUY 或 SELL 信号在 3 根蜡烛内没有触及反转价位,系统直接判为疑似假信号并清空状态。 具体看 BUY 分支,若当前收盘价 closeArray[0] 跌破预设反转位,就打印日志、弹窗报出开仓价(DoubleToString 按 _Digits 精度格式化),并视开关播放 alert.wav;随后 pendingSignal 归零、waitCount 重置。若连续等待满 3 根蜡烛仍未确认,Print 输出“Possible fake BUY signal”,仅弹窗警告而不下单。 SELL 分支镜像对称:closeArray[0] 大于等于 pendingReversalLevel 才确认,否则同样以 waitCount >= 3 作为假信号阈值。外汇与贵金属波动毛刺多,3 根未确认就丢弃信号,能砍掉一批追在毛刺上的亏损单,但也可能放过慢速反转——属于概率取舍而非绝对过滤。 把 waitCount >= 3 改成 5,在 H1 以上周期可能减少摩擦;在 M5 上留 3 更灵敏。开 MT5 把这段塞进 EA 的 OnTick 尾段,用策略测试器跑 EURUSD 近三个月,对比改前改后的成交次数就有体感。
Alert("Close here for BUY signal on ", _Symbol, " at price ", DoubleToString(closeArray[class="num">0], _Digits)); if(EnableSound) PlaySound("alert.wav"); pendingSignal = NO_SIGNAL; waitCount = class="num">0; } else if(waitCount >= class="num">3) { Print("Warning: Possible fake BUY signal - reversal not confirmed in class="num">3 candles."); if(EnableAlerts) Alert("Warning: Possible fake BUY signal on ", _Symbol); pendingSignal = NO_SIGNAL; waitCount = class="num">0; } } else if(pendingSignal == SELL_SIGNAL) { if(closeArray[class="num">0] >= pendingReversalLevel) { Print("Reversal level reached for SELL signal. Close here."); if(EnableAlerts) Alert("Close here for SELL signal on ", _Symbol, " at price ", DoubleToString(closeArray[class="num">0], _Digits)); if(EnableSound) PlaySound("alert.wav"); pendingSignal = NO_SIGNAL; waitCount = class="num">0; } else if(waitCount >= class="num">3) { Print("Warning: Possible fake SELL signal - reversal not confirmed in class="num">3 candles."); if(EnableAlerts) Alert("Warning: Possible fake SELL signal on ", _Symbol); pendingSignal = NO_SIGNAL; waitCount = class="num">0; } } class="kw">return; } class=class="str">"cmt">// Check for a new reversal signal SignalType newSignal = CheckForSignal(sarArray, openArray, closeArray); if(newSignal != NO_SIGNAL) {
「信号触发后如何挂起等待与画箭头」
当 PSAR 翻转判定出新信号时,代码先把 pendingSignal 记下、waitCount 清零,并把当前 Sar 值存为反转参考位 pendingReversalLevel。这一步决定后续最多容忍几根 K 线内确认,原文逻辑是上限 3 根。 若是 BUY_SIGNAL,先 Print 日志说明「等待反转确认(最多 3 根)」,再按 EnableAlerts 弹窗报符号与收盘价(DoubleToString 用 _Digits 控精度)。EnableArrows 开启时,用 CopyLow 取前一根低点,减 _Point*ArrowOffsetMultiplier 偏移后画绿色箭头;取价失败会打印报错而非静默。 SELL_SIGNAL 对称处理:CopyHigh 取前一根高点加偏移画红色箭头。外汇与贵金属波动大,这类信号仅作概率参考,实盘须自验。 别把箭头当进场令:它只是「待确认」标记,真正下单应等 waitCount 内反转成立,否则可能连续假信号。
pendingSignal = newSignal; waitCount = class="num">0; class=class="str">"cmt">// Reset waiting counter pendingReversalLevel = sarArray[class="num">0]; class=class="str">"cmt">// Set reversal level from current PSAR value if(newSignal == BUY_SIGNAL) { Print("Buy signal detected on ", TimeToString(lastBarTime, TIME_DATE|TIME_SECONDS), ". Waiting for reversal confirmation(up to class="num">3 candles)."); if(EnableAlerts) Alert("Buy signal detected on ", _Symbol, " at price ", DoubleToString(closeArray[class="num">0], _Digits)); if(EnableArrows) { class="type">class="kw">double lowVal[]; if(CopyLow(_Symbol, _Period, class="num">1, class="num">1, lowVal) > class="num">0) { class="type">class="kw">double offset = _Point * ArrowOffsetMultiplier; DrawSignalArrow("BuyArrow", lastBarTime, lowVal[class="num">0] - offset, clrGreen, StringToInteger(BuyArrowSymbol)); } else Print("Failed to retrieve low price for arrow placement."); } } else if(newSignal == SELL_SIGNAL) { Print("Sell signal detected on ", TimeToString(lastBarTime, TIME_DATE|TIME_SECONDS), ". Waiting for reversal confirmation(up to class="num">3 candles)."); if(EnableAlerts) Alert("Sell signal detected on ", _Symbol, " at price ", DoubleToString(closeArray[class="num">0], _Digits)); if(EnableArrows) { class="type">class="kw">double highVal[]; if(CopyHigh(_Symbol, _Period, class="num">1, class="num">1, highVal) > class="num">0) { class="type">class="kw">double offset = _Point * ArrowOffsetMultiplier; DrawSignalArrow("SellArrow", lastBarTime, highVal[class="num">0] + offset, clrRed, StringToInteger(SellArrowSymbol)); } else
◍ 箭头定位失败时的日志兜底
在 MT5 自定义指标里画箭头,常需要先取某根 K 线的高点作为纵向坐标。若 iHigh 返回无效值(例如跨周期调用时缓冲区还没就绪),直接拿去 ObjectCreate 会让箭头漂到图表外甚至报错。 上面这段散落的 Print 调用,就是典型的失败分支兜底:当高点取不到时,往专家日志丢一句 "Failed to retrieve high price for arrow placement.",而不是静默跳过。 实盘里这类日志很有用——你挂上指标后若发现该画箭头的地方空白,按 Ctrl+T 看日志有没有这条字符串,就能立刻判断是数据窗口没同步还是索引写错。外汇与贵金属波动快,跨周期取价失败概率不低,看到这条输出先查周期参数再查句柄。
Print("Failed to retrieve high price for arrow placement.");
用模拟盘回测给EA挑刺
上实盘前先在模拟账户把EA跑一遍回测,这是过滤明显逻辑漏洞的最低成本动作。MetaEditor里编译通过后,进MT5点开「策略测试器」,选好EA、时间周期和测试区间,再补几个你觉得敏感的参数,直接按开始。 我自己的回测里, volatility 25 指数那张图高亮了测试窗口内被确认的买、卖信号,后面还附了几段GIF方便看信号触发节奏;阶梯指数也跑了同样的流程,并且截了实盘对接的图。 重点不是看曲线漂亮,而是把信号密集区和滑点、点差叠加时段对一遍。外汇和贵金属杠杆高、跳空频繁,回测里不吃亏的EA,实盘也可能在流动性断层被扫。 别把正态当圣经 回测样本若只取了低波动段,EA对波动率25这类指数会过度自信;手动把测试周期拉长到含至少一次宏观数据行情,再调一次参数才算数。
「把这条线请下神坛」
回测里 PSAR 自动化策略在 14/02/25 发布的版本中给出过积极信号,但周线以上周期才明显压住假信号比例,小周期容易连续触发止损。它从来不是独立盈利的圣杯,只是你原有价格行为框架里的一枚触发器。 从 01/10/24 的图表投影仪到 17/02/2025 的 PSAR EA,前后 14 个工具覆盖了从「幽灵叠图」到「背离对比」的辅助视角,没有哪一个能替你拍板。外汇与贵金属杠杆高,信号过滤条件没验证前直接跟单,本金回撤可能超预期。 真要落地,先把 Parabolic_SAR.mq5 丢进策略测试器,用 H1 以上周期跑一遍 2024 全年 tick 数据,看止损频次再决定挂不挂实盘。工具是给你用的,不是给你跪的。