2025年4月15日 星期二

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

KDJ指標叫做隨機指標,幫助投資者發現趨勢和最佳切入點。KDJ指標在圖中有三根線,分別為K值(快線)、D值(慢線)和J值(方向敏感線),其中K線和D線表示超買或超賣情況,,J線用於顯示K線與D線的偏差。這些線的匯合暗示出現了新的交易機會

理論上講,當K線向上突破D線時,表示股市為上漲趨勢,可以買入;當K線向下突破D線時,表示股市為下跌趨勢,應當賣出。

RSI (Relative strength indicator),叫做相對強弱指標,是一種用來衡量近期市場買賣雙方力量對比的指標。它主要通過比較商品在近期內上漲和下跌的幅度,來判斷市場的多空力量變化。隨著時間的推移,RSI逐漸被廣泛應用於判斷進出場時機,成為投資者常用的技術分析工具之一。

本篇利用 KD進場做多  RSI 向下做空的方式 作為交易策略

PS: 策略寫法是單向持單 (會平掉反向單 再進場)
#include <Trade\Trade.mqh>
#include <MagicMT5_函數庫V1.mqh>

ENUM_TIMEFRAMES 時間週期 = PERIOD_H2;

int OnInit()
{
LoadEA = TimeCurrent();
return(INIT_SUCCEEDED);
}

void OnTick()
  {
   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棒();
//時間濾網
      允許交易時段 = (getTM_hour(TimeCurrent()) >= 18 || getTM_hour(TimeCurrent()) < 10) ;
     }

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

      //+------------------------------------------------------------------+
      //|多單進場  (均線多頭且KD向上交叉)
      //+------------------------------------------------------------------+
      LE_Cond = (TrendDir3L > 0 && CrossOver(a_KA2[2], a_DA2[2], a_KA2[1], a_DA2[1])) ;

      if(LE_Cond == true)
        {
//做多前 有空單先平倉
         if(空單部位() > 0 && BarNumber != OrderBarNo)
           {
            sell_order_close_all(Symbol(), MagicNumber, ORDER_TYPE_SELL);
            CloseOrderNo =  iBarShift(Symbol(),時間週期,LoadEA);
           }

         if(多單部位() == 0 && BarNumber != OrderBarNo)
           {
//距離上筆出場經過一根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


      //+------------------------------------------------------------------+
      //|空單進場 (RSI 指標向下交叉)
      //+------------------------------------------------------------------+
      SE_Cond = (CrossUnder(a_RSIA[2], LowBand, a_RSIA[1], LowBand)) ;
      if(SE_Cond == true)
        {
//做前 有單先平倉
         if(多單部位() > 0 && BarNumber != OrderBarNo)
           {
            buy_order_close_all(Symbol(), MagicNumber, ORDER_TYPE_BUY);
            CloseOrderNo =  iBarShift(Symbol(),時間週期,LoadEA);
           }
         if(空單部位() == 0 && BarNumber != OrderBarNo)
           {
//距離上筆出場經過一根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

   if(多單部位() > 0)
     {
      //     多單進場價格 = get_position_info_double((ulong)多單進場單號, POSITION_PRICE_OPEN);
      //+------------------------------------------------------------------+
      //|    Buy Exit Method 多單 移動停損+固定停利 出場
      //+------------------------------------------------------------------+

      多單進場價格 = LE_EntryPrice(MagicNumber,多單進場單號);
      多單停利價格 = NormalizeDouble(多單進場價格 + TP * Point(),Digits()) ;
      多單停損價格 = NormalizeDouble(多單進場價格 - SL * Point(),Digits()) ;

      bool LXcond61,LXcond62 ;
      double LE_WinPoint ;
      多單最高價 = iHigh(Symbol(),時間週期, iHighest(Symbol(),時間週期,MODE_HIGH,LE_BarsSinceEntry(MagicNumber,多單進場單號,時間週期),1));
      LE_WinPoint = 多單最高價-多單進場價格 ;
      多單停利價格 = 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());
      if((LE_WinPoint/Point()) > (TP*Point()))
         多單停損價格 = NormalizeDouble(多單最高價-LE_WinPoint/2,Digits());

      LXcond61 = (多單進場價格 < 多單停利價格 && Close[1] <= 多單停利價格 && 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) ;
           }
        }
     } // end of 多單部位() > 0

   if(空單部位() > 0)
     {
      //+------------------------------------------------------------------+
      //|    Short Exit Method 空單布林通道下界值 出場
      //+------------------------------------------------------------------+
      // 空單進場價格 = get_position_info_double((ulong)空單進場單號, POSITION_PRICE_OPEN);
      空單進場價格 = SE_EntryPrice(MagicNumber,空單進場單號);

      bool SXcond31,SXcond32 ;
      空單停利價格 = NormalizeDouble(MathMin(a_BBDN[1],a_BBDN[2]),Digits()) ;
      空單停損價格 = NormalizeDouble(MathMin((空單進場價格 + SL * Point()),MathMax(a_BBUP[1],a_BBUP[2])),Digits());
      SXcond31 = (空單進場價格 > 空單停利價格 && Close[1] >= 空單停利價格 && Ask < 空單停利價格) ;
      SXcond32 = (空單進場價格 < 空單停損價格 && Close[1] <= 空單停損價格 && Bid > 空單停損價格) ;
      SX_Cond = (SXcond31 == true || SXcond32 == 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_BBAND();
   set_RSI();
   set_KD() ;
   set_ThreeLine() ;
   set_ATR();

   Day5Range = ((HighD[1] - LowD[1])+(HighD[2] - LowD[2])+(HighD[3] - LowD[3])+(HighD[4] - LowD[4])+(HighD[5] - LowD[5]))/5;
  }

//+--------------------------------------------------------+
//| 設定 開高低收 陣列序列
//+--------------------------------------------------------+
//********BarPrice Array variables
double Open[], High[], Low[], Close[],Range[],Body[],UPshadow[],DNshadow[] ;
double OpenD[], HighD[], LowD[], CloseD[] ;
double OpenW[], HighW[], LowW[], CloseW[] ;
double OpenM[], HighM[], LowM[], CloseM[] ;


//+------------------------------------------------------------------+
//|   設定 開高低收 陣列序列                                                               |
//+------------------------------------------------------------------+
void Set_OHLC_Bar_Series()
  {
   ArraySetAsSeries(Open,true);
   ArraySetAsSeries(High,true);
   ArraySetAsSeries(Low,true);
   ArraySetAsSeries(Close,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) ;
  }
//+------------------------------------------------------------------+
//|  設定 開高低收 陣列序列
//+------------------------------------------------------------------+
void Set_OHLC_Day_Series()
  {
   ArraySetAsSeries(OpenD,true);
   ArraySetAsSeries(HighD,true);
   ArraySetAsSeries(LowD,true);
   ArraySetAsSeries(CloseD,true);
  }
//+------------------------------------------------------------------+
//|   取得日K 開高低收                                                                
//+------------------------------------------------------------------+
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) ;

   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];
     }
  }
