【バックテスト】Backtesting.pyのBacktestクラスの内容を解説

Backtesting.pyのロゴ

投資戦略のバックテストを行なうのは大変ですよね。

そんな時は、既存のライブラリを使うと簡単にそして、高速に行なえます。

今回は、バックテスト用のPythonライブラリであるBacktesting.pyのBacktestクラスについて内容を公式ドキュメントに基づいて見ていきたいと思います。

目次

Backtestクラスの使い方

Backtestクラスは以下のように使います。

from backtesting import Backtest, Strategy
from backtesting.lib import crossover
from backtesting.test import SMA, GOOG

class SmaCross(Strategy):
    def init(self):
        price = self.data.Close
        self.ma1 = self.I(SMA, price, 10)
        self.ma2 = self.I(SMA, price, 20)

    def next(self):
        if crossover(self.ma1, self.ma2):
            self.buy()
        elif crossover(self.ma2, self.ma1):
            self.sell()

# ここでBacktestを使用
bt = Backtest(GOOG, SmaCross, commission=.002,
              exclusive_orders=True)
stats = bt.run()
bt.plot()

上記を実行すると、以下のように過去データに基づいた投資戦略・手法のパフォーマンスを可視化できます。

Start                     2004-08-19 00:00:00
End                       2013-03-01 00:00:00
Duration                   3116 days 00:00:00
Exposure Time [%]                       94.27
Equity Final [$]                     68935.12
Equity Peak [$]                      68991.22
Return [%]                             589.35
Buy & Hold Return [%]                  703.46
Return (Ann.) [%]                       25.42
Volatility (Ann.) [%]                   38.43
Sharpe Ratio                             0.66
Sortino Ratio                            1.30
Calmar Ratio                             0.77
Max. Drawdown [%]                      -33.08
Avg. Drawdown [%]                       -5.58
Max. Drawdown Duration      688 days 00:00:00
Avg. Drawdown Duration       41 days 00:00:00
# Trades                                   93
Win Rate [%]                            53.76
Best Trade [%]                          57.12
Worst Trade [%]                        -16.63
Avg. Trade [%]                           1.96
Max. Trade Duration         121 days 00:00:00
Avg. Trade Duration          32 days 00:00:00
Profit Factor                            2.13
Expectancy [%]                           6.91
SQN                                      1.78
Kelly Criterion                        0.6134
_strategy              SmaCross(n1=10, n2=20)
_equity_curve                          Equ...
_trades                       Size  EntryB...
dtype: object
Backtestingのパフォーマンス

Backtestのインスタンス化の際に指定している引数や、そのあとに使用しているrun、plotメソッドなどについて、以下で解説していきます。

Backtestクラスのパラメータ

class Backtest(data, strategy, *, cash=10000, commission=0.0, margin=1.0,
               trade_on_close=False, hedging=False, exclusive_orders=False)

Backtestのインスタンス化の際に指定できるパラメータとその内容は以下の通りです。

data

dataには、バックテストに用いる過去の価格データフレーム(pd.DataFrame)を指定します。

注意点としては、Open、High、Low、Closeを含んでおく必要があり、それぞれのカラム名も頭文字は大文字で設定しておく必要があります。

トマトソース

openやhighなど小文字の指定だと「`data` must be a pandas.DataFrame with columns ‘Open’, ‘High’, ‘Low’, ‘Close’, and (optionally) ‘Volume’」というエラーが返ってきます。

上記のOHLCデータ以外にも、任意でVolumeデータを渡すこともできます。

任意のカラムも付与可能

また、上記OHLCV以外にも、自身のストラテジーで使用する独自のカラム(例えば期間20の移動平均を格納したma20カラムなど)もデータフレームに付与しておけます。

インデックスはdatetimeまたは0~の数値

dataに渡すデータフレームのインデックスはtimestampまたは0以上の連続した数値のどちらでも使用できます。

strategy

strategyには、Strategyクラスを継承したサブクラスを指定します。

トマトソース

注意点としては、インスタンスではなくクラス名を記載するという点です。

cash

cashには、最初の残高を指定します。

おそらくですが、単位としてはdataとして渡す通貨の単位に合わすとよいと思います。

トマトソース

BTCUSDTの場合はUSDの単位で。BTCJPYの場合はJPYの単位でという感じです。

commision

commisionには、取引所の手数料を指定します。

例えば1%の手数料の場合は、0.01と指定します。

トマトソース

スプレッドを考慮したバックテストを行ないたい場合は、このcommisionの数値を調節することで対応できます。

例えば平均スプレッドがask価格の0.2%だとした場合は、0.0002と指定することである程度のスプレッドを見積もったバックテストを行なえます。

margin

marginには、レバレッジを指定します。

指定の仕方は、レバレッジ数ではなくレバレッジ比率を指定します。

例えば、50倍のレバレッジの場合0.02(1/50)を指定します。

trade_on_close

trade_on_closeでは、成行き注文の実行タイミングを変更できます。

Trueに設定した場合は、次のローソク足の始値ではなく、その足の終わりで約定するようになります。

