均值回歸策略:布林通道 + RSI 組合 MQL5 實作
📌 本文重點
實作均值回歸(Mean Reversion)策略:布林通道邊緣 + RSI 超買超賣共振訊號,含完整進出場邏輯與風險管理。
實作均值回歸(Mean Reversion)策略:布林通道邊緣 + RSI 超買超賣共振訊號,含完整進出場邏輯與風險管理。
均值回歸策略邏輯
均值回歸假設:價格偏離平均值後,有回歸均值的傾向。布林通道下軌 + RSI 超賣 = 雙重確認的做多機會。
#include <Trade\Trade.mqh>
CTrade g_trade;
input int InpBBPeriod = 20; // 布林通道週期
input double InpBBDeviation= 2.0; // 標準差倍數
input int InpRSIPeriod = 14; // RSI 週期
input double InpRSIOversold= 30.0; // RSI 超賣門檻
input double InpRSIOverbought=70.0; // RSI 超買門檻
input int InpATRPeriod = 14;
input double InpATRMult = 1.5;
input double InpRiskPct = 1.0;
input int InpMagic = 20002;
int g_bbHandle = INVALID_HANDLE;
int g_rsiHandle= INVALID_HANDLE;
int g_atrHandle= INVALID_HANDLE;
datetime g_lastBar = 0;
int OnInit()
{
g_bbHandle = iBands(_Symbol, _Period, InpBBPeriod, 0, InpBBDeviation, PRICE_CLOSE);
g_rsiHandle = iRSI(_Symbol, _Period, InpRSIPeriod, PRICE_CLOSE);
g_atrHandle = iATR(_Symbol, _Period, InpATRPeriod);
if (g_bbHandle==INVALID_HANDLE || g_rsiHandle==INVALID_HANDLE || g_atrHandle==INVALID_HANDLE)
return INIT_FAILED;
g_trade.SetExpertMagicNumber(InpMagic);
return INIT_SUCCEEDED;
}
void OnDeinit(const int r) { IndicatorRelease(g_bbHandle); IndicatorRelease(g_rsiHandle); IndicatorRelease(g_atrHandle); }
void OnTick()
{
datetime curBar = iTime(_Symbol, _Period, 0);
if (curBar == g_lastBar) return;
g_lastBar = curBar;
double upper[2], mid[2], lower[2], rsi[2], atr[2];
ArraySetAsSeries(upper,true); ArraySetAsSeries(mid,true);
ArraySetAsSeries(lower,true); ArraySetAsSeries(rsi,true); ArraySetAsSeries(atr,true);
if (CopyBuffer(g_bbHandle, 1, 0, 2, upper) < 2) return;
if (CopyBuffer(g_bbHandle, 0, 0, 2, mid) < 2) return;
if (CopyBuffer(g_bbHandle, 2, 0, 2, lower) < 2) return;
if (CopyBuffer(g_rsiHandle, 0, 0, 2, rsi) < 2) return;
if (CopyBuffer(g_atrHandle, 0, 0, 2, atr) < 2) return;
double close1 = iClose(_Symbol, _Period, 1);
double close2 = iClose(_Symbol, _Period, 2);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
int positions = CountPositions();
// 做多條件:收盤從下軌以下回到上方 + RSI 超賣
bool buySignal = close2 < lower[1] && close1 >= lower[0] && rsi[1] < InpRSIOversold;
// 做空條件:收盤從上軌以上回到下方 + RSI 超買
bool sellSignal = close2 > upper[1] && close1 <= upper[0] && rsi[1] > InpRSIOverbought;
if (buySignal && positions == 0)
{
double sl = ask - atr[1] * InpATRMult;
double tp = mid[1]; // 目標:回歸中軌
int slPips = (int)((ask - sl) / pt);
g_trade.Buy(CalcLots(slPips), _Symbol, ask, NormalizeDouble(sl,_Digits), NormalizeDouble(tp,_Digits), "MR Buy");
Print("均值回歸買入!RSI=", rsi[1], " BB Lower=", lower[0]);
}
if (sellSignal && positions == 0)
{
double sl = bid + atr[1] * InpATRMult;
double tp = mid[1];
int slPips = (int)((sl - bid) / pt);
g_trade.Sell(CalcLots(slPips), _Symbol, bid, NormalizeDouble(sl,_Digits), NormalizeDouble(tp,_Digits), "MR Sell");
Print("均值回歸賣出!RSI=", rsi[1], " BB Upper=", upper[0]);
}
}
int CountPositions() { int n=0; for(int i=PositionsTotal()-1;i>=0;i--) if(PositionGetSymbol(i)==_Symbol&&PositionGetInteger(POSITION_MAGIC)==InpMagic) n++; return n; }
double CalcLots(int sp) { double r=AccountInfoDouble(ACCOUNT_BALANCE)*InpRiskPct/100.0; double tv=SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE); double ts=SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE); double pv=tv*(ts/SymbolInfoDouble(_Symbol,SYMBOL_POINT)); if(pv<=0||sp<=0) return 0.01; double l=r/(sp*pv); double mn=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN),mx=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX),st=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); return NormalizeDouble(MathRound(MathMax(MathMin(l,mx),mn)/st)*st,2); }
策略適用市場
- ✅ 適合:橫盤震盪、範圍明確的市場
- ❌ 不適合:強趨勢市場(價格可能持續偏離)
建議搭配趨勢過濾器(如 ADX < 25 代表無趨勢)限制只在震盪市場交易。
本文由 James Lee 撰寫。內容僅供教育目的,不構成投資建議。