バックテストで最大ドローダウン期間を取得する

オリジナル関数

どうも潤奈です( ・Д・)

皆さんも自作EAなどをバックテストで色々分析していると思います。
その際に最後に表示されるレポートには最大ドローダウンや相対ドローダウンは表示されますが、その最大ドローダウン期間は表示されていません。

実際に運用する際に、「このEAは過去のバックテストでこれだけのドローダウン期間発生していた事がある」という事を知っておけば、「なかなかドローダウンから復活しないぞ?大丈夫か?」という心配が少しでも解消すると思いコードを考えてみました( ・Д・)

スポンサーリンク

コード全文

今回必要なコードは3ブロックに分かれます。

では順番に説明します。

使用する変数を宣言

使用する変数を関数の外で宣言します。記述する位置に関してはOnTick関数より上の位置で、どの関数内に入ってなければ大丈夫です。

それぞれdatetime型で宣言します。
この段階では値を入れずに宣言だけですので、中に入る値は1970年1月1日(MT4仕様)になります。

計測コードを記述

OnTick関数内に最大ドローダウン期間を計測するコードを記述します。
EAではこの中にロジックなど他のコードが入っていると思いますので、良いところへ入れて下さいw

では分解して説明します。

まずはstaticを付けて変数を宣言します。
こうする事で最初の1回だけこの変数が宣言されるようになるので、以降のティック処理時に値が更新される事を防ぎます。

次に説明する順番として、中の一部を非表示にしています。まずはその上下の説明します。

初期動作
if文でBalance変数に入っている初期口座残高と現在の口座残高を比較して、残高が増えていれば中の処理に進みます。

次に、Record変数に現在時刻 TimeCurrent()から計測開始時刻を引く事で、その期間が算出されます。

例)Record=2015.05.10 05:00:00 – 2015.05.10 03:00:00 という計算された場合。
分かりやすく秒に直しますと、2時間=7,200秒になります。
そして1970.01.01 00:00:00に7200秒足された、1970.01.01 02:00:00がRecord変数に記録されるイメージになります。

最後にif文を抜ける前にRecordTime変数に現在時刻と、Balance変数に現在口座残高を記録して抜けます。
これが次のドローダウン期間の計測開始時刻と口座残高になります。

口座残高を更新時動作(最大ドローダウン期間更新)
口座残高を更新するとif文内の処理に進みます。


そして現在時刻と計測開始時刻の期間をRecord変数に記録し、次のif文でDrawdownPeriod変数と比較し、期間を更新していれば中の処理へ進みます。

DrawdownPeriod変数は最初に宣言されている状態であれば、1970.01.01 00:00:00が入っているので、先ほどの例に挙げたRecord=1970.01.01 02:00:00の値が入っている場合はif文の条件満たしているので中の処理に進むようになります。

①DrawdownPeriod変数に最大ドローダウン期間を更新します。
②DrawdownStart変数に計測開始した時の時間を記録します。
③DrawdownEnd変数に現在時刻を記録します。

バックテスト結果を出力コード

バックテストを完了した時に処理されるOnTester関数に計測したデータを出力するコードを記述します。

まず一つはPrint関数で最大ドローダウン期間を計測した時の開始時間と終了時間を出力させます。

次に最大ドローダウン期間を年月日時分の表示で出力させますが、少し工夫が必要です。
DrawdownPeriod変数には1970.01.01 00:00:00の時間から加算された時間がドローダウン期間として記録されています。

それぞれ年月日時分を取得する時に年は1970年、月は1月、日は1日を引く事で加算されているドローダウン期間を出力する事が出来ます。
年はTimeYear()で年を取得して1970を引く。
月はTimeMonth()で月を取得して1を引く。
日はTimeDay()で日を取得して1を引く。
時はTimeHour()で時を取得する。元は0なのでそのまま。
分はTimeMinute()で分を取得する。元は0なのでそのまま。

Print関数でバックテスト後に出力される場所は「操作履歴」タブで以下の様に出力されます。

最後にreturnにDrawdownPeriodの値を返す事で、バックテストの最適化した時にOnTesterに最大ドローダウン期間が秒単位で表示されますので、どのパラメーターが最大ドローダウン期間が短いか確認する事が出来ます。

その他

OnTester()関数はdouble型なので、datetime型のDrawdownPeriod変数をリターンで直接返そうとするとデータの型が違うので以下のような注意が出ますが出力した感じは大丈夫そうです。

エラーが一つでも気になる方は、一度datetime型をlong型の変数に代入して、long型からdouble型に変換して出力させるようなコードにしたらエラーは消えました。

ただしlong型からdouble型に変換する際に精度の損失が発生する可能性があるようです。これに関しては現在の私の知識では確実な事が言えませんので、参考程度にして下さい。

まとめ

実際にEAを運用する時にはドローダウンも気になりますが、そのドローダウンの期間も気になります。

私の開発したDorayakiも長期バックテストを見るとずっと右肩上がりに見えますが、今回のコードを使って検証してみると口座残高を更新しない期間が4ヵ月と13日あったという結果を見る事が出来ます。

つまり1~2ヵ月利益が更新出来なくても過去のバックテストでは発生していた事ですので、まだまだ許容範囲として捉える事が出来ます。(※個人の感想です)

では( ・Д・)

コメント

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