In Vorheriger Artikel haben wir frühere FX-Daten mithilfe der OANDA REST-API gesammelt. Basierend auf diesen Daten werden wir dieses Mal die Methode der strategischen Bewertung des automatischen Handelsbot für Investitionen beschreiben. TL; DR → Backtesting-Dokumentation
Es ist nur ↓
pip install backtesting
Es wird davon ausgegangen, dass die Datenbank mit dem Namen "usd_jpy_4h" die in Vorheriger Artikel erfassten Daten enthält.
Wir verwenden auch talib
, ein Paket für die technische Analyse. Dies kann auch leicht mit Pip fallen gelassen werden.
Die Talib-Dokumentation finden Sie hier [https://mrjbq7.github.io/ta-lib/doc_index.html]
import talib as ta
import pandas as pd
from backtesting import Backtest, Strategy
from backtesting.lib import crossover
import db_access
def get_raw_data(query):
engine = db_access.get_engine()
return pd.read_sql(query, engine)
def get_macd(close, fastperiod=6, slowperiod=13, signalperiod=4):
macd, macdsignal, macdhist = ta.MACD(close, fastperiod=fastperiod, slowperiod=slowperiod, signalperiod=signalperiod)
return macd, macdsignal, macdhist
query = "select distinct * from usd_jpy_4h where datetime between '2019/09/01' and '2020/03/01' order by datetime"
raw_data = get_raw_data(query)
df = raw_data[["datetime","open","high","low","close","volume"]].copy()
df.columns = ['Datetime', 'Open', 'High', 'Low', 'Close', 'Volume']
df['Datetime'] = pd.to_datetime(df['Datetime'])
df = df.reset_index().set_index('Datetime')
class MacdStrategy(Strategy):
macd_fastperiod = 6
macd_slowperiod = 13
macd_signalperiod = 4
profit_pips = 50
loss_pips = 50
profit = profit_pips * 0.01
loss = loss_pips * 0.01
def init(self):
self.macd, self.signal, self.hist = self.I(get_macd, self.data.Close, self.macd_fastperiod, self.macd_slowperiod, self.macd_signalperiod)
def next(self):
if (crossover(self.signal, self.macd)):
self.buy(sl=self.data.Close[-1] - self.loss, tp=self.data.Close[-1] + self.profit)
elif (crossover(self.macd, self.signal)):
self.sell(sl=self.data.Close[-1] + self.loss, tp=self.data.Close[-1] - self.profit)
bt = Backtest(df, MacdStrategy, cash=100000, commission=.00004)
output = bt.run()
print(output)
output
Start 2019-09-01 20:00:00
End 2020-02-28 20:00:00
Duration 180 days 00:00:00
Exposure [%] 74.9074
Equity Final [$] 98647
Equity Peak [$] 101404
Return [%] -1.35297
Buy & Hold Return [%] 1.81654
Max. Drawdown [%] -2.7724
Avg. Drawdown [%] -0.518637
Max. Drawdown Duration 162 days 00:00:00
Avg. Drawdown Duration 21 days 18:00:00
# Trades 66
Win Rate [%] 50
Best Trade [%] 0.457344
Worst Trade [%] -0.68218
Avg. Trade [%] -0.0215735
Max. Trade Duration 10 days 00:00:00
Avg. Trade Duration 2 days 02:00:00
Expectancy [%] 0.275169
SQN -0.538945
Sharpe Ratio -0.0655224
Sortino Ratio -0.107821
Calmar Ratio -0.00778153
_strategy MacdStrategy
dtype: object
raw_data = get_raw_data(query)
df = raw_data[["datetime","open","high","low","close","volume"]].copy()
df.columns = ['Datetime', 'Open', 'High', 'Low', 'Close', 'Volume']
df['Datetime'] = pd.to_datetime(df['Datetime'])
df = df.reset_index().set_index('Datetime')
Hier werden die Daten in der DB erfasst und für das Backtesting formatiert. Beim Backtestin erwarte ich, dass die Spaltennamen im Pandas-Datenrahmen "Offen", "Hoch", "Niedrig", "Schließen", "Lautstärke" (OK ohne) lauten. Es wird auch empfohlen, einen Index mit dem Datum / Uhrzeit-Typ hinzuzufügen. https://kernc.github.io/backtesting.py/doc/examples/Quick%20Start%20User%20Guide.html
You bring your own data. Backtesting ingests data as a pandas.DataFrame with columns 'Open', 'High', 'Low', 'Close', and (optionally) 'Volume'. Such data is easily obtainable (see e.g. pandas-datareader, Quandl, findatapy, ...). Your data frames can have other columns, but these are necessary. DataFrame should ideally be indexed with a datetime index (convert it with pd.to_datetime()), otherwise a simple range index will do.
class MacdStrategy(Strategy):
macd_fastperiod = 6
macd_slowperiod = 13
macd_signalperiod = 4
profit_pips = 50
loss_pips = 50
profit = profit_pips * 0.01
loss = loss_pips * 0.01
def init(self):
self.macd, self.signal, self.hist = self.I(get_macd, self.data.Close, self.macd_fastperiod, self.macd_slowperiod, self.macd_signalperiod)
def next(self):
if (crossover(self.signal, self.macd)):
self.buy(sl=self.data.Close[-1] - self.loss, tp=self.data.Close[-1] + self.profit)
elif (crossover(self.macd, self.signal)):
self.sell(sl=self.data.Close[-1] + self.loss, tp=self.data.Close[-1] - self.profit)
Die Kauf- und Verkaufsstrategie wird durch Erben der "Backtesting-Importstrategie" erstellt. Dieses Mal schreibe ich ein Programm mit einer Strategie des Kaufens und Verkaufens, wenn Macd, einer der technischen Indikatoren, kreuzt. In Anlagestrategien gibt es viele Strategien, die ausgelöst werden, wenn eine Zeitreihenkurve eine andere schneidet. Sie können die Strategie einfach mit crossover () beschreiben. https://kernc.github.io/backtesting.py/doc/backtesting/lib.html#backtesting.lib.crossover Es gibt viele andere nützliche Funktionen. Schauen Sie sich daher bitte die Dokumentation an.
stats = bt.optimize(
macd_fastperiod = [6, 8, 10, 12],
macd_slowperiod = [13, 19, 26],
macd_signalperiod = [4, 7, 9],
profit_pips = [30, 50, 70, 90],
loss_pips = [20, 30, 40, 50]
)
Mit Backtest.optimize ()
können Sie den optimalen Wert / die optimale Kombination für die in der Kauf- und Verkaufsstrategie verwendeten Variablen testen.
Hier ist der von Hand festgelegte Wert bis zu einem gewissen Grad definiert, er kann jedoch in Form von "[i für i in Bereich (10)]" definiert werden (obwohl es sich um eine schwere Verarbeitung zu handeln scheint).
Optimale Parameter können nach Ausführung von optimize () mit stats._strategy
bestätigt werden.
Recommended Posts