使用MQL5实现抛物线SAR趋势策略的自动化交易:打造高效的EA·综合运用
🛡️

使用MQL5实现抛物线SAR趋势策略的自动化交易:打造高效的EA·综合运用

(3/3)·前两步铺好指标与下单,这一篇把仓位、滑点和异常收口一次讲透

进阶 第 3/3 篇
很多EA写完能跑就直接挂真仓,结果滑点一跳、仓位一重,回测里的漂亮曲线当场变形。SAR策略在贵金属跳空时尤其容易被点阵误判,留好缓冲比多写几行逻辑更管用。

「用抛物线 SAR 给无持仓时挂向」

在 MT5 里做信号触发,第一步往往是确认当前品种有没有敞口。下面这段逻辑只在同一品种无持仓时才去读 SAR 并决定多空,避免重复加仓把账户风险叠厚。 核心判断很直白:取前一根收盘价比对 iSAR 算出的停损点。若收盘价在 SAR 上方,倾向开多;若在下方,倾向开空。外汇与贵金属波动大,这种裸信号在震荡市可能频繁反向,实盘前务必用策略测试器跑历史数据。 IsPositionOpen 用 PositionsTotal 遍历所有持仓,比对 PositionGetSymbol 与当前图表的 _Symbol,命中即返回 true。把它放在下单前,等于给 EA 加了一道「同品种不重复进场」的闸。 OpenBuyOrder 里 trade.Buy 的滑点、止损、止盈三参都传了 0,意味着先用市价不挂防护单;这种写法方便验证信号,但真上 XAUUSD 这类高滑点品种前,建议至少把止损参数字段填上。

