For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See:

'ItemCollection' object has no attribute 'broker'

  • 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/', wdir='C:/Users/Google Drive/PPH/walkforward_opt')
      File "C:\Users\Anaconda3\lib\site-packages\spyder_kernels\customize\", line 678, in runfile
    execfile(filename, namespace)
      File "C:\Users\Anaconda3\lib\site-packages\spyder_kernels\customize\", line 106, in execfile
    exec(compile(, filename, 'exec'), namespace)
      File "C:/Users/Google Drive/PPH/Marten/Jamieson2/walkforward_opt/", line 457, in <module>
    results =
      File "C:\Users\Anaconda3\lib\site-packages\backtrader\", line 1127, in run
    runstrat = self.runstrategies(iterstrat)
      File "C:\Users\Anaconda3\lib\site-packages\backtrader\", line 1298, in runstrategies
      File "C:\Users\Anaconda3\lib\site-packages\backtrader\", line 462, in _stop
      File "C:\Users\Anaconda3\lib\site-packages\backtrader\", line 200, in _stop
      File "C:\Users\Anaconda3\lib\site-packages\backtrader\analyzers\", line 64, in stop
    value_cur =[-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"""
            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( 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( != 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.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 or type(ed) is not
                        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),
                    self.slowma[d][(sd, ed)] = btind.SimpleMovingAverage(self.getdatabyname(d),
                    # 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 =
            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
                else:    # We have an open position
                    if self.regime[d][dtidx][0] <= 0 and self.regime[d][dtidx][-1] > 0:    # A sell signal
    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)
                           # Give the results of the above optimization to SMACWalkForward (NOT OPTIONAL)
                           fast=[int(f) for f in],
                           slow=[int(s) for s in wfdf.slow],
                           start_dates=[ for sd in wfdf.start_date],
                           end_dates=[ for ed in wfdf.end_date])
    cerebro_wf.addobservermulti(bt.observers.BuySell)    # Plots up/down arrows
    results =

  • I have gone into "" and changed:

    value_cur =[-i]


        value_cur =[-i]
        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?

  • administrators

    @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 =[-i]
    AttributeError: 'ItemCollection' object has no attribute 'broker'

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

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