2025年9月15日 星期一

MT5 EA交易策略開發教學[15]

策略概述(交易商品 XAUUSD)
這是一個基於多種技術指標的趨勢跟隨與背離交易策略。策略整合MACD背離、ADX趨勢強度、Force Index動能確認等多項指標來識別進場機會,並使用當沖模式(特定時間強制平倉)。

基礎概念
時間週期: H1(1小時)
風險控制: 動態手數計算(基於風險百分比、帳戶餘額與SL),手數限制在0.01~0.3;
資金風控門檻:低於門檻時停止交易
商品平均點差限制: 進場前檢查點差 < 商品平均點差 * Point()
交易限制: 每日限制1次進場;
交易時段: 當沖模式下排除18:00後至01:00前
當沖設定: 是(預設啟用),特定時間(當沖出場時間或01:00)強制平倉

進出場策略
多單進場條件
LE_Cond = (MACD_HDiv_01() && ADX強勢趨勢());
條件分析:
MACD高點背離: 高點在最近2根K棒內發生,但MACD DIF最大值在更早(>2根),且RSI < 70(避免超買)
ADX強勢趨勢: ADX > 25 且上升(確認趨勢強度)
進場方式: 市價單買入,僅在無部位、點差小、今日未進場、BarSinceExit >1時執行

空單進場條件
SE_Cond = (FORCE_ZeroCross() == -1 && FORCE_VolumePrice());

條件分析:
Force Index零線穿越: FORCE_ZeroCross() == -1
Force Index量價確認: FORCE_VolumePrice()
進場方式: 市價單賣出、僅在無部位、點差小、今日未進場、BarSinceExit >1時執行

//+------------------------------------------------------------------+
//| MT5 自動交易程式 (Expert Advisor)                                                 
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>                                             // 引入 MT5 交易函數庫
#include <MagicMT5_函數庫V2.mqh>                                      // 引入自定義函數庫

ENUM_TIMEFRAMES 時間週期 = PERIOD_H2;              // 主交易時間框架(小時圖)
ENUM_TIMEFRAMES 時間框架 = PERIOD_D1;              // 相對大週期(日線圖)

//+------------------------------------------------------------------+
//| 初始化函數,於EA啟動時執行                                      |
//+------------------------------------------------------------------+
int OnInit()
  {
   LoadEA = TimeCurrent(); // 記錄EA載入時間
   return(INIT_SUCCEEDED); // 初始化成功
  }

//+------------------------------------------------------------------+
//| 每tick執行,核心交易邏輯                                         |
//+------------------------------------------------------------------+
void OnTick()
  {
   // 檢查帳戶餘額是否低於資金風控門檻
   if(AccountInfoDouble(ACCOUNT_BALANCE) < 資金風控)
     {
      Alert("**********  資金不足 *************"); // 餘額不足警告
      return;
     }

   BarNumber = iBarShift(Symbol(),時間週期,LoadEA); // 計算從EA載入到當前的K棒數
   BarSinceExit = BarNumber-CloseOrderNo ; // 計算上次平倉後的K棒數
   if((BarNumber == 1 && BarNumber != JudgeNo)) // 初次執行且非重複判斷
     {
      多單進場單號 = Buy_at_MARKET(Symbol(),Lots,0,0,"1st_K",MagicNumber) ; // 開啟市價買單(測試用)
      LX_CloseByTicket(多單進場單號,Lots) ; // 立即平倉
      CloseOrderNo =  iBarShift(Symbol(),時間週期,LoadEA); // 更新平倉K棒編號
     }

   if(BarNumber != JudgeNo) // 新K棒觸發
     {
      換K棒(); // 執行新K棒初始化
      交易時段賦值(); // 設定交易時段狀態
     }

   // 獲取即時市場資訊
   Ask=SymbolInfoDouble(Symbol(),SYMBOL_ASK); // 當前買價
   Bid=SymbolInfoDouble(Symbol(),SYMBOL_BID); // 當前賣價
   AccountBalance=AccountInfoDouble(ACCOUNT_BALANCE); // 帳戶餘額
   Tickvalue=SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_VALUE); // 每跳點價值
   SP = NormalizeDouble(MathAbs(Ask-Bid),Digits()) ; // 計算點差並標準化

