MTF Fantastic Stochastic (FS+)
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © tvenn

//@version=5
indicator(title="MTF Fantastic Stochastic (FS+)", shorttitle="FS+", overlay = true, max_bars_back = 1000, max_lines_count = 400, max_labels_count = 400)

//=Constants
green = #95BD5F
red = #EA1889

// =MTF Stoch
//==================================================================================================================================
grp_MTFSRSI = "MTF Stoch RSI"
smoothK     = input.int(3, "K", minval=1, group=grp_MTFSRSI)
smoothD     = input.int(3, "D", minval=1, group=grp_MTFSRSI)
lengthRSI   = input.int(14, "RSI Length", minval=1, group=grp_MTFSRSI)
lengthStoch = input.int(14, "Stochastic Length", minval=1, group=grp_MTFSRSI)
rsi1        = ta.rsi(close, lengthRSI)
k           = ta.sma(ta.stoch(rsi1, rsi1, rsi1, lengthStoch), smoothK)
d           = ta.sma(k, smoothD)


grp_CTFSRSI1         = "Show current timeframe OB/OS in ribbon"
includeCurrentTFOBOS = input(false, title="Show current timeframe OB/OS in ribbon", group=grp_CTFSRSI1, tooltip="this will include in the ribbon indications where the Stoch RSI is overbought or oversold on the current timeframe")
CTF_1                 = input.string("Chart", title="CTF", options=["Chart"], group=grp_CTFSRSI1, inline="tf1")
CTF_OSTHRESH_1        = input(20, title="", group=grp_CTFSRSI1, inline="tf1")
CTF_OBTHRESH_1        = input(80, title="", group=grp_CTFSRSI1, inline="tf1")


//Primary MTF Stoch RSI confluences
grp_MTFSRSI1             = "MTF Stoch RSI #1"
enableOBOS_1             = input(true, title="Show MTF #1 Stoch RSI OB/OS in ribbon", group=grp_MTFSRSI1, tooltip="This will color a ribbon on the chart to indicate where the MTF Stoch RSI is oversold and overbought.")
useBgColorMTFStochOBOS_1 = input(true, title="Color background where MTF #1 Stoch RSI OB/OS", group=grp_MTFSRSI1, tooltip="This will color the background of the chart to indicate where the MTF Stoch RSI is oversold and overbought.")
useBarColorMTFStochOBOS_1 = input(false, title="Color candles where MTF #1 Stoch RSI OB/OS", group=grp_MTFSRSI1, tooltip="This will color the candles on the chart to indicate where the MTF Stoch RSI is oversold and overbought.")
overboughtColor_1        = input.color(red, title="Stoch overbought color", group=grp_MTFSRSI1)
oversoldColor_1          = input.color(green, title="Stoch oversold color", group=grp_MTFSRSI1)


grp_MTFSRSI1_ = "Stoch RSI MTF #1 [Timeframe] [OS level] [OB level]"
TF_1 = input.string("1", title="TF1", options=["Chart", "1", "2", "3", "4", "5", "8", "10", "15", "20", "30", "45", "60", "120", "240"], group=grp_MTFSRSI1_, inline="mtf1")
TF_2 = input.string("5", title="TF2", options=["Chart", "1", "2", "3", "4", "5", "8", "10", "15", "20", "30", "45", "60", "120", "240"], group=grp_MTFSRSI1_, inline="mtf2")
TF_3 = input.string("15", title="TF3", options=["Chart", "1", "2", "3", "4", "5", "8", "10", "15", "20", "30", "45", "60", "120", "240"], group=grp_MTFSRSI1_, inline="mtf3")

MTF_OSTHRESH_1 = input(20, title="", group=grp_MTFSRSI1_, inline="mtf1")
MTF_OSTHRESH_2 = input(20, title="", group=grp_MTFSRSI1_, inline="mtf2")
MTF_OSTHRESH_3 = input(20, title="", group=grp_MTFSRSI1_, inline="mtf3")

MTF_OBTHRESH_1 = input(80, title="", group=grp_MTFSRSI1_, inline="mtf1")
MTF_OBTHRESH_2 = input(80, title="", group=grp_MTFSRSI1_, inline="mtf2")
MTF_OBTHRESH_3 = input(80, title="", group=grp_MTFSRSI1_, inline="mtf3")


MTF1 = request.security(syminfo.tickerid, TF_1 == "Chart" ? "" : TF_1, k, barmerge.gaps_off)
MTF2 = request.security(syminfo.tickerid, TF_2 == "Chart" ? "" : TF_2, k, barmerge.gaps_off)
MTF3 = request.security(syminfo.tickerid, TF_3 == "Chart" ? "" : TF_3, k, barmerge.gaps_off)

