[PYTHON] Évaluation des performances du bot de trading d'investissement automatique à l'aide du backtesting

motivation

Dans Article précédent, nous avons collecté des données FX passées à l'aide de l'API REST OANDA. Cette fois, sur la base de ces données, nous décrirons la méthode d'évaluation stratégique du bot de trading automatique d'investissement. TL; DR → documentation de backtesting

manière

Environnement

C'est juste ↓

pip install backtesting

Code pour les personnes qui n'ont pas besoin d'explications

On suppose que la base de données appelée ʻusd_jpy_4hcontient les données acquises dans [Article précédent](https://qiita.com/k_0/items/e36162b9c623d27583c9). Nous utilisons égalementtalib`, un package d'analyse technique. Cela peut également être facilement abandonné avec pip. La documentation talib est ici [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

Description du code

création de données d'entrée

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')

Ici, les données de la base de données sont acquises et formatées pour le backtesting. En backtestin, je m'attends à ce que les noms de colonne soient'Open ',' High ',' Low ',' Close ',' Volume '(OK sans cela) dans le pandas Dataframe. Il est également recommandé d'ajouter un index avec le type datetime. 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.

Créer une stratégie de trading

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)

La stratégie d'achat et de vente est créée en héritant de «la stratégie d'importation de backtesting». Cette fois, j'écris un programme avec une stratégie d'achat et de vente lorsque Macd, qui est l'un des indicateurs techniques, croise. Dans les stratégies d'investissement, de nombreuses stratégies se déclenchent lorsqu'une courbe de série chronologique en croise une autre. Vous pouvez facilement décrire la stratégie en utilisant crossover (). https://kernc.github.io/backtesting.py/doc/backtesting/lib.html#backtesting.lib.crossover Il existe de nombreuses autres fonctionnalités utiles, veuillez donc consulter la documentation.

Optimisation variable

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]
)

En utilisant Backtest.optimize (), vous pouvez tester la valeur / combinaison optimale pour les variables utilisées dans la stratégie d'achat et de vente. Ici, la valeur décidée à la main est définie dans une certaine mesure, mais elle peut être définie sous la forme de «[i pour i dans la plage (10)]» (bien que cela semble être un traitement lourd). Les paramètres optimaux peuvent être confirmés avec stats._strategy après avoir exécuté Optimize ().

Recommended Posts

Évaluation des performances du bot de trading d'investissement automatique à l'aide du backtesting
Collecte automatique des cours boursiers à l'aide de python
Fonctionnement du script de trading automatique de monnaie virtuelle
Évaluation des performances de base du langage de programmation
Lancement automatique des programmes Raspberry Pi à l'aide de Systemd