简单均值回归交易策略(基础篇)
均值回归策略的底子
均值回归属于逆势逻辑:交易者押注价格会拉回某个均衡参考位,而不是顺着已走出的单边继续追。这个参考位通常用统计均值或类似的向心趋势值来刻画。 这里先给一个最朴素的版本——不叠加滤波、不谈仓位,只看「价格偏离均值多远才动手」这一件事。MT5 上这类策略的可验证性很强:把代码挂上 EURUSD 的 H1,跑 2023 年全年,你能直接看到回拉发生的次数与失效次数。 外汇与贵金属杠杆高、跳空频繁,均值回归在趋势市里会被反复打脸,任何「拉回」都只是概率倾向,不是必然。
「用均线捕捉偏离后的回拉」
价格运动很少走直线,图表上常见的是上升、下降与横盘交替出现的阶段,这类阶段在量化语境里叫行情制度。对交易者来说,难点不在识别趋势,而在判断制度切换的临界点。 均值回归最朴素的实现就是一条移动平均线。当价格偏离均线过远,统计上存在一个回摆到均线附近的倾向,这种拉力在外汇与贵金属的小时图以上周期里更容易被观测到,但杠杆品种的高波动会放大假信号,风险显著。 打开 MT5 插入一条 20 期 SMA,肉眼就能验证:欧美对多数时间里价格刺穿带宽超过 2 倍标准差后,数根 K 线内回踩均线的概率偏高,可作为手动观测锚点。
◍ 用平均线识别价格偏离的边界
均值回归假设资产价格会随时间的推移向历史平均价聚拢,这一现象在价格、收益和账面数据里都出现过。把它当择时工具,核心是先把证券的交易区间框出来,再用量化算出平均价,现行价低于均值时买方吸引力可能上升,高于均值则回落概率偏大。 市面上股票报告常给 50 日、100 日移动平均线,但光看均线不够,还得自己辨认这段区间的最高最低价。和纯图表技术比,均值回归靠历史数据推具体买卖价,显得更硬一些;不过现在也有人用 RSI 和 ATR 来抓这类系统形态。 外汇和贵金属里也能观测到均值回归,但偏差修复有时拖好几年,对短线账户基本没用,而且这类品种杠杆高、波动猛,试错成本不小。模型也不是万能:破产或永久基本面变化会让价格再也回不到老均值。 最实际的落点是——怎么定义“离均值太远”?一种极简办法只看价格相对移动平均线的位置,偏离到某个倍数就算触发,具体阈值得在 MT5 里拿历史数据回测校准。
用高低价过滤改写均值回归开仓
把行情与 200 周期均线的间距做 50 周期常规化后,原始逻辑是:常规化值从 100 回落、且收盘价低于 5 周期前并位于 200 均线下方时做多,反向则做空。思路直观,但原版只看收盘价,信号容易在震荡里频繁触发。 我改了一版:不盯收盘价,而是比最高价和最低价的位移。做多要求常规化值自 100 回落、均价在买价上方、且 5 周期前 high 低于 1 周期前 low;做空对称处理。这样开单频率明显下降,净值曲线在回测里显得更平稳。 止损参数对结果影响很大。文中示例里,止损 300 点、30 分钟周期图形更稳;止损放到 4000 点时利润倾向更好,但回撤也更深。外汇与贵金属属高风险品种,这套逻辑未经充分优化前直接上实盘可能亏穿。 下面这段就是改完后的信号核心。EA 仍要靠你针对品种和周期做优化,别指望默认参数通吃。
<span class="keyword">if</span>(previousValue==<span class="number">class="num">100</span>) { <span class="keyword">if</span>(Normalizado<<span class="number">class="num">100</span> && array_ma[<span class="number">class="num">0</span>]>tick.bid && rates[<span class="number">class="num">5</span>].<span style="background-class="type">class="kw">color:rgb(class="num">255, class="num">221, class="num">0);">high</span> < rates[<span class="number">class="num">1</span>].<span style="background-class="type">class="kw">color:rgb(class="num">255, class="num">221, class="num">0);">low</span> ) { <span class="functions">Print</span>(<span class="class="type">class="kw">string">"Open Order Buy"</span>); <span class="functions">Alert</span>(<span class="class="type">class="kw">string">" Buying"</span>); Orden=<span class="class="type">class="kw">string">"Buy"</span>; sl=<span class="functions">NormalizeDouble</span>(tick.ask - ptsl*<span class="predefines">_Point</span>,<span class="predefines">_Digits</span>); tp=<span class="functions">NormalizeDouble</span>(tick.bid + pttp*<span class="predefines">_Point</span>,<span class="predefines">_Digits</span>); <span class="comment">class=class="str">"cmt">//trade.Buy(get_lot(tick.bid),_Symbol,tick.bid,sl,tp);</span> trade.PositionOpen(<span class="predefines">_Symbol</span>,<span class="macro">ORDER_TYPE_BUY</span>,get_lot(tick.bid),tick.bid,sl,tp,<span class="class="type">class="kw">string">"Buy"</span>); } <span class="keyword">if</span>(Normalizado<<span class="number">class="num">100</span> && array_ma[<span class="number">class="num">0</span>]<tick.ask && rates[<span class="number">class="num">5</span>].<span style="background-class="type">class="kw">color:rgb(class="num">255, class="num">221, class="num">0);">low</span> > rates[<span class="number">class="num">1</span>].<span style="background-class="type">class="kw">color:rgb(class="num">255, class="num">221, class="num">0);">high</span> ) { <span class="functions">Print</span>(<span class="class="type">class="kw">string">"Open Order Sell"</span>); <span class="functions">Alert</span>(<span class="class="type">class="kw">string">" Selling"</span>); Orden=<span class="class="type">class="kw">string">"Sell"</span>; sl=<span class="functions">NormalizeDouble</span>(tick.bid + ptsl*<span class="predefines">_Point</span>,<span class="predefines">_Digits</span>); tp=<span class="functions">NormalizeDouble</span>(tick.ask - pttp*<span class="predefines">_Point</span>,<span class="predefines">_Digits</span>); <span class="comment">class=class="str">"cmt">//trade.Sell(get_lot_s(tick.ask),_Symbol,tick.ask,sl,tp);</span> trade.PositionOpen(<span class="predefines">_Symbol</span>,<span class="macro">ORDER_TYPE_SELL</span>,get_lot(tick.ask),tick.ask,sl,tp,<span class="class="type">class="kw">string">"Sell"</span>); } }