このページでは、Pythonで作成したFX自動売買ツールのバックテストを行う方法をご紹介しています。
Pythonでバックテストを行うメリットは以下の通りです。
- MT4やMT5のバックテストでは確認することが難しかった細かいところまで手が届くオリジナルのバックテストツールを作成できる。
- バックテスト結果を簡単にグラフ化やデータ分析を行なって可視化できる。
この記事は、以下の前回の記事の続きです。
ティックデータのループ処理部分の作成
前回はバックテスト用のインプットデータである「df_tick」を作成したところまででした。
今回はこのdf_tickデータをループ処理していく部分の作成を行います。
EAモデルの確認
ロジックについては、以下の記事でも採用している非常にシンプルなナンピンマージンロジックを用います。
できる限り上記の自動売買ツール(bot)と同じような変数名を用いて構築していきますので、比較してみてください。
Inputの設定
まず初期設定として、いくつかインプットを定めておきます。
first_lot = 0.01 # 初期ロット
nanpin_range = 200 # ナンピン幅
profit_target = 147 # 利益目標
pip_value = 147 # ピップ値
point = 0.01 #価格の最小単位
初期ロット(first_lot)
1番目のポジションを取得する時のロット数の設定です。最小は0.01ですので、ひとまず0.01に設定しておきます。
ナンピン幅(nanpin_range)
1番目のポジションの後、どれくらい価格が動いたら次のポジションを取りに行くかという価格幅の設定です。200と設定すると、GOLD#の場合、2.00の価格幅を意味します。(厳密には、この後に *pointという形で単位を決めにいきます。)
利益目標(profit_target)
利益目標を金額で設定します。ここでは単位は円で、147円という設定です。1ポジションあたり147円の含み益が発生したら、クローズ注文を行うようなロジックです。
今回使用するのは2022/11/7(月)のティックデータなのですが、この日の1pipsあたりの利益(ピップ値)が0.01lotで約14.7円でしたので、147円という設定にしています。
より詳しくは、以下の記事の「利益目標」についてご確認ください。
ピップ値(pip_value)
バックテストにおいて、利益を円換算して評価していくためのピップ値を設置しておきます。この場合は、lot数が0.01で価格幅が1.00であれば147円という換算レートを意味します。なお、利益目標=ピップ値と設定するモデルなので、価格幅1.00を利益目標としていることにもなります。
価格の最小単位(point)
pointは、通貨ペア(取引対象)毎に定まる最小単位です。XMTradingのGOLDの場合は、point=0.01ですので、これも現実を想定して0.01と設定しておきます。
各変数の初期化
以下の通り、各変数を初期化(=0と設定)しておきます。
buy_position = 0 # buyポジション数の初期化
sell_position = 0 # sellポジション数の初期化
buy_profit = 0 # buyポジションの含み損益の初期化
sell_profit = 0 # sellポジションの含み損益の初期化
current_buy_lot = 0 # 最新のbuyポジションのlot数の初期化
current_sell_lot = 0 # 最新のsellポジションのlot数の初期化
buy_lot = 0 # buyポジションのlot数合計の初期化
sell_lot = 0 # sellポジションのlot数合計の初期化
current_buy_price = 0 # 最新のbuyポジション価格の初期化
current_sell_price = 0 # 最新のsellポジション価格の初期化
buy_price = 0 # buyポジションの平均価格の初期化
sell_price = 0 # sellポジションの平均価格の初期化
これは何をしているかというと、スタート時はポジションを何も持っていない状態ですので、それを表現しています。例えばbuy_position=0というのはbuyポジション数がゼロ、buy_lot=0というのはbuyポジションのlot数がゼロということです。
ループ処理
ここからは、前回の記事で作成したdf_tickを使ったループ処理に入ります。
df_tickの呼び出し
以下の通り、前回の記事で作成したdf_tickを呼び出しておきます。
df_tick = pd.read_pickle('/content/drive/My Drive/backtest/df_tick.pkl')
for i in range(len(df_tick)):
for i in range(len(df_tick)):
これは単純にdf_tickのレコード数だけ、iを0から順番に進めていく処理です。
df_tickを1レコードずつ読み込むことで、MQL4のOnTick関数を再現しているような形になります。
以降は、このforループの中に記載していく処理になります。
現在時刻、価格の取得
まずは、現在時刻と価格、スプレッドを取得しておきます。
time = df_tick['time'][i]
bid = df_tick['bid'][i]
ask = df_tick['ask'][i]
i=0から順番に取得していくわけですが、例えばi=0でどのように取得しているか確認すると、以下のようになります。
このbidとaskを、その時間における価格として、バックテストを行っていきます。
ポジションの含み損益の確認
ここでは、ポジションの含み損益の確認を行います。1番最初のループ処理ではポジションがゼロですが、その後の注文等を経てポジションを持つようになったら、毎回ループの最初に確認する工程になります。
if buy_lot == 0:
buy_profit = 0
else:
buy_profit = round((bid - buy_price) * buy_lot * pip_value / 0.01, 0)
if sell_lot == 0:
sell_profit = 0
else:
sell_profit = round(-(ask - sell_price) * sell_lot * pip_value / 0.01, 0)
コードの解説
まず、buy_lotまたはsell_lotがゼロの時、つまりポジションを持っていない時は、当然ですが含み損益はゼロなので、ゼロにします。
それ以外の場合ですが、buy_profitについては以下のような算式です。
buy_profit = round((bid - buy_price) * buy_lot * pip_value / 0.01, 0)
これは、0.01lotの価格変動1.00あたりの利益がpip_value(147円)という設定なので、この算式で含み損益を円単位で計算することが出来ています。sell_profitも同様です。
続きの記事
以上で、EAのロジックについて大体前半部分の作成が完了しました。
次の記事では、いよいよナンピンマーチンEAの注文部分を構築していきます。