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.log
requires 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
norfloat
, so you can use neithernp.log
normath.log
-
@Jens-Halsberghe But in
next()
, you get a single OHLC bar which is a plain Python object, you can usemath.log
indef next()