Adaptive RSI/Stochastic (ARSIS)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © peacefulLizard50262

//@version=5
indicator("Adaptive RSI/Stochastic")
import lastguru/DominantCycle/2 as d

bes(float source = close, float length = 9)=>
    alpha = 2 / (length + 1)
    var float smoothed = na
    smoothed := alpha * source + (1 - alpha) * nz(smoothed[1])

rsi_count()=>
    high_length = d.mamaPeriod(high, 2, 4096)
    low_length = d.mamaPeriod(low, 2, 4096)
    high_filtered = bes(high, high_length)
    low_filtered = bes(low, low_length)
    change_high = ta.change(high_filtered)
    change_low = -ta.change(low_filtered)
    // Variables
    upMoves = ta.change(high_filtered) > 0 ? change_high : 0
    downMoves = ta.change(low_filtered) < 0 ? change_low : 0
    // Up/down move averages
    upMovesLength = d.mamaPeriod(upMoves, 2, 4096)
    downMovesLength = d.mamaPeriod(downMoves, 2, 4096)
    upAvg = bes(upMoves, upMovesLength)
    downAvg = bes(downMoves, downMovesLength)
    // RSI calculation
    rsi = downAvg != 0 ? 100 - (100 / (1 + upAvg / downAvg)) : 0   

rsi_standard()=>
    close_length = d.mamaPeriod(close, 2, 4096)
    close_filtered = bes(close, close_length)
    up = math.max(ta.change(close_filtered), 0)
    down = -math.min(ta.change(close_filtered), 0)
    up_length = d.mamaPeriod(up, 2, 4096)
    down_length = d.mamaPeriod(down, 2, 4096)
    up_filtered = bes(up, up_length)
    down_filtered = bes(down, down_length)
    rsi = down_filtered == 0 ? 100 : 100 - (100 / (1 + up_filtered / down_filtered))

stochastic(length, smoothing)=>
    close_length = d.mamaPeriod(close, 2, 4096)
    high_length = d.mamaPeriod(high, 2, 4096)
    low_length = d.mamaPeriod(low, 2, 4096)
    close_filtered = bes(close, close_length)
    high_filtered = bes(high, high_length)
    low_filtered = bes(low, low_length)

    stochastic = ta.sma(100 * (close_filtered - ta.lowest(low_filtered, length)) / (ta.highest(high_filtered, length) - ta.lowest(low_filtered, length)), smoothing)
    stochastic_length = d.mamaPeriod(stochastic, 2, 4096)
    stochastic_d = bes(stochastic, stochastic_length)
    [stochastic, stochastic_d]

rsi(select)=>
    switch select
        "Standard RSI" => rsi_standard()
        "Count RSI"    => rsi_count()
        "Stochastic"   => na

select = input.string("Standard RSI", "Select Style", ["Standard RSI","Count RSI","Stochastic"])
smoothing = input.int(1, "Smoothing", 1)
length = input.int(14, "Length", 1, tooltip = "Only avalible for Stochastic.")


rsi = bes(rsi(select), smoothing)
rsi_length = d.mamaPeriod(rsi, 2, 4096)
rsi_smooth = bes(rsi, rsi_length)
[stochastic, stochastic_d] = stochastic(length, smoothing)

colour = color.from_gradient(select == "Stochastic" ? stochastic : rsi, 0, 100, color.new(color.navy, 80), color.new(color.purple, 80))

up_line = hline(20)
hline(50)
dn_line = hline(80)
fill(up_line, dn_line, color = colour)
plot(select == "Stochastic" ? stochastic : rsi, "RSI", color.blue)
plot(select == "Stochastic" ? stochastic_d : rsi_smooth, "MA", color.orange)
