2025年11月21日 星期五

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

核心策略概述 (商品 NAS100)
基於KD/CCI背離識別的反轉交易策略,採用掛單突破進場,整合一雲圖、Donchian Channel等指標定價,搭配當沖模式進行日內交易。

基礎設定
資金門檻: 低於門檻停止交易並發出警示
點差限制: SP < 商品平均點差 × Point()
交易時段: 00:00~16:00
當沖限制: 18:00~01:00禁止開倉,指定時間強制平倉
每日限制: 最多1次進場
冷卻期: BarSinceExit > 1(平倉後至少間隔1根K棒)
新K棒清倉: 自動刪除所有未成交掛單並更新指標
 
多單進場
條件: KD_HDiv_02() && Close[1] > a_BigFastSma[1]
KD高檔背離02: 比較LenA2與LenA2×2週期KD值,最高價位置相同但短週期KD < 長週期KD
趨勢過濾: 收盤價高於大週期快速均線
額外檢查: 最近6筆內有空單平倉 

買入價格: a_ICHI_C[2] + a_ATR2
下單方式: 掛Buy Stop單,條件Close[1] < 買入價格,有效期3600秒
執行條件: 無持倉、不同K棒、冷卻期滿、今日未進場
 
空單進場 
條件: CCI_LDiv_02() && BigMin3L < a_BigAvg13[1]
CCI低檔背離02: 比較LenB1與LenB1×2週期CCI值,最低價位置相同但短週期CCI > 長週期CCI
三線過濾: 7/13/21線最小值低於13線(空頭排列)
 
賣出價格: a_DC_LOW_A[1] - a_ATR[2]×0.382(Donchian下軌-ATR緩衝)
下單方式: 掛Short Stop單,條件Close[1] > 賣出價格,有效期3600秒
執行條件: 無持倉、不同K棒、冷卻期滿、今日未進場
 
多單出場
停利: 進場價 + (TP + Day5Range×0.618) × Point()
動態停損三階段:
盈利 ≤ SL×1.5: 進場價 - SL×Point()
SL×1.5 < 盈利 ≤ TP: 最高價 - SL×Point()/2
盈利 > TP: 最高價 - 盈利/2(回撤50%)
觸發條件: 停利突破或停損突破
 
保本機制: 最高價 > 進場價+TP×0.5時,保本價=進場價+TP×0.168

 
空單出場
停利: 進場價 - TP × Point()
停損: 進場價 + SL × Point()
最小停利: 進場價 - SP×3
觸發條件: (達最小停利 && MACD上穿零線) 或 停損突破
保本機制: 最低價 < 進場價-TP×0.5時,保本價=進場價-TP×0.168

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

ENUM_TIMEFRAMES  時間週期 = PERIOD_M12; // EA 主要運行的時間週期。
ENUM_TIMEFRAMES  時間框架 = PERIOD_H1; // 相對大週期,可能用於趨勢判斷或過濾

//+------------------------------------------------------------------+
//| 初始化函式 (EA 載入時執行一次)
//+------------------------------------------------------------------+
int OnInit()
  {
   LoadEA = TimeCurrent(); // 記錄 EA 載入的當前時間。
   return(INIT_SUCCEEDED); // 初始化成功。
  }

