Python

Running a Massive Backtest on 1M Bars in Python with Backtrader

Running a Massive Backtest on 1M Bars in Python with Backtrader

Python is a very powerful language for backtesting and quantitative analysis. You’re free to use any data sources you want, you can use millions of raws in your backtesting easily. In this article, I show an example of running backtesting over 1 million 1 minute bars from Binance.

Including libraries:

import requests 
import backtrader as bt
import backtrader.analyzers as btanalyzers
import json 
import pandas as pd
import datetime as dt
import matplotlib.pyplot as plt
import qgrid

Function to get data from Binance:

def get_binance_bars(symbol, interval, startTime, endTime):

    url = "https://api.binance.com/api/v3/klines"

    startTime = str(int(startTime.timestamp() * 1000))
    endTime = str(int(endTime.timestamp() * 1000))
    limit = '1000'

    req_params = {"symbol" : symbol, 'interval' : interval, 'startTime' : startTime, 'endTime' : endTime, 'limit' : limit}

    df = pd.DataFrame(json.loads(requests.get(url, params = req_params).text))

    if (len(df.index) == 0):
        return None
    
    df = df.iloc[:, 0:6]
    df.columns = ['datetime', 'open', 'high', 'low', 'close', 'volume']

    df.open      = df.open.astype("float")
    df.high      = df.high.astype("float")
    df.low       = df.low.astype("float")
    df.close     = df.close.astype("float")
    df.volume    = df.volume.astype("float")
   
    df['adj_close'] = df['close']
    
    df.index = [dt.datetime.fromtimestamp(x / 1000.0) for x in df.datetime]

    return df

Using this code you can get all 1m bars from the 1st of January 2019. It works pretty fast, to get 1M 1minute bars it takes only around 4 minutes.

df_list = []
last_datetime = dt.datetime(2019, 1, 1)
while True:
    new_df = get_binance_bars('ETHUSDT', '1m', last_datetime, dt.datetime.now())
    if new_df is None:
        break
    df_list.append(new_df)
    last_datetime = max(new_df.index) + dt.timedelta(0, 1)

df = pd.concat(df_list)
df.shape

Here is a simple backtrader strategy for MA Cross.

class MaCrossStrategy(bt.Strategy):

    def __init__(self):
        ma_fast = bt.ind.SMA(period = 10)
        ma_slow = bt.ind.SMA(period = 50)
        
        self.crossover = bt.ind.CrossOver(ma_fast, ma_slow)

    def next(self):
        if not self.position:
            if self.crossover > 0: 
                self.buy()
        elif self.crossover < 0: 
            self.close()

Creating engine, adding strategies and analyzers:

cerebro = bt.Cerebro()

data = bt.feeds.PandasData(dataname = df)
cerebro.adddata(data)

cerebro.addstrategy(MaCrossStrategy)
cerebro.broker.setcash(1000000.0)

cerebro.addsizer(bt.sizers.PercentSizer, percents = 50)
cerebro.addanalyzer(btanalyzers.SharpeRatio, _name = "sharpe")
cerebro.addanalyzer(btanalyzers.Transactions, _name = "trans")

Running the engine:

back = cerebro.run()

It will take only around 8 minutes to run backtest on 1M rows.

After running the engine you can compute metrics on your backtesting the usual way:

cerebro.broker.getvalue() # Ending balance
back[0].analyzers.sharpe.get_analysis() # Sharpe
len(back[0].analyzers.trans.get_analysis()) # Number of Trades

You can also plot backtesting results using the standard backtrader method. It will be plotted in around a minute and will be a bit messy but it will work:

cerebro.plot()

2 thoughts on “Running a Massive Backtest on 1M Bars in Python with Backtrader”

  1. Hi

    I get following error message, if use
    cerebro.broker.getvalue() # Ending balance
    back[0].analyzers.sharpe.get_analysis() # Sharpe
    len(back[0].analyzers.trans.get_analysis()) # Number of Trades

    cerebro.plot()

    TypeError: super(type, obj): obj must be an instance or subtype of type

  2. Hi

    I get following error message, if use
    cerebro.broker.getvalue() # Ending balance
    back[0].analyzers.sharpe.get_analysis() # Sharpe
    len(back[0].analyzers.trans.get_analysis()) # Number of Trades

    cerebro.plot()

    TypeError: super(type, obj): obj must be an instance or subtype of type

Leave a Comment

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Pine Script Programming Courses
Pine Script Programming Courses
Learn to build your own TradingView Indicators and Strategies
Sidebar Signup Form
If you want to be the first in this business, subscribe to the latest news