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

Need some help creating an On Balance Volume indicator



  • Hi I'd like some help trying to understand why my indicator isn't being accepted into the rest of backtrader. I'm trying to make an OBV indicator, but get stopped with python giving me this error:

    TypeError: must be real number, not LinesOperation

    Here is my code:

    0_1536968421832_postToBacktraderOBV.PNG

    There's probably a few places to look, but I'd greatly appreciate knowing what went wrong.

    Thank you,

    Tag



  • Please show the whole error message to understand what is going on.

    At first glance:

    • I would use class OnBalanceVolume(bt.Indicator)
    • () are used for indexing in the __init__, [] are used for indexing in the next
    • I doubt that self.data has lines, self.data.volume is more appropriate

  • administrators

    @tagteam69 said in Need some help creating an On Balance Volume indicator:

    Here is my code:

    If you post text as opposed to posting an image, people may even be able to quote and point out where you went wrong.



  • Thanks for the quick suggestions. I made some edits to the indicator and seem to have made it further along this time.

    Here is my code:

    from __future__ import (absolute_import, division, print_function, unicode_literals) 
    
    import backtrader as bt
    
    class OnBalanceVolume(bt.Indicator):
        lines = ('obv',)
        params = (('period', 1),)
        plotinfo = dict(subplot=False)  # plot in same axis as the data
        
        def __init__(self):
            self.x = self.data.volume
            self.lines.obv = bt.If(self.data.close(0) > self.data.close(-1), 
                (self.x + self.data.volume), 
                self.x - self.data.volume)
    
    

    The error now comes when I try to log my closing prices in the strategies file I also have.

    ~\Anaconda3\envs\Oanda v20\lib\site-packages\testStrategy\HighLowOBV.py in next(self)
         87     def next(self):
         88         # Simply log the closing price of the series from the reference
    ---> 89         self.log('Close, %.2f' % self.dataclose[0])
         90 
         91         # Check if an order is pending ... if yes, we cannot send a 2nd one
    
    TypeError: 'float' object is not subscriptable
    

    My guess is that this has something to do with self.x and how I want to save my volume sum/diff to it. The value of the data is a float rather than a subscriptable data feed.
    Please let me know if there is anymore info that I should be sharing!

    Thanks again,
    Tag



  • @tagteam69

    Hard to say something since no code defining self.dataclose are shown.


  • administrators

    @tagteam69 said in Need some help creating an On Balance Volume indicator:

    My guess is that this has something to do with self.x

    It doesn't seem so. Yo have a float in self.dataclose and you are trying to treat is as an array.

    @tagteam69 said in Need some help creating an On Balance Volume indicator:

    ---> 89         self.log('Close, %.2f' % self.dataclose[0])
         90 
         91         # Check if an order is pending ... if yes, we cannot send a 2nd one
    
    TypeError: 'float' object is not subscriptable
    

    As @ab_trader points out, we don't really know how you have defined self.dataclose and how you are managing it, so it is impossible to say why you have a float and are expecting an iterable

    @tagteam69 said in Need some help creating an On Balance Volume indicator:

        def __init__(self):
            self.x = self.data.volume
            self.lines.obv = bt.If(self.data.close(0) > self.data.close(-1), 
                (self.x + self.data.volume), 
                self.x - self.data.volume)
    

    In any case, using self.x doesn't seem useful (unless you need for something else we don't know) because:

    • self.x + self.data.volume is also 2.0 * self.data.volume

    and

    • self.x - self.data.volume is always 0.0

    The thing could simply be written as

    self.lines.obv = bt.If(bt.ind.UpDayBool(self.data), 2.0 * self.data.volume, 0.0)
    

    (This shows that there is a pre-canned indicator giving you the boolean you look for with self.data > self.data(-1), and it even takes a period parameter if you need a distance longer than 1)

    But this can be even simplified to:

    self.lines.obv = 2.0 * self.data.volume * (self.data > self.data(-1))
    

    Because if the current price is greater than the previous price the boolean will be a 1 in the multiplication and it will be a 0 if the price is not greater than the previous one.