Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    Portfolio backtesting & Benchmark

    General Code/Help
    3
    7
    761
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • M
      marketwizard last edited by

      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&P500

      And Ideally plot the results of the portfolio and the Benchmark

      I hope that someone can help !

      Cheers
      Marketwizard

      1 Reply Last reply Reply Quote 0
      • run-out
        run-out last edited by

        @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.

        RunBacktest.com

        M 1 Reply Last reply Reply Quote 1
        • M
          marketwizard @run-out last edited by

          @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
                      
          
          run-out 1 Reply Last reply Reply Quote 0
          • run-out
            run-out @marketwizard last edited by

            @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:]):
            

            RunBacktest.com

            M 1 Reply Last reply Reply Quote 1
            • M
              marketwizard @run-out last edited by

              @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
              
              vladisld 1 Reply Last reply Reply Quote 0
              • vladisld
                vladisld @marketwizard last edited by

                @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)
                
                M 1 Reply Last reply Reply Quote 2
                • M
                  marketwizard @vladisld last edited by

                  @vladisld now it works, thank you !

                  However I couldn't understand why... I thought that data was a list ?

                  1 Reply Last reply Reply Quote 1
                  • 1 / 1
                  • First post
                    Last post
                  Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors