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

Would appreciate some help with Connors RSI



  • Hi,

    I'm new to backorder and new to python, so please bare with me.
    I'm trying to implement an indicator for the ConnorsRSI. At a certain point in the algorithm I need to take the RSI of a line that I create, and it gives me back nan instead of an rsi value. I have no clue where I go wrong, and hope that somebody can point me in the right direction.
    Please feel free to give other hints and tips if I make obvious coding mistakes.
    The code for the indicator itself is:

    class ConnorsRSI(bt.Indicator):
        lines = ('crsi','rsi','streak','streak_rsi', 'prank')
        params = (
            ('rsi_length', 3),
            ('streak_length', 2),
            ('loopback_length', 100),
        )
    
        plotlines = dict(
            obv=dict(
                _name='crsi',
                color='purple',
                alpha=0.50
            )
        )
    
        def updown(self):
            upday=False
            downday=False
    
            if self.data[0] > self.data[-1]:
                upday = True
            else:
                upday = False
    
            if self.data[0] < self.data[-1]:
                downday = True
            else:
                downday = False
    
            if upday and self.lines.streak[-1] >= 0:
                self.lines.streak[0] = self.lines.streak[-1] + 1
            elif upday and self.lines.streak[-1] <= 0:
                self.lines.streak[0] = 1
            elif downday and self.lines.streak[-1] <= 0:
                self.lines.streak[0] = self.lines.streak[-1] - 1
            elif downday and self.lines.streak[-1] >= 0:
                self.lines.streak[0] = -1
            elif self.data[0] == self.data[-1]:
                self.lines.streak[0] = 0
            else:
                self.lines.streak[0] = 0
    
        def __init__(self):
    
            # Plot a horizontal Line
            self.plotinfo.plotyhlines = [0]
    
            self.lines.rsi = bt.indicators.RSI(self.data, period=self.params.rsi_length)
            self.lines.prank = bt.indicators.PercentRank(self.data, period=self.params.loopback_length)
    
        def next(self):
            self.updown()
            self.lines.streak_rsi = bt.indicators.RSI(self.lines.streak, period=self.params.streak_length)
    
    
        def nextstart(self):
            self.lines.streak[0] = 0
    

    The issue is in the 'next', where I calculate (or want to calculate) the RSI value over the streaks. The output I get is:

    2016-05-25: Prev: 48.76: Close: 49.26, rsi: 79.21353438233095 Streak: 0.0 Streak_rsi: nan PercentRank: 59
    2016-05-26: Prev: 49.26: Close: 49.04, rsi: 68.50800494096566 Streak: -1.0 Streak_rsi: nan PercentRank: 56
    2016-05-27: Prev: 49.04: Close: 49.45, rsi: 77.14326450516853 Streak: 1.0 Streak_rsi: nan PercentRank: 64
    2016-05-31: Prev: 49.45: Close: 50.09, rsi: 86.08028735088246 Streak: 2.0 Streak_rsi: nan PercentRank: 70
    2016-06-01: Prev: 50.09: Close: 49.95, rsi: 76.29219423676898 Streak: -1.0 Streak_rsi: nan PercentRank: 69
    2016-06-02: Prev: 49.95: Close: 49.6, rsi: 53.48552312948757 Streak: -2.0 Streak_rsi: nan PercentRank: 65
    2016-06-03: Prev: 49.6: Close: 48.95, rsi: 29.183093574328538 Streak: -3.0 Streak_rsi: nan PercentRank: 52
    2016-06-06: Prev: 48.95: Close: 49.27, rsi: 46.97498518905785 Streak: 1.0 Streak_rsi: nan PercentRank: 57
    2016-06-07: Prev: 49.27: Close: 49.24, rsi: 45.37197817316539 Streak: -1.0 Streak_rsi: nan PercentRank: 56
    2016-06-08: Prev: 49.24: Close: 49.18, rsi: 41.15842240824419 Streak: -2.0 Streak_rsi: nan PercentRank: 55
    

    Thanks!



  • You can't do this

    self.lines.streak_rsi = bt.indicators.RSI(self.lines.streak, period=self.params.streak_length)
    

    in the next(), only in __init()__.

    As a solution you may want to bring all calculations into the init() and use bt RSI or calculate RSI in the next() by yourself based on [x] notations. Or apply RSI to streak in a separate indicator.



  • @ab_trader thanks for looking into this. I changed the code as below (calculating the RSI myself in the init(), but still getting the rsi over the streak back as a nan. Is this not what you meant?

    class ConnorsRSI(bt.Indicator):
        lines = ('crsi','rsi','streak', 'streak_rsi','prank')
        params = (
            ('rsi_length', 3),
            ('streak_length', 2),
            ('loopback_length', 100),
        )
    
        plotlines = dict(
            obv=dict(
                _name='crsi',
                color='purple',
                alpha=0.50
            )
        )
    
        def updown(self):
            upday=False
            downday=False
    
            if self.data[0] > self.data[-1]:
                upday = True
            else:
                upday = False
    
            if self.data[0] < self.data[-1]:
                downday = True
            else:
                downday = False
    
            if upday and self.lines.streak[-1] >= 0:
                self.lines.streak[0] = self.lines.streak[-1] + 1
            elif upday and self.lines.streak[-1] <= 0:
                self.lines.streak[0] = 1
            elif downday and self.lines.streak[-1] <= 0:
                self.lines.streak[0] = self.lines.streak[-1] - 1
            elif downday and self.lines.streak[-1] >= 0:
                self.lines.streak[0] = -1
            elif self.data[0] == self.data[-1]:
                self.lines.streak[0] = 0
            else:
                self.lines.streak[0] = 0
    
        def __init__(self):
    
            # Plot a horizontal Line
            self.plotinfo.plotyhlines = [0]
    
            self.lines.rsi = bt.indicators.RSI(self.data, period=self.params.rsi_length)
            self.lines.prank = bt.indicators.PercentRank(self.data, period=self.params.loopback_length)
    
            # calculate rsi over streak
            upday = bt.indicators.UpDay(self.lines.streak, period=self.params.streak_length)
            downday = bt.indicators.DownDay(self.lines.streak, period=self.params.streak_length)
            maup = bt.indicators.MovAv.Smoothed(upday, period=self.params.streak_length)
            madown = bt.indicators.MovAv.Smoothed(downday, period=self.params.streak_length)
            rs = maup / madown
            self.lines.streak_rsi = 100.0 - 100.0 / (1.0 + rs)
    
    
        def next(self):
            self.updown()
    
        def nextstart(self):
            self.lines.streak[0] = 0
    

    Thanks for your support!



  • @Rudi

    UpDay and DownDay indicators are applied to undefined self.lines.streak. I am not surprised that result is nan.

    You may want go deeper into code debugging by yourself with the logging of all interim calculations. Your indicator seems recursive, so this blog post might help

    Developing a Recursive Indicator (with a seed)


  • administrators



  • Brilliant @backtrader ! I'll make sure to add indicators once I get the hang of creating them!