2025年8月25日 星期一

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

策略概述
這是一個基於技術指標的波段交易策略,使用M20時間週期進行交易決策,結合多種技術分析工具來識別趨勢轉折和進出場時機。策略採用風險控制機制,限制每日交易次數並設定資金保護。

基礎概念
時間週期: M20(20分鐘)
風險控制:動態手數計算,風險百分比為1%
資金風控門檻:5000
商品平均點差限制:50點
交易限制: 每日限制1次進場
交易時段: 00:00-16:00(可配置)
停利停損: TP=4800點,SL=1480點

進出場策略
多單進場條件
LE_Cond = (Shrink && High[1] > a_BBUP[1] && Close[1] > Open[1]);


條件分析:
布林帶收縮(Shrink): 上下軌同時收縮,表示波動率降低,蓄勢待發
突破確認(High[1] > a_BBUP[1]): 最高價突破布林帶上軌
紅K確認(Close[1] > Open[1]): 收盤價高於開盤價,確認多頭動能

空單進場條件
SE_Cond = (CCI_HDiv_01() && Low[1] < Lowest_OHLC(Symbol(),時間週期,MODE_LOW,10,1) && 多重死叉確認());

條件分析:
CCI高點背離(CCI_HDiv_01): 價格創新高但CCI未創新高,出現背離信號
創10日新低: 最低價跌破10日最低點
多重死叉確認: 至少2個指標同時出現死叉信號
KD死叉(K線下穿D線)
MACD死叉(DIF下穿MACD線)
RVI死叉
ADX DI死叉

進場價格計算
多單進場價格
BuyPrice = LowD[1] + Range[2]*0.236;
計算方式: 前日最低點 + 第2根K棒區間的23.6%

空單進場價格(編號66)
ShortPrice = HighD[1] - Range[2]*0.236;
計算方式: 前日最高點 - 第2根K棒區間的23.6%

//+------------------------------------------------------------------+
//| MT5 自動交易程式 (Expert Advisor)                               
//| 基於技術指標的趨勢跟隨策略                          
//+------------------------------------------------------------------+
#include <Trade\Trade.mqh>              // 交易功能函式庫
#include <MagicMT5_函數庫V2.mqh>        // 自定義函式庫

ENUM_TIMEFRAMES 時間週期 = PERIOD_M20;  // 主要分析時間週期:20分鐘
ENUM_TIMEFRAMES 時間框架 = PERIOD_H4;   // 相對大週期:4小時

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

//+------------------------------------------------------------------+
//| 主要交易邏輯函數(每個價格跳動時執行)                          
//+------------------------------------------------------------------+
void OnTick()
{
   // 資金風控檢查
   if(AccountInfoDouble(ACCOUNT_BALANCE) < 資金風控)
   {
      Alert("**********  資金不足 *************");
      return;
   }

   // 計算當前K棒位置和距離上次出場的K棒數
   BarNumber = iBarShift(Symbol(),時間週期,LoadEA);
   BarSinceExit = BarNumber - CloseOrderNo;
   
   // 新K棒時執行一次性交易測試(僅在第1根K棒執行)
   if((BarNumber == 1 && BarNumber != JudgeNo))
   {
      // 測試下單功能:開多單後立即平倉
      多單進場單號 = Buy_at_MARKET(Symbol(),Lots,0,0,"1st_K",MagicNumber);
      LX_CloseByTicket(多單進場單號,Lots);
      CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA);
      FastSma = MathMin(LenA1, LenB1);  // 設定快速均線週期
      SlowSma = MathMax(LenA1, LenB1);  // 設定慢速均線週期
   }

   // 新K棒時更新指標和交易時段
   if(BarNumber != JudgeNo)
   {
      換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)
   {
      //+------------------------------------------------------------------+
      //| 多單進場邏輯                                                      |
      //+------------------------------------------------------------------+
      set_BuyCondition();              // 設定多單進場條件
      if(LE_Cond == true && SP <= 商品平均點差)  // 進場條件成立且點差合理
      {
         // 確保空手且不在同一根K棒下單
         if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
         {
 
            // 確保距離上次出場超過1根K棒且當日未超過交易次數限制
            if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
            {

                  多單進場單號 = Buy_at_MARKET(Symbol(),Lots,TP,SL,"BUY MARKET",MagicNumber);
                  OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA);

              } // end of BarSinceExit > 1
           } // end of 空手且不同根K棒() == true
        } // end of LE_Cond == true
      //+------------------------------------------------------------------+
      //| 空單進場邏輯                                                      |
      //+------------------------------------------------------------------+
      set_ShortCondition();            // 設定空單進場條件
      if(SE_Cond == true && SP <= 商品平均點差)  // 進場條件成立且點差合理
      {
         // 確保空手且不在同一根K棒下單
         if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
         {

            // 確保距離上次出場超過1根K棒且當日未超過交易次數限制
            if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
            {

                  空單進場單號 = Short_at_MARKET(Symbol(),Lots,TP,SL,"Short Market",MagicNumber);
                  OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA);

              } //end of BarSinceExit > 1
           } // end of 空手且不同根K棒() == true
        } // end of SE_Cond == true
     } //end of 允許交易時段 == true

   // 即使不在交易時段也允許停損停利
   交易時段外也可停損停利();
   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_BBAND();              // 布林通道
   set_MACD();               // MACD指標
   set_KD();                 // KD指標
   FixBarHL();               // 固定週期高低點

   set_ADX();                // ADX指標
   set_CCI();                // CCI指標
   set_RVI();                // RVI指標
   set_ICHIMOKU();           // 一目均衡表

   // 計算五日平均振幅
   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()) >= 0 && getTM_hour(TimeCurrent()) < 16);
}