//+------------------------------------------------------------------+
//| 計算交易手數                                                  |
//+------------------------------------------------------------------+
   if(動態計算手數 == true) // 若啟用動態手數
     {
      Lots = get_dynamic_lot_size(是否偶數單,Symbol(),風險百分比,AccountBalance,SL) ; // 計算動態手數
      Lots = MathMin(0.3,MathMax(0.01,Lots)) ; // 限制手數範圍0.01~0.3
     }

   // 當沖模式時間限制
   if(當沖 == true)
     {
      接近收盤 = (getTM_hour(TimeCurrent()) >= 18 || getTM_hour(TimeCurrent()) <= 1) ; // 判斷是否接近收盤(18:00-01:00)
      允許交易時段 = (允許交易時段 && !接近收盤) ; // 交易時段需在允許範圍且非收盤時段
     }

   // 允許交易時段內執行進場邏輯
   if(允許交易時段 == true)
     {
      //+------------------------------------------------------------------+
      //| 多單進場邏輯                                                |
      //+------------------------------------------------------------------+
      set_BuyCondition(); // 設定多單進場條件
      if(LE_Cond == true && SP < NormalizeDouble(商品平均點差*Point(),Digits())) // 多單條件成立且點差符合限制
        {
         if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo) // 無部位且非同一K棒
           {
            if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1) // 確保上次平倉後超過1根K棒且當日未進場
              {
           //   市價買入模式
                  多單進場單號 = Buy_at_MARKET(Symbol(),Lots,TP,SL,"BUY MARKET",MagicNumber) ; // 開啟市價買單
                  OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA); // 記錄進場K棒編號

              }
           }
        }
      //+------------------------------------------------------------------+
      //| 空單進場邏輯                                                |
      //+------------------------------------------------------------------+
      set_ShortCondition() ; // 設定空單進場條件
      if(SE_Cond == true && SP < NormalizeDouble(商品平均點差*Point(),Digits())) // 空單條件成立且點差符合限制
        {
         if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo) // 無部位且非同一K棒
           {
            if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1) // 確保上次平倉後超過1根K棒且當日未進場
              {
               // 市價賣出模式
                  空單進場單號 = Short_at_MARKET(Symbol(),Lots,TP,SL,"Short Market",MagicNumber) ; // 開啟市價賣單
                  OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA); // 記錄進場K棒編號
              }
           }
        }
     }

//+------------------------------------------------------------------+
//| 當沖平倉邏輯                                                 |
//+------------------------------------------------------------------+
   if(當沖 == true && (getTM_hour(TimeCurrent()) == 當沖出場時間 || getTM_hour(TimeCurrent()) == 1)) // 當沖模式下到達平倉時間
     {
      if(多單部位() > 0 || 空單部位() > 0) // 若有持倉
        {
         當沖平倉(); // 執行當沖平倉
        }
     }

   交易時段外也可停損停利(); // 交易時段外繼續監控停損停利
   JudgeNo = iBarShift(Symbol(),時間週期,LoadEA); // 更新判斷K棒編號
  }

//+------------------------------------------------------------------+
//| 自訂函數庫:多單部位計數                                      |
//+------------------------------------------------------------------+
int 多單部位()
  {
   int count;
   count = get_TradeCounts(Symbol(), MagicNumber,POSITION_TYPE_BUY) ; // 計算多單數量
   return count ;
  }

//+------------------------------------------------------------------+
//| 自訂函數庫:空單部位計數                                      |
//+------------------------------------------------------------------+
int 空單部位()
  {
   int count;
   count = get_TradeCounts(Symbol(), MagicNumber,POSITION_TYPE_SELL) ; // 計算空單數量
   return count ;
  }

//+------------------------------------------------------------------+
//| 新K棒初始化函數                                              |
//+------------------------------------------------------------------+
void 換K棒()
  {
   // 新K棒時刪除所有掛單
   if(total_pending_order_count(Symbol(), MagicNumber,-1) != 0)
     {
      delete_pending_orders_all(Symbol(), MagicNumber, -1, 0x0000ff); // 刪除所有掛單
     }
   Set_OHLC_Bar_Series(); // 設定K棒開高低收序列
   Set_OHLC_Day_Series(); // 設定日線開高低收序列
   Get_OHLC_Bar(30) ; // 獲取最近30根K棒數據
   Get_OHLC_Day(15) ; // 獲取最近15天日線數據

   set_MACD(); // 計算MACD指標
   set_RSI(); // 計算RSI指標
   set_ADX(); // 計算ADX指標
   set_FORCE_INDEX() ; // 計算Force Index指標

   Day5Range = ((HighD[1] - LowD[1])+(HighD[2] - LowD[2])+(HighD[3] - LowD[3])+(HighD[4] - LowD[4])+(HighD[5] - LowD[5]))/5; // 計算前5天平均範圍
  }

//+------------------------------------------------------------------+
//| 交易時段設定函數                                             |
//+------------------------------------------------------------------+
void 交易時段賦值()
  {
      允許交易時段 = true; // 允許交易
  }