//+------------------------------------------------------------------+
//| OnTick 函式 (每次報價變動時執行)
//+------------------------------------------------------------------+
// OnTick 函數:這是 MT5 EA 的核心函數,每個價格跳動(Tick)都會執行一次。
void OnTick()
  {
   // 資金風控檢查:如果目前帳戶餘額 (ACCOUNT_BALANCE) 低於預設的「資金風控」參數值,則停止交易並發出警報。
   if(AccountInfoDouble(ACCOUNT_BALANCE) < 資金風控)
     {
      Alert("**********  資金不足 *************"); // 彈出警示訊息
      return; // 退出 OnTick 函數,停止執行後續交易邏輯
     }

   // 獲取當前 K 棒的索引:iBarShift 找到指定時間點 (LoadEA,可能是 EA 載入時間或上次平倉時間) 對應的 K 棒索引(從 0 開始,0 代表當前K棒)。
   BarNumber = iBarShift(Symbol(),時間週期,LoadEA);
   // 計算自上次平倉以來經過的 K 棒數量。CloseOrderNo 應該記錄上次平倉時的 BarNumber。
   BarSinceExit = BarNumber-CloseOrderNo ;
   // 檢查是否為新 K 棒的第一個 Tick 並且 BarNumber 不等於 JudgeNo (用於判斷是否換 K 棒的標記)。
   if((BarNumber == 1 && BarNumber != JudgeNo))
     {
      // 執行一組測試性的市價買入和立即平倉操作 (可能用於初始化或獲取單號、滑點測試等)。
      多單進場單號 = Buy_at_MARKET(Symbol(),Lots,0,0,"1st_K",MagicNumber) ; // 市價買入多單
      LX_CloseByTicket(多單進場單號,Lots) ; // 立即平倉多單
      空單進場單號 = Short_at_MARKET(Symbol(),Lots,0,0,"1st_K",MagicNumber) ; // 市價賣出空單
      SX_CloseByTicket(空單進場單號,Lots) ; // 立即平倉空單
      // 更新平倉 K 棒索引。
      CloseOrderNo =  iBarShift(Symbol(),時間週期,LoadEA);
      // 設置 FastSma 和 SlowSma 的參數,可能是取 LenA1 和 LenB1 中的最小值和最大值。
      FastSma = MathMin(LenA1, LenB1);
      SlowSma = MathMax(LenA1, LenB1);
     }

   // 檢查是否換了新的 K 棒 (BarNumber 不等於上一個 Tick 記錄的 JudgeNo)。
   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()) ; // 計算點差 (Ask-Bid 的絕對值,並依商品小數位數標準化)

//+------------------------------------------------------------------+
//|計算交易手數
//+------------------------------------------------------------------+
   // 如果啟用了動態計算手數。
   if(動態計算手數 == true)
     {
      // 根據風險百分比、帳戶餘額和停損點數 (SL) 計算適合的手數。
      Lots = get_dynamic_lot_size(是否偶數單,Symbol(),風險百分比,AccountBalance,SL) ;
      // 限制手數在 0.01 到 0.3 之間 (確保不會過小或過大)。
      Lots = MathMin(0.3,MathMax(0.01,Lots)) ;
     }

   // 如果啟用當沖模式。
   if(當沖 == true)
     {
      // 判斷是否接近收盤時間 (這裡定義為小時 >= 18 或小時 <= 1)。
      接近收盤 = (getTM_hour(TimeCurrent()) >= 18 || getTM_hour(TimeCurrent()) <= 1) ;
      // 更新「允許交易時段」:必須在預設的允許時段內,且不能接近收盤。
      允許交易時段 = (允許交易時段 && !接近收盤) ;
     }
     
   // 如果目前允許交易。
   if(允許交易時段 == true)
     {
      //+------------------------------------------------------------------+
      //|多單進場
      //+------------------------------------------------------------------+
      set_BuyCondition(); // 設定多單進場條件 LE_Cond
      // 檢查多單進場條件是否成立 (LE_Cond == true),且點差 (SP) 小於商品平均點差,且最近幾筆內有空單平倉紀錄。
      if(LE_Cond == true && SP < NormalizeDouble(商品平均點差*Point(),Digits()) && 最近幾筆內有空單平倉(Symbol(),6) == true)
        {
         // 檢查目前是否空手 (沒有多單部位且沒有空單部位),且不是在同一根 K 棒重複下單。
         if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
           {
            買入價格 = Get_BuyPrice() ; // 獲取多單進場的價格 (可能是掛單價)

            // 檢查自上次平倉後經過的 K 棒是否大於 1 根 (避免連續交易),且當日進場次數小於 1 (EntriesToday)。
            if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
              {
                  // 如果多單下單方式是 2 (空手+掛單突破買入)。
                  if(多單下單方式 == 2)
                    {
                     // 檢查前一根 K 棒收盤價是否低於買入價格 (確保是突破買入)。
                     if(Close[1] < 買入價格)
                       {
                        // 空手+掛單突破買入:發送 Buy Stop 掛單。
                        多單進場單號 = Buy_at_STOP(Symbol(),MagicNumber,買入價格,Lots,TP,SL,"BUY STOP",3600) ;
                        OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA); // 記錄下單時的 K 棒索引

                       }
                    }
              } // end of BarSinceExit > 1 (結束自上次平倉後 K 棒數的檢查)
           } // end of 空手且不同根K棒() == true (結束空手和 K 棒的檢查)
        } // end of LE_Cond == true (結束多單進場條件檢查)
      //+------------------------------------------------------------------+
      //|空單進場
      //+------------------------------------------------------------------+
      set_ShortCondition() ; // 設定空單進場條件 SE_Cond
      // 檢查空單進場條件是否成立 (SE_Cond == true),且點差 (SP) 小於商品平均點差。
      if(SE_Cond == true && SP < NormalizeDouble(商品平均點差*Point(),Digits()))
        {
         // 檢查目前是否空手 (沒有多單部位且沒有空單部位),且不是在同一根 K 棒重複下單。
         if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
           {
            賣出價格 = Get_ShortPrice(); // 獲取空單進場的價格 (可能是掛單價)

            // 檢查自上次平倉後經過的 K 棒是否大於 1 根 (避免連續交易),且當日進場次數小於 1 (EntriesToday)。
            if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
              {
                  // 如果空單下單方式是 2 (空手+掛單突破賣出)。
                  if(空單下單方式 == 2)
                    {
                     // 檢查前一根 K 棒收盤價是否高於賣出價格 (確保是突破賣出)。
                     if(Close[1] > 賣出價格)
                       {
                        // 空手+掛單突破賣出:發送 Sell Stop 掛單。
                        空單進場單號 = Short_at_STOP(Symbol(),MagicNumber,賣出價格,Lots,TP,SL,"Short STOP",3600) ;
                        OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA); // 記錄下單時的 K 棒索引

                       }
                    }
              } //end of BarSinceExit > 1 (結束自上次平倉後 K 棒數的檢查)
           } // end of 空手且不同根K棒() == true (結束空手和 K 棒的檢查)
        } // end of SE_Cond == true (結束空單進場條件檢查)
     } //end of 允許交易時段 == true (結束允許交易時段檢查)
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   // 當沖出場時間檢查:如果在當沖模式下,且達到預設的當沖出場時間或凌晨 1 點。
   if(當沖 == true && (getTM_hour(TimeCurrent()) == 當沖出場時間 || getTM_hour(TimeCurrent()) == 1))
     {

      // 如果有多單或空單部位。
      if(多單部位() > 0 || 空單部位() > 0)
        {
         當沖平倉(); // 執行當沖部位的平倉。
        }
     }

   交易時段外也可停損停利(); // 執行停損停利邏輯 (即使不在允許交易時段內)。
   JudgeNo = iBarShift(Symbol(),時間週期,LoadEA); // 更新 JudgeNo 標記,用於判斷下一個 Tick 是否換 K 棒。

  } //end of onTick (OnTick 函數結束)


