第8回 なんちゃってトレンドラインで自動売買バックテストした結果

未分類

第7回でEAに求められる要件の話をしつつ、思慮浅くオリジナルのインジケータを作ってみた話をしましたが、今回はそれを実際に動かしてみます。

今回のEAは前回のインジケータの売買シグナルによってエントリーするというものですが、その他の条件は以下にしました。

  • エントリー時に損切と利確ポイントを入れる
  • ポジションがある場合は新規のポジションは持たない
  • (上記のため)買い(売り)ポジションがある際に売り(買い)シグナルが出ても途転はしない。
  • インジケータのパラメータは0.9、利確0.8、損切0.2

結果は以下の通りです。

それほど悪くはない印象ですが、利確は粘って、損切はあっさりとしているので勝率はその比を単純に反映して悪いです。ここからどうやって最大ドローダウンを下げていく条件を付与すればいいかが今後の課題です。

ちなみに、利確0.5、損切0.5とすると以下の結果になりました。

これだけみると、エントリーポイントとしてはそれほど良いとは言えない印象。損切幅と利確幅同じに設定したらせめて勝率6割とれるようなエントリー条件を見つけたい。

ちなみに同じ損切幅と利確幅だけどさらに小さくして利確0.1、損切0.1とすると・・

勝率はほぼ5分だけど悪いですね。

ここまでやって今後の課題とか思いついたやってみたいことは以下の通り。

  • 値動きから損切幅と利確幅を変動値でセットできるようにしたい。どういう条件にするのがよいか。
  • いろいろ他の方のブログなどをみているとマルチタイムフレーム分析(複数の時間足を分析してトレンドやエントリータイミングを見極める)できるようになる必要がありそう。
  • 実際のエントリー条件など先人のブログをたくさん調べて知識を増やす必要あり。
  • トレール注文もいれたい。普通のFX業者ではできないけど、いつもやれたらいいなと思っているのが、何pips以上利益が出てから何pipsのトレール注文を追加というもの。
  • ディープラーニングも取り入れて条件を見つけ出すこともやってみたい

ということでこのあたりを一つずつやっていこうと思います!

このEAのソースコード

//+------------------------------------------------------------------+
//|                                      FXexp_FXind_maxmine_line.mq4|
//|                                 Copyright (c) 2021, Langtainment |
//|                                    https://tsunagaru-info.com/dr |
//+------------------------------------------------------------------+

#property copyright "Copyright (c) 2021, Langtainment"
#property link      "https://tsunagaru-info.com/dr"

#include <stdlib.mqh>
#include <mylib.mqh> //Copyright (c) 2009, Toyolab FX

//Magic Number
#define MAGIC_NUMBER  20211025

//SIGNAL
#define ENTRY_BUY_SIGNAL   1
#define ENTRY_SELL_SIGNAL  2
#define CLOSE_BUY_SIGNAL   4
#define CLOSE_SELL_SIGNAL  8

//
#define REFERENCE_INDICATOR "original\\FXind_maxmin_line" 

//Common Parameters
extern double Lots =  1;
extern int Slippage = 3;
extern double stop_loss = 0.2;//Parameter 5
extern double take_profit = 0.2;//Parameter 6 

//Unique Parameters
extern double rate = 0.9;

double MaxVal1 = EMPTY_VALUE;
double MaxVal2 = EMPTY_VALUE;
double MaxVal3 = EMPTY_VALUE;
double MinVal1 = EMPTY_VALUE;
double MinVal2 = EMPTY_VALUE;
double MinVal3 = EMPTY_VALUE;

int ticket = 0;
int errorcode = 0;
int Adjusted_Slippage = 0;
datetime Bar_Time     = 0;

bool closed = false;

//+------------------------------------------------------------------+
//| Adjust Slippage according to Number of digits after the decimal point                                                 |
//+------------------------------------------------------------------+
int AdjustSlippage(string Currency,int Slippage_Pips)
{
   int Symbol_Digits = MarketInfo(Currency,MODE_DIGITS);
   
   if(Symbol_Digits == 2 || Symbol_Digits == 4)
   {
      int Calculated_Slippage = Slippage_Pips;
   } 
   else if(Symbol_Digits == 3 || Symbol_Digits == 5)
   {
      Calculated_Slippage = Slippage_Pips * 10;
   }
   else
   {
      //unreachable
   }  
   return(Calculated_Slippage);
   
}

//+-----------------------------------------------------------------------------------------------------------------------------+
//|                                                                                                                             |
//| Oninit() works at the time of EA application, time step change, property change, and MT4 restart, as initialization process. |
//|                                                                                                                             |
//+-----------------------------------------------------------------------------------------------------------------------------+
int Oninit()
{
   Adjusted_Slippage = AdjustSlippage(Symbol(),Slippage);

   return(0);
}

//+------------------------------------------------------------------+
//| Calculate Current Orders                                         |
//+------------------------------------------------------------------+
int CalculateCurrentOrders()
{
   //The number of Current Orders(+:BUY -:SELL)
   int pos=0;

   for(int i=0; i<OrdersTotal(); i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break;
      if(OrderSymbol() == Symbol() && OrderMagicNumber() == MAGIC_NUMBER)
      {
         if(OrderType() == OP_BUY)  pos++;
         if(OrderType() == OP_SELL) pos--;
      }
   }
   return(pos);
}

