loxxvarietyrsi
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © loxx

//@version=5

// @description RSI Variety
//  7 varieties of RSI used in Loxx's indicators and strategies.
//  "rsi_rsi" is regular ta.rsi()
//  "rsi_slo" is slowed down version of regular RSI
//  "rsi_rap" is ta.rsi() but uses SMA instead of RMA, this is the same as Cuttlers RSI
//  "rsi_har" is Michael Harris RSI, but a word of "warning". I left the Harris' rsi in the choices of rsi, 
//      but be advised that, due to the way how Harris rsi is calculated, 
//      if price filtering is used (ie: some randomness is taken away from price series) 
//      Harris RSI tends to produce results that can be "surprising" at the least in some cases. 
//      Even though Harris RSI is good when it comes to natural (semi-random) price usage, 
//      keep in mind what happens if the prices are filtered and why it happens
//  "rsi_rsx" is Jurik's RSX
//  "rsi_cut" is ta.rsi() but uses SMA instead of RMA, this is the same as Rapid RSI 
//  "rsi_ehl" is Ehles' Smoothed RSI

library("loxxvarietyrsi")
import loxx/loxxrsx/1

// @function method for returning 1 of 7 different RSI calculation outputs.
// @param rsiMode string, rsi mode, can be 1 of 7 of the following: "rsi_rsi", "rsi_slo", "rsi_rap", "rsi_har", "rsi_rsx", "rsi_cut", "rsi_ehl"; defaults to "rsi_rsi"
// @param src float, source, either regular source type or some other caculated value.
// @param per int, period lookback.
// @returns float RSI.
// usage:
//      rsiVariety("rsi_rsi", src, per)
export rsiVariety(string rsiMode = "rsi_rsi", float src, int per)=>
    out = 0.
    float _change = 0.
    float _changa = 0.
    switch (rsiMode)
        //Regular RSI, same as ta.rsi(src, per)
        "rsi_rsi"=>
            float alpha = 1.0/math.max(per, 1)
            float change = src - nz(src[1])
            _change := nz(_change[1]) + alpha * (change  - nz(_change[1]) )
            _changa := nz(_changa[1]) + alpha * (math.abs(change) - nz(_changa[1]))
            out := _changa != 0. ? 50.0 * (_change/_changa + 1) : 50.
        // Slow RSI
        "rsi_slo"=>
            float up = 0., float dn = 0., float _rsival = 0.
            for k = 0 to per - 1
                float diff = nz(src[k]) - nz(src[k+1]) 
                if(diff > 0.)
                    up += diff
                else  
                    dn -= diff
            if(up + dn == 0.)
                _rsival := nz(_rsival[1]) + (1 / math.max(per, 1)) * (50 - nz(_rsival[1]))
            else  
                _rsival := nz(_rsival[1]) + (1 / math.max(per, 1)) * (100 * up / (up + dn) - nz(_rsival[1]))
            out := _rsival
        // Rapid RSI, same as Cuttlers RSI
        "rsi_rap"=>
            float up = 0., float dn = 0.
            for k = 0 to per - 1
                float diff = nz(src[k]) - nz(src[k+1]) 
                if(diff > 0.)
                    up += diff
                else  
                    dn -= diff
            out := up + dn == 0. ? 50. : 100 * up / (up + dn)  
        // Harris RSI
        "rsi_har"=>
            float avgUp = 0., float avgDn = 0., float up = 0., float dn = 0.
            for k = 0 to per - 1
                float diff = nz(src[k]) - nz(src[k+1]) 
                if(diff > 0.)  
                    avgUp += diff 
                    up := up + 1
                else   
                    avgDn -= diff 
                    dn := dn + 1
            if (up != 0.) 
                avgUp /= up
            if (dn != 0.) 
                avgDn /= dn
            float rs = 1
            rs := avgDn != 0. ? avgUp / avgDn : rs
            out := 100-100 / (1.0 + rs)
        // RSX RSI      
        "rsi_rsx"=>
            out := loxxrsx.rsx(src, per)
        // Cuttlers RSI, same as Rapid RSI
        "rsi_cut"=>
            float sump = 0., float sumn = 0.
            for k = 0 to per - 1
                float diff = nz(src[k]) - nz(src[k+1]) 
                if (diff > 0.) 
                    sump += diff
                if (diff < 0.) 
                    sumn -= diff
            out := sumn > 0. ? 100. - 100. / (1. + sump / sumn) : 50.
        //Ehlers' Smoothed RSI
        "rsi_ehl"=>
            float up = 0., float dn = 0.
            _prices = (bar_index > 2) ? (src + 2. * src[1] + src[2]) / 4.0 : src
            for k = 0 to per - 1
                float diff = nz(_prices[k]) - nz(_prices[k+1]) 
                if(diff > 0.)
                    up += diff
                else  
                    dn -= diff
            out := 50 * (up-dn) / (up+dn) + 50
        => 0.
    out
  
//example usage

src = close
per = 15

rsi_rsi = rsiVariety("rsi_rsi", src, per)
rsi_slo = rsiVariety("rsi_slo", src, per)
rsi_rap = rsiVariety("rsi_rap", src, per)
rsi_har = rsiVariety("rsi_har", src, per)
rsi_rsx = rsiVariety("rsi_rsx", src, per)
rsi_cut = rsiVariety("rsi_cut", src, per)
rsi_ehl = rsiVariety("rsi_ehl", src, per)

plot(rsi_rsi, "Regular RSI", color = color.white)
plot(rsi_slo, "Slow RSI", color = color.lime)
plot(rsi_rap, "Rapid RSI", color = color.red)
plot(rsi_rsx, "RSX RSI", color = color.fuchsia)
plot(rsi_har, "Harris RSI", color = color.yellow)
plot(rsi_cut, "Cuttlers RSI", color = color.aqua)
plot(rsi_ehl, "Ehlers' Smoothed RSI", color = color.gray)

plot(50., color = bar_index % 2 ? color.white : na)
