このページでは、Pythonで作成したFX自動売買ツールのバックテストを行う方法をご紹介しています。
Pythonでバックテストを行うメリットは以下の通りです。
- MT4やMT5のバックテストでは確認することが難しかった細かいところまで手が届くオリジナルのバックテストツールを作成できる。
- バックテスト結果を簡単にグラフ化やデータ分析を行なって可視化できる。
この記事は、以下の前回の記事の続きです。
ナンピンマーチンEA部分の作成
前回はEAロジック部分のループ処理で価格を取得してポジションの含み損益を確認するところまででした。
今回は、いよいよナンピンマーチンEAの注文部分の工程に入ります。
新規エントリー注文(buy)
まずはbuyポジションの新規エントリー注文です。
if buy_position == 0: # buyポジションがない場合
buy_position = 1 # buyポジション数
current_buy_lot = first_lot # 最新のbuyポジションのlot数
buy_lot = first_lot # buyポジションのlot数合計
current_buy_price = ask # 最新のbuyポジション価格
buy_price = ask # buyポジションの平均価格
1行ずつ解説します。
エントリー条件
if buy_position == 0:
buyポジションがゼロの状態のみに発生する注文なので、この条件を入れます。
buy_position = 1
buyポジションがゼロの状態から、1つポジションを持つので、buyポジション数が1になります。
current_buy_lot = first_lot
1つ目のbuyポジションなので、first_lot(初期設定で定めた0.01)が最新buyポジションのlot数になります。
buy_lot = first_lot
buyポジションが1つのみなので、buyポジションのlot数合計もfirst_lot(初期設定で定めた0.01)になります。
current_buy_price = ask
buyエントリー注文を行ったので、現在価格(ask)が、buyポジション価格になります。
buy_price = ask
buyポジションが1つだけなので、buyポジションの平均価格もaskと同価格になります。
新規sellエントリー注文(sell)
続いて、sellポジションの新規エントリー注文です。
if sell_position == 0: # sellポジションがない場合
sell_position = 1 # sellポジション数
current_sell_lot = first_lot # 最新のsellポジションのlot数
sell_lot = first_lot # sellポジションのlot数合計
current_sell_price = bid # 最新のsellポジション価格
sell_price = bid # sellポジションの平均価格
違いは現在価格にaskではなくbidを用いるくらいで、他はbuyポジションとほぼ同様ですので、解説は省略します。
追加エントリー(ナンピン)注文(buy)
続いて、buyポジションの追加エントリー(ナンピン)注文です。
if buy_position > 0 and ask < current_buy_price - nanpin_range * point:
buy_position += 1 # buyポジション数
x = buy_lot * buy_price # 平均価格算出用
current_buy_lot = round(current_buy_lot * 1.5 + 0.001, 2) # 最新のbuyポジションのlot数
buy_lot += current_buy_lot # buyポジションのlot数合計
current_buy_price = ask # 最新のbuyポジション価格
y = current_buy_lot * current_buy_price # 平均価格算出用
buy_price = round(( x + y ) / buy_lot, 2) # buyポジションの平均価格
1行ずつ解説します。
エントリー条件
if buy_position > 0 and ask < current_buy_price - nanpin_range * point:
buyポジションを持っていて、現在価格(ask)が最新のbuyポジションの価格よりナンピン幅(nanpin_range * point)だけ小さくなった場合にナンピン注文を行うので、この条件を入れます。
buy_position += 1
buyポジションを1つ増やすという意味で、「+=1」とします。
x = buy_lot * buy_price
まだ最新のbuyポジションのbuy_lotとbuy_priceを反映する前の状態で、「buy_lot * buy_price」をxという変数に記録しておきます。この後に平均価格を算出する際に使います。
current_buy_lot = round(current_buy_lot * 1.5 + 0.001, 2)
最新のbuyポジションのlot数を計算してcurrent_buy_lot
を更新します。今回のナンピンマーチンEAモデルは、前のポジションのlot数の1.5倍(0.01未満四捨五入)という設定です。「+0.001」というのは、四捨五入する際にうまく繰り上がらない部分の補整です。
buy_lot += current_buy_lot
計算したcurrent_buy_lotを、buy_lotに加えることによって、buyポジションのlot数合計をアップデートします。例えば、0.01のbuyポジションを持っていて、0.02のナンピン注文を行ったら、lot数合計(buy_lot)は 0.01+0.02=0.03となります。
current_buy_price = ask
現在価格(ask)が、最新のbuyポジション価格になるのは、ナンピン注文でも同様です。
y = current_buy_lot * current_buy_price
最新のbuyポジションの「current_buy_lot * current_buy_price」をyという変数に記録しておきます。この後に平均価格を算出する際に使います。
buy_price = round(( x + y ) / buy_lot, 2)
これまでに記録しておいたxとyを用いて、buyポジション全体の平均価格を算出しています。
追加エントリー(ナンピン)注文(sell)
さらに、sellポジションの追加エントリー(ナンピン)注文です。
if sell_position > 0 and bid > current_sell_price + nanpin_range * point:
sell_position += 1 # sellポジション数
x = sell_lot * sell_price # 平均価格算出用
current_sell_lot = round(current_sell_lot * 1.5 + 0.001, 2) # 最新のsellポジションのlot数
sell_lot += current_sell_lot # sellポジションのlot数合計
current_sell_price = bid # 最新のsellポジション価格
y = current_sell_lot * current_sell_price # 平均価格算出用
sell_price = round(( x + y ) / sell_lot, 2) # sellポジションの平均価格
エントリー条件
if sell_position > 0 and bid > current_sell_price + nanpin_range * point:
sellポジションを持っていて、現在価格(bid)が最新のsellポジションの価格よりナンピン幅(nanpin_range * point)だけ大きくなった場合にナンピン注文を行うので、この条件を入れます。
以降は、buyポジションのナンピン注文とほぼ同様ですので、解説は省略します。
ポジションクローズ注文
最後に、ポジションクローズ注文です。まずは、コードをそのまま載せます。
buyクローズ注文
if buy_position > 0 and buy_profit > profit_target * buy_position:
buy_position = 0 # buyポジション数の初期化
buy_profit = 0 # buy_profitの初期化
current_buy_lot = 0 # 最新のbuyポジションのlot数の初期化
buy_lot = 0 # buyポジションのlot数合計の初期化
current_buy_price = 0 # 最新のbuyポジション価格の初期化
buy_price = 0 # buyポジションの平均価格の初期化
sellクローズ注文
if sell_position > 0 and sell_profit > profit_target * sell_position:
sell_position = 0 # sellポジション数の初期化
sell_profit = 0 # sell_profitの初期化
current_sell_lot = 0 # 最新のsellポジションのlot数の初期化
sell_lot = 0 # sellポジションのlot数合計の初期化
current_sell_price = 0 # 最新のsellポジション価格の初期化
sell_price = 0 # sellポジションの平均価格の初期化
コードの解説
やっていることは非常にシンプルで、利益目標に到達していたら、ポジションのパラメータを全て初期化する(ゼロにする)だけです。
例えば、buyポジション側のクローズ条件は以下の通りです。
if buy_position > 0 and buy_profit > profit_target * buy_position:
これは、buyポジションを1つ以上持っていて、含み損益がprofit_target(147円)×buyポジション数を上回っていたら、と言う条件になります。
ループ処理のコード全文
ここまでに作成したループ処理部分についてまとめたコード全文は以下の通りです。
for i in range(len(df_tick)):
##現在時刻、価格の取得
time = df_tick['time'][i]
bid = df_tick['bid'][i]
ask = df_tick['ask'][i]
##ポジションの含み損益の確認
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エントリー
if buy_position == 0: # buyポジションがない場合
buy_position = 1 # buyポジション数
current_buy_lot = first_lot # 最新のbuyポジションのlot数
buy_lot = first_lot # buyポジションのlot数合計
current_buy_price = ask # 最新のbuyポジション価格
buy_price = ask # buyポジションの平均価格
##新規sellエントリー
if sell_position == 0: # sellポジションがない場合
sell_position = 1 # sellポジション数
current_sell_lot = first_lot # 最新のsellポジションのlot数
sell_lot = first_lot # sellポジションのlot数合計
current_sell_price = bid # 最新のsellポジション価格
sell_price = bid # sellポジションの平均価格
##追加buyエントリー
if buy_position > 0 and ask < current_buy_price - nanpin_range * point:
buy_position += 1 # buyポジション数
x = buy_lot * buy_price # 平均価格算出用
current_buy_lot = round(current_buy_lot * 1.5 + 0.001, 2) # 最新のbuyポジションのlot数
buy_lot += current_buy_lot # buyポジションのlot数合計
current_buy_price = ask # 最新のbuyポジション価格
y = current_buy_lot * current_buy_price # 平均価格算出用
buy_price = round(( x + y ) / buy_lot, 2) # buyポジションの平均価格
##追加sellエントリー
if sell_position > 0 and bid > current_sell_price + nanpin_range * point:
sell_position += 1 # sellポジション数
x = sell_lot * sell_price # 平均価格算出用
current_sell_lot = round(current_sell_lot * 1.5 + 0.001, 2) # 最新のsellポジションのlot数
sell_lot += current_sell_lot # sellポジションのlot数合計
current_sell_price = bid # 最新のsellポジション価格
y = current_sell_lot * current_sell_price # 平均価格算出用
sell_price = round(( x + y ) / sell_lot, 2) # sellポジションの平均価格
##buyクローズ
if buy_position > 0 and buy_profit > profit_target * buy_position:
buy_position = 0 # buyポジション数の初期化
buy_profit = 0 # buy_profitの初期化
current_buy_lot = 0 # 最新のbuyポジションのlot数の初期化
buy_lot = 0 # buyポジションのlot数合計の初期化
current_buy_price = 0 # 最新のbuyポジション価格の初期化
buy_price = 0 # buyポジションの平均価格の初期化
##sellクローズ
if sell_position > 0 and sell_profit > profit_target * sell_position:
sell_position = 0 # sellポジション数の初期化
sell_profit = 0 # sell_profitの初期化
current_sell_lot = 0 # 最新のsellポジションのlot数の初期化
sell_lot = 0 # sellポジションのlot数合計の初期化
current_sell_price = 0 # 最新のsellポジション価格の初期化
sell_price = 0 # sellポジションの平均価格の初期化
続きの記事
以上、これまでの記事で紹介したコードを順番にコピペしていけば、基本的なバックテストモデルの完成です。実際に実行してみましょう。エラーも出ずに実行が完了すれば、上手くいっています。
ただし、そこで気付く、もしくは、既にお気付きかもしれませんが、ただ回りきるだけで特にアウトプットがありません。そうです。結果の出力処理を入れていないのです。
そこで次回の記事では、結果の出力処理を追加して、よりバックテストツールとして使えるような状態に仕上げていきたいと思います。