Paste this indicator into TradingView. Chart mode uses the public default lengths. Turn on the twelve-close fixture to reproduce the table above: it substitutes the twelve prices into the first twelve loaded bars and retains their results in an on-chart table. Load at least twelve bars. Fixture mode disables alerts and is independent of the market prices; it is a calculation check, not a backtest.
Original implementation of the stated public formula. Fixture mode fixes its own lengths and multiplier. Chart plots remain live; only alert conditions require a confirmed close.pine
//@version=6
indicator("TDI: explicit formula and fixture", overlay = false, precision = 2)
fixture = input.bool(false, "Use twelve-close fixture")
nInput = input.int(13, "RSI length", minval = 1)
fInput = input.int(2, "Fast SMA length", minval = 1)
sInput = input.int(7, "Signal SMA length", minval = 1)
bInput = input.int(34, "Band window", minval = 2)
k = input.float(1.6185, "Band multiplier", minval = 0.0)
n = fixture ? 3 : nInput
fLength = fixture ? 2 : fInput
sLength = fixture ? 3 : sInput
bLength = fixture ? 4 : bInput
multiplier = fixture ? 1.6185 : k
var prices = array.from(100.0, 102.0, 101.0, 104.0, 103.0, 102.0, 101.0, 103.0, 100.0, 99.0, 101.0, 98.0)
active = not fixture or bar_index < array.size(prices)
source = fixture ? (active ? array.get(prices, bar_index) : na) : close
change = ta.change(source)
u = ta.rma(math.max(change, 0.0), n)
d = ta.rma(math.max(-change, 0.0), n)
total = u + d
r = active and not na(total) ? (total == 0 ? 50.0 : 100.0 * u / total) : na
fast = ta.sma(r, fLength)
signal = ta.sma(r, sLength)
base = ta.sma(r, bLength)
sd = ta.stdev(r, bLength, true)
upper = base + multiplier * sd
lower = base - multiplier * sd
upCross = ta.crossover(fast, signal)
downCross = ta.crossunder(fast, signal)
ready = active and not na(base) and not na(fast[1]) and not na(signal[1])
confirmedUp = not fixture and ready and barstate.isconfirmed and upCross
confirmedDown = not fixture and ready and barstate.isconfirmed and downCross
plot(active ? fast : na, "Fast RSI SMA", color.green, 2)
plot(active ? signal : na, "Signal RSI SMA", color.red, 2)
plot(active ? base : na, "Market base line", color.orange)
plot(active ? upper : na, "Upper RSI band", color.blue)
plot(active ? lower : na, "Lower RSI band", color.blue)
plot(r, "Raw RSI", display = display.data_window)
plot(active ? sd : na, "Population RSI SD", display = display.data_window)
hline(50, "RSI midpoint", color.gray)
alertcondition(confirmedUp, "Confirmed bullish TDI cross", "Fast TDI SMA crossed above signal SMA at bar close.")
alertcondition(confirmedDown, "Confirmed bearish TDI cross", "Fast TDI SMA crossed below signal SMA at bar close.")
formatValue(float value) => na(value) ? "na" : str.tostring(value, "#.00")
var audit = table.new(position.top_right, 7, 13, bgcolor = color.white, border_width = 1)
if fixture and barstate.isfirst
labels = array.from("Bar / close", "RSI", "Fast", "Signal", "Base", "Lower", "Upper")
for col = 0 to 6
table.cell(audit, col, 0, array.get(labels, col), text_color = color.black)
if fixture and active
row = bar_index + 1
table.cell(audit, 0, row, str.tostring(row) + " / " + str.tostring(source), text_color = color.black)
values = array.from(r, fast, signal, base, lower, upper)
for col = 0 to 5
table.cell(audit, col + 1, row, formatValue(array.get(values, col)), text_color = color.black)