言い訳がましいタイトルだが(笑)、PythonでMT5のウォークフォワードテストを少しだけ楽にするコードを書いてみた。残念ながらウォークフォワードテストそのものができるわけではない。
MT5側で最適化をする準備をした上でPyhtonでMT5を起動し、指定した開始時間と終了時間で最適化を実行する。
ただそれだけの機能だが、Python側で開始時間と終了時間をずらしながらループすれば、イン期間での最適化の繰り返しを自動でやってくれるというわけだ。ウォークフォワードテストではその部分が面倒なので、いくらかは楽になる。
文章だけ見ると、これはこれで面倒そうだが、一度やってみれば後は楽だ(と思う)。
なお、PythonでMT5を起動し、最適化する関数を作るにあたっては豊嶋先生の以下の記事を参考にした。
環境
- Python: 3.9.16 64-bit
- Spyder IDE: 5.4.1
- OANDA MetaTrader 5: 5.00 build 4153
- MetaEditor: 5.00 build 4153
MT5を起動し、最適化する関数
ここのコードと下にある「Pyhonで最適化のループ」のコードはSpyderで実行することを想定している。
Spyderの「IPython Console」にコピペして「Enter」キーを押せば実行できる。
なお、実行中、Spyderの作業フォルダに「myconfig.ini」というファイルを作ってバックテストに必要な設定を書き込んでいるが、もし万が一(そんな偶然はないと思うが)同フォルダ内に同名のファイルがあると上書きしてしまうので注意。
import pandas as pd import subprocess from bs4 import BeautifulSoup def optimize(expert,symbol,period,start_year,start_month,start_day,end_year, end_month,end_day,model,optimization_criterion,install_folder, data_folder): from_date='FromDate='+str(start_year)+'.'+str(start_month)+'.'+str(start_day) to_date='ToDate='+str(end_year)+'.'+str(end_month)+'.'+str(end_day) f=open('myconfig.ini','w') param=['[Tester]\n', 'Expert='+expert+'\n', 'Symbol='+symbol+'\n', 'Period='+period+'\n', 'Model='+str(model)+'\n', 'ExecutionMode=0\n', 'Optimization=1\n', 'OptimizationCriterion='+str(optimization_criterion)+'\n', 'ForwardMode=0\n', 'Report=report\n', 'ReplaceReport=1\n', 'ShutdownTerminal=1\n', from_date+'\n', to_date] f.writelines(param) f.close() subprocess.run(install_folder+'\\terminal64.exe /config:myconfig.ini') with open(data_folder+'\\report.xml') as fp: soup = BeautifulSoup(fp, 'xml') df = pd.DataFrame() for r,row in enumerate(soup.find_all('Row')): for c,cell in enumerate(row.find_all('Data')): df.loc[r, c] = cell.string df.columns=df.iloc[0] df=df.iloc[1] df=df.iloc[2:] return df
最適化をする前の準備
インストールフォルダーのパス
先ずMT5をインストールしているフォルダーのパスを調べる。
OANDAのMT5なら
C:\Program Files\OANDA MetaTrader 5
になると思うが、これを「'」で囲み、「\」は2つにして
'C:\\Program Files\\OANDA MetaTrader 5'
とする。
別の業者であればそれに合わせる。
データフォルダーのパス
次にMT5のデータフォルダーのパスを調べる。
その手順は
- MT5のメニューバーの「ファイル」をクリックする。
- 「データフォルダを開く」をクリックする。
- パスをコピーする。
恐らく
C:\Users\****\AppData\Roaming\MetaQuotes\Terminal\********************************
のようになっていると思うので、やはり、これを「'」で囲み、「\」は2つにして
'C:\\Users\\****\\AppData\\Roaming\\MetaQuotes\\Terminal\\********************************'
とする。
MT5側の準備
ここではサンプルEAの「MACD Sample」を使って最適化することにする。
最適化するパラメータは「Take Profit (pips)」と「Trailing Stop Level (pips)」の2つとし、20pipsから200pipsまで20pips刻みで最適化しよう。
その他のパラメータはデフォルトのまま。
- MT5のストラテジーテスターで「エクスパート」を「Examples\MACD\MACD Sample.ex5」にする。
- 「パラメータ」タブをクリックする。
- 「Take Profit (pips)」にチェックを入れ、「スタート」、「ステップ」、「ストップ」をそれぞれ20、20、200とする。
- 「Trailing Stop Level (pips)」にチェックを入れ、「スタート」、「ステップ」、「ストップ」をそれぞれ20、20、200とする。
- MT5を終了する。
開始時間と終了時間をずらしながら最適化するにはPythonによってMT5を起動する必要があるので、一旦終了させる。
Pyhonで最適化のループ
ここではユーロドルの1時間足を使って最適化することにしよう。
「モデル」は「始値のみ」、「オプティマイズ」の指標は「残高最大」にする。
なお、上の関数により、「フォワード」は「キャンセル」、「延滞」は「延滞ゼロ、理想的な実行」に自動的に変更される。
また、「入金」の数字と通貨、「レバレッジ」は普段使っている設定が使われる。ここでは「1000000」、「JPY」、「1:25」の設定で実行した。
開始期間は2009年1月1日、終了時間は2014年1月1日として、1年ずつ後ろにずらし、計10回ループする。
そして終了年と、オプティマイズ指標で最良だったパラメータ値でのパフォーマンス等を出力する。
ループが1回終了するたびにMT5は再起動する。
expert='Examples\MACD\MACD Sample.ex5' # 指定しないと正常に動作しない symbol='EURUSD' # 指定しないと直前の設定が使われる period='H1' # 指定しないとH1になる start_year=2009 start_month=1 start_day=1 end_year=2014 end_month=1 end_day=1 model=2 # 0:全ティック、1:1分足OHLC、2:始値のみ、3:数値計算、4:リアルティックに基づいたすべてのティック optimization_criterion=0 # 0:残高最大、1:最大利益率、2:最大予想ペイオフ、3:最小ドローダウン、4:最大回復係数、5:最大シャープレシオ、6:カスタム最大 install_folder='C:\\Program Files\\OANDA MetaTrader 5' data_folder='C:\\Users\\****\\AppData\\Roaming\\MetaQuotes\\Terminal\\********************************' for i in range(10): df=optimize(expert,symbol,period,start_year+i,start_month,start_day, end_year+i,end_month,end_day,model,optimization_criterion, install_folder,data_folder) print(end_year+i) print(df) print('\n')
出力
2014 0 Profit 159821 Expected Payoff 1664.802083 Profit Factor 2.704830 Recovery Factor 4.692750 Sharpe Ratio 3.122384 Custom 0 Equity DD % 3.2884 Trades 96 InpTakeProfit 40 InpTrailingStop 20 Name: 1, dtype: object 2015 0 Profit 190314 Expected Payoff 2409.037975 Profit Factor 2.377659 Recovery Factor 4.625334 Sharpe Ratio 2.146057 Custom 0 Equity DD % 3.6932 Trades 79 InpTakeProfit 200 InpTrailingStop 200 Name: 1, dtype: object 2016 0 Profit 178058 Expected Payoff 2000.651685 Profit Factor 1.950870 Recovery Factor 1.881802 Sharpe Ratio 1.940135 Custom 0 Equity DD % 8.0390 Trades 89 InpTakeProfit 200 InpTrailingStop 40 Name: 1, dtype: object 2017 0 Profit 140856 Expected Payoff 1697.060241 Profit Factor 1.627961 Recovery Factor 1.488634 Sharpe Ratio 1.359581 Custom 0 Equity DD % 8.4097 Trades 83 InpTakeProfit 200 InpTrailingStop 40 Name: 1, dtype: object 2018 0 Profit 234116 Expected Payoff 2787.095238 Profit Factor 2.168535 Recovery Factor 2.474250 Sharpe Ratio 1.816929 Custom 0 Equity DD % 8.5059 Trades 84 InpTakeProfit 160 InpTrailingStop 200 Name: 1, dtype: object 2019 0 Profit 203823 Expected Payoff 2516.333333 Profit Factor 1.983635 Recovery Factor 2.154099 Sharpe Ratio 1.554359 Custom 0 Equity DD % 9.1116 Trades 81 InpTakeProfit 160 InpTrailingStop 200 Name: 1, dtype: object 2020 0 Profit 183006 Expected Payoff 2506.931507 Profit Factor 1.962571 Recovery Factor 1.934095 Sharpe Ratio 1.424284 Custom 0 Equity DD % 9.2862 Trades 73 InpTakeProfit 160 InpTrailingStop 200 Name: 1, dtype: object 2021 0 Profit 79357 Expected Payoff 1167.014706 Profit Factor 1.461464 Recovery Factor 0.905034 Sharpe Ratio 0.990896 Custom 0 Equity DD % 7.7021 Trades 68 InpTakeProfit 120 InpTrailingStop 40 Name: 1, dtype: object 2022 0 Profit 72227 Expected Payoff 1146.460317 Profit Factor 1.585237 Recovery Factor 0.823719 Sharpe Ratio 1.146981 Custom 0 Equity DD % 7.8130 Trades 63 InpTakeProfit 120 InpTrailingStop 40 Name: 1, dtype: object 2023 0 Profit 20315 Expected Payoff 369.363636 Profit Factor 1.149393 Recovery Factor 0.232065 Sharpe Ratio 0.341220 Custom 0 Equity DD % 8.5149 Trades 55 InpTakeProfit 60 InpTrailingStop 200 Name: 1, dtype: object
イン期間ではそこそこ勝っているようだが、パラメータ値はあまり安定しておらず、果たしてアウト期間で勝てるかどうかといったところ。
また、1時間足で始値のみなので、利食いと損切りのどちらが先にヒットしたかの判定もあいまいになり、この結果はあまり信用できないとも言える。
今回はあくまでも使い方の説明なので、細かいところには立ち入らない。
ウォークフォワードテストをする場合
ウォークフォワードテストをする場合は、上で調べた最適なパラメータ値を利用する。
アウト期間を1年とするなら、上の出力ではイン期間の終了年を表示させているので、その年をアウト期間にすればいい。
2014年から2023年まで実行するなら以下のようなコードをEAに加える。
そしてparam1が「Take Profit (pips)」に、param2が「Trailing Stop Level (pips)」に設定されるようにEAに修正を加える。
double param1=0; double param2=0; MqlDateTime mdt; TimeCurrent(mdt); if(mdt.year==2014) { param1=40; param2=20; } (中略) if(mdt.year==2023) { param1=60; param2=200; }