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

Trying to run from latest source code



  • I am trying to run backtrader from the latest source code but am getting an error when I execute cerebro.run()

    AttributeError: 'NoneType' object has no attribute '_next_stid'
    

    Update & Solution: I resolved this issue, so posting the solution here. I have left the original question below for context. The issue was occurring because in my Jupyter Notebook I was importing from libs.backtrader to make sure that I was importing the source code and not the installed pip install version. The source code, however uses import backtrader as bt throughout which was pulling in the install version. There is a function called findowner which attempts to search the call stack for the owner of the strategy and because of the different imports the stack frames were different and couldn't find the cerebro instance and hence findowner returned None which triggered the error.
    Solution: I modified my Jupyter Notebook so that it too had import backtrader as bt but before the import statement I added sys.path = ['libs/backtrader'] + sys.path which prepended my local directory to the sys.path which caused both my Jupyter Notebook and the source code to find the backtrader module in the local directory before searching the pip install paths.


    Original Question:

    I have been successfully running backtrader from a pip install inside a conda env and am running inside a Jupyter Notebook environment. Everything has been working fine using the installed version of backtrader.

    I have made a couple of minor changes to the source code so I have cloned the backtrader repo to a local folder and have simlinked the folder inside my Jupyter Notebook folder.

    # common root folder is 'code'
    cd code/
    
    # clone backtrader into code/backtrader
    git clone https://github.com/backtrader/backtrader.git
    
    # code/project is where the jupyter notebook is
    # change directory to libs/ directory inside project directory
    cd project/libs/
    
    #inside libs/ directory create a symlink to backtrader folder
    ln -s ~/.../code/backtrader backtrader
    
    # /code/backtrader - backtrader project folder
    # /code/project - my jupyter notebook folder
    # /code/project/libs/backtrader - symlinked backtrader folder
    # /code/project/data/equities - folder containing dataset
    

    Inside my jupyter notebook I am importing the project as

    from libs.backtrader import backtrader as bt
    from libs.backtrader.backtrader import indicators as btind
    from libs.backtrader.backtrader import feeds as btfeeds
    

    I am using one of the example strategies and sample data sets

    class TestStrategy(bt.Strategy):
    
        def log(self, txt, dt=None):
            ''' Logging function fot this strategy'''
            dt = dt or self.datas[0].datetime.date(0)
            print('%s, %s' % (dt.isoformat(), txt))
    
        def __init__(self):
            # Keep a reference to the "close" line in the data[0] dataseries
            self.dataclose = self.datas[0].close
    
        def next(self):
            # Simply log the closing price of the series from the reference
            self.log('Close, %.2f' % self.dataclose[0])
    
            if self.dataclose[0] < self.dataclose[-1]:
                # current close less than previous close
    
                if self.dataclose[-1] < self.dataclose[-2]:
                    # previous close less than the previous close
    
                    # BUY, BUY, BUY!!! (with all possible default parameters)
                    self.log('BUY CREATE, %.2f' % self.dataclose[0])
                    self.buy()
    

    Then I run the strategy as

    cerebro = bt.Cerebro()
    
    # Add the strategy
    cerebro.addstrategy(TestStrategy)
    
    # path to data
    datapath = 'data/equities/orcl-1995-2014.txt'
    
    # Create a Data Feed
    data = bt.feeds.YahooFinanceCSVData(
        dataname=datapath,
        # Do not pass values before this date
        fromdate=datetime.datetime(2000, 1, 1),
        # Do not pass values before this date
        todate=datetime.datetime(2000, 12, 31),
        # Do not pass values after this date
        reverse=False)
    
    # Add the Data Feed to Cerebro
    cerebro.adddata(data)
    
    # Set up broker
    cerebro.broker.setcash(100000.0)
    
    # Run 
    cerebro.run()
    

    Running this produces the following error. Running the exact same code using the pip installed version of backtrader does not cause the error

    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-40-166ad5063c49> in <module>()
    ----> 1 cerebro.run(runonce=False)
    
    ~/Dropbox/Work/Code/Trading/strategies/libs/backtrader/backtrader/cerebro.py in run(self, **kwargs)
       1125             # let's skip process "spawning"
       1126             for iterstrat in iterstrats:
    -> 1127                 runstrat = self.runstrategies(iterstrat)
       1128                 self.runstrats.append(runstrat)
       1129                 if self._dooptimize:
    
    ~/Dropbox/Work/Code/Trading/strategies/libs/backtrader/backtrader/cerebro.py in runstrategies(self, iterstrat, predata)
       1215             sargs = self.datas + list(sargs)
       1216             try:
    -> 1217                 strat = stratcls(*sargs, **skwargs)
       1218             except bt.errors.StrategySkipError:
       1219                 continue  # do not add strategy to the mix
    
    ~/Dropbox/Work/Code/Trading/strategies/libs/backtrader/backtrader/metabase.py in __call__(cls, *args, **kwargs)
         84     def __call__(cls, *args, **kwargs):
         85         cls, args, kwargs = cls.doprenew(*args, **kwargs)
    ---> 86         _obj, args, kwargs = cls.donew(*args, **kwargs)
         87         _obj, args, kwargs = cls.dopreinit(_obj, *args, **kwargs)
         88         _obj, args, kwargs = cls.doinit(_obj, *args, **kwargs)
    
    ~/Dropbox/Work/Code/Trading/strategies/libs/backtrader/backtrader/strategy.py in donew(cls, *args, **kwargs)
         70         # Find the owner and store it
         71         _obj.env = _obj.cerebro = cerebro = findowner(_obj, bt.Cerebro)
    ---> 72         _obj._id = cerebro._next_stid()
         73 
         74         return _obj, args, kwargs
    
    AttributeError: 'NoneType' object has no attribute '_next_stid'
    

    It seems like findowner is not finding the cerebro instance. I am wondering if this is because of the way strategy.py it is importing backtrader and instead of using the local code, is importing the pip installed version

    # strategy.py 
       32   from .utils.py3 import (filter, keys, integer_types, iteritems, itervalues,
       33       map, MAXINT, string_types, with_metaclass)
     
    >> 34   import backtrader as bt
       35   from .lineiterator import LineIterator, StrategyBase
    

  • administrators

    @sfkiwi said in Trying to run from latest source code:

    from libs.backtrader import backtrader as bt
    from libs.backtrader.backtrader import indicators as btind
    from libs.backtrader.backtrader import feeds as btfeeds
    

    It's not clear what you are trying to achieve, but that's clearly wrong and bound to break things.



  • @backtrader What I was trying to do was have my project import the library from the source directly rather than from the installed package. I'm fairly new to python so if there is a standard way to achieve this then please enlighten me.

    For now I have just added my local source code path to the front of sys.path which works and doesn't break things.


  • administrators

    @sfkiwi It's not about enlightening ... if the standard snippets using backtrader show (for example, there are additional import forms of course)

    import backtrader as bt
    from backtrader import indicators as btind
    

    and your script shows

    from libs.backtrader import backtrader as bt
    from libs.backtrader.backtrader import indicators as btind
    from libs.backtrader.backtrader import feeds as btfeeds
    

    It seems like if you want to have backtrader in backtrader, like if you were trying to override things by having a backtrader package inside another backtrader package. I cannot tell you what this breaks or of if it breaks something, but it is for sure the wrong approach and it probably breaks things (as you have experienced)

    There is no magic as to how to use the source, from the README in the repository:

    From source:

    • Place the backtrader directory found in the sources inside your project

    This is just like this for any Python package if you don't want to use pip or pipenv or easy_install (no longer trendy these days). Of course there may be exceptions for packages which manipulate the path and do dirty things during initialization, but these are the exception and backtrader is for sure not amongts them.