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

SQN indicator for regime shifts



  • Hi,

    I'm trying to create the SQN indicator for regime shifts (as created by Van Tharpe). I'm encountering an error when running it in the strategy

    Indicator:

    class SQN(bt.Indicator):
        
        lines = ('SQN_value',)
        
        def __init__(self):
            
            self.logreturns = np.log(self.data.close[0]/self.data.close[-1])
            self.stdev = bt.indicators.StdDev(self.logreturns, period=100)
            self.SMA = bt.indicators.SMA(self.logreturns, period=100)
            
        
        def next(self):
            
            self.SQN_value[0] = self.SMA[0]*np.sqrt(100)/self.stdev[0]        
    
    

    in strategy:

    class Strategy(bt.Strategy):
        
        def log(self, txt, dt=None):
            ''' Logging function for this strategy'''
            dt = dt or self.datas[0].datetime.datetime(0)
            print('%s, %s' % (dt.strftime("%Y-%m-%d %H:%M"), txt))    
        
        def __init__(self):
            
            self.SQNval = SQN(self.datas[0])
            
        def next(self):
            
            self.log(self.SQNval[0])
            
    if __name__ == '__main__':
    
        cerebro = bt.Cerebro()
    
        # Add a strategy
        cerebro.addstrategy(Strategy)
        # Create a Data Feed
        data = bt.feeds.PandasData(dataname=df)
        # Add the Data Feed to Cerebro
        cerebro.adddata(data)
        
        cerebro.run()
    

    error:

    ---------------------------------------------------------------------------
    IndexError                                Traceback (most recent call last)
    <ipython-input-81-2795bce82ea1> in <module>
         25     cerebro.adddata(data)
         26 
    ---> 27     cerebro.run()
    
    ~\Anaconda3\lib\site-packages\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:
    
    ~\Anaconda3\lib\site-packages\backtrader\cerebro.py in runstrategies(self, iterstrat, predata)
       1291                     self._runonce_old(runstrats)
       1292                 else:
    -> 1293                     self._runonce(runstrats)
       1294             else:
       1295                 if self.p.oldsync:
    
    ~\Anaconda3\lib\site-packages\backtrader\cerebro.py in _runonce(self, runstrats)
       1650         '''
       1651         for strat in runstrats:
    -> 1652             strat._once()
       1653             strat.reset()  # strat called next by next - reset lines
       1654 
    
    ~\Anaconda3\lib\site-packages\backtrader\lineiterator.py in _once(self)
        295 
        296         for indicator in self._lineiterators[LineIterator.IndType]:
    --> 297             indicator._once()
        298 
        299         for observer in self._lineiterators[LineIterator.ObsType]:
    
    ~\Anaconda3\lib\site-packages\backtrader\lineiterator.py in _once(self)
        295 
        296         for indicator in self._lineiterators[LineIterator.IndType]:
    --> 297             indicator._once()
        298 
        299         for observer in self._lineiterators[LineIterator.ObsType]:
    
    ~\Anaconda3\lib\site-packages\backtrader\lineiterator.py in _once(self)
        295 
        296         for indicator in self._lineiterators[LineIterator.IndType]:
    --> 297             indicator._once()
        298 
        299         for observer in self._lineiterators[LineIterator.ObsType]:
    
    ~\Anaconda3\lib\site-packages\backtrader\linebuffer.py in _once(self)
        628 
        629         self.preonce(0, self._minperiod - 1)
    --> 630         self.oncestart(self._minperiod - 1, self._minperiod)
        631         self.once(self._minperiod, self.buflen())
        632 
    
    ~\Anaconda3\lib\site-packages\backtrader\lineroot.py in oncestart(self, start, end)
        163         Only called once and defaults to automatically calling once
        164         '''
    --> 165         self.once(start, end)
        166 
        167     def once(self, start, end):
    
    ~\Anaconda3\lib\site-packages\backtrader\linebuffer.py in once(self, start, end)
        670 
        671         for i in range(start, end):
    --> 672             dst[i] = src[i + ago]
        673 
        674 
    
    IndexError: array assignment index out of range
    

    any help is much appreciated



  • @Jens-Halsberghe said in SQN indicator for regime shifts:

    self.data.close[0]/self.data.close[-1]

    Not sure if this will fix all the code but the square brackets need to be round in init because you are dealing with the whole line, not just one bar of the line..

    self.data.close(0)/self.data.close(-1)
    


  • @run-out doesn't fix it unfortunately.



  • np.log requires array-like variable. self.data.close(0)/self.data.close(-1) ratio calculated in the __init__() doesn't return this type of variable.



  • @ab_trader thanks. when I take the log away it works. alternatively I tried math.log but it's also giving me an error. I don't see another way to take a log?

    Additionally, from the error, I would have never guessed this is the problem. I find it at times quite challenging to debug.

    error I'm getting when using math.log

    ---------------------------------------------------------------------------
    TypeError                                 Traceback (most recent call last)
    <ipython-input-105-342bb33a11f0> in <module>
         26     cerebro.adddata(data)
         27 
    ---> 28     cerebro.run()
    
    ~\Anaconda3\lib\site-packages\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:
    
    ~\Anaconda3\lib\site-packages\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
    
    ~\Anaconda3\lib\site-packages\backtrader\metabase.py in __call__(cls, *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)
         89         _obj, args, kwargs = cls.dopostinit(_obj, *args, **kwargs)
         90         return _obj
    
    ~\Anaconda3\lib\site-packages\backtrader\metabase.py in doinit(cls, _obj, *args, **kwargs)
         76 
         77     def doinit(cls, _obj, *args, **kwargs):
    ---> 78         _obj.__init__(*args, **kwargs)
         79         return _obj, args, kwargs
         80 
    
    <ipython-input-105-342bb33a11f0> in __init__(self)
          8     def __init__(self):
          9 
    ---> 10         self.SQNval = SQN(self.datas[0])
         11 
         12     def next(self):
    
    ~\Anaconda3\lib\site-packages\backtrader\indicator.py in __call__(cls, *args, **kwargs)
         51     def __call__(cls, *args, **kwargs):
         52         if not cls._icacheuse:
    ---> 53             return super(MetaIndicator, cls).__call__(*args, **kwargs)
         54 
         55         # implement a cache to avoid duplicating lines actions
    
    ~\Anaconda3\lib\site-packages\backtrader\metabase.py in __call__(cls, *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)
         89         _obj, args, kwargs = cls.dopostinit(_obj, *args, **kwargs)
         90         return _obj
    
    ~\Anaconda3\lib\site-packages\backtrader\metabase.py in doinit(cls, _obj, *args, **kwargs)
         76 
         77     def doinit(cls, _obj, *args, **kwargs):
    ---> 78         _obj.__init__(*args, **kwargs)
         79         return _obj, args, kwargs
         80 
    
    <ipython-input-104-464714667728> in __init__(self)
          5     def __init__(self):
          6 
    ----> 7         self.logreturns = math.log(self.data.close(0)/self.data.close(-1))
          8         self.stdev = bt.indicators.StdDev(self.logreturns, period=100)
          9         self.SMA = bt.indicators.SMA(self.logreturns,period=100)
    
    TypeError: must be real number, not LinesOperation
    


  • @Jens-Halsberghe said in SQN indicator for regime shifts:

    alternatively I tried math.log but it's also giving me an error.

    math.logrequires the number, so it will not work also.

    I don't see another way to take a log?

    You need to write your own indicator which calculates log of the number and than use it. In the indicator you put calculations in the next, so you can use math.log.



  • @Jens-Halsberghe Backtrader uses its own datastructure to store OHLC lines, the structure is neither nump.ndarray nor float, so you can use neither np.log nor math.log



  • @Jens-Halsberghe But in next(), you get a single OHLC bar which is a plain Python object, you can use math.log in def next()


Log in to reply
 

});