This is a python library to make backtesting and walkfoward testing with financial data.
Python 3
pip install backtesting-walkfoward
or
git clone https://github.com/JoaoZati/backtesting_walkfoward.git
from backtesting_walkfoward.backtesting import Backtesting
import numpy as np
import pandas as pd
you can place indicators in dataframe, but it cant be optimized in walkfoward and you should pass with_indicators=True. It's great for fundamental data and web scraped data.
data_yf = DownloadData('MSFT')
df_msft = data_yf.dataframe.copy()
backtesting = Backtesting(df_msft)
backtesting.data_class.plot_bokeh_ohlc()
5. Create one indicator function with data_class as first parameter (if your strategy use indicators).
def moving_avarange(data_class, x, y):
df = data_class.dataframe.copy()
ma_fast = np.array(df.close.rolling(x).mean())
ma_slow = np.array(df.close.rolling(y).mean())
return {'ma_fast': ma_fast, 'ma_slow': ma_slow}
pass the function to backtesting object with x and y values (pass values to indicators args, can make in indicator function how many args you want):
backtesting.indicator(moving_avarange, 12, 200)
6. Create your logic entry and exits functions. Note you can create: Buy Enter, Buy Close, Sell Enter, Sell Close. For stop loss or trailing stop you dont need create a function. Its implemented in backtesting (see more later).
def buy_enter_ma(data_class):
mf = data_class.indicators['ma_fast']
ms = data_class.indicators['ma_slow']
op = data_class.open
be = np.zeros(len(mf))
for i in range(len(be)):
if i < 2 or not mf[i] or not ms[i]:
continue
if mf[i - 2] <= ms[i - 2] and mf[i - 1] > ms[i - 1]:
be[i] = op[i]
return be
def sell_enter_ma(data_class):
mf = data_class.indicators['ma_fast']
ms = data_class.indicators['ma_slow']
op = data_class.open
se = np.zeros(len(mf))
for i in range(len(se)):
if i < 2 or not mf[i] or not ms[i]:
continue
if mf[i - 2] >= ms[i - 2] and mf[i - 1] < ms[i - 1]:
se[i] = op[i]
return se
note: the only two rules are: first it need data_class as first parameter and should return one numpy array with 1 column.
backtesting.buy_enter(buy_enter_ma)
backtesting.sell_enter(sell_enter_ma)
backtesting.backtesting(revert=True)
note 1: I run revert=True here because I'm running a crossover strategy, revert=True makes the backtesting close order and open a new order in inverse direction when an inverse signal was made. Ex: If a candle in the simulation are long, but a sell signal was made. It closes the long position and sell after that.
note 2: You can run sell_stop_loss=True, buy_stop_loss=True to set stop losses and set values with ssl_value={value} and bsl_value={value} respectively.
To see metrics just run code bellow, it returns a dictionary with number of trades, total return and winrate:
metrics_results = backtesting.results()
backtesting.data_class.plot_bokeh_indicators(
line_indicators={'ma_fast': 'blue', 'ma_slow': 'yellow'},
circle_indicators={'buy_enter_price': 'green', 'sell_enter_price': 'red'}
)
1. How we already have the data, indicator function and logic functions. To setup walkfowad you just need to:
walkfoward = WalkFoward(
df_msft, 500, 1000,
indicator_main_function=moving_avarange,
buy_enter_function=buy_enter_ma, sell_enter_function=sell_enter_ma,
revert=True
)
result_walkfoward = walkfoward.run_walkfoward(x_list=[12, 20, 30], y_list=[100, 200, 300], z_list=[0])
metrics_walkfoward = walkfoward.show_results()
4. For plot the results. Just create a DataClass with result_walkfoward with indicators and plot it:
data_wf.plot_bokeh_indicators(
line_indicators={'ma_fast': 'blue', 'ma_slow': 'yellow'},
circle_indicators={'buy_enter_price': 'green', 'sell_enter_price': 'red'},
title='Walkfowad Crossover AAPL'
)