Pretty often you want to backtest your strategy on multiple instruments and you’re interested in how it will work together. In this article, I will show you how easy it is to do that in Python using Backtrader.
To load multiple data sources to Backtrader you can use the following code:
stocks = ['AAPL', 'MSFT', 'AMZN', 'TSLA', 'V'] for s in stocks: data = bt.feeds.YahooFinanceData(dataname = s, fromdate = datetime(2010, 1, 1), todate = datetime(2020, 1, 1)) cerebro.adddata(data, name = s)
The idea is pretty simple. In a loop you go through list of stocks you want to add to your backtest and add them 1 by 1 with the same code as for single stock.
The strategy logic is a bit more complex. You have run your signals for all the stocks in a loop and save them to an array. After that get corresponding signals and trade correct stocks. Here is an example of “__init__” function for multiple stocks:
def __init__(self): self.crossovers = [] for d in self.datas: ma_fast = bt.ind.SMA(d, period = self.params.fast_length) ma_slow = bt.ind.SMA(d, period = self.params.slow_length) self.crossovers.append(bt.ind.CrossOver(ma_fast, ma_slow))
Here is an example of “next” function where I trade multiple stocks based on the corresponding signal:
def next(self): for i, d in enumerate(self.datas): if not self.getposition(d).size: if self.crossovers[i] > 0: self.buy(data = d) elif self.crossovers[i] < 0: self.close(data = d)
Here is the entire code:
import backtrader as bt import backtrader.analyzers as btanalyzers import matplotlib from datetime import datetime class MaCrossStrategy(bt.Strategy): params = ( ('fast_length', 5), ('slow_length', 25) ) def __init__(self): self.crossovers = [] for d in self.datas: ma_fast = bt.ind.SMA(d, period = self.params.fast_length) ma_slow = bt.ind.SMA(d, period = self.params.slow_length) self.crossovers.append(bt.ind.CrossOver(ma_fast, ma_slow)) def next(self): for i, d in enumerate(self.datas): if not self.getposition(d).size: if self.crossovers[i] > 0: self.buy(data = d) elif self.crossovers[i] < 0: self.close(data = d) cerebro = bt.Cerebro() stocks = ['AAPL', 'MSFT', 'AMZN', 'TSLA', 'V'] for s in stocks: data = bt.feeds.YahooFinanceData(dataname = s, fromdate = datetime(2010, 1, 1), todate = datetime(2020, 1, 1)) cerebro.adddata(data, name = s) cerebro.addstrategy(MaCrossStrategy) cerebro.broker.setcash(1000000.0) cerebro.addsizer(bt.sizers.PercentSizer, percents = 10) cerebro.addanalyzer(btanalyzers.SharpeRatio, _name = "sharpe") cerebro.addanalyzer(btanalyzers.Returns, _name = "returns") cerebro.addanalyzer(btanalyzers.Transactions, _name = "trans") back = cerebro.run() cerebro.broker.getvalue() back[0].analyzers.returns.get_analysis()['rnorm100'] back[0].analyzers.sharpe.get_analysis() back[0].analyzers.trans.get_analysis()