2025年8月1日 星期五

MT5 外匯商品 交易策略開發 [11]

多單進場方式  (RVI_HDiv_01() && Close[1] > 流動性池底部價格 && Close[1] > a_KC_UPPER_B[1]) ; 

// RVI高點背離+突破流動性池底部+突破Keltner上軌B  

空單進場方式 ~ (BBUP_VTrend() && Close[1] < Close[2] && Close[1] < (High[1]+Low[1])/2) ; 

// 布林帶V型收縮+價格下降+弱勢收盤

#include <Trade\Trade.mqh>
#include <MagicMT5_函數庫V1.mqh>
ENUM_TIMEFRAMES  時間週期 = PERIOD_M12 ;
ENUM_TIMEFRAMES  時間框架 = PERIOD_H1; //相對大週期

//+------------------------------------------------------------------+
//|                                                               
//+------------------------------------------------------------------+
int OnInit()
  {
   LoadEA = TimeCurrent();
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//|                                                               
//+------------------------------------------------------------------+
void OnTick()
  {
   if(AccountInfoDouble(ACCOUNT_BALANCE) < 資金風控)
     {
      Alert("**********  資金不足 *************");
      return;
     }

   BarNumber = iBarShift(Symbol(),時間週期,LoadEA);
   BarSinceExit = BarNumber-CloseOrderNo ;
   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);
     }

   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)) ;
     }

   if(隔日沖 == true)
     {
      接近收盤 = (getTM_hour(TimeCurrent()) >= 22 || getTM_hour(TimeCurrent()) <= 1) ;
      允許交易時段 = (允許交易時段 && !接近收盤) ;
     }

   if(允許交易時段 == true)
     {
      //+------------------------------------------------------------------+
      //|多單進場
      //+------------------------------------------------------------------+
      set_BuyCondition();
      if(LE_Cond == true)
        {
         if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
           {
            買入價格 = Get_BuyPrice() ;

            if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
              {
               if(多單下單方式 == 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)
        {
         if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
           {
            賣出價格 = Get_ShortPrice();

            if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
              {
               if(空單下單方式 == 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
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(隔日沖 == true && getTM_hour(TimeCurrent()) == 隔日沖出場時間)
     {

      if(多單部位() > 0 || 空單部位() > 0)
        {
         隔日沖平倉();
        }
     }
   交易時段外也可停損停利();
   JudgeNo = iBarShift(Symbol(),時間週期,LoadEA);

  } //end of onTick


//+------------------------------------------------------------------+
//|        自訂函數庫                                                          |
//+------------------------------------------------------------------+
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 ;
  }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void 換K棒()
  {
// 新K棒刪除所有掛單
   if(total_pending_order_count(Symbol(), MagicNumber,-1) != 0)
     {
      delete_pending_orders_all(Symbol(), MagicNumber, -1, 0x0000ff);

     }
   Set_OHLC_Bar_Series(); //保留
   Set_OHLC_Day_Series(); //保留
   Get_OHLC_Bar(30) ; //保留
   Get_OHLC_BigBar(15) ; //保留
   Get_OHLC_Day(15) ; //保留
   set_BarInfo(); //保留
   set_ATR(); //保留

   set_BBAND();
   set_RVI();

// ***************
   set_KELTNER_CHANNEL() ;

   Day5Range = ((HighD[1] - LowD[1])+(HighD[2] - LowD[2])+(HighD[3] - LowD[3])+(HighD[4] - LowD[4])+(HighD[5] - LowD[5]))/5;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void 交易時段賦值()
  {

   if(交易時段編號 == 36)
      允許交易時段 = (getTM_hour(TimeCurrent()) >= 6 && getTM_hour(TimeCurrent()) < 10) || (getTM_hour(TimeCurrent()) >= 14 && getTM_hour(TimeCurrent()) < 18);

  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void 隔日沖平倉()
  {
   if(getTM_hour(TimeCurrent()) == 隔日沖出場時間)
     {
      if(多單部位() > 0 && BarNumber != CloseOrderNo)
         LX_CloseByTicket(多單進場單號,Lots) ;
      if(空單部位() > 0 && BarNumber != CloseOrderNo)
         SX_CloseByTicket(空單進場單號,Lots) ;
      CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
     }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void 交易時段外也可停損停利()
  {
// 交易時段外也可停損停利
   if(多單部位() > 0)
     {
      //     多單進場價格 = get_position_info_double((ulong)多單進場單號, POSITION_PRICE_OPEN);
      //+------------------------------------------------------------------+
      //|    Buy Exit Method RSI 高檔背離+固定停損
      //+------------------------------------------------------------------+
      double 多單最小停利 = 0.0;
      bool LX_MinPF = false ;
      多單進場價格 = LE_EntryPrice(MagicNumber,多單進場單號);
      多單最小停利 = NormalizeDouble(多單進場價格 + SP*3,Digits()) ;
      LX_MinPF = Bid > 多單最小停利 ;
      // LX_MinPF = true ;
      多單停利價格 = NormalizeDouble(多單進場價格 + TP * Point(),Digits()) ;
      多單停損價格 = NormalizeDouble(多單進場價格 - SL * Point(),Digits()) ;

      if(多單出場方式 == 21)
        {
         LX_Cond = ((LX_MinPF == true && (RSI_HDiv_02() == true)) || (Close[1] >= 多單停損價格 && Bid < 多單停損價格)) ;
        }

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

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

         if(多單部位() == 0)
           {
            CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
           }
        }
     } // end of 多單部位() > 0

   if(空單部位() > 0)
     {
      //+------------------------------------------------------------------+
      //|    Short Exit Method 移動停利+固定停損
      //+------------------------------------------------------------------+
      double 空單最小停利 = 0.0;
      bool SX_MinPF = false ;
      空單進場價格 = SE_EntryPrice(MagicNumber,空單進場單號);
      空單最小停利 = NormalizeDouble(空單進場價格 - SP*3,Digits()) ;
      SX_MinPF = Ask < 空單最小停利 ;
      //    SX_MinPF = true ;
      空單停利價格 = NormalizeDouble(空單進場價格 - TP * Point(),Digits()) ;
      空單停損價格 = NormalizeDouble(空單進場價格 + SL * Point(),Digits()) ;

      if(空單出場方式 == 13)
        {
         空單停利價格 = NormalizeDouble(空單進場價格 - (TP+Day5Range) * Point(),Digits()) ;
         SX_Cond = ((Close[1] >= 空單停利價格 && Ask < 空單停利價格) || (Close[1] <= 空單停損價格 && Ask > 空單停損價格)) ;
        }
      //---------------------------------------------------------空單出場

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

         if(空單部位() == 0)
           {
            CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
           }
        }
     } // end of 空單部位() > 0
  } // end of 交易時段外也可停損停利()


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

      BuyPrice = OpenD[1] + Range[2]*2 ;

   return NormalizeDouble(BuyPrice,Digits()) ;
  } // end of get BuyPrice

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

      ShortPrice = Lowest_OHLC(Symbol(),時間框架,MODE_LOW,LenB1,2) - a_ATR[2]*FracB;

   return NormalizeDouble(ShortPrice,Digits()) ;
  } // end of get ShortPrice
//+------------------------------------------------------------------+
//|多單模組編號
//+------------------------------------------------------------------+
void set_BuyCondition()
  {

      LE_Cond = (RVI_HDiv_01() && Close[1] > 流動性池底部價格 && Close[1] > a_KC_UPPER_B[1]) ; // RVI高點背離+突破流動性池底部+突破Keltner上軌B

  }

//+------------------------------------------------------------------+
//| 空單模組編號
//+------------------------------------------------------------------+
void set_ShortCondition()
  {

      SE_Cond = (BBUP_VTrend() && Close[1] < Close[2] && Close[1] < (High[1]+Low[1])/2) ; // 布林帶V型收縮+價格下降+弱勢收盤

  }
//+--------------------------------------------------------+
//| 設定 開高低收 陣列序列
//+--------------------------------------------------------+
//********BarPrice Array variables
double Open[], High[], Low[], Close[],Range[],Body[],UPshadow[],DNshadow[] ;
double BigOpen[], BigHigh[], BigLow[], BigClose[] ;
double OpenD[], HighD[], LowD[], CloseD[] ;
long Volume[],BigVolume[] ;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Set_OHLC_Bar_Series()
  {
   ArraySetAsSeries(Open,true);
   ArraySetAsSeries(High,true);
   ArraySetAsSeries(Low,true);
   ArraySetAsSeries(Close,true);
   ArraySetAsSeries(Volume,true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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_BigBar_Series()
  {
   ArraySetAsSeries(BigOpen,true);
   ArraySetAsSeries(BigHigh,true);
   ArraySetAsSeries(BigLow,true);
   ArraySetAsSeries(BigClose,true);
   ArraySetAsSeries(BigVolume,true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Get_OHLC_BigBar(int argCount)
  {
   get_OpenData(Symbol(),時間框架,argCount,BigOpen) ;
   get_HighData(Symbol(),時間框架,argCount,BigHigh) ;
   get_LowData(Symbol(),時間框架,argCount,BigLow) ;
   get_CloseData(Symbol(),時間框架,argCount,BigClose) ;
   get_VolumeData(Symbol(),時間框架,argCount,BigVolume) ;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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) ;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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) ;

   for(int i = 0; i < ArraySize(Open)-1; i=i+1)
     {
      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);
   ArraySetAsSeries(a_ATR, true);
   get_IndexData(h_ATR,0,0,5,a_ATR) ;
  }


//+------------------------------------------------------------------+
//|  BBand 指標 取值
//+------------------------------------------------------------------+
bool UpBreak,DnBreak,Shrink ;
double a_BBUP[],a_BBDN[] ;
void set_BBAND()
  {
   int BBLen,h_BBUP,h_BBDN ;

   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) ;

  }

//+------------------------------------------------------------------+
//|   RVI 指標                                                               |
//+------------------------------------------------------------------+
double a_RVI_1[], a_RVI_2[] ;
void set_RVI()
  {
   int h_RVI_1,h_RVI_2 ;
   h_RVI_1 = iRVI(Symbol(),時間週期,LenB1);
   ArraySetAsSeries(a_RVI_1, true);
   h_RVI_2 = iRVI(Symbol(),時間週期,LenB1);
   ArraySetAsSeries(a_RVI_2, true);

   get_IndexData(h_RVI_1,0,0,5,a_RVI_1) ;
   get_IndexData(h_RVI_2,1,0,5,a_RVI_2) ;
  }

//+------------------------------------------------------------------+
//|    RSI 高檔背離                                                              |
//+------------------------------------------------------------------+
bool RSI_HDiv_02()
  {
   int h_rsi1,h_rsi2 ;
   double a_rsi1[],a_rsi2[] ;
   int high1,high2 ;

   h_rsi1 = iRSI(Symbol(),PERIOD_CURRENT,LenA1,PRICE_CLOSE) ;
   ArrayResize(a_rsi1, LenA1);
   ArraySetAsSeries(a_rsi1,true) ;
   h_rsi2 = iRSI(Symbol(),PERIOD_CURRENT,LenA1*2,PRICE_CLOSE) ;
   ArrayResize(a_rsi2, LenA1*2);
   ArraySetAsSeries(a_rsi2,true) ;

   high1 = iHighest(Symbol(), 時間週期,MODE_HIGH,LenA1,1);
   high2 = iHighest(Symbol(), 時間週期,MODE_HIGH,LenA1*2,1);

   get_IndexData(h_rsi1,0,0,ArraySize(a_rsi1),a_rsi1) ;
   get_IndexData(h_rsi2,0,0,ArraySize(a_rsi2),a_rsi2) ;

   if((a_rsi1[high1] < a_rsi2[high2] && high1 == high2))
     {
      return true;
     }
   return false;
  }

//+------------------------------------------------------------------+
//|   布林軌道線 V轉                                                               |
//+------------------------------------------------------------------+
bool BBUP_VTrend()
  {
   if(a_BBUP[1] > a_BBUP[2] && a_BBUP[2] > a_BBUP[3] && a_BBUP[5] > a_BBUP[4] && a_BBUP[4] > a_BBUP[3])
     {
      return true;
     }
   return false;
  }

//+------------------------------------------------------------------+
//| Keltner Channel 指標自訂函數
//+------------------------------------------------------------------+
double a_KC_UPPER_B[], a_KC_LOWER_B[], a_KC_MIDDLE_B[], a_KC_ATR_B[] ; // Keltner Channel B組:上軌、下軌、中線陣列
void set_KELTNER_CHANNEL()
  {
   int h_EMA_B ;                     // EMA句柄(中線)
   int h_ATR_B ;                     // ATR句柄(用於計算通道寬度)

// 建立 Keltner Channel B組指標句柄(使用 LenB1 週期)
   h_EMA_B = iMA(Symbol(), 時間週期, LenB1, 0, MODE_EMA, PRICE_CLOSE);
   h_ATR_B = iATR(Symbol(), 時間週期, LenB1);
   ArraySetAsSeries(a_KC_UPPER_B, true);               // 設定B組上軌陣列為時間序列
   ArraySetAsSeries(a_KC_LOWER_B, true);               // 設定B組下軌陣列為時間序列
   ArraySetAsSeries(a_KC_MIDDLE_B, true);              // 設定B組中線陣列為時間序列
   ArraySetAsSeries(a_KC_ATR_B, true);                 // 設定B組ATR陣列為時間序列

// 調整陣列大小
   ArrayResize(a_KC_UPPER_B, 20);
   ArrayResize(a_KC_LOWER_B, 20);
   ArrayResize(a_KC_MIDDLE_B, 20);
   ArrayResize(a_KC_ATR_B, 20);

// 獲取EMA和ATR數據
   get_IndexData(h_EMA_B, 0, 0, 20, a_KC_MIDDLE_B);    // 獲取B組EMA數據作為中線
   get_IndexData(h_ATR_B, 0, 0, 20, a_KC_ATR_B);       // 獲取B組ATR數據

   for(int i = 0; i < ArraySize(a_KC_MIDDLE_B)-1; i++)
     {
      // Keltner Channel 計算:
      // 上軌 = EMA + (ATR × 倍數)
      // 下軌 = EMA - (ATR × 倍數)
      a_KC_UPPER_B[i] = a_KC_MIDDLE_B[i] + (a_KC_ATR_B[i] * 1.5);
      a_KC_LOWER_B[i] = a_KC_MIDDLE_B[i] - (a_KC_ATR_B[i] * 1.5);
     }
  }
//+------------------------------------------------------------------+
//|   RVI 高檔背離  
//+------------------------------------------------------------------+
bool RVI_HDiv_01()
  {
   if((ArrayMaximum(High) !=0 && ArrayMaximum(High) <= 2) && (ArrayMaximum(a_RVI_1) > 2) && a_RVI_1[1] < 0.5)
     {
      return true;
     }
   return false;
  }

// 流動性池價格計算 (ICT 概念)
double 流動性池頂部價格 = Highest_OHLC(Symbol(), 時間週期, MODE_HIGH, 20, 5);
double 流動性池底部價格 = Lowest_OHLC(Symbol(), 時間週期, MODE_LOW, 20, 5);


交易商品 XAUUSD 樣本內區間 2019/1/1 ~2023/6/30 交易手數 固定 0.1手

隔日沖



沒有留言:

張貼留言