FXオートトレードプログラムを開発する会(6)

前回のリンク
次回のリンク

今回は作成したプログラムの性能評価の方法と,ランダムに取引するプログラムを実際に評価した結果を紹介します.

スポンサーリンク

基本的な性能評価の方法

1.表示>ストラテジーテスターをおしてストラテジーテスターを表示(もしくはCTRL+R).

2.設定タブで主に以下の要素を設定

  • 検証するエキスパート(取引プログラム)
  • 銘柄(ドル円等)
  • ローソク足の間隔(日足等)
  • テストに使用する期間

3.右下のスタートボタンでテストを実行.テスト終了後にバックテストで性能を見ることができる.性能評価の項目の詳細は以下の公式URLを見てみてください.

Testing report: https://www.metatrader5.com/en/terminal/help/algotrading/testing_report

MAE : Maximum adverse excursion

MFE: Maximum favorable excursion

今回は以下の自作ランダム取引プログラムに対して性能評価を行ってみたいと思います.

スポンサーリンク

ランダム取引プログラム

ここは今回使用したランダム取引プログラムについての説明です.時間のない方は飛ばしても問題ないです.

WGN : https://www.mql5.com/ja/docs/standardlibrary/mathematics/stat/normal/mathrandomnormal

コントロールとしてのランダム取引プログラムは以下の4つが考えられます.

  1. トレードタイミングは一定で,ポジションの数量は一定
  2. トレードタイミングだけランダムで,ポジションの数量は一定
  3. トレードタイミングは一定で,ポジションの数量はランダム
  4. トレードタイミングとポジションの数量ともにランダム

今回作成したプログラムは上記の2のプログラムです.

ローソク足の間隔でランダムに一定量(口座の余剰証拠金の2%)売り買いします.つまり日足なら1日に1回取引のタイミングがあり,まず,取引を行うか否かがランダムに決定されます.もし取引を行うことになった場合は,ポジションを持っていれば決済し,持っていなければ新しいポジションの売りか買いかをランダムに選択するようになっています.

//+------------------------------------------------------------------+
//|                                               random20201017.mq5 |
//|                                         Copyright 2020, Sciotein |
//|                                            https://sciotein.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Sciotein"
#property link      "https://sciotein.com/"
#property version   "1.00"
#include <Trade\Trade.mqh>
#include <Math\Stat\Uniform.mqh>
#include <Math\Stat\Math.mqh>

input double MaximumRisk        = 0.02;    // Maximum Risk in percentage
input double DecreaseFactor     = 3;       // Descrease factor

//---
int    ExtHandle=0;
bool   ExtHedging=false;
CTrade ExtTrade;

#define MA_MAGIC 564321

//--- related random
int max_sample_num = 1000000; //sample number of random data
double low_lim = 0;
double upp_lim = 1;
double rnd_open_close[];
double rnd_open_rate = 0.1;
double rnd_close_rate = 0.1;
double rnd_sign_trade[];
double sell_rate = 0.5; //buy_rate = 1- sell_rate
int rnd_ind_oc = 0;
int rnd_int_sign = 0;
//int rand_type_mode =1; 
//1:timing static, lot static
//2:timing random, lot static
//3:timing static, lot random
//4:timing random, lot random

//+------------------------------------------------------------------+
//| Calculate optimal lot size                                       |
//+------------------------------------------------------------------+
double TradeSizeOptimized(void)
  {
   double price=0.0;
   double margin=0.0;
//--- select lot size
   if(!SymbolInfoDouble(_Symbol,SYMBOL_ASK,price))
      return(0.0);
   if(!OrderCalcMargin(ORDER_TYPE_BUY,_Symbol,1.0,price,margin))
      return(0.0);
   if(margin<=0.0)
      return(0.0);

   double lot=NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN_FREE)*MaximumRisk/margin,2);
   
//--- normalize and check limits
   double stepvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP);
   lot=stepvol*NormalizeDouble(lot/stepvol,0);

   double minvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);
   if(lot<minvol)
      lot=minvol;

   double maxvol=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);
   if(lot>maxvol)
      lot=maxvol;
//--- return trading volume
   return(lot);
  }
//+------------------------------------------------------------------+
//| Check for open position conditions                               |
//+------------------------------------------------------------------+
void CheckForOpen(void)
  {
   MqlRates rt[2];
//--- go trading only for first ticks of new bar
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates of ",_Symbol," failed, no history");
      return;
     }
   if(rt[1].tick_volume>1)
      return;

