2025年7月1日 星期二

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

這支 EA 運用了RSI 指標背離作為進出場的條件 在今年表現得相當不錯

多單進場方式 RSI 低檔背離   掛單突破進場做多
空單進場方式 ~ RSI 高檔背離   掛單突破進場做空

#include <Trade\Trade.mqh>
#include <MagicMT5_函數庫V1.mqh>
ENUM_TIMEFRAMES  時間週期 = PERIOD_M6 ;
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);
     }
   if(BarNumber != JudgeNo)
     {
      換K棒();
//時間濾網
      允許交易時段 = (getTM_hour(TimeCurrent()) >= 14 && getTM_hour(TimeCurrent()) < 18) || getTM_hour(TimeCurrent()) >= 22 || getTM_hour(TimeCurrent()) < 2;

     }
   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(Lots_AutoCal == true)
     {
      Lots = get_dynamic_lot_size(Lots_Even,Symbol(),RiskPercent,AccountBalance,SL) ;
      Lots = MathMin(0.3,MathMax(0.01,Lots)) ;
     }
   if(允許交易時段 == true)
     {
      //+------------------------------------------------------------------+
      //|多單進場 RSI 低檔背離
      //+------------------------------------------------------------------+
      LE_Cond =(RSI_LDiv_01()) ;

      if(LE_Cond == true)
        {
         if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
           {
            買入價格 = NormalizeDouble(MathMax(Open[1],MathMax(Open[2],Open[3])),Digits()) ;

//距離上筆出場經過一根K棒 且當日未進場    
            if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
              {
               // 空手+掛單限價買入
                  if(Close[1] > 買入價格)
                    {
                     多單進場單號 = Buy_at_LIMIT(Symbol(),MagicNumber,買入價格,Lots,TP,SL,"BUY STOP",3600) ;
                     OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA);

                    }
              } // end of BarSinceExit > 1
           } // end of 空手且不同根K棒() == true
        } // end of LE_Cond == true
      //+------------------------------------------------------------------+
      //|空單進場  RSI 高檔背離
      //+------------------------------------------------------------------+
      SE_Cond =(RSI_HDiv_01())  ;
      if(SE_Cond == true)
        {
         if(多單部位() == 0 && 空單部位() == 0 && BarNumber != OrderBarNo)
           {
            賣出價格 = NormalizeDouble(MathMin(Open[1],MathMin(Open[2],Open[3])),Digits());
//距離上筆出場經過一根K棒 且當日未進場 
            if(BarSinceExit > 1 && EntriesToday(MagicNumber,Symbol()) < 1)
              {
                  // 空手+掛單限價賣出
                 if(Close[1] < 賣出價格)
                    {
                     空單進場單號 = Short_at_LIMIT(Symbol(),MagicNumber,賣出價格,Lots,TP,SL,"Short STOP",3600) ;
                     OrderBarNo = iBarShift(Symbol(),時間週期,LoadEA);

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

   if(多單部位() > 0)
     {
      //+------------------------------------------------------------------+
      //|    Buy Exit Method  多單  以均線通道及固定停損平倉
      //+------------------------------------------------------------------+
      多單進場價格 = LE_EntryPrice(MagicNumber,多單進場單號);

         bool LXcond41,LXcond42 ;
         多單停利價格 = NormalizeDouble(a_Avg21[1] + (High[1]-Low[1]) * 2,Digits());
         多單停損價格 = NormalizeDouble(MathMax((多單進場價格 - SL * Point()),a_Avg21[1] - (High[1]-Low[1]) * 2),Digits());
         LXcond41 = (多單進場價格 < 多單停利價格 && Close[1] <= 多單停利價格 && Bid > 多單停利價格) ;
         LXcond42 = (多單進場價格 > 多單停損價格 && Close[1] >= 多單停損價格 && Bid < 多單停損價格) ;
         LX_Cond = (LXcond41 == true || LXcond42 == true) ;

      //---------------------------------------------------------多單出場
      if(LX_Cond == true && BarNumber != CloseOrderNo && BarNumber != OrderBarNo && LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期) > 0)
        {
         LX_CloseByTicket(多單進場單號,Lots) ;
         if(多單部位() == 0)
           {
            CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
           }
        }
     } // end of 多單部位() > 0
   if(空單部位() > 0)
     {
      //+------------------------------------------------------------------+
      //|    Short Exit Method  空單 以固定方式停利及移動停損平倉
      //+------------------------------------------------------------------+
      空單進場價格 = SE_EntryPrice(MagicNumber,空單進場單號);
      空單停利價格 = NormalizeDouble(空單進場價格 - TP * Point(),Digits()) ;
      空單停損價格 = NormalizeDouble(空單進場價格 + SL * Point(),Digits()) ;
         bool SXcond61,SXcond62 ;
         double SE_WinPoint ;
         空單最低價 = iLow(Symbol(),時間週期, iLowest(Symbol(),時間週期,MODE_LOW,SE_BarsSinceEntry(MagicNumber,空單進場單號,時間週期),1));
         SE_WinPoint = 空單進場價格-空單最低價 ;
         空單停利價格 = NormalizeDouble(空單進場價格 - (TP+Day5Range*0.618) * Point(),Digits()) ;
         if((SE_WinPoint/Point()) <= (SL*Point()*1.5))
            空單停損價格 = NormalizeDouble(空單進場價格+SL*Point(),Digits());
         if((SE_WinPoint/Point()) > (SL*Point()*1.5) && (SE_WinPoint/Point()) <= (TP*Point()))
            空單停損價格 = NormalizeDouble(空單最低價+SL*Point()/2,Digits());
         if((SE_WinPoint/Point()) > (TP*Point()))
            空單停損價格 = NormalizeDouble(空單最低價+SE_WinPoint/2,Digits());

         SXcond61 = (空單進場價格 > 空單停利價格 && Close[1] >= 空單停利價格 && Ask < 空單停利價格) ;
         SXcond62 = (空單進場價格 < 空單停損價格 && Close[1] <= 空單停損價格 && Ask > 空單停損價格) ;
         SX_Cond = (SXcond61 == true || SXcond62 == true) ;

      //---------------------------------------------------------空單出場
      if(SX_Cond == true && BarNumber != CloseOrderNo && SE_BarsSinceEntry(MagicNumber,空單進場單號,時間週期) > 0)
        {
         SX_CloseByTicket(空單進場單號,Lots) ;
         if(空單部位() == 0)
           {
            CloseOrderNo = iBarShift(Symbol(),時間週期,LoadEA) ;
           }
        }
     } // end of 空單部位() > 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(10) ; //保留
   Get_OHLC_Day(10) ; //保留
   set_BarInfo(); //保留

   set_RSI();
   set_ThreeLine() ;

  }
//+--------------------------------------------------------+
//| 設定 開高低收 陣列序列
//+--------------------------------------------------------+
//********BarPrice Array variables
double Open[], High[], Low[], Close[],Range[],Body[],UPshadow[],DNshadow[] ;
double OpenD[], HighD[], LowD[], CloseD[] ;
//+------------------------------------------------------------------+
//|                                                             
//+------------------------------------------------------------------+
void Set_OHLC_Bar_Series()
  {
   ArraySetAsSeries(Open,true);
   ArraySetAsSeries(High,true);
   ArraySetAsSeries(Low,true);
   ArraySetAsSeries(Close,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) ;
  }
//+------------------------------------------------------------------+
//|                                                                 
//+------------------------------------------------------------------+
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];
     }
  }
