今回は,ボリンジャーバンドを利用した売買をバックテストしてみます.
バックテストとは,過去のデータを用いて手法の妥当性をテストすることをいいます.
バックテストには,Pythonライブラリ『Backtesting.py』を用います.Backtesting.pyの使い方は,以下の記事をご覧ください.
【Python】Backtesting.pyで株取引をバックテストして戦略を最適化
また,ボリンジャーバンドについては以下の記事をご覧ください.
ボリンジャーバンドとは?テクニカル分析には欠かせない基礎指標です
TA-LibとBacktesting.pyのインストール
今回使用する主なライブラリは,TA-LibとBacktesting.pyです.
Backtesting.pyは,pipでインストールできます.
pip install backtesting
TA-Libのインストールは少し厄介です.以下の記事を参考にインストールしてください.
今回使用するその他のライブラリは,基本的にはpipでインストールできると思いますので必要に応じてインストールしてください.
ボリンジャーバンドによる売買手法のバックテスト
データの取得
とりあえず,2018年1月1日~現在のApple(AAPL)の株価でバックテストを行います.
import pandas_datareader.data as web
import datetime
start = datetime.date(2018,1,1)
end = datetime.date.today()
data = web.DataReader('AAPL', 'yahoo', start, end)
株価の取得については,以下の記事を読むと良いと思います.
Pythonのpandas datareaderをインストールして株価データを取得する方法【日本株・米国株】
株価時系列データを取得してCSVファイルに保存する方法と呼び出す方法
ボリンジャーバンドによる売買
まず,ボリンジャーバンドをTA-Libで計算する関数を作ります.
import talib as ta
def BB(close, n, nu, nd):
upper, middle, lower = ta.BBANDS(close, timeperiod=n, nbdevup=nu, nbdevdn=nd, matype=0)
return upper, lower
また,Backtesting.py用にボリンジャーバンドによる売買クラスを作ります.
今回行う戦略は単純で,+3σバンドを上回れば売り,-3σバンドを下回れば買いを入れます.ボリンジャーバンドを形成する移動平均は25日とします.
from backtesting import Backtest, Strategy # バックテスト、ストラテジー
from backtesting.lib import crossover
class BBsigma(Strategy):
n = 25 #移動平均日数
nu = 3 #何σか
nd = 3 #何σか
def init(self):
self.upper, self.lower = self.I(BB, self.data.Close, self.n, self.nu, self.nd)
def next(self): # チャートデータの行ごとに呼び出される
#+3σより大きいなら売り
if self.data.Close > self.upper:
self.position.close()
#-3σより小さいなら買い
elif self.data.Close < self.lower:
self.buy() # 買い
バックテストを実行
# バックテストを設定
bt = Backtest(
data, # チャートデータ
BBsigma, # 売買戦略
cash=1000, # 最初の所持金
commission=0.00495, # 取引手数料
margin=1.0, # レバレッジ倍率の逆数(0.5で2倍レバレッジ)
trade_on_close=True, # True:現在の終値で取引,False:次の時間の始値で取引
exclusive_orders=True #自動でポジションをクローズ(オープン)
)
output = bt.run() # バックテスト実行
print(output) # 実行結果(データ)
bt.plot() # 実行結果(グラフ)
実行結果
Start 2018-01-02 00:00:00
End 2021-04-21 00:00:00
Duration 1205 days 00:00:00
Exposure Time [%] 26.3538
Equity Final [$] 1750.66
Equity Peak [$] 1750.66
Return [%] 75.0663
Buy & Hold Return [%] 209.997
Return (Ann.) [%] 18.5089
Volatility (Ann.) [%] 26.2425
Sharpe Ratio 0.705302
Sortino Ratio 1.29385
Calmar Ratio 0.744809
Max. Drawdown [%] -24.8505
Avg. Drawdown [%] -3.38444
Max. Drawdown Duration 64 days 00:00:00
Avg. Drawdown Duration 11 days 00:00:00
# Trades 4
Win Rate [%] 50
Best Trade [%] 54.6309
Worst Trade [%] -5.52182
Avg. Trade [%] 15.4658
Max. Trade Duration 155 days 00:00:00
Avg. Trade Duration 78 days 00:00:00
Profit Factor 8.65117
Expectancy [%] 17.9514
SQN 1.19919
_strategy BBsigma
_equity_curve ...
_trades Size EntryBa...
4回の取引で資産が1000 → 1750(+75%)となりました.
他の銘柄で試してみる
右肩上がりの銘柄では手法によらずうまくいってしまいそうなので,他の銘柄でもやってみます.
スチールダイナミクス(STLD)
import pandas_datareader.data as web
import datetime
start = datetime.date(2018,1,1)
end = datetime.date.today()
data = web.DataReader('STLD', 'yahoo', start, end)
実行結果
Equity Final [$] 1258.02
IBM(IBM)
import pandas_datareader.data as web
import datetime
start = datetime.date(2018,1,1)
end = datetime.date.today()
data = web.DataReader('IBM', 'yahoo', start, end)
実行結果
Equity Final [$] 1062.76
スチールダイナミクス,IBMでもプラスとなりました.
感想
Appleのようなマクロに上がっている株でも,スチールダイナミクスやIBMのような上がっていない株でも,ボリンジャーバンドによる売買で利益が出ることが確認できました.
しかし,利益は出やすいですがApple株でも+75%と,増加額は小さめです.
例えば,MACDによるApple株の売買のバックテストでは+112~250%程度のリターンが出力されました.
MACDシグナルでの売買をバックテストする(Backtesting.py&TA-Lib)
今回行ったボリンジャーバンドによる売買では,±3σを判定バンドとしたため,取引回数が少なかったことが原因であると考えられます.
そこで,判定バンドを±2σで行ってみたところ,以下のような結果が得られました.
Apple
Equity Final [$] 1361.76
Return [%] 36.1757
スチールダイナミクス
Equity Final [$] 754.746
Return [%] -24.5254
IBM
Equity Final [$] 1064.73
Return [%] 6.47287
なんと,Appleでのリターンは下がってしまい,スチールダイナミクスに至ってはマイナスになってしまいました.IBMでは±3σのときよりも良くなりましたが,微増です.
ボリンジャーバンドによる売買は安定的である一方,それだけでは大きく儲けを出せない感じですね.ボリンジャーバンドはマクロな視点で参考にするのが良さそうです.
まとめコード
import pandas_datareader.data as web
import datetime
start = datetime.date(2018,1,1)
end = datetime.date.today()
data = web.DataReader('AAPL', 'yahoo', start, end)
from backtesting import Backtest, Strategy # バックテスト、ストラテジー
from backtesting.lib import crossover
import talib as ta
def BB(close, n, nu, nd):
upper, middle, lower = ta.BBANDS(close, timeperiod=n, nbdevup=nu, nbdevdn=nd, matype=0)
return upper, lower
class BBsigma(Strategy):
n = 25 #移動平均日数
nu = 3 #何σか
nd = 3 #何σか
def init(self):
self.upper, self.lower = self.I(BB, self.data.Close, self.n, self.nu, self.nd)
def next(self): # チャートデータの行ごとに呼び出される
#+3σより大きいなら売り
if self.data.Close > self.upper:
self.position.close()
#-3σより小さいなら買い
elif self.data.Close < self.lower:
self.buy() # 買い
# バックテストを設定
bt = Backtest(
data, # チャートデータ
BBsigma, # 売買戦略
cash=1000, # 最初の所持金
commission=0.00495, # 取引手数料
margin=1.0, # レバレッジ倍率の逆数(0.5で2倍レバレッジ)
trade_on_close=True, # True:現在の終値で取引,False:次の時間の始値で取引
exclusive_orders=True #自動でポジションをクローズ(オープン)
)
output = bt.run() # バックテスト実行
print(output) # 実行結果(データ)
bt.plot() # 実行結果(グラフ)
コメント