RSI - Dynamic Overbought/Oversold Range
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © HeWhoMustNotBeNamed

//   __    __            __       __  __                  __       __                        __      __    __              __      _______             __    __                                          __ 
//  /  |  /  |          /  |  _  /  |/  |                /  \     /  |                      /  |    /  \  /  |            /  |    /       \           /  \  /  |                                        /  |
//  $$ |  $$ |  ______  $$ | / \ $$ |$$ |____    ______  $$  \   /$$ | __    __   _______  _$$ |_   $$  \ $$ |  ______   _$$ |_   $$$$$$$  |  ______  $$  \ $$ |  ______   _____  ____    ______    ____$$ |
//  $$ |__$$ | /      \ $$ |/$  \$$ |$$      \  /      \ $$$  \ /$$$ |/  |  /  | /       |/ $$   |  $$$  \$$ | /      \ / $$   |  $$ |__$$ | /      \ $$$  \$$ | /      \ /     \/    \  /      \  /    $$ |
//  $$    $$ |/$$$$$$  |$$ /$$$  $$ |$$$$$$$  |/$$$$$$  |$$$$  /$$$$ |$$ |  $$ |/$$$$$$$/ $$$$$$/   $$$$  $$ |/$$$$$$  |$$$$$$/   $$    $$< /$$$$$$  |$$$$  $$ | $$$$$$  |$$$$$$ $$$$  |/$$$$$$  |/$$$$$$$ |
//  $$$$$$$$ |$$    $$ |$$ $$/$$ $$ |$$ |  $$ |$$ |  $$ |$$ $$ $$/$$ |$$ |  $$ |$$      \   $$ | __ $$ $$ $$ |$$ |  $$ |  $$ | __ $$$$$$$  |$$    $$ |$$ $$ $$ | /    $$ |$$ | $$ | $$ |$$    $$ |$$ |  $$ |
//  $$ |  $$ |$$$$$$$$/ $$$$/  $$$$ |$$ |  $$ |$$ \__$$ |$$ |$$$/ $$ |$$ \__$$ | $$$$$$  |  $$ |/  |$$ |$$$$ |$$ \__$$ |  $$ |/  |$$ |__$$ |$$$$$$$$/ $$ |$$$$ |/$$$$$$$ |$$ | $$ | $$ |$$$$$$$$/ $$ \__$$ |
//  $$ |  $$ |$$       |$$$/    $$$ |$$ |  $$ |$$    $$/ $$ | $/  $$ |$$    $$/ /     $$/   $$  $$/ $$ | $$$ |$$    $$/   $$  $$/ $$    $$/ $$       |$$ | $$$ |$$    $$ |$$ | $$ | $$ |$$       |$$    $$ |
//  $$/   $$/  $$$$$$$/ $$/      $$/ $$/   $$/  $$$$$$/  $$/      $$/  $$$$$$/  $$$$$$$/     $$$$/  $$/   $$/  $$$$$$/     $$$$/  $$$$$$$/   $$$$$$$/ $$/   $$/  $$$$$$$/ $$/  $$/  $$/  $$$$$$$/  $$$$$$$/ 
//                                                                                                                                                                                                          
//                                                                                                                                                                                                          
//
//@version=5
indicator('RSI - Dynamic Overbought/Oversold Range', shorttitle='RSI-DR')
resolution = input.timeframe('', title='Resolution', group='RSI')
source = input.source(close, title='Source', group='RSI')
length = input.int(14, title='Length', group='RSI')
repaint = input.bool(true, title='Repaint', group='RSI')
stickToRange = input.bool(true, title='Sticky Range', group='RSI')
method = input.string('highlow', title='Detection Method', group='Overbought/Oversold Range', options=['highlow', 'sma', 'ema', 'rma', 'hma', 'wma', 'vwma', 'swma'])
rangeLength = input.int(50, step=10, title='Length', group='Overbought/Oversold Range')

f_security(_sym, _res, _src, _rep) =>
    request.security(_sym, _res, _src[not _rep and barstate.isrealtime ? 1 : 0])[_rep or barstate.isrealtime ? 0 : 1]

f_get_ma(source, method, rangeLength) =>
    method == 'sma' ? ta.sma(source, rangeLength) : method == 'ema' ? ta.ema(source, rangeLength) : method == 'rma' ? ta.rma(source, rangeLength) : method == 'hma' ? ta.hma(source, rangeLength) : method == 'wma' ? ta.wma(source, rangeLength) : method == 'vwma' ? ta.vwma(source, rangeLength) : method == 'swma' ? ta.swma(source) : method == 'high' ? ta.highest(source, rangeLength) : method == 'low' ? ta.lowest(source, rangeLength) : na

f_rsi_high(source, length, method, rangeLength) =>
    f_get_ma(ta.highest(ta.rsi(source, length), rangeLength), method == 'highlow' ? 'low' : method, length)

f_rsi_low(source, length, method, rangeLength) =>
    f_get_ma(ta.lowest(ta.rsi(source, length), rangeLength), method == 'highlow' ? 'high' : method, length)

rsi = f_security(syminfo.tickerid, resolution, ta.rsi(source, length), repaint)
rsiHigh = f_security(syminfo.tickerid, resolution, f_rsi_high(source, length, method, rangeLength), repaint)
rsiLow = f_security(syminfo.tickerid, resolution, f_rsi_low(source, length, method, rangeLength), repaint)

highCrossover = rsi[1] >= rsiHigh[1]
lowCrossover = rsi[1] <= rsiLow[1]

if stickToRange and not(highCrossover or lowCrossover)
    rsiHigh := nz(rsiHigh[1], rsiHigh)
    rsiLow := nz(rsiLow[1], rsiLow)
    rsiLow

plot(rsi, title='RSI', color=color.new(color.blue, 0))
plot(rsiHigh, title='Overbought', color=color.new(color.red, 0))
plot(rsiLow, title='Oversold', color=color.new(color.green, 0))

