pythonindicatorrsi

Review RSI function - Python


does this RSI code looks correct for you? RSI I'm getting with this code are very often touching oscillator peaks (0 or 100) when comparing to RSIs on different market data apps (TradingView etc.) they hardly ever do that.

Does this formula looks correct? I found it in quite old book Technical Traders Guide to Computer Analysis of the Futures Market. Also it returns almost identical results as RSI=100-(100-RS) where RS=AVG GAIN/AVG LOSS. But still I'm a bit mad that results are different comparing to RSIs available on the web...

# 
# Formula used:
#
# RSI(n) = 100 * (avg_up(n) / (avg_up(n)+avg_down(n)))
#
# Where:
#
# avg_up = average percentage gain from n-periods
# avg_down = average percentage loss from n-periods
# n = number of periods to calculate averages
#

def calculate_percentage_gains_and_losses(prices):
    
    percentage = {"gains":[0.0],
                  "losses":[0.0]}

    for i in range(len(prices)-1):
        
        diff=((float(prices[i + 1]) / float(prices[i]))*100)-100
        
        if diff>=0:
            percentage["gains"].append(diff)
            percentage["losses"].append(0.0)
        else:
            percentage["losses"].append(abs(diff))
            percentage["gains"].append(0.0)

    return percentage

def calculate_avg_percentage_gains_and_losses(prices, gains, losses, periods):

    avg_percentage = {"gains":[ 0.0 for x in range(periods - 1)], 
                      "losses":[ 0.0 for x in range(periods - 1)]}

    for i in range(periods,len(prices)+1):
            avg_percentage["gains"].append(sum(gains[i - periods:i]) / periods)
            avg_percentage["losses"].append(sum(losses[i - periods:i]) / periods)

    return avg_percentage

def calculate_relative_strength_index(prices, periods):

    percentage = calculate_percentage_gains_and_losses(prices)
    avg_percentage = calculate_avg_percentage_gains_and_losses(prices, percentage["gains"], percentage["losses"], periods)
    rsi_list=[0.0 for x in range(periods - 1)]

    for i in range(periods - 1, len(prices)):
        rsi = 100 * round((avg_percentage["gains"][i] / (avg_percentage["gains"][i] + avg_percentage["losses"][i])), 2)
        rsi_list.append(rsi)

    return rsi_list

EDIT Here is the code after adjustment

def calculate_percentage_gains_and_losses(prices):
    
    percentage = {"gains":[0.0],
                  "losses":[0.0]}

    for i in range(len(prices)-1):
        
        diff=((float(prices[i + 1]) / float(prices[i]))*100)-100
        
        if diff>=0:
            percentage["gains"].append(diff)
            percentage["losses"].append(0.0)
        else:
            percentage["losses"].append(abs(diff))
            percentage["gains"].append(0.0)

    return percentage

def calculate_smoothed_avg_percentage_gains_and_losses(prices, gains, losses, periods):

    avg_percentage = {"gains":[ 0.0 if i<(periods-1) else sum(gains[:periods]) / periods for i in range(periods)], 
                      "losses":[ 0.0 if i<(periods-1) else sum(losses[:periods]) / periods for i in range(periods)]}

    for i in range(periods, len(prices)):
        avg_percentage["gains"].append((gains[i] + (avg_percentage["gains"][i-1]* (periods-1))) / periods)
        avg_percentage["losses"].append((losses[i] + (avg_percentage["losses"][i-1]* (periods-1))) / periods)

    return avg_percentage

def calculate_relative_strength_index(prices, periods):

    percentage = calculate_percentage_gains_and_losses(prices)
    avg_percentage = calculate_smoothed_avg_percentage_gains_and_losses(prices, percentage["gains"], percentage["losses"], periods)
    rsi=[ 0.0 if i < (periods-1) else round((100 * (avg_percentage["gains"][i] / (avg_percentage["gains"][i] + avg_percentage["losses"][i]))),2) for i in range(len(prices))]

    return rsi

Solution

  • Firstly, issues with formula: your RSI formula is calculated differently to the usual. As you acknowledge, RS is normally calculated as (Avg gains)/(Avg losses) yet you use (Avg gains)/((Avg gains) + (Avg losses)). While there may be strong correlation between the two, they are two different formulas and will therefore give you different answers. Furthermore you use percentage gains/losses when most charting platforms use raw gains/losses. And finally, you use a simple average of the gains/losses (known as Cutler's RSI). The much more widely used Wells Wilder RSI uses a smoothed average given by: Avg gain = (gain + (prev gain) * (period -1))/period The upshot is you will get very different numbers.

    Secondly, your code: While I have not scrutinized your code with a fine tooth comb, there are several issues rendering the code, at best, inefficient. If you intend on continuing to code in Python you MUST learn AND understand list comprehension and how to use it. It is what makes Python so useful and powerful. You have used it merely to initialize some lists. There are many websites and books that cover list comprehension quite extensively, just google it. Additionally, if you intend to use python to calculate series information on chronologically ordered data, I strongly recommend you import the pandas module and use DataFrames rather than lists. DataFrames are like database records that keeps all data neatly in the row they belong two and are easily manipulated. List will get messy as you try to line up the data.

    I will not provide code at this point because I think you already have plenty to think a bout and work on but will happily help once you have understood the above.