RSI Levels, Multi-Timeframe
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © jmosullivan

// The relative strength index (RSI) is a momentum indicator that measures the magnitude of recent price changes to evaluate 
// overbought or oversold conditions. The RSI is normally displayed as an oscillator separately from price and can have a 
// reading from 0 to 100. This indicator takes the RSI and plots the 30 & 70 levels onto the price chart so you can see when 
// price is going to meet the 30 or 70 levels. The reason the 30 & 70 levels are important is because many traders (and bots)
// use those as signals to buy (at 30 RSI) or sell (at 70 RSI). Additionally, this indicator allows you to display not just 
// the RSI levels of your currently viewed timeframe on the chart, but also shows the RSI levels of up to 6 different 
// timeframes on the same chart. This allows you to quickly see if multiple RSI levels are aligning across different timelines,
// which is an even stronger indication that price is going to change direction when it meets those levels on the chart. There
// are a lot of nice configuration options, like:

//  * Style customization (color, thickness, size)
//  * Labels on the chart so you can tell which plots are the RSI levels
//  * Optionally display the plot as a horizontal line if all you care about is the RSI level right now
//  * Toggle overbought (RSI 70) or oversold (RSI 30) on/off completely

// Credit to @abdomi for the RSI Levels script, which inspired this one. That script only allows you to see RSI levels for your 
// current timeframe on your current timeframe.

//@version=5
indicator("RSI Lvls MTF", overlay = true)

// Functions
tf_toint(tf) =>
    int rtf = switch tf
    	"1" => 60
    	"2" => 120
    	"3" => 180
    	"5" => 300
    	"10" => 600
    	"13" => 780
    	"15" => 900
    	"30" => 1800
    	"45" => 2700
    	"60" => 3600
    	"120" => 7200
    	"180" => 10800
    	"240" => 14400
    	"360" => 21600
    	"480" => 28800
    	"720" => 43200
    	"1D" => 86400
    	"D" => 86400
    	"1W" => 604800
    	"W" => 604800
    	"1M" => 2592000
    	"M" => 2592000
    	=> 1 // default
    rtf

tfm_toint() =>
    int rtf = 0
    if (timeframe.isseconds)
        rtf := timeframe.multiplier
    if (timeframe.isminutes)
        rtf := timeframe.multiplier * 60
    if (timeframe.isdaily)
        rtf := timeframe.multiplier * 60 * 60 * 24
    if (timeframe.isweekly)
        rtf := timeframe.multiplier * 60 * 60 * 24 * 7
    if (timeframe.ismonthly)
        rtf := timeframe.multiplier * 60 * 60 * 24 * 30
    rtf
    
tf_tostring(tf) =>
    string rtf = switch tf
    	"1" => "1m"
    	"2" => "2m"
    	"3" => "3m"
    	"5" => "5m"
    	"13" => "13m"
    	"15" => "15m"
    	"30" => "30m"
    	"45" => "45m"
    	"60" => "1h"
    	"120" => "2h"
    	"180" => "3h"
    	"240" => "4h"
    	"360" => "6h"
    	"480" => "8h"
    	"720" => "12h"
    	"D" => "1D"
    	"W" => "1W"
    	"M" => "1M"
    	=> tf // default
    rtf

tf_str(tf, suffix) =>
    tf_tostring(tf) + " " + suffix

// Function to do the plotting (adapted from abdomi's script)
rsi_to_plot(tf, rsi_lvl, len) =>
    ep = 2 * len - 1
    auc = request.security(syminfo.tickerid, tf, ta.ema(math.max(close - close[1], 0), ep))
    adc = request.security(syminfo.tickerid, tf, ta.ema(math.max(close[1] - close, 0), ep))
    x = (len - 1) * ( adc * rsi_lvl / (100 - rsi_lvl) - auc)
    x >= 0 ? close + x : close + x * (100 - rsi_lvl) / rsi_lvl

// Configuration
grp_mn = "Global Line Settings"
length                  = input(       group=grp_mn, defval=14,    title="RSI Length")
linewidth               = input.int(   group=grp_mn, defval=1,     title="Line Weight",           options=[1,2,3,4])
lbl_txtsize             = input.string(group=grp_mn, defval=size.normal, title="Label Text Size", options=[size.auto, size.tiny, size.small, size.normal, size.large, size.huge])
lbl_offset              = input.int(   group=grp_mn, defval=4,     title="Label Offset",          minval=0, maxval=100)
show_labels             = input.bool(  group=grp_mn, defval=true,  title="Show Labels")
do_line                 = input.bool(  group=grp_mn, defval=false, title="Do Horizontal Lines")
do_ob                   = input.bool(  group=grp_mn, defval=true,  title="Show Overbought RSIs")
do_os                   = input.bool(  group=grp_mn, defval=true,  title="Show Oversold RSIs")

grp   = "Timeframe Visibility & Colors"
transparency = 50
show_1  = input.bool(defval=true, title="", inline="tf1", group=grp)
show_2  = input.bool(defval=true, title="", inline="tf2", group=grp)
show_3  = input.bool(defval=true, title="", inline="tf3", group=grp)
show_4  = input.bool(defval=true, title="", inline="tf4", group=grp)
show_5  = input.bool(defval=true, title="", inline="tf5", group=grp)
show_6  = input.bool(defval=true, title="", inline="tf6", group=grp)
tf_1    = input.timeframe(defval="5",   title="", inline="tf1", group=grp)
tf_2    = input.timeframe(defval="15",  title="", inline="tf2", group=grp)
tf_3    = input.timeframe(defval="60",  title="", inline="tf3", group=grp)
tf_4    = input.timeframe(defval="240", title="", inline="tf4", group=grp)
tf_5    = input.timeframe(defval="720", title="", inline="tf5", group=grp)
tf_6    = input.timeframe(defval="D",   title="", inline="tf6", group=grp)
color_1 = input.color(defval=color.new(color.lime, transparency),  title="", inline="tf1", group=grp)
color_2 = input.color(defval=color.new(color.green, transparency), title="", inline="tf2", group=grp)
color_3 = input.color(defval=color.new(color.aqua, transparency),  title="", inline="tf3", group=grp)
color_4 = input.color(defval=color.new(color.blue, transparency),  title="", inline="tf4", group=grp)
color_5 = input.color(defval=color.new(color.navy, transparency),  title="", inline="tf5", group=grp)
color_6 = input.color(defval=color.new(color.black, transparency), title="", inline="tf6", group=grp)