//+------------------------------------------------------------------+
//| Close Positions                                             |
//+------------------------------------------------------------------+
void ClosePositions()
{
   for(int i=0; i<OrdersTotal(); i++)
   {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false) break;
      if(OrderMagicNumber() != MAGIC_NUMBER || OrderSymbol() != Symbol()) continue;
      //Check Order type 
      if(OrderType() == OP_BUY)
      {
         closed = OrderClose(OrderTicket(),OrderLots(),Bid,Adjusted_Slippage,White);
         if(closed==False)
         {
            errorcode=GetLastError(); 
            printf("OrderClose Error! error_code:%d , detail:%s ",errorcode,ErrorDescription(errorcode));
         }
         break;
      }
      else if(OrderType() == OP_SELL)
      {
         closed = OrderClose(OrderTicket(),OrderLots(),Ask,Adjusted_Slippage,White);
         if(closed==False)
         {
            errorcode=GetLastError(); 
            printf("OrderClose Error! error_code:%d , detail:%s ",errorcode,ErrorDescription(errorcode));
         }
         break;
      }
      else
      {
         //unreachable
      }
   }
}

//+------------------------------------------------------------------+
//| SIGNAL                                                      |
//+------------------------------------------------------------------+
int AnalyzeSignal()
{
   int flags = 0;
   
   MaxVal1 = iCustom(NULL,0,REFERENCE_INDICATOR,rate,0,1);  
   MinVal1 = iCustom(NULL,0,REFERENCE_INDICATOR,rate,1,1);  
   MaxVal2 = iCustom(NULL,0,REFERENCE_INDICATOR,rate,0,2);  
   MinVal2 = iCustom(NULL,0,REFERENCE_INDICATOR,rate,1,2); 
   MaxVal3 = iCustom(NULL,0,REFERENCE_INDICATOR,rate,0,3); 
   MinVal3 = iCustom(NULL,0,REFERENCE_INDICATOR,rate,1,3);  
   
   if((MaxVal1 < MaxVal2) && (MaxVal2 > MaxVal3))
   {
      Print(MaxVal1,"<",MaxVal2,">",MaxVal3);
      return flags = ENTRY_SELL_SIGNAL;
   }
   else if((MinVal1 > MinVal2) && (MinVal2 < MinVal3)) { Print(MinVal1,">",MinVal2,"<",MinVal3); return flags = ENTRY_BUY_SIGNAL; } else { //no operation } return flags; } //+--------------------------------------------------------------------------------------------------------------------------------------+ //| | //| OnTick() works at the timing when the rate of the currency pair on the chart you applied is delivered, as the main processing. | //| | //+--------------------------------------------------------------------------------------------------------------------------------------+ void OnTick(){ //Check if allowable trade at opening-price if(Volume[0] > 1 || IsTradeAllowed() == false)
   {
      return;
   }


   //Calculate Current Orders
   int pos = CalculateCurrentOrders();   

   //Check signal
   int signal = AnalyzeSignal();
   
   if(pos != 0) return; // test
   
   //BUY signal
   if(pos <= 0 && ((signal & ENTRY_BUY_SIGNAL) == ENTRY_BUY_SIGNAL)) { ClosePositions(); if(!MyOrderSend(OP_BUY,Lots,Ask,Adjusted_Slippage,Ask - stop_loss,Ask + take_profit,"",MAGIC_NUMBER)) { errorcode=GetLastError(); printf("Send Error! error_code:%d , detail:%s ",errorcode,ErrorDescription(errorcode)); } } //SELL signal else if(pos >= 0 && ((signal & ENTRY_SELL_SIGNAL) == ENTRY_SELL_SIGNAL))
   {
      ClosePositions();

      if(!MyOrderSend(OP_SELL,Lots,Bid,Adjusted_Slippage,Bid + stop_loss,Bid - take_profit,"",MAGIC_NUMBER)){
         errorcode=GetLastError();
         printf("Send Error! error_code:%d , detail:%s ",errorcode,ErrorDescription(errorcode));
      }
   }
   //Close BUY position
   else if(pos > 0  && ((signal & CLOSE_BUY_SIGNAL) == CLOSE_BUY_SIGNAL))
   {
      ClosePositions();
   }
   //Close SELL position
   else if(pos < 0  && ((signal & CLOSE_SELL_SIGNAL) == CLOSE_SELL_SIGNAL))
   {
      ClosePositions();
   }
   else
   {
      //no operation
   }
   return;

}



 

ソースコード中、今までOrderSendとしていたところをMyOrderSendとしている場所があります。

こちらは、FXメタトレーダー入門(豊島久道著)の中で紹介されている関数で、エラー処理などをやってくれるので今回採用しています。Ordersendで書き直すと、

OrderSend(Symbol(),OP_SELL,Lots,Bid,Adjusted_Slippage,Bid + stop_loss,Bid - take_profit,"",MAGIC_NUMBER,0,Blue);

となります。最後のBlueはバックテストなどで表示される矢印の色なので、OP_BUYの場合はREDにします。

 

コメント

タイトルとURLをコピーしました