プルバックシステム
株価が時々、下落しながらも全体としては上昇基調のときがあります。この下落した瞬間に買って上昇したときに買えば利益が見込めます。所謂、押し目買いです。これを Backtesting.pyで実装してみます。押し目買いは別名プルバックとも言います。
Backtesting.pyをつかって、トゥーシャー・シャンデ の「売買システム入門」で紹介されている プルバックシステムを試してみます。結論から言うと、Buy & Holdの方が良い成績となりました。
最適化は置いておいて、実装してみることが目的です。
Backtesting.pyについて
OHLCVからなる pandasのデータフレームを渡すと、バックテストをしてくれる関数です。
標準では移動平均クロスのライブラリが準備されていますが、それ以外のアルゴリズムを試したいときは、自分で関数を書く必要があります。
プログラムサンプル
#一つ上のディレクトリにある、自作のライブラリを読み込む仕組み
import sys
import os
sys.path.append(os.path.abspath(‘.’))
#ここから backte
from backtesting import Backtest, Strategy
from backtesting.test import SMA, GOOG
import pandas as pd
import bbank_public
df = bbank_public.get_df_years(‘btc_jpy’,2016,2018)
def low_x(close,n):
ret = pd.Series(close).rolling(window=n).min()
return ret
def high_x(close,n):
ret = pd.Series(close).rolling(window=n).max()
return ret
class PullbackStrategy(Strategy):
def init(self):
# 50日SMA
self.sma50 = self.I(SMA, self.data.Close, 50)
# 過去5日間の最安値
self.low5 = self.I(low_x,self.data.Close,5)
# 過去20日間の最高値
self.high20 = self.I(high_x,self.data.Close,20)
def next(self):
# 現在の価格が50日SMAより上で、かつ過去5日間の新しい安値である場合に購入
if self.data.Close[–1] > self.sma50[–1]:
if self.data.Close[–1] == self.low5[–1]:
self.buy()
#保有中のポジションがあり、その価格が20日間の最高値に達した場合、ポジションをクローズ
elif self.position:
if self.data.Close[–1] >= self.high20[–1]:
self.position.close()
bt = Backtest(df, PullbackStrategy, cash=100000, commission=0.0012)
stats = bt.run()
print(stats)
# オプション:バックテストの結果を図示
bt.plot()
input()
import bbank_public
df = bbank_public.get_df_years(‘btc_jpy’,2016,2018)
自作関数でbitbankからビットコイン価格を読み込む
Backtesting.pyのプログラムの構造
class PullbackStrategy(Strategy):
戦略をクラスで定義します。
で、戦略に使うデータを準備します。データはPandasのシリーズのようです。
self.data に株価データが入っています。self.data.Close で終値を取り出せます。
これ以外に今回は、以下の3つのデータを準備しました。
# 50日SMA
self.sma50 = self.I(SMA, self.data.Close, 50)
# 過去5日間の最安値
self.low5 = self.I(low_x,self.data.Close,5)
# 過去20日間の最高値
self.high20 = self.I(high_x,self.data.Close,20)
smaはライブラリ付属の関数で簡単に計算できます。5日間安値 と 20日間高値は自作関数で計算しました。 自作関数は、Strategyクラスの外で準備しています。
以降で、準備したデータを先頭から一つづつ処理をしてバックテストをしてくれます。
bt = Backtest(df, PullbackStrategy, cash=100000, commission=0.0012)
stats = bt.run()
print(stats)
dfは準備した OHLCVデータから成るデータフレームを渡します。pullbackStrategyで今回作成したクラスを渡しています。chshで所持金を、commissionで手数料の割合を指定しています。0.01 で 1%になります。今回だと0.12%です。
# オプション:バックテストの結果を図示
bt.plot()
バックテストの結果をグラフにしてブラウザに表示してくれます。
クラスと外の関数について
def low_x(close,n):
ret = pd.Series(close).rolling(window=n).min()
return ret
def high_x(close,n):
ret = pd.Series(close).rolling(window=n).max()
return ret
closeで終値のデータを n は窓関数の期間です。
low_x で n日間の最安値(終値ベース)
high_x で n日間の最高値(終値ベース)を計算して値を返します。
def init(self):
# 50日SMA
self.sma50 = self.I(SMA, self.data.Close, 50)
# 過去5日間の最安値
self.low5 = self.I(low_x,self.data.Close,5)
# 過去20日間の最高値
self.high20 = self.I(high_x,self.data.Close,20)
繰り返しになりますが、データを準備します。
def next(self):
# 現在の価格が50日SMAより上で、かつ過去5日間の新しい安値である場合に購入
if self.data.Close[–1] > self.sma50[–1]:
if self.data.Close[–1] == self.low5[–1]:
self.buy()
#保有中のポジションがあり、その価格が20日間の最高値に達した場合、ポジションをクローズ
elif self.position:
if self.data.Close[–1] >= self.high20[–1]:
self.position.close()
next(self):
でデータ列を先頭から順番に読み込んで処理してくれます
self.data.Close[-1] で現在の終値を参照します。
終値が50日移動平均を上回っていて、
なおかつ、終値が5日間の安値である場合に購入。
現在、ポジションがあり、終値が 20日高値と同じ以上であれば、ポジションを閉じる(売る)
結果
bt = Backtest(df, PullbackStrategy, cash=100000, commission=0.0012)
Start 2016–01–03 09:00:00
End 2017–12–31 09:00:00
Duration 728 days 00:00:00
Exposure Time [%] 91.758242
Equity Final [$] 3089032.6016
Equity Peak [$] 4488828.6016
Return [%] 2989.032602
Buy & Hold Return [%] 3188.288375
Return (Ann.) [%] 459.738472
Volatility (Ann.) [%] 502.60624
Sharpe Ratio 0.914709
Sortino Ratio 10.225645
Calmar Ratio 12.183191
Max. Drawdown [%] –37.735473
Avg. Drawdown [%] –8.328166
Max. Drawdown Duration 155 days 00:00:00
Avg. Drawdown Duration 16 days 00:00:00
# Trades 2
Win Rate [%] 100.0
Best Trade [%] 2387.975583
Worst Trade [%] 26.565646
Avg. Trade [%] 461.152597
Max. Trade Duration 475 days 00:00:00
Avg. Trade Duration 334 days 00:00:00
Profit Factor NaN
Expectancy [%] 1207.270615
SQN 1.016987
_strategy PullbackStrategy
_equity_curve …
_trades Size EntryBa…
いろいろででてきました。
Return [%] で損益率です。2989%
Buy & Hold Return [%] が 3188%なので、トレードするよりもホールドしておいた方が成績がよかったことになります。
というか、ビットコインの場合、半減期に合わせて Buy & Holdしておくのが一番良いような気がします。
[rakuten id=”book:10956603″ kw=”売買システム入門 相場金融工学の考え方→作り方→評価法 (Wizard book series)トゥーシャー・S.シャンデ”]