突破策略 EA:開盤區間突破與波動突破 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 撰寫。內容僅供教育目的,不構成投資建議。

Similar Posts

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *