Advance Decline Index
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © viewer405

//@version=5
indicator(title="ADD Indicator", shorttitle="ADD")

bullColor = #26a69a
bearColor = #ef5350

timeInterval = input.timeframe("", title="Time Interval")
style = input.string("line", title="Candle Style", options=["bars", "line", "candles", "ratio"])
default = input.string("USI:ADD", title="Default Ticker", options=["USI:ADD", "USI:ADDQ", "USI:ADDA", "USI:ADVDEC.US", "USI:ADVDEC.NY", "USI:ADVDEC.NQ", "USI:ADVDEC.DJ", "USI:ADVDEC.AM", "USI:ADVDEC.AX"])

enableSummaryTable = input.bool(true, "Enable Summary Table")
enableThresholds = input.bool(true, "Enable Threshold Lines")
enableMA = input.bool(false, "Enable Moving Averages")

ma1Length = input.int(10, "1st MA Length")
ma2Length = input.int(20, "2nd MA Length")
ma1Source = input.string("close", "1st MA Source", options=["open", "high", "low", "close", "hl2", "hlc3", "ohlc4"])
ma2Source = input.string("close", "2nd MA Source", options=["open", "high", "low", "close", "hl2", "hlc3", "ohlc4"])
ma1Type = input.string("ema", "1st MA Type", options=["ema", "sma"])
ma2Type = input.string("ema", "2nd MA Type", options=["ema", "sma"])

prefix = switch syminfo.prefix
	"NYSE" => "USI:ADVDEC.NY"
	"NASDAQ" => "USI:ADVDEC.NQ"
	"USI" => syminfo.ticker
	=> ""

adType = switch syminfo.type
	"crypto" => "USI:ADDQ" // Crypto is behaving like tech sector, use NASDAQ.
	"economic" => ""
	"fund" => ""
	"cfd" => "" // (contract for difference)
	"dr" => "" // (depository receipt)
	"stock" => "USI:ADVDEC.US"
	"index" => ""
	=> ""

index = switch syminfo.ticker
	"ES" => "USI:ADD"
	"SPY" => "USI:ADD"
	"SPX" => "USI:ADD"
	"NQ" => "USI:ADDQ"
	"QQQ" => "USI:ADDQ"
	"TQQQ" => "USI:ADDQ"
	"NASDAQ" => "USI:ADDQ"
	"YM" => "USI:ADVDEC.DJ"
	"DJI" => "USI:ADVDEC.DJ"
	=> ""

uIndex = switch syminfo.ticker
	"ES" => "USI:ADV"
	"SPY" => "USI:ADV"
	"SPX" => "USI:ADV"
	"NQ" => "USI:ADVQ"
	"QQQ" => "USI:ADVQ"
	"TQQQ" => "USI:ADVQ"
	"NASDAQ" => "USI:ADVQ"
	"YM" => "USI:ADVN.DJ"
	"DJI" => "USI:ADVN.DJ"
	=> ""

dIndex = switch syminfo.ticker
	"ES" => "USI:DECL"
	"SPY" => "USI:DECL"
	"SPX" => "USI:DECL"
	"NQ" => "USI:DECLQ"
	"QQQ" => "USI:DECLQ"
	"TQQQ" => "USI:DECLQ"
	"NASDAQ" => "USI:DECLQ"
	"YM" => "USI:DECL.DJ"
	"DJI" => "USI:DECL.DJ"
	=> ""

ticker = prefix != "" ? prefix : (adType != "" ? adType : (index != "" ? index : default))

// As of 2022, TradingView has not yet resolved data issues when querying daily
// candlestick data for USI:ADD. Use 390 minutes instead of the daily. It
// equates to 6 1/2 hours that the markets are open Monday to Friday.
if timeframe.isdaily and style == "candles"
	timeInterval := '390'

uO = request.security(uIndex, timeInterval, open)
uH = request.security(uIndex, timeInterval, high)
uL = request.security(uIndex, timeInterval, low)
uC = request.security(uIndex, timeInterval, close)

dO = request.security(dIndex, timeInterval, open)
dH = request.security(dIndex, timeInterval, high)
dL = request.security(dIndex, timeInterval, low)
dC = request.security(dIndex, timeInterval, close)

ratio = uC > dC ? math.round(uC / dC, 2) : -math.round(dC / uC, 2)

o = request.security(ticker, timeInterval, open)
h = request.security(ticker, timeInterval, high)
l = request.security(ticker, timeInterval, low)
c = request.security(ticker, timeInterval, close)

getMASourcePrice(source, o, h, l, c) =>
	price = switch source
		"open" => o
		"high" => h
		"low" => l
		"close" => c
		"hl2" => (h + l) / 2
		"hlc3" => (h + l + c) / 3
		"ohlc4" => (o + h + l + c) / 4
		=> c
	price

ma1Price = getMASourcePrice(ma1Source, o, h, l, c)
ma2Price = getMASourcePrice(ma2Source, o, h, l, c)
ma1 = ma1Type == "ema" ? ta.ema(ma1Price, ma1Length) : ta.sma(ma1Price, ma1Length)
ma2 = ma2Type == "ema" ? ta.ema(ma2Price, ma2Length) : ta.sma(ma2Price, ma2Length)

plot(ma1, "1st MA", display = enableMA ? display.all : display.none, color=color.fuchsia)
plot(ma2, "2nd MA", display = enableMA ? display.all : display.none, color=color.aqua)

if barstate.islast and enableSummaryTable
	table legend = table.new(position.top_right, 3, 4, bgcolor = color.gray, frame_width = 2)
	table.cell(legend, 0, 0, ticker + " " + str.tostring(c) + " | Ratio: " + str.tostring(ratio) + ":1")
	table.cell(legend, 0, 1, uIndex + " " + str.tostring(uC))
	table.cell(legend, 0, 2, dIndex + " " + str.tostring(dC))

isBar = style == "bars" ? true : false
isLine = style == "line" ? true : false
isRatio = style == "ratio" ? true : false
isCandle = style == "candles" ? true : false

plot(c, display=isLine ? display.all : display.none)
plot(ratio, style = plot.style_columns, display = isRatio ? display.all : display.none)
plotbar(open=o, high=h, low=l, close=c, color=c < o ? bearColor : bullColor, display=isBar ? display.all : display.none)
plotcandle(open=o, high=h, low=l, close=c, color=c < o ? bearColor : bullColor, bordercolor=na, display=isCandle ? display.all : display.none)

hline(0, "Middle Band", color=color.new(#787B86, 50), display = enableThresholds ? display.all : display.none)
hline(500, "Upper Band +500", color=color.new(bullColor, 75), display = display.none)
hline(-500, "Lower Band -500", color=color.new(bearColor, 75), display = display.none)
hline(1000, "Upper Band +1000", color=color.new(bullColor, 50), display = enableThresholds ? display.all : display.none)
hline(-1000, "Lower Band -1000", color=color.new(bearColor, 50), display = enableThresholds ? display.all : display.none)
hline(1500, "Upper Band +1500", color=color.new(bullColor, 25), display = display.none)
hline(-1500, "Lower Band -1500", color=color.new(bearColor, 25), display = display.none)
hline(2000, "Upper Band +2000", color=color.new(bullColor, 0), display = enableThresholds ? display.all : display.none)
hline(-2000, "Lower Band -2000", color=color.new(bearColor, 0), display = enableThresholds ? display.all : display.none)