Portfolio backtesting & Benchmark
-
Hello,
I'm currently backtesting my strategies on multiple stocks using mutiple datafeeds.
I would like to compare my portfolio strategy returns to a benchmark (like the S&P500).
In the backtrader documentation I found this article:
https://www.backtrader.com/blog/posts/2016-07-22-benchmarking/benchmarking/However, with the solutions proposed in the article, I suppose that if I add the S&P500 to cerebro, that cerebro will also backtest my strategy on the S&P500 as well.
What I'm trying to do is a bit different. For example:
Test the strategy on MSFT, BAC, JNJ, FB and APPL
Compare the results to the S&P500And Ideally plot the results of the portfolio and the Benchmark
I hope that someone can help !
Cheers
Marketwizard -
@marketwizard Put your benchmark line in first, then the rest of your stocks. Then when you are in next, simply trade self.datas[1] and greater.
-
@run-out How can I trade self.datas[1] and greater ?
Here is the code of my Init and Next funtions:
def __init__(self): self.inds = dict() for i, d in enumerate(self.datas): self.inds[d] = dict() # Define the indicators self.inds[d]['ema50'] = bt.indicators.EMA(d.close, period=50) self.inds[d]['ema200'] = bt.indicators.EMA(d.close, period=200) self.inds[d]['atr'] = bt.indicators.ATR(d, period=14) # Define the crossover signals self.inds[d]['bull_cross'] = bt.indicators.CrossOver(self.inds[d]['ema50'], self.inds[d]['ema200']) self.inds[d]['bull_cross'].plotinfo.subplot = False self.inds[d]['bear_cross'] = bt.indicators.CrossOver(self.inds[d]['ema200'], self.inds[d]['ema50']) self.inds[d]['bear_cross'].plotinfo.subplot = False if i > 0: # Check we are not on the first loop of data feed: if self.p.oneplot == True: d.plotinfo.plotmaster = self.datas[0] def start(self): self.order = None # sentinel to avoid operations on pending order self.curpos = None def prenext(self): self.next() def next(self): for i, d in enumerate(self.datas): #dt, dn = self.datetime.date(), d._name pos = self.getposition(d).size # Get the Amount of cash in the Portfolio cash = self.broker.get_cash() if self.order: return # pending order execution if not pos: # check if we already have an open position on the stock if self.inds[d]['bull_cross'][0] > 0.0: # Calculation of the Stock Qty to buy depending on our risk strategy # calculate the absolute stop loss distance with atr pdist = self.inds[d]['bull_cross'][0] * self.p.atrdist # calculate the stop price self.pstop = d.close[0] - pdist # calculate the amount of shares to buy / sell depending on the stop loss and the risk strategy qty = math.floor((cash * self.p.trade_risk) / pdist) # calculate the maximum exposure depending on the risk strategy portfolio_exposure_calc = qty * d.close[0] portfolio_exposure_strategy = cash * self.p.portfolio_expo qty = math.floor(portfolio_exposure_strategy / d.close[0]) self.order = self.buy(data=d, size=qty) else: # in the market if self.inds[d]['bear_cross'][0]: self.close(data=d) # stop met - get out
-
@marketwizard said in Portfolio backtesting & Benchmark:
for i, d in enumerate(self.datas):
datas is just a list, so like this:
for i, d in enumerate(self.datas[1:]):
-
@run-out thank you, it works for trading the datas excluding the first one.
However, when I try to use the benchmark observer I receive an error.
Here is the code I use for adding the datas to cerebro:for i in range(len(datalist)): data = bt.feeds.GenericCSVData( dataname=datalist[i][0], # Do not pass values before this date fromdate=datetime(fromDate.year, fromDate.month, fromDate.day), # Do not pass values before this date todate=datetime(datetime.today().year, datetime.today().month, datetime.today().day), nullvalue=0.0, dtformat=('%Y-%m-%d'), datetime=0, open=1, high=2, low=3, close=4, volume=5, openinterest=-1 ) cerebro.adddata(data, name=datalist[i][1]) # Set the Cash for the Strategy cerebro.broker.setcash(icap) # Set the comissions cerebro.broker.setcommission(commission=0.005) #Add the benchmark Observer cerebro.addobserver(bt.observers.Benchmark, data=data[0])
and the error message:
Traceback (most recent call last): File "C:/Users/marketwizard/PycharmProjects/marketwizard_Backtests_PF/02_MW_EMA_RSI_V2_PF_Benchmark/main.py", line 339, in <module> cerebro.addobserver(bt.observers.Benchmark, data=data[1]) File "C:\Users\marketwizard\PycharmProjects\Algotrading_libraries1\lib\site-packages\backtrader\lineseries.py", line 467, in __getitem__ return self.lines[0][key] File "C:\Users\marketwizard\PycharmProjects\Algotrading_libraries1\lib\site-packages\backtrader\linebuffer.py", line 163, in __getitem__ return self.array[self.idx + ago] IndexError: array index out of range Process finished with exit code 1
-
@marketwizard said in Portfolio backtesting & Benchmark:
cerebro.addobserver(bt.observers.Benchmark, data=data[0])
I believe it should be:
cerebro.addobserver(bt.observers.Benchmark, data=data)
-
@vladisld now it works, thank you !
However I couldn't understand why... I thought that data was a list ?