//+------------------------------------------------------------------+
//|                                                             
//+------------------------------------------------------------------+
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) ;
  }

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

//+------------------------------------------------------------------+
//|  指標及通道計算                                                                |
//+------------------------------------------------------------------+
double a_RSIA[],a_RSIB[] ;
void set_RSI()
  {
   int h_RSIA,h_RSIB ;
   h_RSIA = iRSI(Symbol(),時間週期,LenA1,PRICE_CLOSE) ;
   ArraySetAsSeries(a_RSIA,true) ;
   get_IndexData(h_RSIA,0,0,5,a_RSIA) ;

   h_RSIB = iRSI(Symbol(),時間週期,LenB1,PRICE_CLOSE) ;
   ArraySetAsSeries(a_RSIB,true) ;
   get_IndexData(h_RSIB,0,0,5,a_RSIB) ;

  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double a_Avg7[],a_Avg13[],a_Avg21[],a_Avg60[],Max3L,Min3L ;
int TrendDir3L ;
void set_ThreeLine()
  {
   int h_Avg21 ;
   h_Avg21 = iMA(Symbol(),時間週期,21,0,MODE_SMA,PRICE_CLOSE) ;
   ArraySetAsSeries(a_Avg21,true) ;

   get_IndexData(h_Avg21,0,0,5,a_Avg21) ;
}
 
//+------------------------------------------------------------------+
//| 進出場條件
//+------------------------------------------------------------------+

bool RSI_LDiv_01()
  {
   if((ArrayMinimum(Low) !=0 && ArrayMinimum(Low) <= 2) && (ArrayMinimum(a_RSIA) > 2) && (a_RSIA[1] > 30))
     {
      return true;
     }
   return false;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool RSI_HDiv_01()
  {
   if((ArrayMaximum(High) !=0 && ArrayMaximum(High) <= 2) && (ArrayMaximum(a_RSIA) > 2) && (a_RSIA[1] < 70))
     {
      return true;
     }
   return false;
  }

//+------------------------------------------------------------------+
交易商品 XAUUSD 樣本內區間 2019/1/1 ~2022/12/31 交易手數 固定 0.1手

波段




沒有留言:

張貼留言