allMTFStochOB_1 = (MTF1 > MTF_OBTHRESH_1 and MTF2 > MTF_OBTHRESH_2 and MTF3 > MTF_OBTHRESH_3)
allMTFStochOS_1 = (MTF1 < MTF_OSTHRESH_1 and MTF2 < MTF_OSTHRESH_2 and MTF3 < MTF_OSTHRESH_3)

obColor_1 = (k > CTF_OBTHRESH_1+10 ? color.new(overboughtColor_1, 50) : enableOBOS_1 and k > CTF_OBTHRESH_1 ? color.new(overboughtColor_1, 70) : na)
osColor_1 = (k < CTF_OSTHRESH_1-10 ? color.new(oversoldColor_1, 50) : enableOBOS_1 and k < CTF_OSTHRESH_1 ? color.new(oversoldColor_1, 70) : na)

allOBColor_1 = (allMTFStochOB_1 ? overboughtColor_1 : na)
allOSColor_1 = (allMTFStochOS_1 ? oversoldColor_1 : na)

plotchar(k, title="Current TF SRSI overbought", color=(includeCurrentTFOBOS ? obColor_1 : na), char="■", location=location.bottom)
plotchar(k, title="Current TF SRSI oversold", color=(includeCurrentTFOBOS ? osColor_1 : na), char="■", location=location.bottom)
plotchar(k, title="3x TF all overbought", color=(enableOBOS_1 ? allOBColor_1 : na), char="■", location=location.bottom)
plotchar(k, title="3x TF all oversold", color=(enableOBOS_1 ? allOSColor_1 : na), char="■", location=location.bottom)

//bgcolor
bgcolor((useBgColorMTFStochOBOS_1 and allMTFStochOB_1 ? color.new(allOBColor_1, 90) : (useBgColorMTFStochOBOS_1 and allMTFStochOS_1 ? color.new(allOSColor_1, 90) : na)), title='Stoch RSI OB/OS background colour')
barcolor(useBarColorMTFStochOBOS_1 and allMTFStochOB_1 ? allOBColor_1 : (useBarColorMTFStochOBOS_1 and allMTFStochOS_1 ? allOSColor_1 : na))

//Secondary MTF Stoch RSI confluences
grp_MTFSRSI2             = "MTF Stoch RSI #2"
enableOBOS_2             = input(true, title="Show MTF #2 Stoch RSI OB/OS in ribbon", group=grp_MTFSRSI2, tooltip="This will color a ribbon on the chart to indicate where the MTF Stoch RSI is oversold and overbought.")
useBgColorMTFStochOBOS_2 = input(false, title="Color background where MTF #2 Stoch RSI OB/OS", group=grp_MTFSRSI2, tooltip="This will color the background of the chart to indicate where the MTF Stoch RSI is oversold and overbought.")
useBarColorMTFStochOBOS_2 = input(false, title="Color candles where MTF #2 Stoch RSI OB/OS", group=grp_MTFSRSI2, tooltip="This will color the candles on the chart to indicate where the MTF Stoch RSI is oversold and overbought.")
overboughtColor_2        = input.color(color.rgb(255, 68, 68, 50), title="Stoch overbought color", group=grp_MTFSRSI2)
oversoldColor_2          = input.color(color.rgb(43, 117, 46, 50), title="Stoch oversold color", group=grp_MTFSRSI2)

grp_MTFSRSI2_= "Stoch RSI MTF #2 [Timeframe] [OS level] [OB level]"
TF_1_2      = input.string("15", title="TF1", options=["Chart", "1", "2", "3", "4", "5", "8", "10", "15", "20", "30", "45", "60", "120", "240"], group=grp_MTFSRSI2_, inline="mtf1")
TF_2_2      = input.string("30", title="TF2", options=["Chart", "1", "2", "3", "4", "5", "8", "10", "15", "20", "30", "45", "60", "120", "240"], group=grp_MTFSRSI2_, inline="mtf2")
TF_3_2      = input.string("120", title="TF3", options=["Chart", "1", "2", "3", "4", "5", "8", "10", "15", "20", "30", "45", "60", "120", "240"], group=grp_MTFSRSI2_, inline="mtf3")

MTF_OSTHRESH_1_2 = input(20, title="", group=grp_MTFSRSI2_, inline="mtf1")
MTF_OSTHRESH_2_2 = input(20, title="", group=grp_MTFSRSI2_, inline="mtf2")
MTF_OSTHRESH_3_2 = input(20, title="", group=grp_MTFSRSI2_, inline="mtf3")

MTF_OBTHRESH_1_2 = input(80, title="", group=grp_MTFSRSI2_, inline="mtf1")
MTF_OBTHRESH_2_2 = input(80, title="", group=grp_MTFSRSI2_, inline="mtf2")
MTF_OBTHRESH_3_2 = input(80, title="", group=grp_MTFSRSI2_, inline="mtf3")

MTF1_2 = request.security(syminfo.tickerid, TF_1_2 == "Chart" ? "" : TF_1_2, k, barmerge.gaps_off)
MTF2_2 = request.security(syminfo.tickerid, TF_2_2 == "Chart" ? "" : TF_2_2, k, barmerge.gaps_off)
MTF3_2 = request.security(syminfo.tickerid, TF_3_2 == "Chart" ? "" : TF_3_2, k, barmerge.gaps_off)

allMTFStochOB_2 = (MTF1_2 > MTF_OBTHRESH_1_2 and MTF2_2 > MTF_OBTHRESH_2_2 and MTF3_2 > MTF_OBTHRESH_3_2)
allMTFStochOS_2 = (MTF1_2 < MTF_OSTHRESH_1_2 and MTF2_2 < MTF_OSTHRESH_2_2 and MTF3_2 < MTF_OSTHRESH_3_2)

obColor_2 = (k > 90 ? color.new(overboughtColor_2, 50) : enableOBOS_2 and k > 80 ? color.new(overboughtColor_2, 70) : na)
osColor_2 = (k < 10 ? color.new(oversoldColor_2, 50) : enableOBOS_2 and k < 20 ? color.new(oversoldColor_2, 70) : na)

allOBColor_2 = (allMTFStochOB_2 ? overboughtColor_2 : na)
allOSColor_2 = (allMTFStochOS_2 ? oversoldColor_2 : na)


plotchar(k, title="3x TF all overbought", color=(enableOBOS_2 ? allOBColor_2 : na), char="■", location=location.bottom)
plotchar(k, title="3x TF all oversold", color=(enableOBOS_2 ? allOSColor_2 : na), char="■", location=location.bottom)

bgcolor((useBgColorMTFStochOBOS_2 and allMTFStochOB_2 ? color.new(allOBColor_2, 90) : (useBgColorMTFStochOBOS_2 and allMTFStochOS_2 ? color.new(allOSColor_2, 90) : na)), title='Stoch RSI OB/OS background colour')
barcolor(useBarColorMTFStochOBOS_2 and allMTFStochOB_2 ? allOBColor_2 : (useBarColorMTFStochOBOS_2 and allMTFStochOS_2 ? allOSColor_1 : na))

//Alerts
alertcondition((allMTFStochOB_1 and not allMTFStochOB_1[1]) or (allMTFStochOS_1 and not allMTFStochOS_1[1]), title="MTF #1 Stoch OB/OS Detected in FS+", message="MTF #1 Stoch OB/OS Detected in FS+")
alertcondition((allMTFStochOB_1 and not allMTFStochOB_1[1]), title="MTF #1 Stoch Overbought Detected in FS+", message="MTF #1 Stoch Overbought Detected in FS+")
alertcondition((allMTFStochOS_1 and not allMTFStochOS_1[1]), title="MTF #1 Stoch Oversold Detected in FS+", message="MTF #1 Stoch Oversold Detected in FS+")

alertcondition((allMTFStochOB_2 and not allMTFStochOB_2[1]) or (allMTFStochOS_2 and not allMTFStochOS_2[1]), title="MTF #2 Stoch OB/OS Detected in FS+", message="MTF #2 Stoch OB/OS Detected in FS+")
alertcondition((allMTFStochOB_2 and not allMTFStochOB_2[1]), title="MTF #2 Stoch Overbought Detected in FS+", message="MTF #2 Stoch Overbought Detected in FS+")
alertcondition((allMTFStochOS_2 and not allMTFStochOS_2[1]), title="MTF #2 Stoch Oversold Detected in FS+", message="MTF #2 Stoch Oversold Detected in FS+")


//Oscillator value table
grp_TABLE       = "MTF Table"
showMTFVals     = input(false, title="Show MTF table for", group=grp_TABLE, inline="table")
MTFTableType    = input.string("MTF #1 & #2", options=["MTF #1", "MTF #2", "MTF #1 & #2"], title="", group=grp_TABLE, inline="table")
dashboardSize   = input.string(title='', defval='Mobile', options=['Mobile', 'Desktop'], group=grp_TABLE, inline="table")
labelPos        = input.string(title="Table position", defval='Top right', options=['Top right', 'Top left', 'Bottom right', 'Bottom left'], group=grp_TABLE)
MTFLabelColor   = input(color.new(color.white, 100), title="Table color", group=grp_TABLE)
valueColor      = color.new(color.white, 30)
labelColor      = color.new(color.white, 70)