//--- check signals
   ENUM_ORDER_TYPE signal=WRONG_VALUE;
   
   if(rnd_sign_trade[rnd_int_sign]<sell_rate)
      signal=ORDER_TYPE_SELL;    // sell conditions
   else
     {
      signal=ORDER_TYPE_BUY;  // buy conditions
     }
   rnd_int_sign++;
//--- additional checking
   if(signal!=WRONG_VALUE)
     {
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100)
         ExtTrade.PositionOpen(_Symbol,signal,TradeSizeOptimized(),
                               SymbolInfoDouble(_Symbol,signal==ORDER_TYPE_SELL ? SYMBOL_BID:SYMBOL_ASK),
                               0,0);
     }
//---
  }
//+------------------------------------------------------------------+
//| Check for close position conditions                              |
//+------------------------------------------------------------------+
void CheckForClose(void)
  {
   MqlRates rt[2];
//--- go trading only for first ticks of new bar
   if(CopyRates(_Symbol,_Period,0,2,rt)!=2)
     {
      Print("CopyRates of ",_Symbol," failed, no history");
      return;
     }
   if(rt[1].tick_volume>1)
      return;
//--- positions already selected before
   bool signal=false;
   long type=PositionGetInteger(POSITION_TYPE);

   if(type==(long)POSITION_TYPE_BUY)
      signal=true;
   if(type==(long)POSITION_TYPE_SELL)
      signal=true;
//--- additional checking
   if(signal)
     {
      if(TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) && Bars(_Symbol,_Period)>100)
         ExtTrade.PositionClose(_Symbol,3);
     }
//---
  }
//+------------------------------------------------------------------+
//| Position select depending on netting or hedging                  |
//+------------------------------------------------------------------+
bool SelectPosition()
  {
   bool res=false;
//--- check position in Hedging mode
   if(ExtHedging)
     {
      uint total=PositionsTotal();
      for(uint i=0; i<total; i++)
        {
         string position_symbol=PositionGetSymbol(i);
         if(_Symbol==position_symbol && MA_MAGIC==PositionGetInteger(POSITION_MAGIC))
           {
            res=true;
            break;
           }
        }
     }
//--- check position in Netting mode
   else
     {
      if(!PositionSelect(_Symbol))
         return(false);
      else
         return(PositionGetInteger(POSITION_MAGIC)==MA_MAGIC); //---check Magic number
     }
//--- result for Hedging mode
   return(res);
  }
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(void)
  {
//--- prepare trade class to control positions if hedging mode is active
   ExtHedging=((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING);
   ExtTrade.SetExpertMagicNumber(MA_MAGIC);
   ExtTrade.SetMarginMode();
   ExtTrade.SetTypeFillingBySymbol(Symbol());
//--- initialize random seed 
   MathSrand(GetTickCount());
//--- 一様分布からサンプルを取得する

   MathRandomUniform(low_lim,upp_lim,max_sample_num,rnd_open_close);
   MathRandomUniform(low_lim,upp_lim,max_sample_num,rnd_sign_trade);
//--- ok
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(void)
  {
//---
   if(SelectPosition()){
      if(rnd_open_close[rnd_ind_oc]<rnd_open_rate){
         CheckForClose();
      }
   }else{
      if(rnd_open_close[rnd_ind_oc]<rnd_close_rate){
         CheckForOpen();
      }
   }
   rnd_ind_oc++;
   
   if(rnd_ind_oc>=max_sample_num){
      MathRandomUniform(low_lim,upp_lim,max_sample_num,rnd_open_close);
      MathRandomUniform(low_lim,upp_lim,max_sample_num,rnd_sign_trade);
      rnd_ind_oc = 0;
      rnd_int_sign = 0;
   }
//---
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
  }
//+------------------------------------------------------------------+

テスト条件

検証するエキスパート(取引プログラム):random20201017.mq5

銘柄(ドル円等):USDJPY

ローソク足の間隔(日足等):H1(1時間足)

テストに使用する期間:2019/1/1~2020/10/16

テスト結果

ストラテジーテスターのグラフタブを選択すると以下のように口座残高の推移をみることができます.ランダムなので毎回結果は変わりますが今回の場合は最終的に200ドル程度儲かっているようです.

口座の資金の変動

ストラテジーテスターのバックテストタブを選択すると以下のように取引の詳細を見ることができます.

取引の詳細

次回のリンクはこちら

コメント

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