Pythonで為替取引のロジックのバックテストを行う方法(入門編)
こんばんは、新米データサイエンティスト(@algon_fx)です。気づけば、あっという間にGWも終わってしまいましたね。皆さんは充実した連休を過ごせましたか?
会社で使っているMACを新調したのですが、すこぶるほど作業が捗ります。Windowsマシンを使っていた時は半年に一度、最新スペックに買い換えていました。Macを使うようになってからは1〜2年に一度と頻度が下がりました。
しかし、長生きするMacと言えど、やはり定期的に最新のスペックへ買い換えた方が良いのだなと確信しました。個人用のMacも機会があれば買い換えようと思います。
さて、今日はPythonを使ってFXの自動売買ロジックのバックテストを行う方法(入門編)をまとめます。バックテストは非常に奥の深いタスクです。この記事は初めてPythonを使ってバックテストをやってみようと考えている方向けの入門記事です。私が普段やっているバックテストの実装を公開するものではありませんので悪しからず。
バックテストとは
バックテストとは自動売買トレードで自身が書いたロジック(売り買いの仕組み)を、過去の為替レートを使って検証する事を指します。
売買ロジックに機械学習を使うにしても、ルールベースのロジックにしても、自動売買をやっている人にとってバックテストは必須のタスクと言っても過言ではありません。
一言にバックテストと言っても、その実は非常に奥深いです。FX自動売買で最も使われることの多いMT4にも豊富なバックテストの機能が搭載しています。私のようにFX APIとPythonを使って自動売買をしているトレーダーは、バックテストを行う方法は大きく分けて2つの手段があります。
一つはオープンソースとして公開されているバックテストのライブラリを使うことです。海外を中心にPython向けのバックテストのライブラリが複数公開されています。二つ目の方法は自作する方法です。高機能なバックテストのライブラリもありますが、ある程度のレベルになるとバックテストを自作している人も多いです。
Pythonバックテストのライブラリ
本記事はバックテストライブラリの一つ「backtesting.py」を使います。Pythonで行えるバックテストのライブラリとして有名どころとしては「PyAlgoTrade」や「Backtrader」などがあります。
それぞれライブラリによって得手、不得手が異なります。最初のうちは自分の使用用途に合わせてライブラリを選択すると良いかと。簡単に概要をまとめました。
PyAlgoTrade
おそらく最も頻繁に使われるPythonのバックテストライブラリです。サポートしている注文方法が豊富で成行注文はもちろんのこと、指値や逆指値なども使えます。またドキュメントも豊富なので使いやすい。(英語のみ)
github : github.com/gbeced/pyalgotrade
backtrader
backtraderはPyAlgoTraderと同様に海外で人気のライブラリです。最も特徴的なのはOANDAのREST APIに対応している点ですかね。ドキュメントも豊富ですが、コミュニティも非常に活発で、海外で使っている人が多いので困った時にとても助かります。(英語)
公式 : https://www.backtrader.com/
backtesting.py
個人的に初心者におすすめなのがBacktesting.pyです。上記の2つと比較すると機能的にはかなり劣りますが、逆にシンプルなため初心者には手っ取り早く使えるライブラリです。特徴としてバックテストの処理がとても高速なこと、テクニカル指標のライブラリTa-Libをサポートしていることでしょうか。(参照:Ta-libとは)
本記事はPythonを使ったバックテスト入門編ということで、このBacktesting.pyを使って簡単なバックテストを行なってみたいと思います。
STEP1 インストールとデータ準備
では早速やっていきましょう。まずはバックテストライブラリのインストールを各自の環境で行なってください。PyPi経由でインストールすることが可能です。
$ pip install backtesting
インストールが完了したらデータをpandsaのデータフレームとして読み込みましょう。データの連携があるバックテストライブラリもありますが、Backtesting.pyは自前でデータの用意が必要です。すでに為替レートのデータがある方はpandasのDataFrameとして読み込んでください。ない方は下記のリンクからドル円の10分足データのCSVをダウンロードしましょう。(参照:大量の為替データをAPIから取得する方法)
使うデータ
usd_10min_api.csv
ではJupyter Notebook(またはGoogle Colab)を立ち上げてCSVファイルを読み込みましょう。Colabを使う方はこちらの記事を参照してください。また別途、colabの環境にBacktesting.pyをインストールする必要があります。
まずは必要なライブラリをインポートします。
1 2 3 4 5 6 7 8 9 |
import pandas as pd import matplotlib.pyplot as plt import mpl_finance from mpl_finance import candlestick2_ohlc import datetime %matplotlib inline |
続いて為替レートを保持するCSVファイルを読み込みましょう。Backtesting.pyで扱うデータフレームのインデックスはDatetimeIndex型でなくてはいけません。read_csv関数で読み込む際にparse_dates引数を使いDatetimeIndex型のインデックスラベルを指定します。
1 2 3 4 5 6 |
# データの読み込み usecols = ['time','close','open','high','low'] df = pd.read_csv("usd_10min_api.csv", usecols=usecols, index_col='time', parse_dates=True) df.tail(2) |
1 2 3 4 5 6 7 8 |
-- 出力 close open high low time 2018-08-10 16:00:00 110.915 111.012 111.018 110.909 2018-08-10 16:10:00 110.773 110.913 110.927 110.692 |
また、カラム名の頭文字は大文字でなくてはいけません。columns属性を使い各カラム名を更新してあげましょう。
1 2 3 4 |
df.columns = ['Close','Open','High','Low'] df.columns |
1 2 3 4 5 |
-- 出力 Index(['Close', 'Open', 'High', 'Low'], dtype='object') |
これでデータの準備は整いました。
STEP2 トレードロジックを書く
冒頭でも触れた通り、バックテストとは自分で書いた何かしらの取引ロジックを過去の為替レートのデータを使って検証するものです。取引ロジックがいかに過去データに対して上手くトレードできるかを検証するわけです。
この取引ロジックがpythonを使ってFXトレードでは最も要となる部分です。今回は最も単純な取引ロジックとして「単純移動平均を使ったゴールデンクロス・ デッドクロス」を採用しましょう。意味が不明な方は下記の記事をご参考下さい。
参考1:Pythonでゴールデンクロスとデッドクロスを分析する方法
参考2:単純移動平均線(Simple Moving Average)の使い方とPythonでの書き方(List + Numpy + Ta-Libの3パターン)
上の参考2の記事でも詳細を示しましたが、単純移動平均は純粋に指定した一定期間の平均値を取るものです。pandsaのrollingメソッドを使ったユーザー定義関数を作りましょう。
1 2 3 4 5 |
# 単純移動平均を算出する関数 def SMA(values, n): return pd.Series(values).rolling(n).mean() |
いよいよBacktesting.pyのライブラリの登場です。backtestingからStrategyとcrossoverをインポートします。
1 2 3 4 |
from backtesting import Strategy from backtesting.lib import crossover |
続いて最も要であるトレードロジックの部分を書きます。下記のコードを見て頂ければ概ね判ると思いますが、とても単純なロジックです。終値からSMA関数で単純移動平均を算出して短期移動平均はsma1、長期移動平均はsma2とします。
短期が長期を超えたらゴールデンクロスで買い注文、短期が長期を下回ったらデッドクロスで売り注文をそれぞれ書いています。短期の期間は3、長期の期間は6と指定しています。(これは適当です)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class SmaCross(Strategy): n1 = 3 n2 = 6 def init(self): self.sma1 = self.I(SMA, self.data['Close'], self.n1) self.sma2 = self.I(SMA, self.data['Close'], self.n2) def next(self): if crossover(self.sma1, self.sma2): self.buy() elif crossover(self.sma2, self.sma1): self.sell() |
1 2 3 4 5 |
-- 出力 BokehJS 1.1.0 successfully loaded. |
とてもシンプルではありますが、これでロジック部分は完了です。
STEP3 バックテストを実行
データも揃い、シンプルではありますがトレードロジックも書けました。いよいよ実際にバックテストを行ってみましょう!
冒頭でも書きましたが、backtesting.pyのメリットは非常にシンプルな事です。下のコートでバックテスを実行してくれます。たったこれだけ。
cash引数はバックテストで使う原資の金額をドル単位で入力します。今回は500ドルとしました。commissionは取引所の手数料を指定することが可能です。今回は0です。
ではやってみましょう!
1 2 3 4 5 |
from backtesting import Backtest bt = Backtest(df[1500:2000], SmaCross, cash=500, commission=0) bt.run() |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
-- 出力 Start 2018-03-16 00:40:00 End 2018-03-21 11:50:00 Duration 5 days 11:10:00 Exposure [%] 98.3482 Equity Final [$] 497.713 Equity Peak [$] 503.605 Return [%] -0.457486 Buy & Hold Return [%] 0.386501 Max. Drawdown [%] -1.33024 Avg. Drawdown [%] -0.0839133 Max. Drawdown Duration 0 days 16:20:00 Avg. Drawdown Duration 0 days 02:55:00 # Trades 95 Win Rate [%] 35.7895 Best Trade [%] 0.416292 Worst Trade [%] -0.19907 Avg. Trade [%] -0.00473836 Max. Trade Duration 2 days 00:20:00 Avg. Trade Duration 0 days 01:22:00 Expectancy [%] 0.0590866 SQN -0.524512 Sharpe Ratio -0.0536938 Sortino Ratio -0.0952974 Calmar Ratio -0.00356202 _strategy SmaCross dtype: object |
今回はとってもシンプルなロジックです。単純にゴールデンクロスが起きたら買い注文を入れて、デッドクロスが起きたら売り注文を出すだけです。結果は上の通りです。重要な部分だけ掻い摘んで確認してみましょう。
startとendはバックテストで使った為替レートのデータの最初の最後の時間です。Durationは期間です。5 days 11:10:00と出ているので、つまり5日と約半日分のデータですね。最も重要と言えるのがEquity Final [$]です。これはトレードロジックを使いトレードをした結果、過去為替レートの状況下で最終的な金額です。500ドルで始めたトレードですが、今回は497.713と少し損をしています。
他にもWin Rate [%]で勝率を確認できます。全体のトレード回数(# Trades)は95回に対して、35.7895%のトレードで利益が出た結果でした。
STEP4 バックテストの結果を可視化
Backtesting.pyにはバックテストの結果を簡単に可視化するメソッドが用意されています。STEP3で実行したバックテストの結果を可視化してみましょう。
1 2 3 |
bt.plot() |
詳細の解説は行いませんが、こちらはインタラクティブなプロットを吐き出してくれます。最上部のEquityのグラフは資金推移を表します。2段目のProfit / lossはトレードロジックで行われたトレードを利益と損益で可視化します。最下部は実際の終値のレートと単純移動平均(短期と長期)、さらにトレードも併せて可視化します。
まとめ
今回はバックテストライブラリ「Backtesting.py」を使って、とてもシンプルなバックテストの方法を初心者向けにまとめました。
記事でも解説した通り他にも高機能なバックテストライブラリは存在します。また、ある程度自動売買を続けていくと、ライブラリでは対応ができず、最終的にはバックテストを自分で組む羽目になります(笑)
個人的にbacktesing.pyは機能は少ないものの、しっかりドキュメントを読めば、必要最低限の努力でそれなりのバックテストが出来るので初心者向けと考えています。backtesting.pyには他にもパラメータの最適化などを行ってくれる機能もあります。(これはこれで便利ですよ)
以上です!ブログ読んでいただきありがとうございます!Twitterでも色々と発信しているので、是非フォローお願いします!
ディスカッション
コメント一覧
ありがとうございます。
とてもわかりやすく、いつも参考にさせていただいております。