Multiple Ticker Stochastic RSI
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © sxiong1111
// Script Created On:   8/29/2023
// Script Updated On:   8/29/2023
// Script Version:      1.0
// Research Source:     https://www.investopedia.com/terms/s/stochrsi.asp
// Description:         According to Investopedia, the Stochastic RSI is a technical indicator ranging between 0 and 100, based on applying the Stochastic oscillator formula to a set of relative strength index (RSI).  This gives users a better
//                      sense of whether the current RSI value is overbought or oversold.  When the value is above 80, the security's price is considered overbought.  When the value is below 20, the security's price is considered oversold.
//                      The goal of this indicator is to compare 3 different tickers, averaging the resulting data and then outputting the results in a standard Stochastic RSI view.

// Formula:             Stochastic RSI = (RSI - min[RSI]) / (max[RSI] - min[RSI])

//@version=5
indicator(title = "Multiple Ticker Stochastic RSI", shorttitle = "MTS RSI", format = format.price, precision = 2, timeframe = "", timeframe_gaps = true)


ticker1 = input.string(defval = "", title = "Ticker Symbol 1", tooltip = "This field is always locked to the ticker symbol for the current chart window that's in scope.\n\nAny text entries in this text field will have no effect.  This means that if your current charting window is on SPY, this ticker will be SPY.", group = "Tickers")
ticker2 = input.symbol(defval = "NDAQ", title = "Ticker Symbol 2", tooltip = "User-defined ticker # 2", group = "Tickers")
ticker3 = input.symbol(defval = "DIA", title = "Ticker Symbol 3", tooltip = "User-defined ticker # 3", group = "Tickers")

kLineSetting = input.bool(defval = false, title = "Show K Lines Separately",  tooltip = "If enabled, there will be three different K lines; each for the three different tickers.  The single D line will be the average of all three tickers.\n\nIf disabled, the data from three different tickers will be averaged into a single K line.", group = "Stochastic RSI Settings")
smoothKDouble = input.bool(defval = false, title = "Apply Double K Smoothing",  tooltip = "If enabled, the K data will have double smoothing, which can help you visualize the directional movement better with reduced sharp K and D lines.  If disabled, the K data will retain its standard smoothing.\n\nAlso, note that if you enable this setting and the buy and/or sell visual indicator, you can potentially see an early buy/sell entry.", group = "Stochastic RSI Settings")
smoothK = input.int(defval = 3, title = "Smooth K", minval = 1, group = "Stochastic RSI Settings")
smoothD = input.int(defval = 3, title = "Smooth D", minval = 1, group = "Stochastic RSI Settings")
lengthRSI = input.int(defval = 14, title = "RSI Length", minval = 1, group = "Stochastic RSI Settings")
lengthStochastic = input.int(defval = 14, title = "Stochastic Length", minval = 1, group = "Stochastic RSI Settings")
bandUpper = input.int(defval = 80, title = "Overbought Line Level", minval = -50, maxval = 150, tooltip = "This is the Stochastic RSI overbought level.  The default is 80.", group = "Stochastic RSI Settings")
bandMiddle = input.int(defval = 50, title = "Middle Line Level", minval = -50, maxval = 150, tooltip = "This is the Stochastic RSI middle level.  The default is 50.", group = "Stochastic RSI Settings")
bandLower = input.int(defval = 20, title = "Oversold Line Level", minval = -50, maxval = 150, tooltip = "This is the Stochastic RSI oversold level.  The default is 20.", group = "Stochastic RSI Settings")
maType = input.string(defval = "SMA", title = "Moving Average Calculation Type", options = ["SMA", "EMA", "HULL", "VOLUME WEIGHT"], tooltip = "You can choose either SMA, EMA, HULL or VOLUME WEIGHTED moving averages for the data calculations.", group = "Stochastic RSI Visual Settings")

smoothKColor1 = input.color(color.new(#FCCF3E, 10), title = "Smooth K Line Color (Ticker 1)", tooltip = "This is the K line color of the ticker in the current chart window.", group = "Stochastic RSI Visual Settings")
smoothKColor2 = input.color(color.new(#8AC287, 10), title = "Smooth K Line Color (Ticker 2)", tooltip = "This is the K line color of ticker #2.", group = "Stochastic RSI Visual Settings")
smoothKColor3 = input.color(color.new(#AA96C6, 10), title = "Smooth K Line Color (Ticker 3)", tooltip = "This is the K line color of ticker #3.", group = "Stochastic RSI Visual Settings")
smoothKColorA = input.color(color.new(#00A7E3, 10), title = "Smooth K Line Color (Average)", tooltip = "This is the average K line color, if you've disabled the 'Show K Lines Separately' settings above.", group = "Stochastic RSI Visual Settings")
smoothDColor = input.color(color.new(#ED6C00, 10), title = "Smooth D Line Color", tooltip = "This is the D line color.", group = "Stochastic RSI Visual Settings")
kLineStyle = input.int(defval = 1, title = "Smooth K Line Thickness", minval = 1, maxval = 10, tooltip = "This is the line thickness for the Smooth K line.  The numerical value setting here affects all K lines.", group = "Stochastic RSI Visual Settings")
dLineStyle = input.int(defval = 1, title = "Smooth D Line Thickness", minval = 1, maxval = 10, tooltip = "This is the line thickness for the Smooth D line.", group = "Stochastic RSI Visual Settings")
ulBandLineColor = input.color(color.new(#9F9F99, 50), title = "Upper/Lower Band Line Color", tooltip = "This is the line color of both the upper and lower band lines.", group = "Stochastic RSI Visual Settings")
mmBandLineColor = input.color(color.new(#9F9F99, 80), title = "Middle Band Line Color", tooltip = "This is the line color of the middle band line.", group = "Stochastic RSI Visual Settings")
bandFillColor = input.color(color.new(#AE9183, 95), title = "Band Background Fill Color", tooltip = "This is the background fill color of the band.", group = "Stochastic RSI Visual Settings")
bandLineStyle = input.string(defval = "Dashed", title = "Upper/Lower Band Line Style", options = ["Solid", "Dotted", "Dashed"], tooltip = "This is the line style for the upper and lower bands.", group = "Stochastic RSI Visual Settings")
bandMiddleLineStyle = input.string(defval = "Dashed", title = "Middle Band Line Style", options = ["Solid", "Dotted", "Dashed"], tooltip = "This is the line style for the middle band.", group = "Stochastic RSI Visual Settings")

showBuySignal = input.bool(defval = false, title = "Show Potential Buy Signals",  tooltip = "If enabled, the potential buy signals are shown.\n\nPlease note that the potential buy signals only work off the average K all 3 tickers.  This is irrespective if you choose to show all 3 K lines separately or not.", group = "Stochastic RSI Visual Settings")
showSellSignal = input.bool(defval = false, title = "Show Potential Sell Signals",  tooltip = "If enabled, the potential sell signals are shown.\n\nPlease note that the potential sell signals only work off the average K all 3 tickers.  This is irrespective if you choose to show all 3 K lines separately or not.", group = "Stochastic RSI Visual Settings")
buySignalColor = input.color(color.new(#42B9AC, 20), title = "Potential Buy Signal Color", tooltip = "This is the potential buy signal color.", group = "Stochastic RSI Visual Settings")
sellSignalColor = input.color(color.new(#CD4479, 20), title = "Potential Sell Signal Color", tooltip = "This is the potential sell signal color.", group = "Stochastic RSI Visual Settings")
buySellSignalSize = input.int(defval = 5, title = "Potential Buy/Sell Signal Visual Indicator Size", minval = 1, maxval = 20, tooltip = "This is the user-defined size of the potential buy/sell visual indicator.", group = "Stochastic RSI Visual Settings")

src1 = close
src2 = request.security(ticker2, timeframe.period, close)
src3 = request.security(ticker3, timeframe.period, close)

bLineStyle = hline.style_dashed
if (bandLineStyle == "Solid")
    bLineStyle := hline.style_solid
if (bandLineStyle == "Dotted")
    bLineStyle := hline.style_dotted
bmLineStyle = hline.style_dashed
if (bandMiddleLineStyle == "Solid")
    bmLineStyle := hline.style_solid
if (bandMiddleLineStyle == "Dotted")
    bmLineStyle := hline.style_dotted

rsi = 0.00
k = 0.00
k1 = 0.00
k2 = 0.00
k3 = 0.00
d = 0.00
dAVG = 0.00
avgSRC = math.avg(src1, src2, src3)
enableAVG = true

if (maType == "EMA")
    if (kLineSetting == true)
        rsi1 = ta.rsi(src1, lengthRSI)
        k1 := ta.ema(ta.stoch(rsi1, rsi1, rsi1, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k1 := ta.ema(k1, smoothK)
        d1 = ta.ema(k1, smoothD)

        rsi2 = ta.rsi(src2, lengthRSI)
        k2 := ta.ema(ta.stoch(rsi2, rsi2, rsi2, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k2 := ta.ema(k2, smoothK)
        d2 = ta.ema(k2, smoothD)

        rsi3 = ta.rsi(src3, lengthRSI)
        k3 := ta.ema(ta.stoch(rsi3, rsi3, rsi3, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k3 := ta.ema(k3, smoothK)
        d3 = ta.ema(k3, smoothD)
        dAVG := math.avg(d1, d2, d3)
    else
        enableAVG := false
        rsi := ta.rsi(avgSRC, lengthRSI)
        k := ta.ema(ta.stoch(rsi, rsi, rsi, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k := ta.ema(k, smoothK)
        d := ta.ema(k, smoothD)
else if (maType == "SMA")
    if (kLineSetting == true)
        rsi1 = ta.rsi(src1, lengthRSI)
        k1 := ta.sma(ta.stoch(rsi1, rsi1, rsi1, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k1 := ta.sma(k1, smoothK)
        d1 = ta.sma(k1, smoothD)

        rsi2 = ta.rsi(src2, lengthRSI)
        k2 := ta.sma(ta.stoch(rsi2, rsi2, rsi2, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k2 := ta.sma(k2, smoothK)
        d2 = ta.sma(k2, smoothD)

        rsi3 = ta.rsi(src3, lengthRSI)
        k3 := ta.sma(ta.stoch(rsi3, rsi3, rsi3, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k3 := ta.sma(k3, smoothK)
        d3 = ta.sma(k3, smoothD)
        dAVG := math.avg(d1, d2, d3)
    else
        enableAVG := false
        rsi := ta.rsi(avgSRC, lengthRSI)
        k := ta.sma(ta.stoch(rsi, rsi, rsi, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k := ta.sma(k, smoothK)
        d := ta.sma(k, smoothD)
else if (maType == "HULL")
    if (kLineSetting == true)
        rsi1 = ta.rsi(src1, lengthRSI)
        k1 := ta.hma(ta.stoch(rsi1, rsi1, rsi1, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k1 := ta.hma(k1, smoothK)
        d1 = ta.hma(k1, smoothD)

        rsi2 = ta.rsi(src2, lengthRSI)
        k2 := ta.hma(ta.stoch(rsi2, rsi2, rsi2, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k2 := ta.hma(k2, smoothK)
        d2 = ta.hma(k2, smoothD)

        rsi3 = ta.rsi(src3, lengthRSI)
        k3 := ta.hma(ta.stoch(rsi3, rsi3, rsi3, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k3 := ta.hma(k3, smoothK)
        d3 = ta.hma(k3, smoothD)
        dAVG := math.avg(d1, d2, d3)
    else
        enableAVG := false
        rsi := ta.rsi(avgSRC, lengthRSI)
        k := ta.hma(ta.stoch(rsi, rsi, rsi, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k := ta.hma(k, smoothK)
        d := ta.hma(k, smoothD)
else
    if (kLineSetting == true)
        rsi1 = ta.rsi(src1, lengthRSI)
        k1 := ta.vwma(ta.stoch(rsi1, rsi1, rsi1, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k1 := ta.vwma(k1, smoothK)
        d1 = ta.vwma(k1, smoothD)

        rsi2 = ta.rsi(src2, lengthRSI)
        k2 := ta.vwma(ta.stoch(rsi2, rsi2, rsi2, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k2 := ta.vwma(k2, smoothK)
        d2 = ta.vwma(k2, smoothD)

        rsi3 = ta.rsi(src3, lengthRSI)
        k3 := ta.vwma(ta.stoch(rsi3, rsi3, rsi3, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k3 := ta.vwma(k3, smoothK)
        d3 = ta.vwma(k3, smoothD)
        dAVG := math.avg(d1, d2, d3)
    else
        enableAVG := false
        rsi := ta.rsi(avgSRC, lengthRSI)
        k := ta.vwma(ta.stoch(rsi, rsi, rsi, lengthStochastic), smoothK)
        if (smoothKDouble == true)
            k := ta.vwma(k, smoothK)
        d := ta.vwma(k, smoothD)

buyCrossOver = ta.crossover(k, d)
sellCrossOver = ta.crossunder(k, d)
buyCrossOverBand = false
sellCrossOverBand = false
if ((k >= d) and ta.cross(k, bandLower))
    buyCrossOverBand := true
if ((k <= d) and ta.cross(k, bandUpper))
    sellCrossOverBand := true
alertcondition(buyCrossOver, title = "Stochastic RSI Buy", message = "{{ticker}}: Stochastic RSI Crossed Over D")
alertcondition(buyCrossOver, title = "Stochastic RSI Sell", message = "{{ticker}}: Stochastic RSI Crossed Under D")
alertcondition(buyCrossOverBand, title = "Stochastic RSI Buy Oversold", message = "{{ticker}}: Stochastic RSI Crossed Over both D and Oversold Level")
alertcondition(sellCrossOverBand, title = "Stochastic RSI Sell Overbought", message = "{{ticker}}: Stochastic RSI Crossed Under both D and Overbought Level")

plot(enableAVG == true ? k1 : na, title = "Smooth K1", color = smoothKColor1, linewidth = kLineStyle, style = plot.style_line)
plot(enableAVG == true ? k2: na, title = "Smooth K2", color = smoothKColor2, linewidth = kLineStyle, style = plot.style_line)
plot(enableAVG == true ? k3 : na, title = "Smooth K3", color = smoothKColor3, linewidth = kLineStyle, style = plot.style_line)
plot(enableAVG == true ? dAVG : na, title = "Smooth D", color = smoothDColor, linewidth = dLineStyle, style = plot.style_line)
plot(enableAVG == false ? k : na, title = "Smooth K", color = smoothKColorA, linewidth = kLineStyle, style = plot.style_line)
plot(enableAVG == false ? d : na, title = "Smooth D", color = smoothDColor, linewidth = dLineStyle, style = plot.style_line)
LU = hline(bandUpper, title = "Band Upper", color = ulBandLineColor, linewidth = 1, linestyle = bLineStyle)
LL = hline(bandLower, title = "Band Lower", color = ulBandLineColor, linewidth = 1, linestyle = bLineStyle)
hline(bandMiddle, title = "Band Middle", color = mmBandLineColor, linewidth = 1, linestyle = bmLineStyle)
fill(LU, LL, title = "Fill Color", color = bandFillColor)
plot(buyCrossOverBand == true and showBuySignal == true ? bandLower : na, title = "Buy Signal", color = buySignalColor, linewidth = buySellSignalSize, style = plot.style_circles)
plot(sellCrossOverBand == true and showSellSignal == true ? bandUpper : na, title = "Sell Signal", color = sellSignalColor, linewidth = buySellSignalSize, style = plot.style_circles)
