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

Must be real number, not LinesOperation



  • Hi there, I'm attempting to make a custom stochastic of my own after browsing a couple on these forums. I'm gonna jump straight into the code.

    class MyStochastic(bt.Indicator):
        lines = ('Stoc', 'MyStoch',)
    
        def __init__(self):
        
            self.f = math.degrees(1.44 * 3.14159 / 10)
            self.a1 = math.exp(-self.f)
            self.b1 = 2 * self.a1 * math.cos(self.f)
            self.c2 = self.b1
            self.c3 = -self.a1 * self.a1
            self.c1 = 1 - self.c2 - self.c3
        
            super(MyStochastic,self).__init__()
        
        def prenext(self):
            self.HighestC = bt.indicators.Highest(period=9)
            self.LowestC = bt.indicators.Lowest(period=9)
            self.l.Stoc[0] = (self.data[0]-self.LowestC/(self.HighestC-self.LowestC))
            self.lines.MyStoch[0] = self.c1*(self.l.Stoc[0]+self.l.Stoc[0])/2 + self.c2*self.l.Stoc[0] + self.c3*self.l.Stoc[0]
       
        def nextstart(self):
            self.HighestC = bt.indicators.Highest(period=9)
            self.LowestC = bt.indicators.Lowest(period=9)
            self.l.Stoc[0] = (self.data[0]-self.LowestC/(self.HighestC-self.LowestC))
            self.lines.MyStoch[0] = self.c1*(self.l.Stoc[0]+self.l.Stoc[-1])/2 + self.c2*self.l.MyStoch[-1] + self.c3*self.l.MyStoch[-1]
           
        def next(self):
            self.HighestC = bt.indicators.Highest(period=9)
            self.LowestC = bt.indicators.Lowest(period=9)
            self.l.Stoc[0] = (self.data[0]-self.LowestC/(self.HighestC-self.LowestC))
            self.lines.MyStoch[0] = self.c1*(self.l.Stoc[0]+self.l.Stoc[-1])/2 + self.c2*self.l.MyStoch[-1] + self.c3*self.l.MyStoch[-2]
    

    Here's just a quick description of why I have it setup the way it is:
    Using the three sections (prenext, nextstart, next) allow me to initialize the lines properly. This is a fix that the user @Guwop seemed unable to find. I have confirmed the effectiveness of this method with other recursive indicators before this one.

    I use the super(MyStochastic,self).init() because I also utilize the Highest and Lowest indicators, and it is my understanding that under these circumstances that including super() is necessary.

    Here is the error message I receive upon running...

    <ipython-input-12-4e36424d155e> in prenext(self)
         75         self.HighestC = bt.indicators.Highest(period=9)
         76         self.LowestC = bt.indicators.Lowest(period=9)
    ---> 77         self.l.Stoc[0] = ((self.data[0]-self.LowestC)/(self.HighestC-self.LowestC))
         78         self.lines.MyStoch[0] = self.c1*(self.l.Stoc[0]+self.l.Stoc[0])/2 + self.c2*self.l.Stoc[0] + self.c3*self.l.Stoc[0]
         79 
    
    ~\Anaconda3\lib\site-packages\backtrader\linebuffer.py in __setitem__(self, ago, value)
        220             value (variable): value to be set
        221         '''
    --> 222         self.array[self.idx + ago] = value
        223         for binding in self.bindings:
        224             binding[ago] = value
    
    TypeError: must be real number, not LinesOperation 
    

    I'm not quite sure what it is that separates the values of self.l.Stoc[0] from self.l.MyStoch[0], because as I have mentioned previously, in other recursive indicators of mine, setting values to a lines object in the same manner as MyStoch has been no problem. Additionally, I have swapped out self.data[0] for an integer and receive the same error. I'd appreciate any help. Love the platform by the way. Thanks!



  • Consider declaring indicators once in __init__:

    self.HighestC = bt.indicators.Highest(self.data, period=9)
    self.LowestC = bt.indicators.Lowest(self.data, period=9)
    

    and then use

    self.l.Stoc[0] = (self.data[0]-self.LowestC[0])/(self.HighestC[0]-self.LowestC[0])


  • Alternatively in __init__ only:

    HighestC = bt.indicators.Highest(self.data, period=9)
    LowestC = bt.indicators.Lowest(self.data, period=9)
    self.l.Stoc = (self.data-LowestC)/(HighestC-LowestC)


  • @adrtod Yes that worked! Thank you very much. If it isn't too much to ask, would you mind explaining why it works that way? From what I had thought, init is a def that is only called once, and so the values for Highest/Lowest would only be calculated once, and not change with new data. Obviously this is not the case... does this mean that init is in fact called more than once?



  • __init__ is called only once and only declares the indicators as objects, no computation is done during __init__ but they are handled automatically.
    The same applies when using operators to combine indicators, see https://www.backtrader.com/docu/concepts.html#operators-using-natural-constructs
    See also https://www.backtrader.com/docu/induse.html and https://www.backtrader.com/docu/inddev.html



  • @adrtod, Thank you for the explanation it's all making sense now - especially considering how the declarative approach to indicators is setup.


  • administrators

    Overtaken by @adrtod. Glad to see someone with such an intimate knowledge of things.