2015年4月22日水曜日

EAをつくってみよう4 バックテストを実行してみよう。

サンプルのEAを作成したため、次はバックテストを行ってみたいと思います。

MT4のバックテストはEA開発者だけではなくEAを使う人にも必須の作業のようで、あちこちのページに方法が書かれています。
FX-ON 2.4 メタトレーダーのバックテスト方法

このページを参考にバックテストを実施する為の準備を行います。
さっそく作成したEAのバックテストを実行してみましょう。

backtest1.PNG
エキスパートアドバイザーの選択は、前回の記事で作成したSample1を選択します。
あんまり長い期間だと時間がかかるため、「日付と時間を使用」にチェックを入れて、「差出人」2000.01.01 「終了日」2014.12.31と14年間を選択します。(差出人????? 誤訳かリソース設定ミスかと思いますが開始日のことです。私の使用しているMT4 - OANDAだけでしょうか??? )

2,3分放置すると終了します。
テスターの下部になるグラフを表示します。
backtest2.PNG

・・・・・・・・・・・・・・・・。
ま、こんなもんですよね。

さて、素直に動作すればよいのですが、実際にはロジックミス等が発生して取引しないことも多々あります。
新しいMT4にはデバッガが搭載されていて、動作させながらのデバッグも可能です。
豊嶋先生のコラムにやり方が具体的に記載されています。MT5向けですが、新しいMT4ではメタエディタがMT5と統一されているため、MT4でも対応可能です。(豊嶋先生のブログにはいつもお世話になっていてEA開発者として尊敬するばかりです。本も数冊買わせていただきました。)

ただし、デバッグを行うときには、現在の選択口座がデモ口座になっているか注意したほうがよさそうです。自動売買を行うチェックを間違えて入れっぱなしにしていた時、大参事になる可能性があります。

こちらのデバッグだと、現在の値を見てシグナルを発生させたりしますが、たまにしかシグナルを出さないようなEAだとテストに時間がかかります。
その場合は、コード内にPrint文を埋め込んでバックテストの操作履歴タブにて確認していきます。

あんまり長い期間を行うと操作履歴が大量に発生しますので、「日付と時間を使用」を予想される数トレード分ぐらいにしてから実行して確認していきます。
Sample1の中のGetSignal関数に正しく5分おきに過去シグナルを更新しているか確認するPrint文を埋め込んでみました。
// デバッグモード ON
#define DEBUG

//------------------------------------------------------------------
// 売買シグナルを取得する。
// return 買1 シグナルなし0 売-1
int GetSignal()
{
static double ma1 = 0 ;
static double ma2 = 0 ;
static MqlDateTime old;

MqlDateTime now;
TimeCurrent(now);

static int signal = 0 ;

//確定したモメンタムが100の境界を超えたかどうか。
if( now.min != old.min && now.min % 5 == 0 )
{
#ifdef DEBUG
Print("now=", StructToTime(now), " old=", StructToTime(old));
#endif
// 必要な時だけ、パラメーターを計算するようにする。
double m1 = iMomentum(NULL, PERIOD_CURRENT, MoPeriod, MoPrice, 1) ;
double m2 = iMomentum(NULL, PERIOD_CURRENT, MoPeriod, MoPrice, 2) ;

signal = m1 > 100 && m2 < 100 ? 1 : m1 < 100 && m2 > 100 ? -1 : 0;
}

// 現在のモメンタムがシグナル値と同じ方向にあるかどうか。
// 同じ方向にない場合、シグナルを取り消す。
double m0 = iMomentum(NULL, 0, MoPeriod, MoPrice, 0) ;
if( signal > 0 && m0 < 100 ) signal = 0;
if( signal < 0 && m0 > 100 ) signal = 0;

old = now;
return signal ;
}


backtest3.PNG

操作履歴タブには、埋め込んだPrint文の出力結果が表示されています。
バックテストでテストをする場合、基本はPrint文でコツコツと確認していく方法になりそうです。

また、Print文は#ifdef DEBUG ~ #endifで囲った中に記載しています。これは#define DEBUGがどこかに定義してある場合、この中を有効にするというプリプロセッサとなります。
このようにしておくことで、#define DEBUGを入れたり消したりすることでプログラムの動作を変えることができます。if文での判定でも同じ動きをしますが、デバッグコードの場合、#ifdefで行うのが一般的です。これは#fidefはコンパイル時に判定する為、条件が成立しない場合は最終的な実行ファイルにはコードの内容が含まれません。そのため、デバッグコードによるパフォーマンスの低下を避けることが出来ます。

ちなみにストラテジテスターの操作履歴は、ファイルとしても残っています。
Windows7の場合は下記でした。
c:\Users\(ユーザ名)\AppData\Roaming\MetaQuotes\Terminal\(口座毎のシステムID)\tester\logs

口座IDはメタエディタのナビゲーターの適当なフォルダのプロパティを表示すると、フォルダのプロパティが表示されます。
backtest4.png

フォルダプロパティの場所の項目にWindows上でのフォルダが表示されていますので、そこからたどることが可能です。
backtest5.PNG

操作履歴ベースでのファイルだと、正しくシグナルが出ているかどうか判定が難しいです。
そこで、次回はバックテスト中のシグナル結果をcsvに出力する方法を書いていきたいと思います。