//+------------------------------------------------------------------+
//| 停損停利執行(即使在非交易時段也可執行)     
//+------------------------------------------------------------------+
void 交易時段外也可停損停利()
{
   // 多單停損停利邏輯
   if(多單部位() > 0)
   {
      double 多單最小停利 = 0.0;
      bool LX_MinPF = false;
      
      // 獲取多單進場價格和計算停損停利價格
      多單進場價格 = LE_EntryPrice(MagicNumber,多單進場單號);
      多單最小停利 = NormalizeDouble(多單進場價格 + SP*3,Digits());  // 最小獲利保護
      LX_MinPF = Bid > 多單最小停利;  // 是否達到最小獲利
      多單停利價格 = NormalizeDouble(多單進場價格 + TP * Point(),Digits());
      多單停損價格 = NormalizeDouble(多單進場價格 - SL * Point(),Digits());

      // 多單出場條件

         // 達到最小獲利且MACD下穿零軸,或觸及停損
         LX_Cond = ((LX_MinPF == true && CrossUnder(a_MACD[2],0,a_MACD[1],0)) || 
                    (Close[1] >= 多單停損價格 && Bid < 多單停損價格));

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

   // 空單停損停利邏輯
   if(空單部位() > 0)
   {
      double 空單最小停利 = 0.0;
      bool SX_MinPF = false;
      
      // 獲取空單進場價格和計算停損停利價格
      空單進場價格 = SE_EntryPrice(MagicNumber,空單進場單號);
      空單最小停利 = NormalizeDouble(空單進場價格 - SP*3,Digits());  // 最小獲利保護
      SX_MinPF = Ask < 空單最小停利;  // 是否達到最小獲利
      空單停利價格 = NormalizeDouble(空單進場價格 - TP * Point(),Digits());
      空單停損價格 = NormalizeDouble(空單進場價格 + SL * Point(),Digits());

      // 空單出場條件

         // 達到最小獲利且一目均衡表金叉,或觸及停損
         SX_Cond = ((SX_MinPF == true && CrossOver(a_ICHI_C[2],a_ICHI_B[2],a_ICHI_C[1],a_ICHI_B[1])) || 
                    (Close[1] <= 空單停損價格 && Ask > 空單停損價格));

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

//+------------------------------------------------------------------+
//| 多單進場條件設定
//+------------------------------------------------------------------+
void set_BuyCondition()
{
      // 布林帶收縮 + 突破上軌 + 紅K確認
      LE_Cond = (Shrink && High[1] > a_BBUP[1] && Close[1] > Open[1]);
}

//+------------------------------------------------------------------+
//| 空單進場條件設定
//+------------------------------------------------------------------+
void set_ShortCondition()
{
      // CCI高點背離 + 創10日新低 + 多重死叉確認
      SE_Cond = (CCI_HDiv_01() && Low[1] < Lowest_OHLC(Symbol(),時間週期,MODE_LOW,10,1) && 多重死叉確認());
}

//+------------------------------------------------------------------+
//| 價格數據數組變數宣告                                                |
//+------------------------------------------------------------------+
double Open[], High[], Low[], Close[], Range[], Body[], UPshadow[], DNshadow[];  // K棒數據
double OpenD[], HighD[], LowD[], CloseD[];                                       // 日線數據
long Volume[], BigVolume[];                                                      // 成交量數據

//+------------------------------------------------------------------+
//| 設定K棒價格數據序列                                                 |
//+------------------------------------------------------------------+
void Set_OHLC_Bar_Series()
{
   ArraySetAsSeries(Open,true);   // 設定為時間序列(最新數據索引為0)
   ArraySetAsSeries(High,true);
   ArraySetAsSeries(Low,true);
   ArraySetAsSeries(Close,true);
   ArraySetAsSeries(Volume,true);
}

//+------------------------------------------------------------------+
//| 獲取K棒價格數據                                                     |
//+------------------------------------------------------------------+
void Get_OHLC_Bar(int argCount)
{
   get_OpenData(Symbol(),時間週期,argCount,Open);     // 獲取開盤價數據
   get_HighData(Symbol(),時間週期,argCount,High);     // 獲取最高價數據
   get_LowData(Symbol(),時間週期,argCount,Low);       // 獲取最低價數據
   get_CloseData(Symbol(),時間週期,argCount,Close);   // 獲取收盤價數據
   get_VolumeData(Symbol(),時間週期,argCount,Volume); // 獲取成交量數據
}

//+------------------------------------------------------------------+
//| 設定日線價格數據序列                                                |
//+------------------------------------------------------------------+
void Set_OHLC_Day_Series()
{
   ArraySetAsSeries(OpenD,true);   // 設定為時間序列
   ArraySetAsSeries(HighD,true);
   ArraySetAsSeries(LowD,true);
   ArraySetAsSeries(CloseD,true);
}

//+------------------------------------------------------------------+
//| 獲取日線價格數據                                                    |
//+------------------------------------------------------------------+
void Get_OHLC_Day(int argCount)
{
   get_OpenData(Symbol(),PERIOD_D1,argCount,OpenD);   // 獲取日線開盤價
   get_HighData(Symbol(),PERIOD_D1,argCount,HighD);   // 獲取日線最高價
   get_LowData(Symbol(),PERIOD_D1,argCount,LowD);     // 獲取日線最低價
   get_CloseData(Symbol(),PERIOD_D1,argCount,CloseD); // 獲取日線收盤價
}

//+------------------------------------------------------------------+
//| 計算K棒基本資訊(實體、影線等)                                      |
//+------------------------------------------------------------------+
void set_BarInfo()
{
   // 調整陣列大小並設定為時間序列
   ArrayResize(Range,ArraySize(Open));
   ArraySetAsSeries(Range,true);
   ArrayResize(Body,ArraySize(Open));
   ArraySetAsSeries(Body,true);
   ArrayResize(UPshadow,ArraySize(Open));
   ArraySetAsSeries(UPshadow,true);
   ArrayResize(DNshadow,ArraySize(Open));
   ArraySetAsSeries(DNshadow,true);

   // 計算每根K棒的基本資訊
   for(int i = 0; i < ArraySize(Open)-1; i++)
   {
      Range[i] = High[i] - Low[i];                           // 振幅
      Body[i] = MathAbs(Close[i] - Open[i]);                 // 實體大小
      UPshadow[i] = High[i] - MathMax(Close[i],Open[i]);     // 上影線
      DNshadow[i] = MathMin(Close[i],Open[i]) - Low[i];      // 下影線
   }
}

//+------------------------------------------------------------------+
//| ATR指標設定                                                        |
//+------------------------------------------------------------------+
double a_ATR[];
void set_ATR()
{
   int h_ATR;
   h_ATR = iATR(Symbol(),時間週期,LenB2);  // 創建ATR指標句柄
   ArraySetAsSeries(a_ATR, true);
   get_IndexData(h_ATR,0,0,5,a_ATR);      // 獲取ATR數據
}

//+------------------------------------------------------------------+
//| 布林通道指標設定                                                    |
//+------------------------------------------------------------------+
bool UpBreak, DnBreak, Shrink;  // 布林帶狀態變數
double a_BBUP[], a_BBDN[];      // 布林帶上下軌數組

void set_BBAND()
{
   int BBLen, h_BBUP, h_BBDN;
   bool ShrinkUp, ShrinkDn;

   BBLen = MathMax(LenA2,LenB2);  // 布林帶週期
   
   // 創建布林帶指標句柄
   h_BBUP = iBands(Symbol(),時間週期,BBLen,0,2,PRICE_CLOSE);
   ArraySetAsSeries(a_BBUP, true);
   h_BBDN = iBands(Symbol(),時間週期,BBLen,0,2,PRICE_CLOSE);
   ArraySetAsSeries(a_BBDN, true);
   
   // 獲取布林帶數據
   get_IndexData(h_BBUP,1,0,10,a_BBUP);  // 上軌數據
   get_IndexData(h_BBDN,2,0,10,a_BBDN);  // 下軌數據

   // 判斷布林帶突破狀態
   UpBreak = (High[1] > a_BBUP[1]) && (High[2] > a_BBUP[2]);     // 向上突破
   DnBreak = Low[1] < a_BBDN[1] && Low[2] < a_BBDN[2];           // 向下突破
   
   // 判斷布林帶收縮狀態
   ShrinkUp = a_BBUP[1] > a_BBUP[2] && a_BBUP[2] > a_BBUP[3] && 
              a_BBUP[5] > a_BBUP[4] && a_BBUP[4] > a_BBUP[3];    // 上軌收縮
   ShrinkDn = a_BBDN[1] < a_BBDN[2] && a_BBDN[2] < a_BBDN[3] && 
              a_BBDN[5] < a_BBDN[4] && a_BBDN[4] < a_BBDN[3];    // 下軌收縮
   Shrink = ShrinkUp || ShrinkDn;                                // 布林帶收縮
}

//+------------------------------------------------------------------+
//| MACD指標設定                                                       |
//+------------------------------------------------------------------+
double a_DIF[], a_MACD[], a_OSC[];  // MACD相關數組

void set_MACD()
{
   int MacdLen, FastLen, SlowLen;
   int h_DIF, h_MACD;
   
   // 計算MACD參數
   MacdLen = MathMax(LenA1,LenB1);
   if(MacdLen > 15)
      MacdLen = 15;                                  // 限制最大週期
   FastLen = (int)MathRound(MacdLen*1.33);          // 快線週期
   SlowLen = (int)MathRound(MacdLen*2.66);          // 慢線週期

   // 創建MACD指標句柄
   h_DIF = iMACD(Symbol(),時間週期,FastLen,SlowLen,MacdLen,PRICE_WEIGHTED);
   ArraySetAsSeries(a_DIF, true);
   h_MACD = iMACD(Symbol(),時間週期,FastLen,SlowLen,MacdLen,PRICE_WEIGHTED);
   ArraySetAsSeries(a_MACD, true);

   // 獲取MACD數據
   get_IndexData(h_DIF,0,0,10,a_DIF);    // DIF線(快線-慢線)
   get_IndexData(h_MACD,1,0,10,a_MACD);  // MACD線(DIF的移動平均)

   // 計算MACD柱狀圖
   ArraySetAsSeries(a_OSC, true);
   ArrayResize(a_OSC,ArraySize(a_DIF));
   for(int i = 0; i < ArraySize(a_OSC); i++)
   {
      a_OSC[i] = a_DIF[i] - a_MACD[i];   // 柱狀圖 = DIF - MACD
   }
}

//+------------------------------------------------------------------+
//| KD指標設定                                                         |
//+------------------------------------------------------------------+
int h_KA2, h_DA2, h_KB2, h_DB2;                           // KD指標句柄
double a_KA2[], a_DA2[], a_JA2[], a_KB2[], a_DB2[], a_JB2[]; // KD指標數組

void set_KD()
{
   // 創建KD指標句柄(兩組不同參數)
   h_KA2 = iStochastic(Symbol(),時間週期,LenA2,3,3,MODE_EMA,STO_LOWHIGH);
   ArraySetAsSeries(a_KA2,true);
   h_DA2 = iStochastic(Symbol(),時間週期,LenA2,3,3,MODE_EMA,STO_LOWHIGH);
   ArraySetAsSeries(a_DA2,true);
   h_KB2 = iStochastic(Symbol(),時間週期,LenB2,3,3,MODE_SMA,STO_LOWHIGH);
   ArraySetAsSeries(a_KB2,true);
   h_DB2 = iStochastic(Symbol(),時間週期,LenB2,3,3,MODE_SMA,STO_LOWHIGH);
   ArraySetAsSeries(a_DB2,true);

   // 獲取KD數據
   get_IndexData(h_KA2,0,0,5,a_KA2);  // K線A組
   get_IndexData(h_DA2,1,0,5,a_DA2);  // D線A組
   get_IndexData(h_KB2,0,0,5,a_KB2);  // K線B組
   get_IndexData(h_DB2,1,0,5,a_DB2);  // D線B組

   // 計算J線(A組)
   ArraySetAsSeries(a_JA2, true);
   ArrayResize(a_JA2,ArraySize(a_KA2));
   for(int i = 0; i < ArraySize(a_JA2); i++)
   {
      a_JA2[i] = a_DA2[i]*3 - a_KA2[i]*2;  // J = 3*D - 2*K
   }

   // 計算J線(B組)
   ArraySetAsSeries(a_JB2, true);
   ArrayResize(a_JB2,ArraySize(a_KB2));
   for(int i = 0; i < ArraySize(a_JB2); i++)
   {
      a_JB2[i] = a_DB2[i]*3 - a_KB2[i]*2;  // J = 3*D - 2*K
   }
}

//+------------------------------------------------------------------+
//| 固定週期高低點計算                                                  |
//+------------------------------------------------------------------+
double FixLenH, FixLenL, FixLenHL, FixLen33, FixLen67;  // 固定週期價格變數
int FixLenHPB, FixLenLPB;                               // 高低點距離當前的K棒數

void FixBarHL()
{
   // 計算60期高低點
   FixLenH = Highest_OHLC(Symbol(),時間週期,MODE_HIGH,60,2);  // 60期最高價
   FixLenL = Lowest_OHLC(Symbol(),時間週期,MODE_LOW,60,2);   // 60期最低價
   FixLenHL = FixLenH - FixLenL;                            // 高低價差
   FixLen33 = FixLenL + FixLenHL*0.33;                      // 33%回撤位
   FixLen67 = FixLenL + FixLenHL*0.67;                      // 67%回撤位
   
   // 計算高低點距離當前的K棒數
   FixLenHPB = BarsLast(High[1] == FixLenH,時間週期);       // 最高點出現的K棒數
   FixLenLPB = BarsLast(Low[1] == FixLenL,時間週期);        // 最低點出現的K棒數
}

//+------------------------------------------------------------------+
//| ADX指標設定                                                        |
//+------------------------------------------------------------------+
double a_ADX[], a_PLUSDI[], a_MINUSDI[];  // ADX指標數組

void set_ADX()
{
   int h_ADX, h_PLUSDI, h_MINUSDI;
   
   // 創建ADX指標句柄
   h_ADX = iADX(Symbol(),時間週期,LenA2);
   ArraySetAsSeries(a_ADX, true);
   h_PLUSDI = iADX(Symbol(),時間週期,LenA2);
   ArraySetAsSeries(a_PLUSDI, true);
   h_MINUSDI = iADX(Symbol(),時間週期,LenA2);
   ArraySetAsSeries(a_MINUSDI, true);

   // 獲取ADX數據
   get_IndexData(h_ADX,0,0,5,a_ADX);        // ADX主線
   get_IndexData(h_PLUSDI,1,0,5,a_PLUSDI);  // +DI線
   get_IndexData(h_MINUSDI,2,0,5,a_MINUSDI); // -DI線
}

//+------------------------------------------------------------------+
//| CCI指標設定                                                        |
//+------------------------------------------------------------------+
double a_CCI[];  // CCI指標數組

void set_CCI()
{
   int h_CCI;
   h_CCI = iCCI(Symbol(),時間週期,LenB1,PRICE_CLOSE);  // 創建CCI指標句柄
   ArraySetAsSeries(a_CCI, true);
   get_IndexData(h_CCI,0,0,5,a_CCI);                  // 獲取CCI數據
}

//+------------------------------------------------------------------+
//| RVI指標設定                                                        |
//+------------------------------------------------------------------+
double a_RVI_1[], a_RVI_2[];  // RVI指標數組

void set_RVI()
{
   int h_RVI_1, h_RVI_2;
   
   // 創建RVI指標句柄
   h_RVI_1 = iRVI(Symbol(),時間週期,LenB1);
   ArraySetAsSeries(a_RVI_1, true);
   h_RVI_2 = iRVI(Symbol(),時間週期,LenB1);
   ArraySetAsSeries(a_RVI_2, true);

   // 獲取RVI數據
   get_IndexData(h_RVI_1,0,0,5,a_RVI_1);  // RVI主線
   get_IndexData(h_RVI_2,1,0,5,a_RVI_2);  // RVI信號線
}

//+------------------------------------------------------------------+
//| 一目均衡表指標設定                                                  |
//+------------------------------------------------------------------+
double a_ICHI_B[], a_ICHI_C[], a_ICHI_SA[], a_ICHI_SB[], a_ICHI_LC[];  // 一目均衡表數組

void set_ICHIMOKU()
{
   int h_ICHI_C, h_ICHI_B, h_ICHI_SA, h_ICHI_SB, h_ICHI_LC;
   
   // 創建一目均衡表指標句柄
   h_ICHI_C = iIchimoku(Symbol(),時間週期,9,26,52);
   ArraySetAsSeries(a_ICHI_C, true);
   h_ICHI_B = iIchimoku(Symbol(),時間週期,9,26,52);
   ArraySetAsSeries(a_ICHI_B, true);
   h_ICHI_SA = iIchimoku(Symbol(),時間週期,9,26,52);
   ArraySetAsSeries(a_ICHI_SA, true);
   h_ICHI_SB = iIchimoku(Symbol(),時間週期,9,26,52);
   ArraySetAsSeries(a_ICHI_SB, true);
   h_ICHI_LC = iIchimoku(Symbol(),時間週期,9,26,52);
   ArraySetAsSeries(a_ICHI_LC, true);

   // 獲取一目均衡表數據
   get_IndexData(h_ICHI_C,0,0,5,a_ICHI_C);   // 轉換線(天線)
   get_IndexData(h_ICHI_B,1,0,5,a_ICHI_B);   // 基準線(地線)
   get_IndexData(h_ICHI_SA,2,0,5,a_ICHI_SA); // 先行帶A
   get_IndexData(h_ICHI_SB,3,0,5,a_ICHI_SB); // 先行帶B
   get_IndexData(h_ICHI_LC,4,0,5,a_ICHI_LC); // 延遲線
}

//+------------------------------------------------------------------+
//| 進出場條件判斷函數                                                  |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| CCI高點背離檢測函數                                                |
//+------------------------------------------------------------------+
bool CCI_HDiv_01()
{
   // 檢查價格創新高但CCI未創新高的背離現象
   if((ArrayMaximum(High) != 0 && ArrayMaximum(High) <= 2) &&  // 價格最高點在近期
      (ArrayMaximum(a_CCI) > 2) &&                             // CCI最高點較遠
      a_CCI[1] < 150)                                          // 當前CCI低於150
   {
      return true;
   }
   return false;
}

//+------------------------------------------------------------------+
//| ADX DI死叉檢測函數                                                 |
//+------------------------------------------------------------------+
bool ADX_DI死叉()
{
   // 檢測+DI下穿-DI的死叉信號
   if(a_PLUSDI[2] >= a_MINUSDI[2] && a_PLUSDI[1] < a_MINUSDI[1])
   {
      return true;
   }
   return false;
}

//+------------------------------------------------------------------+
//| RVI死叉檢測函數                                                    |
//+------------------------------------------------------------------+
bool RVI_死叉()
{
   // 檢測RVI主線下穿信號線的死叉信號
   if(a_RVI_1[2] >= a_RVI_2[2] && a_RVI_1[1] < a_RVI_2[1])
   {
      return true;
   }
   return false;
}

//+------------------------------------------------------------------+
//| 多重死叉確認函數                                                    |
//+------------------------------------------------------------------+
bool 多重死叉確認()
{
   int CrossDN_count = 0;  // 死叉信號計數器
   
   // 檢查KD死叉
   if(a_KA2[1] < a_DA2[1] && a_KA2[2] >= a_DA2[2])
      CrossDN_count++;
   
   // 檢查MACD死叉
   if(a_DIF[1] < a_MACD[1] && a_DIF[2] >= a_MACD[2])
      CrossDN_count++;
   
   // 檢查RVI死叉
   if(RVI_死叉())
      CrossDN_count++;
   
   // 檢查ADX DI死叉
   if(ADX_DI死叉())
      CrossDN_count++;

   // 至少2個指標同時出現死叉才確認信號
   if(CrossDN_count >= 2)
   {
      return true;
   }
   return false;
}


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


沒有留言:

張貼留言