Backtesting.pyの使い方 その4
さて、今回はビットコインのやつをやります。
前回のコードのこの部分を
start = datetime.date(2018,1,1)
end = datetime.date.today()
data = web.DataReader('AAPL', 'yahoo', start, end)
以下のように変更してください。
periods = ["60", "300"] # 60sec, 5min300
query = {"periods": ','.join(periods), "before": "", "after": "1596207600"}
rspJson = json.loads(requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc", params=query).text)
ohlcvs = rspJson["result"]
for period in periods:
ohlcv_data = ohlcvs[period]
ohlcv_ary = np.asarray(ohlcv_data)
ohlcv_aryT = ohlcv_ary.T
ts = ohlcv_aryT[0]
Open = ohlcv_aryT[1]
High = ohlcv_aryT[2]
Low = ohlcv_aryT[3]
Close = ohlcv_aryT[4]
Volume = ohlcv_aryT[5]
data = pd.DataFrame(ohlcv_ary)
data.columns = ['ts','Open','High','Low','Close','Adj_Close','Volume']
これはOHLCVの値をクリプトウォッチからビットフライヤーのものを取得するようになっています。
以下の部分を
bt = Backtest(data, MDCross, cash=10_000, commission=.002)
以下のように変更してください。
bt = Backtest(data, MDCross, cash=100000000, margin=0.5, commission=.002)
これはBacktesting.pyが小数点以下のロットに対応していないためです。元本を1000万円にします。
それでは実行してみましょう。
相変わらずダメダメですね。
それでは最適化してみましょうか。
結果は以下。
うーんちょっとマシになりましたがこれではダメですね。
ここで私のお気に入りのADXを追加します。
以下の部分を
def MACD(values, m1, m2, ms):
macd, macdsignal, macdhist = ta.MACD(data.Close, fastperiod=m1, slowperiod=m2, signalperiod=ms)
return macd, macdsignal, macdhist
class MDCross(Strategy):
n1 = 10
n2 = 20
m1 = 10
m2 = 20
ms = 5
def init(self):
self.sma1 = self.I(SMA, self.data.Close, self.n1)
self.sma2 = self.I(SMA, self.data.Close, self.n2)
self.macd, self.macdsignal, self.macdhist = self.I(MACD, self.data.Close, self.m1, self.m2, self.ms)
def next(self):
if crossover(self.macd, self.macdsignal):
self.position.close()
self.buy()
elif crossover(self.macdsignal, self.macd):
self.position.close()
self.sell()
変更した実行結果はこちら。
Start 0.0
End 5999.0
Duration 5999.0
Exposure Time [%] 54.15
Equity Final [$] 161234102.968
Equity Peak [$] 164798462.968
Return [%] 61.234103
Buy & Hold Return [%] 6.021588
Return (Ann.) [%] 0.0
Volatility (Ann.) [%] NaN
Sharpe Ratio NaN
Sortino Ratio NaN
Calmar Ratio 0.0
Max. Drawdown [%] -7.599317
Avg. Drawdown [%] -1.549435
Max. Drawdown Duration 883.0
Avg. Drawdown Duration 56.140351
# Trades 9.0
Win Rate [%] 66.666667
Best Trade [%] 5.285285
Worst Trade [%] -1.006603
Avg. Trade [%] 2.774556
Max. Trade Duration 1231.0
Avg. Trade Duration 360.888889
Profit Factor 13.940548
Expectancy [%] 2.805118
SQN 3.149682
_strategy MDCross(m1=5,m2=...
_equity_curve Equi...
_trades Size EntryBa...
なかなかいい感じですね。パラメータはMACDは5,75,85。ADXはスパン45。
ADXの閾値は30以上40以下としているのがミソです。
コードは以下。
それではまた。
from backtesting import Strategy
from backtesting.lib import crossover
from backtesting import Backtest
import pandas as pd
import pandas_datareader.data as web
import datetime
import talib as ta
import json
import requests
import numpy as np
periods = ["60", "300"] # 60sec, 5min300
query = {"periods": ','.join(periods), "before": "", "after": "1596207600"}
rspJson = json.loads(requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc", params=query).text)
ohlcvs = rspJson["result"]
for period in periods:
ohlcv_data = ohlcvs[period]
ohlcv_ary = np.asarray(ohlcv_data)
ohlcv_aryT = ohlcv_ary.T
ts = ohlcv_aryT[0]
Open = ohlcv_aryT[1]
High = ohlcv_aryT[2]
Low = ohlcv_aryT[3]
Close = ohlcv_aryT[4]
Volume = ohlcv_aryT[5]
data = pd.DataFrame(ohlcv_ary)
data.columns = ['ts','Open','High','Low','Close','Adj_Close','Volume']
def SMA(values, n):
return pd.Series(values).rolling(n).mean()
def MACD(values, m1, m2, ms):
macd, macdsignal, macdhist = ta.MACD(data.Close, fastperiod=m1, slowperiod=m2, signalperiod=ms)
return macd, macdsignal, macdhist
def ADX(high, low, close, ls):
real = ta.ADX(data.High, data.Low, data.Close, timeperiod=ls)
return real
class MDCross(Strategy):
n1 = 10
n2 = 20
m1 = 55
m2 = 130
ms = 5
ls = 45
def init(self):
self.sma1 = self.I(SMA, self.data.Close, self.n1)
self.sma2 = self.I(SMA, self.data.Close, self.n2)
self.macd, self.macdsignal, self.macdhist = self.I(MACD, self.data.Close, self.m1, self.m2, self.ms)
self.real = self.I(ADX, self.data.High, self.data.Low, self.data.Close, self.ls)
def next(self):
if crossover(self.macd, self.macdsignal) and self.real > 30 and self.real < 40:
self.position.close()
self.buy()
elif crossover(self.macdsignal, self.macd) and self.real > 30 and self.real < 40:
self.position.close()
self.sell()
bt = Backtest(data, MDCross, cash=100000000, margin=0.5, commission=.002)
'''
stats = bt.run()
print(stats)
bt.plot()
'''
stats=bt.optimize(m1=range(5, 100, 10),m2=range(5, 100, 10),ms=range(5, 100, 10),maximize='Equity Final [$]', method='grid', constraint=lambda p: p.m1 < p.m2)
print(stats)
bt.plot()