//+------------------------------------------------------------------+
//|   計算布林通道值                                                               |
//+------------------------------------------------------------------+
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) ;
  }
//+------------------------------------------------------------------+
//|  計算RSI值
//+------------------------------------------------------------------+
double a_RSIA[];
void set_RSI()
  {
   int h_RSIA;
   h_RSIA = iRSI(Symbol(),時間週期,LenA1,PRICE_CLOSE) ;
   ArraySetAsSeries(a_RSIA,true) ;
   get_IndexData(h_RSIA,0,0,5,a_RSIA) ;

  }
//+------------------------------------------------------------------+
//|   計算KD值                                                              
//+------------------------------------------------------------------+
double a_KA2[], a_DA2[];
void set_KD()
  {
   int h_KA2,h_DA2 ;
   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);

   get_IndexData(h_KA2,0,0,5,a_KA2) ;
   get_IndexData(h_DA2,1,0,5,a_DA2) ;

  }

//+------------------------------------------------------------------+
//| 計算短中長均線                                                            
//+------------------------------------------------------------------+
double a_Avg7[],a_Avg13[],a_Avg21[],Max3L,Min3L ;
int TrendDir3L ;
void set_ThreeLine()
  {
   int h_Avg7,h_Avg13,h_Avg21,h_Avg60 ;
   h_Avg7 = iMA(Symbol(),時間週期,7,0,MODE_SMA,PRICE_CLOSE) ;
   ArraySetAsSeries(a_Avg7,true) ;
   h_Avg13 = iMA(Symbol(),時間週期,13,0,MODE_SMA,PRICE_CLOSE) ;
   ArraySetAsSeries(a_Avg13,true) ;
   h_Avg21 = iMA(Symbol(),時間週期,21,0,MODE_SMA,PRICE_CLOSE) ;
   ArraySetAsSeries(a_Avg21,true) ;

   get_IndexData(h_Avg7,0,0,5,a_Avg7) ;
   get_IndexData(h_Avg13,0,0,5,a_Avg13) ;
   get_IndexData(h_Avg21,0,0,5,a_Avg21) ;

   Max3L = MathMax(a_Avg7[1],MathMax(a_Avg13[1],a_Avg21[1])) ;
   Min3L = MathMin(a_Avg7[1],MathMin(a_Avg13[1],a_Avg21[1])) ;
   if(a_Avg7[1] > a_Avg13[1] && a_Avg13[1] > a_Avg21[1])
      TrendDir3L = 1 ;
   else
      if(a_Avg7[1] < a_Avg13[1] && a_Avg13[1] < a_Avg21[1])
         TrendDir3L = -1 ;
      else
         TrendDir3L = 0 ;
  }

//+------------------------------------------------------------------+
//|   計算真實區間                                                          
//+------------------------------------------------------------------+
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) ;
  }
交易商品 XAUUSDXXX 樣本內區間 2019/1/1 ~2022/12/31 交易手數 固定 0.1手





沒有留言:

張貼留言