今回は作成したプログラムの性能評価の方法と,ランダムに取引するプログラムを実際に評価した結果を紹介します.
基本的な性能評価の方法
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つが考えられます.
- トレードタイミングは一定で,ポジションの数量は一定
- トレードタイミングだけランダムで,ポジションの数量は一定
- トレードタイミングは一定で,ポジションの数量はランダム
- トレードタイミングとポジションの数量ともにランダム
今回作成したプログラムは上記の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ドル程度儲かっているようです.

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

次回のリンクはこちら
コメント