//+------------------------------------------------------------------+
//|        自訂函數庫                                                      
//+------------------------------------------------------------------+
// 獲取多單部位數量。
int 多單部位()
  {
   int count;
   // get_TradeCounts 自訂函數:獲取指定商品、MagicNumber、指定類型 (POSITION_TYPE_BUY) 的持倉數量。
   count = get_TradeCounts(Symbol(), MagicNumber,POSITION_TYPE_BUY) ;
   return count ;
  }

//+------------------------------------------------------------------+
//|                                                                
//+------------------------------------------------------------------+
// 獲取空單部位數量。
int 空單部位()
  {
   int count;
   // get_TradeCounts 自訂函數:獲取指定商品、MagicNumber、指定類型 (POSITION_TYPE_SELL) 的持倉數量。
   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(); // 保留:設置日 K 棒的開高低收系列數據
   Get_OHLC_Bar(30) ; // 保留:獲取 K 棒的開高低收數據 (可能是前 30 根)
   Get_OHLC_Day(15) ; // 保留:獲取日 K 棒的開高低收數據 (可能是前 15 根)
   set_ATR(); // 保留:計算 ATR 指標

   set_MACD(); // 計算 MACD 指標
   BigFloatTwoLine(); // 計算某種兩線指標
   set_BigThreeLine(); // 計算某種三線指標

   set_ICHIMOKU(); // 計算 ICHIMOKU (一目均衡表) 指標
   set_DONCHIAN_CHANNEL() ; // 計算 DONCHIAN_CHANNEL (唐奇安通道) 指標

   // 計算前 5 日平均波幅 (日 K 棒的高點減去低點的平均)。
   Day5Range = ((HighD[1] - LowD[1])+(HighD[2] - LowD[2])+(HighD[3] - LowD[3])+(HighD[4] - LowD[4])+(HighD[5] - LowD[5]))/5;
  }
