2025年9月3日 星期三

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

策略概述(交易商品 XAUUSD)
這是一個基於多重技術指標的日內交易策略,使用H1(小時)時間週期進行交易決策。策略結合唐奇安通道突破、RSI超買超賣、MACD背離等多種技術分析工具來識別進出場時機,並採用嚴格的風險控制和當沖平倉機制。

基礎概念
時間週期: H1(1小時)
風險控制: 動態手數計算,風險百分比為1%
資金風控門檻: 5000
商品平均點差限制: 50點
交易限制: 每日限制1次進場
交易時段: 06:00-22:00
當沖設定: 23:00或01:00強制平倉
停利停損: TP=3360點,SL=1000點

進出場策略
多單進場條件
LE_Cond = (High[1] >= a_DC_HIGH_A[3] && a_RSIA[1] > 70);

條件分析:
唐奇安通道突破: 前一根K棒最高價突破第3根K棒的唐奇安通道上軌
RSI超買確認: RSI指標大於70,確認強勢上漲動能
進場方式: 市價單買入

空單進場條件
SE_Cond = (Black3Bar_LClose());

條件分析:
三黑創低收: 連續3根陰線且收盤價創新低
高點下降趨勢: 確認空頭趨勢形成
跌破支撐: 跌破第四根K棒低點
進場方式: 市價單賣出

進場價格計算
多單進場價格
BuyPrice = (FVG_多頭上緣價格 + FVG_多頭下緣價格) / 2;
計算方式: FVG多頭缺口的中間價位

空單進場價格
ShortPrice = MathMin(High[1], MathMin(High[2], High[3]));
計算方式: 取前3根K棒中的最低高點

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

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


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

//+------------------------------------------------------------------+
//| 每tick執行函數                                                
//+------------------------------------------------------------------+
void OnTick()
{
   // 檢查帳戶餘額是否低於風控門檻
   if(AccountBalance < 資金風控)
   {
      Alert("**********  資金不足 *************"); // 提示資金不足
      return;
   }

   // 計算當前 K 棒編號及自上次平倉後的 K 棒數
   BarNumber = iBarShift(Symbol(), 時間週期, LoadEA);
   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 棒編號
   }

   // 新 K 棒時執行相關計算
   if(BarNumber != JudgeNo)
   {
      換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));                                         // 限制手數範圍
   }

   // 當沖模式:限制進場時間
   if(當沖 == true)
   {
      接近收盤 = (getTM_hour(TimeCurrent()) >= 18 || getTM_hour(TimeCurrent()) <= 1); // 18:00 至次日 1:00 為接近收盤
      允許交易時段 = (允許交易時段 && !接近收盤);                                    // 更新交易時段狀態
   }

   // 在允許交易時段內執行進場邏輯
   if(允許交易時段 == true)
   {
      //+------------------------------------------------------------------+
      //| 多單進場                                                      
      //+------------------------------------------------------------------+
      set_BuyCondition(); // 設定多單進場條件
      if(LE_Cond == true && SP < NormalizeDouble(商品平均點差 * Point(), Digits()))
      {
         if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
         {
            if(BarSinceExit > 1 && EntriesToday(MagicNumber, Symbol()) < 1)
            {

                  多單進場單號 = 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)
         {

            if(BarSinceExit > 1 && EntriesToday(MagicNumber, Symbol()) < 1)
            {

                  空單進場單號 = 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_BarInfo();         // 計算 K 棒資訊(範圍、實體、上影線、下影線)
   set_ATR();             // 計算 ATR 指標
   set_MACD();            // 計算 MACD 指標
   set_RSI();             // 計算 RSI 指標
   set_DONCHIAN_CHANNEL(); // 計算 Donchian Channel
   計算FVG價格();         // 計算公平價值缺口(FVG)價格
   Day5Range = ((HighD[1] - LowD[1]) + (HighD[2] - LowD[2]) + (HighD[3] - LowD[3]) + 
                (HighD[4] - LowD[4]) + (HighD[5] - LowD[5])) / 5; // 計算五日平均震幅
}

//+------------------------------------------------------------------+
//| 自訂函數:設定交易時段                                        
//+------------------------------------------------------------------+
void 交易時段賦值()
{
      允許交易時段 = (getTM_hour(TimeCurrent()) >= 6 && getTM_hour(TimeCurrent()) < 22); // 交易時段:6:00-22:00
}

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

//+------------------------------------------------------------------+
//| 自訂函數:交易時段外檢查停損停利                        
//+------------------------------------------------------------------+
void 交易時段外也可停損停利()
{
   // 多單停損停利
   if(多單部位() > 0)
   {
      多單進場價格 = LE_EntryPrice(MagicNumber, 多單進場單號); // 獲取多單進場價格
      double 多單最小停利 = NormalizeDouble(多單進場價格 + SP * 3, Digits()); // 最小停利:進場價 + 3 倍點差
      bool LX_MinPF = Bid > 多單最小停利; // 檢查是否達到最小停利
      多單停利價格 = NormalizeDouble(多單進場價格 + TP * Point(), Digits()); // 止盈價格
      多單停損價格 = NormalizeDouble(多單進場價格 - SL * Point(), Digits()); // 止損價格


         LX_Cond = ((LX_MinPF == true && MACD_HDiv_01() == true) || 
                    (Close[1] >= 多單停損價格 && Bid < 多單停損價格)); // 出場條件:MACD 背離或觸及止損
    
      if(LX_Cond == true && BarNumber != CloseOrderNo && LE_BarsSinceEntry(MagicNumber, 多單進場單號, 時間週期) > 0)
      {
         LX_CloseByTicket(多單進場單號, Lots); // 平倉多單
         if(多單部位() == 0)
            CloseOrderNo = iBarShift(Symbol(), 時間週期, LoadEA); // 更新平倉 K 棒編號
      }
   }

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

         SX_Cond = ((SX_MinPF == true && MACD_LDiv_01() == true) || 
                    (Close[1] <= 空單停損價格 && Ask > 空單停損價格)); // 出場條件:MACD 背離或觸及止損
    
      if(SX_Cond == true && BarNumber != CloseOrderNo && SE_BarsSinceEntry(MagicNumber, 空單進場單號, 時間週期) > 0)
      {
         SX_CloseByTicket(空單進場單號, Lots); // 平倉空單
         if(空單部位() == 0)
            CloseOrderNo = iBarShift(Symbol(), 時間週期, LoadEA); // 更新平倉 K 棒編號
      }
   }
}

//+------------------------------------------------------------------+
//| 自訂函數:設定多單進場條件                                      
//+------------------------------------------------------------------+
void set_BuyCondition()
{
      LE_Cond = (High[1] >= a_DC_HIGH_A[3] && a_RSIA[1] > 70); // 條件:價格突破 Donchian Channel 上軌且 RSI > 70
}

//+------------------------------------------------------------------+
//| 自訂函數:設定空單進場條件                                    
//+------------------------------------------------------------------+
void set_ShortCondition()
{
      SE_Cond = (Black3Bar_LClose()); // 條件:三黑創低收形態
}


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

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


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





沒有留言:

張貼留言