使用MQL5实现抛物线SAR趋势策略的自动化交易:打造高效的EA(基础篇)
「用抛物线SAR在MT5里跑出自动化趋势单」
抛物线 SAR(Parabolic SAR)是 Welles Wilder 发明的趋势跟随指标,点在价格下方为多头信号,点在上方为空头信号。把它接进 MQL5 的 EA 框架,就能在 MT5 上实现无人值守的趋势跟踪交易,适合外汇与贵金属这类高波动、高风险的品种。 实际加载时,SAR 的步长(Step)和最大值(Max)是两个核心参数。默认 Step=0.02、Max=0.2,在 EURUSD 的 H1 周期回看,参数过小会频繁反转产生毛刺信号,过大则进场滞后吃掉一段趋势。外汇与贵金属杠杆交易风险极高,任何参数组合都只代表历史概率,不预示未来收益。 下面这段 MQL5 片段演示了在 EA 的 OnTick 里读取 SAR 值并判断多空位置的最小骨架,复制进 MT5 的 EA 模板即可编译验证。
为什么用 EA 把人为抖动抹平
算法交易的核心价值不在「跑得更快」,而在于把人的犹豫和情绪偏见从执行链里摘掉。系统按预设参数在快节奏行情里下单,每次逻辑一致,不会因为上一笔止损就手软、也不会因为连赚就加注。 在 MT5 里用 EA 固化一套规则是主流做法,本文以抛物线 SAR 为触发条件,演示从指标信号到自动下单的完整构建过程。读者可以直接开 MT5 的 EA 向导,把 SAR 的步长、最大值先按默认 0.02 / 0.2 跑一遍,感受信号翻转频率。
◍ SAR 点怎么跟着价格跑
抛物线 SAR 是 Welles Wilder 在 1978 年提出的趋势跟踪工具,它在 K 线外侧排布一串点:点在价格下方意味着上升市,点在上方则是下降市,点的翻面位置往往对应趋势可能结束的潜在反转区。 SAR 步长直接决定点贴着价格的松紧。步长调低,点会明显落后于价格,信号少但滤噪强;步长调高,点紧贴价格,反转捕捉快但假突破概率上升。MT5 里默认步长是 0.02,加速上限默认 0.2。 加速因子让 SAR 在趋势里逐步追赶价格:单边走得越久,步长按 0.02 每次累加直到触顶 0.2,点会加速靠拢价格,给持仓者一个动态出场参考。外汇与贵金属波动大、杠杆高,SAR 在趋势市有用,震荡市反复挨耳光属正常风险。 单独用 SAR 做外汇/大宗商品趋势单可行,但更常见的是叠一个均线或 ATR 过滤横盘,降低反向点频发带来的磨损。
「把SAR信号写成可跑的EA骨架」
EA头部先挂版权与版本,再 #include <Trade\Trade.mqh> 引入交易类,否则开平仓函数根本编不过。输入参数里 LotSize 默认 0.2 手,SAR_Step 给 0.02、SAR_Maximum 给 0.2,滑点容限 3 点——这几个值直接决定仓位风险与指标灵敏度,外汇和贵金属波动属性不同,加载前最好按品种重设。
OnInit 只在加载时跑一次,示例里只 Print 一句初始化成功并返回 INIT_SUCCEEDED;若返回 INIT_FAILED 终端会直接拦住EA运行。OnDeinit 在移除或重编译时触发,日志会带 reason 代码,开发期靠它区分是手动删、重编还是终端关闭,必要时在这里释放文件句柄或存状态。
真正干活的是 OnTick,每来一个报价就执行。它先用 iSAR(_Symbol,_Period,0.02,0.2) 算当前抛物线值,再用 iClose(_Symbol,_Period,1) 抓前一根已完成K线收盘价,存进 lastPrice。注意参数 1 代表已收盘那根,当前根还在画不能拿来比。
开仓前用 !IsPositionOpen(_Symbol) 卡一道:同品种有仓就跳过,避免重复下单刷屏。SAR 本质是跟踪止损线,收盘价跌破 SAR 倾向趋势反转,EA 拿这个比较代替人工判断,情绪干扰会小一些,但外汇/贵金属高风险,信号错判概率始终存在。
下面这段就是上述逻辑的代码骨架,复制进 MT5 策略测试器能直接编译观察信号触发:
class="macro">#class="kw">property copyright "Copyright class="num">2024, MetaQuotes Ltd." "Duke" class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class="macro">#include <Trade\Trade.mqh> class=class="str">"cmt">//--- Input parameters class="kw">input class="type">class="kw">double LotSize = class="num">0.2; class=class="str">"cmt">// Lot size for trading class="kw">input class="type">class="kw">double SAR_Step = class="num">0.02; class=class="str">"cmt">// Parabolic SAR step class="kw">input class="type">class="kw">double SAR_Maximum = class="num">0.2; class=class="str">"cmt">// Parabolic SAR maximum class="kw">input class="type">int Slippage = class="num">3; class=class="str">"cmt">// Slippage for orders class=class="str">"cmt">//--- Trade object CTrade trade; class="type">int OnInit() { class=class="str">"cmt">//--- Initialization code here Print("Parabolic SAR EA Initialized"); class="kw">return(INIT_SUCCEEDED); } class="type">void OnDeinit(class="kw">const class="type">int reason) { class=class="str">"cmt">//--- Cleanup code here Print("Parabolic SAR EA Deinitialized"); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert tick function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- Get the Parabolic SAR value class="type">class="kw">double sar = iSAR(_Symbol, _Period, SAR_Step, SAR_Maximum); class=class="str">"cmt">// Calculate the Parabolic SAR value class="type">class="kw">double lastPrice = iClose(_Symbol, _Period, class="num">1); class=class="str">"cmt">// Get the close price of the previous candle class=class="str">"cmt">//--- Check if there is an existing position if(!IsPositionOpen(_Symbol)) {