//+------------------------------------------------------------------+
//|                                                               
//+------------------------------------------------------------------+
// 交易時段賦值函數。
void 交易時段賦值()
  {

      // 設定允許交易時段為凌晨 0 點到下午 16 點之前。
      允許交易時段 = (getTM_hour(TimeCurrent()) >= 0 && getTM_hour(TimeCurrent()) < 16);

  }

//+------------------------------------------------------------------+
//|                                                             
//+------------------------------------------------------------------+
// 當沖平倉函數。
void 當沖平倉()
  {
   // 檢查是否達到當沖出場時間或凌晨 1 點。
   if((getTM_hour(TimeCurrent()) == 當沖出場時間 || getTM_hour(TimeCurrent()) == 1))
     {
      // 如果有多單部位且不是在當前 K 棒平倉。
      if(多單部位() > 0 && BarNumber != CloseOrderNo)
         LX_CloseByTicket(多單進場單號,Lots) ; // 平倉多單
      // 如果有空單部位且不是在當前 K 棒平倉。
      if(空單部位() > 0 && BarNumber != CloseOrderNo)
         SX_CloseByTicket(空單進場單號,Lots) ; // 平倉空單
      CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ; // 更新平倉 K 棒索引
     }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
// 交易時段外也可停損停利函數:執行所有部位的出場邏輯。
void 交易時段外也可停損停利()
  {
// 交易時段外也可停損停利
   // 多單出場邏輯
   if(多單部位() > 0)
     {
      //+------------------------------------------------------------------+
      //|    Buy Exit Method (多單出場方法)
      //+------------------------------------------------------------------+
      double 多單最小停利 = 0.0, 多單保本價格 = 0.0 ; // 初始化多單最小停利和保本價格
      bool LX_MinPF = false, LongPull = false ; // 初始化最小獲利標記和回檔標記
      多單進場價格 = LE_EntryPrice(MagicNumber,多單進場單號); // 獲取多單進場價格
      多單最小停利 = NormalizeDouble(多單進場價格 + SP*3,Digits()) ; // 定義最小獲利價格:進場價 + 3 倍點差
      LX_MinPF = Bid > 多單最小停利 ; // 檢查當前買價 (Bid) 是否超過最小獲利價格
      // LX_MinPF = true ; // 註釋掉的行,可能是測試用
      多單停利價格 = NormalizeDouble(多單進場價格 + TP * Point(),Digits()) ; // 計算固定停利價格 (進場價 + TP 點數)
      多單停損價格 = NormalizeDouble(多單進場價格 - SL * Point(),Digits()) ; // 計算固定停損價格 (進場價 - SL 點數)

      //多單保本出場
      // 如果啟用了「保藍設定」(可能是某種移動停損或保本機制)。
      if(保藍設定 == true)
        {
         // 獲取多單進場後 K 線的最高價。
         多單最高價 = iHigh(Symbol(),時間週期, iHighest(Symbol(),時間週期,MODE_HIGH,LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期),1));
         多單最高價 = NormalizeDouble(多單最高價,Digits()) ;

         // 如果最高價超過進場價 + 0.5 倍停利點數。
         if(多單最高價 > 多單進場價格+TP * Point()*0.5)
           {
            LongPull = true ; // 設定回檔標記
            多單保本價格 = NormalizeDouble(多單進場價格+TP * Point()*0.168,Digits()) ; // 計算保本價格 (黃金分割比例 0.168)
            // 設定保本出場條件:已回檔 (LongPull) 且前一根 K 棒收盤價高於保本價格,但當前買價 (Bid) 跌破保本價格。
            LX_Cond = (LongPull == true && Close[1] >= 多單保本價格 && Bid < 多單保本價格);
           }
         else
            LX_Cond = false ; // 否則出場條件不成立

         // 如果保本出場條件成立,且不是在當前 K 棒平倉,且持倉時間大於 0 根 K 棒。
         if(LX_Cond == true && BarNumber != CloseOrderNo && LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期) > 0)
           {
            LX_CloseByTicket(多單進場單號,Lots) ; // 平倉多單

            // 如果所有多單部位都已平倉。
            if(多單部位() == 0)
              {
               CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ; // 更新平倉 K 棒索引
              }
           }
        }

      // 如果多單出場方式是 (可能是某種追蹤停損或動態停損/停利)。

         bool LXcond61,LXcond62 ;
         double LE_WinPoint ;
         // 重新獲取多單進場後 K 線的最高價。
         多單最高價 = iHigh(Symbol(),時間週期, iHighest(Symbol(),時間週期,MODE_HIGH,LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期),1));
         LE_WinPoint = 多單最高價-多單進場價格 ; // 計算浮動利潤點數
         // 動態停利價格計算:進場價 + (TP + 5日平均波幅 * 0.618) 點數
         多單停利價格 = NormalizeDouble(多單進場價格 + (TP+Day5Range*0.618) * Point(),Digits()) ;
         // 動態停損價格調整 (根據浮動利潤調整停損點位)。
         if((LE_WinPoint/Point()) <= (SL*Point()*1.5)) // 如果浮動利潤點數較小
            多單停損價格 = NormalizeDouble(多單進場價格-SL*Point(),Digits()); // 使用固定停損
         if((LE_WinPoint/Point()) > (SL*Point()*1.5) && (LE_WinPoint/Point()) <= (TP*Point())) // 如果浮動利潤中等
            多單停損價格 = NormalizeDouble(多單最高價-SL*Point()/2,Digits()); // 停損移動到最高價回撤 0.5 倍停損點
         if((LE_WinPoint/Point()) > (TP*Point())) // 如果浮動利潤較大 (超過 TP)
            多單停損價格 = NormalizeDouble(多單最高價-LE_WinPoint/2,Digits()); // 停損移動到最高價回撤 0.5 倍浮動利潤

         // 停利條件 61:前一根 K 棒收盤價低於停利價,但當前買價 (Bid) 突破停利價。
         LXcond61 = (多單進場價格 < 多單停利價格 && Close[1] <= 多單停利價格 && Bid > 多單停利價格) ;
         // 停損條件 62:前一根 K 棒收盤價高於停損價,但當前買價 (Bid) 跌破停損價。
         LXcond62 = (多單進場價格 > 多單停損價格 && Close[1] >= 多單停損價格 && Bid < 多單停損價格) ;
         LX_Cond = (LXcond61 == true || LXcond62 == true) ; // 最終出場條件為停利或停損達成
        

      //---------------------------------------------------------多單出場

      // 執行多單出場。
      if(LX_Cond == true && BarNumber != CloseOrderNo && LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期) > 0)
        {
         LX_CloseByTicket(多單進場單號,Lots) ; // 平倉多單

         // 如果所有多單部位都已平倉。
         if(多單部位() == 0)
           {
            CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ; // 更新平倉 K 棒索引
           }
        }
     } // end of 多單部位() > 0 (結束多單出場邏輯)

   // 空單出場邏輯
   if(空單部位() > 0)
     {
      //+------------------------------------------------------------------+
      //|    Short Exit Method (空單出場方法)
      //+------------------------------------------------------------------+
      double 空單最小停利 = 0.0, 空單保本價格 = 0.0 ; // 初始化空單最小停利和保本價格
      bool SX_MinPF = false, ShortPull = false ; // 初始化最小獲利標記和回檔標記
      空單進場價格 = SE_EntryPrice(MagicNumber,空單進場單號); // 獲取空單進場價格
      空單最小停利 = NormalizeDouble(空單進場價格 - SP*3,Digits()) ; // 定義最小獲利價格:進場價 - 3 倍點差
      SX_MinPF = Ask < 空單最小停利 ; // 檢查當前賣價 (Ask) 是否低於最小獲利價格
      //    SX_MinPF = true ; // 註釋掉的行,可能是測試用
      空單停利價格 = NormalizeDouble(空單進場價格 - TP * Point(),Digits()) ; // 計算固定停利價格 (進場價 - TP 點數)
      空單停損價格 = NormalizeDouble(空單進場價格 + SL * Point(),Digits()) ; // 計算固定停損價格 (進場價 + SL 點數)

      //空單保本出場
      // 如果啟用了「保藍設定」(可能是某種移動停損或保本機制)。
      if(保藍設定 == true)
        {
         // 獲取空單進場後 K 線的最低價。
         空單最低價 = iLow(Symbol(),時間週期, iLowest(Symbol(),時間週期,MODE_LOW,SE_BarsSinceEntry(MagicNumber,空單進場單號,時間週期),1));
         空單最低價 = NormalizeDouble(空單最低價,Digits()) ;

         // 如果最低價低於進場價 - 0.5 倍停利點數。
         if(空單最低價 < 空單進場價格-TP * Point()*0.5)
           {
            ShortPull = true ; // 設定回檔標記
            空單保本價格 = NormalizeDouble(空單進場價格-TP * Point()*0.168,Digits()) ; // 計算保本價格 (黃金分割比例 0.168)
            // 設定保本出場條件:已回檔 (ShortPull) 且前一根 K 棒收盤價低於保本價格,但當前賣價 (Ask) 突破保本價格。
            SX_Cond = (ShortPull == true && Close[1] <= 空單保本價格 && Ask > 空單保本價格);
           }
         else
            SX_Cond = false ; // 否則出場條件不成立

         // 如果保本出場條件成立,且不是在當前 K 棒平倉,且持倉時間大於 0 根 K 棒。
         if(SX_Cond == true && BarNumber != CloseOrderNo && SE_BarsSinceEntry(MagicNumber,空單進場單號,時間週期) > 0)
           {
            SX_CloseByTicket(空單進場單號,Lots) ; // 平倉空單

            // 如果所有空單部位都已平倉。
            if(空單部位() == 0)
              {
               CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ; // 更新平倉 K 棒索引
              }
           }       

         // 出場條件:達到最小獲利且 MACD 交叉 (CrossOver) 或跌破固定停損價。
         SX_Cond = ((SX_MinPF == true && CrossOver(a_MACD[2],0,a_MACD[1],0)) || (Close[1] <= 空單停損價格 && Ask > 空單停損價格)) ;


      //---------------------------------------------------------空單出場

      // 執行空單出場。
      if(SX_Cond == true && BarNumber != CloseOrderNo && SE_BarsSinceEntry(MagicNumber,空單進場單號,時間週期) > 0)
        {
         SX_CloseByTicket(空單進場單號,Lots) ; // 平倉空單

         // 如果所有空單部位都已平倉。
         if(空單部位() == 0)
           {
            CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ; // 更新平倉 K 棒索引
           }
        }
     } // end of 空單部位() > 0 (結束空單出場邏輯)
  } // end of 交易時段外也可停損停利() (結束出場總函數)