//+------------------------------------------------------------------+
//| 交易時段外停損停利監控                                       |
//+------------------------------------------------------------------+
void 交易時段外也可停損停利()
  {
   // 多單出場邏輯
   if(多單部位() > 0)
     {
      多單進場價格 = LE_EntryPrice(MagicNumber,多單進場單號); // 獲取多單進場價格
      多單最小停利 = NormalizeDouble(多單進場價格 + SP*3,Digits()) ; // 計算最小停利(進場價+3倍點差)
      LX_MinPF = Bid > 多單最小停利 ; // 檢查是否達到最小停利
      多單停利價格 = NormalizeDouble(多單進場價格 + TP * Point(),Digits()) ; // 計算停利價格
      多單停損價格 = NormalizeDouble(多單進場價格 - SL * Point(),Digits()) ; // 計算停損價格

         LX_Cond = ((LX_MinPF == true && CrossUnder(a_OSC[2],0,a_OSC[1],0)) || (Close[1] >= 多單停損價格 && Bid < 多單停損價格)) ; // 出場條件:最小停利+OSC下穿零線 或 觸及停損

      if(LX_Cond == true && BarNumber != CloseOrderNo && LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期) > 0) // 出場條件成立且非同一K棒
        {
         LX_CloseByTicket(多單進場單號,Lots) ; // 平倉多單
         if(多單部位() == 0) // 若無多單部位
           {
            CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ; // 更新平倉K棒編號
           }
        }
     }

   // 空單出場邏輯
   if(空單部位() > 0)
     {
      空單進場價格 = SE_EntryPrice(MagicNumber,空單進場單號); // 獲取空單進場價格
      空單最小停利 = NormalizeDouble(空單進場價格 - SP*3,Digits()) ; // 計算最小停利(進場價-3倍點差)
      SX_MinPF = Ask < 空單最小停利 ; // 檢查是否達到最小停利
      空單停利價格 = NormalizeDouble(空單進場價格 - TP * Point(),Digits()) ; // 計算停利價格
      空單停損價格 = NormalizeDouble(空單進場價格 + SL * Point(),Digits()) ; // 計算停損價格

         SX_Cond = ((SX_MinPF == true && CrossOver(a_OSC[2],0,a_OSC[1],0)) || (Close[1] <= 空單停損價格 && Ask > 空單停損價格)) ; // 出場條件:最小停利+OSC上穿零線 或 觸及停損


      if(SX_Cond == true && BarNumber != CloseOrderNo && SE_BarsSinceEntry(MagicNumber,空單進場單號,時間週期) > 0) // 出場條件成立且非同一K棒
        {
         SX_CloseByTicket(空單進場單號,Lots) ; // 平倉空單
         if(空單部位() == 0) // 若無空單部位
           {
            CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ; // 更新平倉K棒編號
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| 設定多單進場條件                                              |
//+------------------------------------------------------------------+
void set_BuyCondition()
  {
      LE_Cond = (MACD_HDiv_01() && ADX強勢趨勢()) ; // MACD高點背離+ADX強勢趨勢
  }

//+------------------------------------------------------------------+
//| 設定空單進場條件                                              |
//+------------------------------------------------------------------+
void set_ShortCondition()
  {
      SE_Cond = (FORCE_ZeroCross() == -1 && FORCE_VolumePrice()) ; //零線穿越+量價確認
  }

//+------------------------------------------------------------------+
//| 當沖平倉函數                                                 |
//+------------------------------------------------------------------+
void 當沖平倉()
  {
   if((getTM_hour(TimeCurrent()) == 當沖出場時間 || getTM_hour(TimeCurrent()) == 1)) // 到達當沖平倉時間
     {
      if(多單部位() > 0 && BarNumber != CloseOrderNo) // 有多單且非同一K棒
         LX_CloseByTicket(多單進場單號,Lots) ; // 平倉多單
      if(空單部位() > 0 && BarNumber != CloseOrderNo) // 有空單且非同一K棒
         SX_CloseByTicket(空單進場單號,Lots) ; // 平倉空單
      CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ; // 更新平倉K棒編號
     }
  }


回測結果
測試參數交易商品:XAUUSD(黃金)
樣本內區間:2019/1/1 ~ 2023/8/31
交易手數:固定0.1手
時間框架:H2 小時圖表
交易模式:當沖交易

現在就加入《外匯實戰 MT5 EA基礎班》,用量化思維,開啟你的交易新紀元!


★ ~~~ 早鳥優惠 ( 2025/11/13 前報名) ~~~ ★ 
🎁限量加碼 贈送 實戰EA *2
(XAUUSD *1 + NAS100 * 1)
可攜伴2位參加文創手作聖誕樹 DIY才藝班




沒有留言:

張貼留言