// Prevent TFs below the current TF to be shown (TV Calculates them incorrectly)
if tf_toint(tf_1) < tfm_toint()
    show_1 := false

if tf_toint(tf_2) < tfm_toint()
    show_2 := false

if tf_toint(tf_3) < tfm_toint()
    show_3 := false

if tf_toint(tf_4) < tfm_toint()
    show_4 := false

if tf_toint(tf_5) < tfm_toint()
    show_5 := false

if tf_toint(tf_6) < tfm_toint()
    show_6 := false

// Define the plots
rsi_1_30 = show_1 and do_os ? rsi_to_plot(tf_1, 30, length) : na
rsi_1_70 = show_1 and do_ob ? rsi_to_plot(tf_1, 70, length) : na
rsi_2_30 = show_2 and do_os ? rsi_to_plot(tf_2, 30, length) : na
rsi_2_70 = show_2 and do_ob ? rsi_to_plot(tf_2, 70, length) : na
rsi_3_30 = show_3 and do_os ? rsi_to_plot(tf_3, 30, length) : na
rsi_3_70 = show_3 and do_ob ? rsi_to_plot(tf_3, 70, length) : na
rsi_4_30 = show_4 and do_os ? rsi_to_plot(tf_4, 30, length) : na
rsi_4_70 = show_4 and do_ob ? rsi_to_plot(tf_4, 70, length) : na
rsi_5_30 = show_5 and do_os ? rsi_to_plot(tf_5, 30, length) : na
rsi_5_70 = show_5 and do_ob ? rsi_to_plot(tf_5, 70, length) : na
rsi_6_30 = show_6 and do_os ? rsi_to_plot(tf_6, 30, length) : na
rsi_6_70 = show_6 and do_ob ? rsi_to_plot(tf_6, 70, length) : na

plot_offset = do_line ? -9999 : 0

// Plot them
plot(rsi_1_30, title="30 RSI Level 1", color=color_1, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)
plot(rsi_1_70, title="70 RSI Level 1", color=color_1, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)
plot(rsi_2_30, title="30 RSI Level 2", color=color_2, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)
plot(rsi_2_70, title="70 RSI Level 2", color=color_2, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)
plot(rsi_3_30, title="30 RSI Level 3", color=color_3, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)
plot(rsi_3_70, title="70 RSI Level 3", color=color_3, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)
plot(rsi_4_30, title="30 RSI Level 4", color=color_4, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)
plot(rsi_4_70, title="70 RSI Level 4", color=color_4, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)
plot(rsi_5_30, title="30 RSI Level 5", color=color_5, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)
plot(rsi_5_70, title="70 RSI Level 5", color=color_5, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)
plot(rsi_6_30, title="30 RSI Level 6", color=color_6, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)
plot(rsi_6_70, title="70 RSI Level 6", color=color_6, editable=false, trackprice=do_line, offset=plot_offset, linewidth=linewidth)

// Labels
do_label(do_lbl, ix_loc, src, txt, txtsize, clr) =>
    if (do_lbl)
        var label lbl = na
        label.delete(lbl)
        lbl := label.new(x=ix_loc, y=src, text=txt, style=label.style_none, textcolor=clr, size=txtsize, textalign=text.align_left)

if show_labels
    os="OS"
    ob="OB"
    do_label(show_1, bar_index[0] + lbl_offset, rsi_1_30, tf_str(tf_1, os), lbl_txtsize, color_1)
    do_label(show_1, bar_index[0] + lbl_offset, rsi_1_70, tf_str(tf_1, ob), lbl_txtsize, color_1)
    do_label(show_2, bar_index[0] + lbl_offset, rsi_2_30, tf_str(tf_2, os), lbl_txtsize, color_2)
    do_label(show_2, bar_index[0] + lbl_offset, rsi_2_70, tf_str(tf_2, ob), lbl_txtsize, color_2)
    do_label(show_3, bar_index[0] + lbl_offset, rsi_3_30, tf_str(tf_3, os), lbl_txtsize, color_3)
    do_label(show_3, bar_index[0] + lbl_offset, rsi_3_70, tf_str(tf_3, ob), lbl_txtsize, color_3)
    do_label(show_4, bar_index[0] + lbl_offset, rsi_4_30, tf_str(tf_4, os), lbl_txtsize, color_4)
    do_label(show_4, bar_index[0] + lbl_offset, rsi_4_70, tf_str(tf_4, ob), lbl_txtsize, color_4)
    do_label(show_5, bar_index[0] + lbl_offset, rsi_5_30, tf_str(tf_5, os), lbl_txtsize, color_5)
    do_label(show_5, bar_index[0] + lbl_offset, rsi_5_70, tf_str(tf_5, ob), lbl_txtsize, color_5)
    do_label(show_6, bar_index[0] + lbl_offset, rsi_6_30, tf_str(tf_6, os), lbl_txtsize, color_6)
    do_label(show_6, bar_index[0] + lbl_offset, rsi_6_70, tf_str(tf_6, ob), lbl_txtsize, color_6)
    