[PYTHON] Leistungsbewertung des automatischen Investment Trading Bot mittels Backtesting

Motivation

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

Weise

Umgebung

Es ist nur ↓

pip install backtesting

Code für Personen, die keine Erklärung benötigen

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

Codebeschreibung

Erstellung von Eingabedaten

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.

Erstellen einer Handelsstrategie

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.

Variable Optimierung

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

Leistungsbewertung des automatischen Investment Trading Bot mittels Backtesting
Automatische Erfassung von Aktienkursen mit Python
Betrieb des automatischen Handelsskripts für virtuelle Währungen
Leistungsbewertung der Programmiersprache auf Basisebene
Automatischer Start von Raspberry Pi-Programmen mit Systemd