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/

    'ItemCollection' object has no attribute 'broker'

    General Code/Help
    2
    4
    1101
    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.
    • Stuj79
      Stuj79 last edited by

      I am trying to run a Cerebro instance backtest and am getting the following error:

        File "<ipython-input-120-b8cab2f96cd8>", line 1, in <module>
      runfile('C:/Users/Google Drive/PPH/walkforward_opt/main_optim.py', wdir='C:/Users/Google Drive/PPH/walkforward_opt')
      
        File "C:\Users\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 678, in runfile
      execfile(filename, namespace)
      
        File "C:\Users\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 106, in execfile
      exec(compile(f.read(), filename, 'exec'), namespace)
      
        File "C:/Users/Google Drive/PPH/Marten/Jamieson2/walkforward_opt/main_optim.py", line 457, in <module>
      results = cerebro_wf.run()
      
        File "C:\Users\Anaconda3\lib\site-packages\backtrader\cerebro.py", line 1127, in run
      runstrat = self.runstrategies(iterstrat)
      
        File "C:\Users\Anaconda3\lib\site-packages\backtrader\cerebro.py", line 1298, in runstrategies
      strat._stop()
      
        File "C:\Users\Anaconda3\lib\site-packages\backtrader\strategy.py", line 462, in _stop
      analyzer._stop()
      
        File "C:\Users\Anaconda3\lib\site-packages\backtrader\analyzer.py", line 200, in _stop
      self.stop()
      
        File "C:\Users\Anaconda3\lib\site-packages\backtrader\analyzers\annualreturn.py", line 64, in stop
      value_cur = self.strategy.stats.broker.value[-i]
      
      AttributeError: 'ItemCollection' object has no attribute 'broker'
      

      I am especially confused by this error as I believe the code that is causing the error is part of the built in "annualreturn" analyzer code which I have not changed.

      Why would my strategy be creating an "ItemCollection" object where it is not supposed to?

      Has anyone come across this before?

      My full strategy class and other code is below if needed:

      class SMACWalkForward(bt.Strategy):
      
          """The SMAC strategy but in a walk-forward analysis context"""
      
          params = {"start_dates": None,    # Starting days for trading periods (a list)
      
                    "end_dates": None,      # Ending day for trading periods (a list)
      
                    "fast": None,           # List of fast moving average windows, corresponding to start dates (a list)
      
                    "slow": None}           # Like fast, but for slow moving average window (a list)
      
          # All the above lists must be of the same length, and they all line up
      
       
      
          def __init__(self):
      
              """Initialize the strategy"""
      
              print("STARTING WALKFORWARD STRATEGY")
      
              self.fastma = dict()
      
              self.slowma = dict()
      
              self.regime = dict()
      
       
      
              self.date_combos = [c for c in zip(self.p.start_dates, self.p.end_dates)]
      
       
      
              # Error checking
      
              if type(self.p.start_dates) is not list or type(self.p.end_dates) is not list or \
      
                 type(self.p.fast) is not list or type(self.p.slow) is not list:
      
                  raise ValueError("Must past lists filled with numbers to params start_dates, end_dates, fast, slow.")
      
              elif len(self.p.start_dates) != len(self.p.end_dates) or \
      
                  len(self.p.fast) != len(self.p.start_dates) or len(self.p.slow) != len(self.p.start_dates):
      
                  raise ValueError("All lists passed to params must have same length.")
      
       
      
              for d in self.getdatanames():
      
                  self.fastma[d] = dict()
      
                  self.slowma[d] = dict()
      
                  self.regime[d] = dict()
      
       
      
                  # Additional indexing, allowing for differing start/end dates
      
                  for sd, ed, f, s in zip(self.p.start_dates, self.p.end_dates, self.p.fast, self.p.slow):
      
                      # More error checking
      
                      if type(f) is not int or type(s) is not int:
      
                          raise ValueError("Must include only integers in fast, slow.")
      
                      elif f > s:
      
                          raise ValueError("Elements in fast cannot exceed elements in slow.")
      
                      elif f <= 0 or s <= 0:
      
                          raise ValueError("Moving average windows must be positive.")
      
       
      
                      if type(sd) is not dt.date or type(ed) is not dt.date:
      
                          raise ValueError("Only datetime dates allowed in start_dates, end_dates.")
      
                      elif ed - sd < dt.timedelta(0):
      
                          raise ValueError("Start dates must always be before end dates.")
      
       
      
                      # The moving averages
      
                      # Notice that different moving averages are obtained for different combinations of
      
                      # start/end dates
      
                      self.fastma[d][(sd, ed)] = btind.SimpleMovingAverage(self.getdatabyname(d),
      
                                                                 period=f,
      
                                                                 plot=False)
      
                      self.slowma[d][(sd, ed)] = btind.SimpleMovingAverage(self.getdatabyname(d),
      
                                                                 period=s,
      
                                                                 plot=False)
      
       
      
                      # Get the regime
      
                      self.regime[d][(sd, ed)] = self.fastma[d][(sd, ed)] - self.slowma[d][(sd, ed)]
      
                      # In the future, use the backtrader indicator btind.CrossOver()
      
       
      
          def next(self):
      
              """Define what will be done in a single step, including creating and closing trades"""
      
       
      
              # Determine which set of moving averages to use
      
              curdate = self.datetime.date(0)
      
              dtidx = None    # Will be index
      
              # Determine which period (if any) we are in
      
              for sd, ed in self.date_combos:
      
                  # Debug output
      
                  #print('{}: {} < {}: {}, {} < {}: {}'.format(
      
                  #    len(self), sd, curdate, (sd <= curdate), curdate, ed, (curdate <= ed)))
      
                  if sd <= curdate and curdate <= ed:
      
                      dtidx = (sd, ed)
      
              # Debug output
      
              #print('{}: the dtixdx is {}, and curdate is {};'.format(len(self), dtidx, curdate))
      
              for d in self.getdatanames():    # Looping through all symbols
      
                  pos = self.getpositionbyname(d).size or 0
      
                  if dtidx is None:    # Not in any window
      
                      break            # Don't engage in trades
      
                  if pos == 0:    # Are we out of the market?
      
                      # Consider the possibility of entrance
      
                      # Notice the indexing; [0] always mens the present bar, and [-1] the bar immediately preceding
      
                      # Thus, the condition below translates to: "If today the regime is bullish (greater than
      
                      # 0) and yesterday the regime was not bullish"
      
                      if self.regime[d][dtidx][0] > 0 and self.regime[d][dtidx][-1] <= 0:    # A buy signal
      
                          self.buy(data=self.getdatabyname(d))
      
       
      
                  else:    # We have an open position
      
                      if self.regime[d][dtidx][0] <= 0 and self.regime[d][dtidx][-1] > 0:    # A sell signal
      
                          self.sell(data=self.getdatabyname(d))
      
      datafile = 'GETI-B.ST_daily.csv'
      
      
      market = datafile.split('-')[0]
      
                                     
      
      ohlc = pd.read_csv(datafile, index_col='date', parse_dates=True,dayfirst=True)
      
      ohlc = ohlc[ohlc['1. open']!= 0]
      
      ohlc.columns = ['open', 'high', 'low', 'close', 'volume']
      
      ohlc = ohlc[['open', 'high', 'low', 'close']]
      
      ohlc= ohlc[ohlc.index > datetime.datetime(2000, 12, 31)]
      
      cerebro_wf = Cerebro(stdstats=False)
      
      cerebro_wf.broker.setcash(1000000)
      
      cerebro_wf.broker.setcommission(0.02)
      
      cerebro_wf.addstrategy(SMACWalkForward,
      
                             # Give the results of the above optimization to SMACWalkForward (NOT OPTIONAL)
      
                             fast=[int(f) for f in wfdf.fast],
      
                             slow=[int(s) for s in wfdf.slow],
      
                             start_dates=[sd.date() for sd in wfdf.start_date],
      
                             end_dates=[ed.date() for ed in wfdf.end_date])
      
      cerebro_wf.adddata(data)
      
      cerebro_wf.addobserver(AcctValue)
      
      cerebro_wf.addobservermulti(bt.observers.BuySell)    # Plots up/down arrows
      
      cerebro_wf.addsizer(PropSizer)
      
      cerebro_wf.addanalyzer(AcctStats)
      
      
      
       
      
      results = cerebro_wf.run()
      Stuj79 B 2 Replies Last reply Reply Quote 0
      • Stuj79
        Stuj79 @Stuj79 last edited by

        I have gone into "annualreturn.py" and changed:

        value_cur = self.strategy.stats.broker.value[-i]
        

        to:

        try:
            value_cur = self.strategy.stats.broker.value[-i]
        except:
            value_cur = self.strategy.stats.acctvalue[-i]
        

        and it now seems to work - but surely I should not be changing the backtrader source code!

        Does anyone have any idea?

        1 Reply Last reply Reply Quote 0
        • B
          backtrader administrators @Stuj79 last edited by

          @stuj79 said in 'ItemCollection' object has no attribute 'broker':

          cerebro_wf = Cerebro(stdstats=False)
          

          You are removing the reference which the analyzer needs, hence the error.

          @stuj79 said in 'ItemCollection' object has no attribute 'broker':

          value_cur = self.strategy.stats.broker.value[-i]
          
          AttributeError: 'ItemCollection' object has no attribute 'broker'
          

          In any case, you'd be better off using TimeReturn

          1 Reply Last reply Reply Quote 1
          • Stuj79
            Stuj79 last edited by

            @backtrader said in 'ItemCollection' object has no attribute 'broker':

            erebro_wf = Cerebro(stdstats=False)

            Amazing! Thanks so much for your quick reply!! That has indeed solved the issue.

            1 Reply Last reply Reply Quote 0
            • 1 / 1
            • First post
              Last post
            Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
            $(document).ready(function () { app.coldLoad(); }); }