デフォルトはFalseで、その場合は該当のローソク足の終値ではなく次の足の始値で約定になります。

hedging

hedgingでは両建ての有無の指定を行なえます。

Trueに設定した場合は、両建てを行うことができます。

デフォルトのFalseの場合は、FIFO注文として反対ポジションを保有している場合に新規注文とならず、保有している古い反対ポジションから順に決済されるようになります。

exclusive_orders

exclusive_ordersでは、各注文時にポジションを閉じるか否かの設定を行なえます。

Trueに設定すると各新規注文時に保持しているポジションを解消してから、新しく注文を行ないます。

トマトソース

ドテンのシュミレーションを行う場合には、これが使えそうですね。

Backtestクラスのメソッド3つ

Backtestクラスのメソッドは以下の3つです。

Backtestクラスのメソッド
  1. run
  2. plot
  3. optimize

それぞれ簡単に解説していきます。

plot

def plot(self, *, results=None, filename=None, plot_width=None, plot_equity=True,
         plot_return=False, plot_pl=True, plot_volume=True, plot_drawdown=False,
         smooth_equity=False, relative_equity=True, superimpose=True, resample=True,
         reverse_indicators=False, show_legend=True, open_browser=True)

plotでは、バックテストの経過を可視化できます。

指定できるパラメータはいろいろとありますが、重要そうなものは以下の通りです。

パラメータ内容
resultsバックテストの結果を指定できます。
指定しない場合は最後にrunした結果が使用されます。
filenameHTMLとして保存するパスを指定できます。
デフォルトではstrategy/parameter-dependentファイルが現在のワーキングディレクトリに保存されます。
plot_widthプロットの幅を指定します。デフォルトでは100%が指定されています。
(高さは自動で調整されます)
plot_equityイクイティ(開始残高+アセット)を描写の有無を指定します。Trueにしておくことで資産の変動が描写されます。
plot_returnリターンの描写有無を指定します。
plot_pl損益(P/L)の描写の有無を指定します。
plot_volumevolumeを描写有無を指定します。
volumeの描写にはVolume情報をデータフレームに渡しておく必要があります。
plot_drawdownドローダウンの描写有無を指定します。
relative_equityイクイティの%表示に指定します。

上記以外のパラメータについては公式ドキュメントをご参照ください。

run

def run(self, **kwargs)

runでは、バックテストの実行を行ないます。

返却値として結果と統計データがpd.Seriesで返ってきます。

トマトソース

ちなみに、**kwargsはストラテジーのパラメータとして解釈されるようです。

optimize

def optimize(self, *, maximize='SQN', method='grid', max_tries=None, constraint=None,
             return_heatmap=False, return_optimization=False, random_state=None,
             **kwargs)

optimizeでは、ストラテジーのパラメータの最適値を探索できます。

optimize関数に指定できるパラメータと内容は以下の通りです。

パラメータ内容
maximize最適化する際にどの値を最大化するかを指定します。
Strategy.run()で返却されるpd.Seriesのキーを指定できます。
例:最終残高の最大化の場合はEquity Final [$]と指定。
methodgridまたはskoptを指定します。
・gridでは、パラメーターの組み合わせの直積にわたる網羅的(またはランダムな)検索が実行されます。
・最大でmax_triesの評価を行い、モデルベースの最適化を使用して近似最適な戦略パラメーターを見つけます。
max_tries実行最大回数を指定します。
methodがgridの場合は、最大回数を指定することでランダムグリッドサーチが実行されるようになります。
0~1の間の小数点
constraint最適化するパラメータのコンビネーションの制約を指定します。
例)
backtest.optimize(sma1=[5, 10, 15], sma2=[10, 20, 40],
constraint=lambda p: p.sma1 < p.sma2)
この場合は、sma1が10とsma2が10の場合のパターンは実行されません。
return_heatmapパラメータのコンビネーションのヒートマップを返却するか否かを指定します。
return_optimizationmethodがskoptの場合、scipy.optimize.OptimizeResultも返却されます。
random_state最適化の結果を再現したい場合は、固定の整数をこのパラメータに指定します。

まとめ:Backtesting.pyを使って、らくにバックテストを行なおう

from backtesting import Backtest, Strategy
from backtesting.lib import crossover
from backtesting.test import SMA, GOOG

class SmaCross(Strategy):
    def init(self):
        price = self.data.Close
        self.ma1 = self.I(SMA, price, 10)
        self.ma2 = self.I(SMA, price, 20)

    def next(self):
        if crossover(self.ma1, self.ma2):
            self.buy()
        elif crossover(self.ma2, self.ma1):
            self.sell()

# ここでBacktestを使用
bt = Backtest(GOOG, SmaCross, commission=.002,
              exclusive_orders=True)
stats = bt.run()
bt.plot()

今回は、仮想通貨や株式、為替などのストラテジーのパフォーマンスを確認できるバックテストを行なえるPythonライブラリ『Backtesting.py』のBacktestクラスについて解説しました。

これがあると、わざわざ自分でバックテストのコードを書かずに、気軽にバックテストできるのでかなり良いですね。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次