前回AWSで作成したVPSにOANDAのMT4をインストールし、デモを実施しようとしましたが、検証に使っていたMT4の日足の本数が5本ではなかったことが分かりました。
結果的にパラメータを再度設定し直すことになりましたが、せっかくなのでウォークフォワードテストを取り入れてみようと思いました。
Table of Contents
参考にした書籍は以下のものです。
システムトレード検証と実践 自動売買の再現性と許容リスク/ケビン・J・ダービー/長尾慎太郎/山下恵美子【1000円以上送料無料】 価格:8,424円 |
ウォークフォワードテストの手法が書かれており、テストにパスした戦略は実戦でも通用する可能性が高いとの情報がありました。
私が実施しているパラメータ設定のすべてをウォークフォワードの対象としてしまうと、検証に時間がかかるため、以下のメインの2つのパラメータのみウォークフォワードテストを組み込むことにしました。
- シグナルを生成する期間
- ポジションを持ってから手仕舞いするまでの経過足数
バックテスト期間はできるだけ長くとりたかったので、ウォークフォワード期間はトータル5年とし、直近までの全データを含んだバックテスト結果から、次の1年間のパラメータを決めるという方法を選択しました。
2005年から2014年までの期間で最適化を行い、2015年のパラメータを決定します。次は2005年から2015年までの期間で最適化をし・・・といった具合に連続してフォワードテストを実施して、その資産曲線を見て判断していこうと思います。
ウォークフォワード期間が変わるごとにパラメータを変更しながらバックテストを実施することで、連続した資産曲線を得ることができます。
そのために以下のコードを追加しました。
まずは外部変数です。
extern bool walkforward = false; // ウォークフォワードテスト true:する extern int walk0_Closetime = 0; // 基準経過時間 extern int walk0_signal = 0; // 基準シグナル 期間を指定 extern int walk0_signal2 = 0; // 基準シグナル2 期間を指定 extern int walk1_Closetime = 0; // ウォークフォワード1経過時間 extern int walk1_signal = 0; // ウォークフォワード1シグナル extern int walk1_signal2 = 0; // ウォークフォワード1シグナル2 extern string walk1_start = "2010.1.1"; // ウォークフォワード1スタート extern int walk2_Closetime = 0; // ウォークフォワード2経過時間 extern int walk2_signal = 0; // ウォークフォワード2シグナル extern int walk2_signal2 = 0; // ウォークフォワード2シグナル2 extern string walk2_start = "2011.1.1"; // ウォークフォワード2スタート extern int walk3_Closetime = 0; // ウォークフォワード3経過時間 extern int walk3_signal = 0; // ウォークフォワード3シグナル extern int walk3_signal2 = 0; // ウォークフォワード3シグナル2 extern string walk3_start = "2012.1.1"; // ウォークフォワード3スタート extern int walk4_Closetime = 0; // ウォークフォワード4経過時間 extern int walk4_signal = 0; // ウォークフォワード4シグナル extern int walk4_signal2 = 0; // ウォークフォワード4シグナル2 extern string walk4_start = "2013.1.1"; // ウォークフォワード4スタート extern int walk5_Closetime = 0; // ウォークフォワード5経過時間 extern int walk5_signal = 0; // ウォークフォワード5シグナル extern int walk5_signal2 = 0; // ウォークフォワード5シグナル2 extern string walk5_start = "2014.1.1"; // ウォークフォワード5スタート 最新
walkX_startにはウォークフォワードテストの開始日をパラメータで設定します。
Closetimeが経過足数で、signalはシグナル生成の期間になります。
// フォワードテスト用コード void forwardparameter(void) { int signalperiod,signalperiod2; if(StrToTime(walk1_start)<=TimeCurrent()&&TimeCurrent()<=StrToTime(walk2_start)){ Closetime = walk1_Closetime; signalperiod = walk1_signal; signalperiod2 = walk1_signal2; }else if(StrToTime(walk2_start)<=TimeCurrent()&&TimeCurrent()<=StrToTime(walk3_start)){ Closetime = walk2_Closetime; signalperiod = walk2_signal; signalperiod2 = walk2_signal2; }else if(StrToTime(walk3_start)<=TimeCurrent()&&TimeCurrent()<=StrToTime(walk4_start)){ Closetime = walk3_Closetime; signalperiod = walk3_signal; signalperiod2 = walk3_signal2; }else if(StrToTime(walk4_start)<=TimeCurrent()&&TimeCurrent()<=StrToTime(walk5_start)){ Closetime = walk4_Closetime; signalperiod = walk4_signal; signalperiod2 = walk4_signal2; }else if(StrToTime(walk5_start)<=TimeCurrent()){ Closetime = walk5_Closetime; signalperiod = walk5_signal; signalperiod2 = walk5_signal2; }else{ Closetime = walk0_Closetime; signalperiod = walk0_signal; signalperiod2 = walk0_signal2; } if( ZscoreEnable == true ){ BandsPeriod = signalperiod; }else if( DonchanEnable == true ){ DonchanPeriod = signalperiod; }else if( RSIEnable == true ){ RSIPeriod = signalperiod; }else if( MAEnable == true ){ MAfastPeriod = signalperiod; MAslowPeriod = signalperiod2; } }
walkforwardがtrueのときのみ 上記の関数をtickごとに実行して、パラメータを設定します。
ボリンジャーバンド、ドンチャン、RSI、移動平均のうち一つにシグナル生成の期間パラメータを設定します。
まずは最初のバックテスト期間(2005~2014年)で最適化を行い、良いパラメータの組み合わせを選びます。その値はwalk0_Closetime、walk0_signal、walk0_signal2へ設定し、そのままウォークフォワード1も設定します。walk_1Closetime・・・を設定となります。
ウォークフォワード1スタートへは 2014.1.1といった具合に開始日を指定します。
続いて、次のバックテスト期間(2005~2015年)で最適化を行い、同じようにパラメータを決定していき、最後のフォワード用パラメータまで設定します。