Calculating Multi-Timeframe Backtests in Python with Backtrader

Pretty often it can be interesting to backtest a strategy across several timeframes. In the simple case you want to have a signal on one timeframe and just want a confirmation for another higher timeframe. In this video, I will show you how easy it is to use multiple timeframes in Backtrader backtests in Python.

It’s really easy to do that in Backtrader with resampledata function. You can use it like that for example to get 5m bars loaded into the engine:

cerebro.resampledata(data, timeframe = bt.TimeFrame.Minutes, compression = 5)

After that in the strategy you can use it as just an additional data source. In my example, I can use it as data1:

 ma_fast_ht = bt.ind.SMA(self.data1, period = 5)
 ma_slow_ht = bt.ind.SMA(self.data1, period = 10)
 self.above = ma_fast_ht > ma_slow_ht

Here is the entire code for this example:

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

class MaCrossStrategy(bt.Strategy):

    def __init__(self):
        
        ma_fast = bt.ind.SMA(period = 5)
        ma_slow = bt.ind.SMA(period = 10)
        
        self.crossover = bt.ind.CrossOver(ma_fast, ma_slow)
        
        ma_fast_ht = bt.ind.SMA(self.data1, period = 5)
        ma_slow_ht = bt.ind.SMA(self.data1, period = 10)
        
        self.above = ma_fast_ht > ma_slow_ht

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

btcusd = pd.read_csv("/storage/data/bybit_btcusd_1m.csv", index_col = 0, parse_dates = True)
btcusd = btcusd.iloc[-10000:,]

cerebro = bt.Cerebro()

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

cerebro.resampledata(data, timeframe = bt.TimeFrame.Minutes, compression = 5)

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

cerebro.addsizer(bt.sizers.PercentSizer, percents = 50)
cerebro.addanalyzer(btanalyzers.Returns, _name = "returns")

back = cerebro.run()
cerebro.broker.getvalue()

Leave a Reply

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