//+------------------------------------------------------------------+
//| 依編號Get_BuyPrice
//+------------------------------------------------------------------+
double Get_BuyPrice()
  {
   double BuyPrice=0.0 ;

      // 買入價格 = 一目均衡表 C 線 (a_ICHI_C[2]) + 2 根 K 棒前的 ATR 值。
      BuyPrice = a_ICHI_C[2] + a_ATR[2] ;

   return NormalizeDouble(BuyPrice,Digits()) ; // 標準化價格並返回
  } // end of get BuyPrice

//+------------------------------------------------------------------+
//| 依編號Get_ShortPrice
//+------------------------------------------------------------------+
double Get_ShortPrice()
  {
   double ShortPrice=0.0 ;

      // 賣出價格 = 唐奇安通道的最低線 (a_DC_LOW_A[1]) - 2 根 K 棒前的 ATR 值 * 0.382 (黃金分割)。
      ShortPrice = a_DC_LOW_A[1] - a_ATR[2]*0.382 ;

   return NormalizeDouble(ShortPrice,Digits()) ; // 標準化價格並返回
  } // end of get ShortPrice
  
//+------------------------------------------------------------------+
//|多單模組編號
//+------------------------------------------------------------------+
// 設置多單進場條件。
void set_BuyCondition()
  {

      // 多單進場條件 (LE_Cond) = KD 高檔背離 02 成立 且 前一根 K 棒收盤價高於大趨勢快線。
      LE_Cond = (KD_HDiv_02() && Close[1] > a_BigFastSma[1]) ; // KD高檔背離02+收盤價高於快線

  }

//+------------------------------------------------------------------+
//| 空單模組編號
//+------------------------------------------------------------------+
// 設置空單進場條件。
void set_ShortCondition()
  {
      // 空單進場條件 (SE_Cond) = CCI 低檔背離 02 成立 且 三線最低值低於 13 線。
      SE_Cond = (CCI_LDiv_02() && BigMin3L < a_BigAvg13[1]) ; // CCI低檔背離02+三線最低值低於13線
  }

回測結果
測試參數交易商品:NAS100(那斯達克指數)
樣本內區間:2019/1/1 ~ 2023/9/30
交易手數:固定 1 手
時間框架: M12 圖表
交易模式:當沖交易

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



沒有留言:

張貼留言