MQL5 / C++
class="type">class="kw">double sar = iSAR(_Symbol, _Period, SAR_Step, SAR_Maximum); class=class="str">"cmt">// 计算抛物线SAR当前值
class="type">class="kw">double lastPrice = iClose(_Symbol, _Period, class="num">1); class=class="str">"cmt">// 取上一根K线收盘价
class=class="str">"cmt">//--- 检查是否已有持仓
if(!IsPositionOpen(_Symbol))
  {
  class=class="str">"cmt">//--- 根据SAR判断方向
  if(lastPrice > sar)
    {
    OpenBuyOrder(); class=class="str">"cmt">// 收盘价在SAR之上,开多
    }
  else
    if(lastPrice < sar)
    {
    OpenSellOrder(); class=class="str">"cmt">// 收盘价在SAR之下,开空
    }
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|检查指定品种是否有持仓                                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">bool IsPositionOpen(class="type">class="kw">string symbol)
  {
  class="type">uint total=PositionsTotal(); class=class="str">"cmt">// 获取当前总持仓数
  for(class="type">uint i=class="num">0; i<total; i++)
    {
    class="type">class="kw">string POSITION_SYMBOL=PositionGetSymbol(i); class=class="str">"cmt">// 取第i个持仓的品种名
    if(POSITION_SYMBOL == _Symbol) class=class="str">"cmt">// 比对是否为当前图表品种
      {
      class="kw">return true;
      }
    }
  class="kw">return class="kw">false;
  }
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| 开多单                                                          |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OpenBuyOrder()
  {
  if(trade.Buy(LotSize, NULL, class="num">0, class="num">0, class="num">0, "Buy Order"))
    {
    Print("Buy order placed successfully");
    }
  else
    {
    Print("Error placing buy order: ", GetLastError());
    }
  }

用 Sell 接口把空单真正发出去

上面这段函数就是把做空逻辑落到 MT5 执行层的最后一步。CTrade 对象的 Sell 方法在市价直接丢单,LotSize 是外部传进来的手数,第二参 NULL 表示用当前品种,后面三个 0 分别代表滑点、止损、止盈全部不预设,尾串只是订单备注。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Open a Sell order                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OpenSellOrder()
  {
   if(trade.Sell(LotSize, NULL, class="num">0, class="num">0, class="num">0, "Sell Order"))
     {
      Print("Sell order placed successfully");
     }
   else
     {
      Print("Error placing sell order: ", GetLastError());
     }
  }
逐行拆一下:第 5 行调用 trade.Sell,成功返回 true 就进第 7 行打印确认;失败则走 else 分支,用 GetLastError 把具体错误码打出来,方便你查 4756(交易上下文占用)或 10030(无效参数)这类常见坑。 到这个函数写完,EA 的骨架就通了——信号判定、持仓检查、下单动作三段连起来就能跑。回测里这类纯市价空单在黄金 1 分钟图上平均延迟通常在 10~40 毫秒,但外汇和贵金属杠杆高,滑点扩大时实盘成交价可能偏离预期,仓位需按自己能扛的回撤来缩。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Open a Sell order                                                |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OpenSellOrder()
  {
   if(trade.Sell(LotSize, NULL, class="num">0, class="num">0, class="num">0, "Sell Order"))
     {
      Print("Sell order placed successfully");
     }
   else
     {
      Print("Error placing sell order: ", GetLastError());
     }
  }

◍ M1 tick 回测暴露的币种适应性

在 MT5 策略测试器中跑了一组基于 M1 图表、逐 tick 撮合的回测,标的选 USDJPY,样本区间锁定 2024-01-01 至 2024-08-05。这种粒度能逼出策略在极小波动下的真实反应,比仅用收盘价回放更接近实盘滑点环境。 反复换参数在 USDJPY 的 M1 上跑了几次后,倾向认为该逻辑对 USDJPY 与 EURUSD 都还能吃得开,进场信号在这两个直盘上的触发频率与回撤形态相对可控。 但把同一套搬到 GBPUSD 就明显水土不服,英镑的跳空与伦敦时段脉冲容易把止损扫在不利位置,实测胜率与回撤比都弱于前两个币种。外汇及贵金属杠杆交易高风险,上述结论仅基于特定区间回测,换周期或换年份可能失效,请自行在 MT5 用 tick 数据重跑验证。

「画得少,看得清」

把 SAR 步长和最大值调顺,再挂上跟踪止损,这个朴素 EA 才有从 demo 回测走到实盘的可能。原文给出的修正版 mq5 仅 4.08 KB,说明策略骨架极轻,重活都在参数优化与多轮测试上。 外汇与贵金属波动剧烈,自动化只是替你挡掉疲劳和手误,不挡亏损;任何回测亮眼的数字都不构成未来收益承诺,概率倾向比保证更诚实。 下面这段 OnTick 是整套逻辑的眼:只取当前品种周期的 SAR 值,没加任何过滤。你想验证,直接开 MT5 把 SAR_Step、SAR_Maximum 改成 0.01 / 0.2 跑一遍 EURUSD 小时图就懂。 真正能用的系统,是你在上面叠了风控和确认条件之后的东西,不是这个 23 KB 的 ex5 本身。

MQL5 / C++
class="type">void OnTick()
  {
class=class="str">"cmt">//--- 获取抛物线 SAR 值
   class="type">class="kw">double sar = iSAR(_Symbol, _Period, SAR_Step, SAR_Maximum);          class=class="str">"cmt">// 计算抛物线 SAR 值
让小布替你盯EA的异常心跳
这些诊断小布盯盘的 AIGC 已内置,打开对应品种页即可看到EA脱钩、滑点超阈和SAR点阵背离的实时提示,把重复劳动交给小布,你专注决策。

常见问题

步长调低、最大值设小可降敏感度,但会滞后;建议结合波动率过滤,趋势市再放开参数,外汇贵金属本身高风险需严控暴露。
可显式关闭定时器、删除自建图形对象、释放指标句柄;终端关闭与重编译触发源不同,日志分型便于定位开发期问题。
可以,小布盯盘的品种页内置AIGC诊断,能捕获EA停止、滑点异常和指标背离并推送,省去自建看板。
跳空使点阵重置滞后,趋势判定可能翻转;加开盘过滤或暂停新单直至点阵重排,能降低误触发概率。