_MTF1labelColor(val, ob, os) =>
    val > ob ? overboughtColor_1 : (val < os ? oversoldColor_1 : valueColor)

_MTF2labelColor(val, ob, os) =>
    val > ob ? overboughtColor_2 : (val < os ? oversoldColor_2 : valueColor)

_labelPos = switch labelPos
    "Top right" => position.top_right
    "Top left" => position.top_left
    "Bottom right" => position.bottom_right
    "Bottom left" => position.bottom_left

_size = switch dashboardSize
    "Mobile" => size.small
    "Desktop" => size.normal

//Oscillator value label
var table label = table.new(position.top_right, 4, 4, bgcolor = MTFLabelColor, frame_width = 0, frame_color = color.new(color.gray, 100))
// We only populate the table on the last bar.
if barstate.islast and showMTFVals
    if (MTFTableType=="MTF #1")
        table.cell(label, 0, 0, text="StochRSI", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 0, 1, text=TF_1+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 1, 1, text=str.tostring(math.floor(MTF1)), width=3, text_color=_MTF1labelColor(MTF1, MTF_OBTHRESH_1, MTF_OSTHRESH_1), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))
        table.cell(label, 0, 2, text=TF_2+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 1, 2, text=str.tostring(math.floor(MTF2)), width=3, text_color=_MTF1labelColor(MTF2, MTF_OBTHRESH_2, MTF_OSTHRESH_2), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))
        table.cell(label, 0, 3, text=TF_3+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 1, 3, text=str.tostring(math.floor(MTF3)), width=3, text_color=_MTF1labelColor(MTF3, MTF_OBTHRESH_3, MTF_OSTHRESH_3), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))
    else if (MTFTableType=="MTF #2")
        table.cell(label, 0, 0, text="StochRSI", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 0, 1, text=TF_1_2+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 1, 1, text=str.tostring(math.floor(MTF1_2)), width=3, text_color=_MTF2labelColor(MTF1_2, MTF_OBTHRESH_1_2, MTF_OSTHRESH_1_2), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))
        table.cell(label, 0, 2, text=TF_2_2+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 1, 2, text=str.tostring(math.floor(MTF2_2)), width=3, text_color=_MTF2labelColor(MTF2_2, MTF_OBTHRESH_2_2, MTF_OSTHRESH_2_2), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))
        table.cell(label, 0, 3, text=TF_3_2+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 1, 3, text=str.tostring(math.floor(MTF3_2)), width=3, text_color=_MTF2labelColor(MTF3_2, MTF_OBTHRESH_3_2, MTF_OSTHRESH_3_2), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))
    else if (MTFTableType=="MTF #1 & #2")
        table.cell(label, 0, 0, text="StochRSI", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 0, 1, text=TF_1+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 1, 1, text=str.tostring(math.floor(MTF1)), width=3, text_color=_MTF1labelColor(MTF1, MTF_OBTHRESH_1, MTF_OSTHRESH_1), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))
        table.cell(label, 0, 2, text=TF_2+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 1, 2, text=str.tostring(math.floor(MTF2)), width=3, text_color=_MTF1labelColor(MTF2, MTF_OBTHRESH_2, MTF_OSTHRESH_2), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))
        table.cell(label, 0, 3, text=TF_3+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 1, 3, text=str.tostring(math.floor(MTF3)), width=3, text_color=_MTF1labelColor(MTF3, MTF_OBTHRESH_3, MTF_OSTHRESH_3), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))

        table.cell(label, 2, 1, text=TF_1_2+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 3, 1, text=str.tostring(math.floor(MTF1_2)), width=3, text_color=_MTF2labelColor(MTF1_2, MTF_OBTHRESH_1_2, MTF_OSTHRESH_1_2), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))
        table.cell(label, 2, 2, text=TF_2_2+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 3, 2, text=str.tostring(math.floor(MTF2_2)), width=3, text_color=_MTF2labelColor(MTF2_2, MTF_OBTHRESH_2_2, MTF_OSTHRESH_2_2), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))
        table.cell(label, 2, 3, text=TF_3_2+"m", text_color=labelColor, text_halign=text.align_left, text_size=size.small, bgcolor=color.new(#000000, 100))
        table.cell(label, 3, 3, text=str.tostring(math.floor(MTF3_2)), width=3, text_color=_MTF2labelColor(MTF3_2, MTF_OBTHRESH_3_2, MTF_OSTHRESH_3_2), text_halign=text.align_right, text_size=_size, bgcolor=color.new(#000000, 100))
        