突破策略 EA:開盤區間突破與波動突破 MQL5 實作
📌 本文重點
實作兩種突破策略:亞洲盤開盤區間突破(Asian Session Range Breakout)與 Donchian Channel 波動突破,含完整 MQL5 程式碼與風險管理。
實作兩種突破策略:亞洲盤開盤區間突破(Asian Session Range Breakout)與 Donchian Channel 波動突破,含完整 MQL5 程式碼與風險管理。
突破策略的核心邏輯
突破策略假設:當價格突破某個重要的支撐/壓力水平時,會繼續朝突破方向移動。常見形式包括開盤區間突破、前日高低點突破、通道突破等。
策略一:亞洲盤區間突破
亞洲盤(00:00–08:00 GMT)通常波動較小,形成一個區間。歐洲盤開盤後突破這個區間時進場。
#include <Trade\Trade.mqh>
CTrade g_trade;
input int InpAsiaStartHour = 0; // 亞洲盤開始(GMT)
input int InpAsiaEndHour = 8; // 亞洲盤結束(GMT)
input int InpEntryHour = 8; // 進場時間(GMT)
input int InpCloseHour = 20; // 平倉時間(GMT)
input double InpRiskPct = 1.0;
input int InpMagic = 20001;
double g_rangeHigh = 0, g_rangeLow = 0;
bool g_rangeSet = false;
datetime g_lastDay = 0;
int OnInit() { g_trade.SetExpertMagicNumber(InpMagic); return INIT_SUCCEEDED; }
void OnTick()
{
datetime now = TimeCurrent();
MqlDateTime dt;
TimeToStruct(now, dt);
// 新的一天,重置區間
datetime today = now - dt.hour*3600 - dt.min*60 - dt.sec;
if (today != g_lastDay)
{
g_rangeHigh = 0; g_rangeLow = 0;
g_rangeSet = false; g_lastDay = today;
}
// 收集亞洲盤高低點
if (dt.hour >= InpAsiaStartHour && dt.hour < InpAsiaEndHour)
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if (g_rangeHigh == 0 || ask > g_rangeHigh) g_rangeHigh = ask;
if (g_rangeLow == 0 || bid < g_rangeLow) g_rangeLow = bid;
}
// 標記區間已就緒
if (dt.hour == InpAsiaEndHour && !g_rangeSet && g_rangeHigh > 0)
{
g_rangeSet = true;
Print("亞洲盤區間:High=", g_rangeHigh, " Low=", g_rangeLow);
}
// 強制平倉時間
if (dt.hour >= InpCloseHour) { CloseAll(); return; }
// 進場邏輯(只在指定時段後)
if (!g_rangeSet || dt.hour < InpEntryHour) return;
if (CountPositions() > 0) return;
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double spread = (ask - bid);
double rangeSize = g_rangeHigh - g_rangeLow;
// 向上突破
if (ask > g_rangeHigh + spread)
{
double sl = g_rangeLow;
double tp = ask + rangeSize;
int slPips = (int)((ask - sl) / pt);
g_trade.Buy(CalcLots(slPips), _Symbol, ask, sl, tp, "Range Break UP");
}
// 向下突破
else if (bid < g_rangeLow - spread)
{
double sl = g_rangeHigh;
double tp = bid - rangeSize;
int slPips = (int)((sl - bid) / pt);
g_trade.Sell(CalcLots(slPips), _Symbol, bid, sl, tp, "Range Break DOWN");
}
}
int CountPositions() { int n=0; for(int i=PositionsTotal()-1;i>=0;i--) if(PositionGetSymbol(i)==_Symbol&&PositionGetInteger(POSITION_MAGIC)==InpMagic) n++; return n; }
void CloseAll() { for(int i=PositionsTotal()-1;i>=0;i--) { if(PositionGetSymbol(i)!=_Symbol) continue; if(PositionGetInteger(POSITION_MAGIC)!=InpMagic) continue; g_trade.PositionClose(PositionGetInteger(POSITION_TICKET)); } }
double CalcLots(int slPips) { 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||slPips<=0) return 0.01; double l=r/(slPips*pv); double mn=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); double mx=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX); double st=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); return NormalizeDouble(MathRound(MathMax(MathMin(l,mx),mn)/st)*st,2); }
策略二:Donchian Channel 突破
input int InpDonchianPeriod = 20; // 通道週期(前N根K線的最高/最低點)
void CheckDonchianBreakout()
{
static datetime lastBar = 0;
datetime curBar = iTime(_Symbol, _Period, 0);
if (curBar == lastBar) return;
lastBar = curBar;
// 計算前 N 根已完成K線的最高/最低點(不含當前K線)
double highest = iHigh(_Symbol, _Period, 1);
double lowest = iLow(_Symbol, _Period, 1);
for (int i = 2; i <= InpDonchianPeriod; i++)
{
highest = MathMax(highest, iHigh(_Symbol, _Period, i));
lowest = MathMin(lowest, iLow(_Symbol, _Period, i));
}
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if (CountPositions() > 0) return;
// 向上突破前N根最高點
if (ask > highest)
{
double sl = lowest;
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
g_trade.Buy(CalcLots((int)((ask-sl)/pt)), _Symbol, ask, sl, 0, "Donchian UP");
}
// 向下突破前N根最低點
else if (bid < lowest)
{
double sl = highest;
double pt = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
g_trade.Sell(CalcLots((int)((sl-bid)/pt)), _Symbol, bid, sl, 0, "Donchian DOWN");
}
}
本文由 James Lee 撰寫。內容僅供教育目的,不構成投資建議。