Paste the full indicator into Pine Editor. Fixture mode places the 12 closes on the first 12 dataset bars, so scroll to the beginning and inspect Fixture bar in the Data Window. Later fixture observations are intentionally missing. The chart supplies only a bar clock. Switch Pane units to inspect one scale at a time; all stages remain in the Data Window. T marks the TSI upward crossing at bar 9 and M marks the MACD upward crossing at bar 11. Every displayed value and marker waits for the chart bar to close.
Original Pine v6 comparison with explicit EMA states, a common signal seed policy, flat/missing modes and independent fixture reference values. Syntax checked with Pineify; no orders are placed.pine
//@version=6
indicator("True Strength Index vs MACD: same closes", overlay = false, precision = 6)
mode = input.string("Fixture", "Data", options = ["Fixture", "Flat", "Missing", "Chart close"])
scale = input.float(1.0, "Price multiplier", minval = 0.001)
longLen = input.int(5, "TSI first EMA length", minval = 1)
shortLen = input.int(3, "TSI second EMA length", minval = 1)
fastLen = input.int(3, "MACD fast EMA length", minval = 1)
slowLen = input.int(5, "MACD slow EMA length", minval = 1)
signalLen = input.int(3, "Shared signal EMA length", minval = 1)
pane = input.string("TSI", "Pane units", options = ["TSI", "MACD"])
// Each written call owns a separate state. Missing data resets all stages.
emaStep(float x, int length, bool reset, float seed) =>
var float state = na
float alpha = 2.0 / (length + 1)
state := reset ? seed : alpha * x + (1.0 - alpha) * state
state
var prices = array.from(100.0, 100.0, 104.0, 108.0, 112.0, 108.0, 109.0, 110.0, 111.0, 112.0, 113.0, 114.0)
// Anchor the 12 samples at the dataset's first bar; later fixture bars are na.
float raw = mode == "Chart close" ? close : bar_index < 12 ? array.get(prices, bar_index) : na
if mode == "Flat"
raw := 100.0
if mode == "Missing" and bar_index == 6
raw := na
c = raw * scale
reset = na(c) or na(c[1])
delta = na(c) ? na : na(c[1]) ? 0.0 : c - c[1]
zeroSeed = na(c) ? na : 0.0
p1 = emaStep(delta, longLen, reset, zeroSeed)
p2 = emaStep(p1, shortLen, reset, zeroSeed)
a1 = emaStep(math.abs(delta), longLen, reset, zeroSeed)
a2 = emaStep(a1, shortLen, reset, zeroSeed)
tsi = a2 > 0 ? 100.0 * p2 / a2 : na
fast = emaStep(c, fastLen, reset, c)
slow = emaStep(c, slowLen, reset, c)
macd = fast - slow
// Start both signal EMAs on the first jointly defined observation.
signalReset = na(tsi) or na(tsi[1])
tsiSignal = emaStep(tsi, signalLen, signalReset, tsi)
macdSignal = emaStep(macd, signalLen, signalReset, na(tsi) ? na : macd)
hist = macd - macdSignal
var int consecutive = 0
consecutive := na(c) ? 0 : consecutive + 1
warmup = mode == "Chart close" ? 10 * math.max(math.max(longLen, shortLen), math.max(math.max(fastLen, slowLen), signalLen)) : 0
ready = consecutive > warmup and not na(tsiSignal) and not na(macdSignal)
confirmed = barstate.isconfirmed
upTsi = ready and ready[1] and tsi > tsiSignal and tsi[1] <= tsiSignal[1]
upMacd = ready and ready[1] and hist > 0 and hist[1] <= 0
plot(confirmed and pane == "TSI" ? tsi : na, "TSI pane", color.blue)
plot(confirmed and pane == "TSI" ? tsiSignal : na, "TSI signal pane", color.orange)
plot(confirmed and pane == "MACD" ? macd : na, "MACD pane", color.blue)
plot(confirmed and pane == "MACD" ? macdSignal : na, "MACD signal pane", color.orange)
plot(confirmed ? bar_index : na, "Fixture bar", display = display.data_window)
plot(confirmed ? c : na, "Close", display = display.data_window)
plot(confirmed ? delta : na, "Change", display = display.data_window)
plot(confirmed ? p1 : na, "Change EMA 1", display = display.data_window)
plot(confirmed ? p2 : na, "Change EMA 2", display = display.data_window)
plot(confirmed ? a1 : na, "Abs change EMA 1", display = display.data_window)
plot(confirmed ? a2 : na, "Abs change EMA 2", display = display.data_window)
plot(confirmed ? tsi : na, "TSI", display = display.data_window)
plot(confirmed ? tsiSignal : na, "TSI signal", display = display.data_window)
plot(confirmed ? fast : na, "Fast EMA", display = display.data_window)
plot(confirmed ? slow : na, "Slow EMA", display = display.data_window)
plot(confirmed ? macd : na, "MACD", display = display.data_window)
plot(confirmed ? macdSignal : na, "MACD signal", display = display.data_window)
plot(confirmed ? hist : na, "MACD histogram", display = display.data_window)
plot(confirmed and ready ? (tsi > tsiSignal ? 1 : 0) : na, "TSI above signal", display = display.data_window)
plot(confirmed and ready ? (hist > 0 ? 1 : 0) : na, "MACD above signal", display = display.data_window)
plotchar(confirmed and upTsi, "TSI crosses above signal", "T", location.top, color.blue)
plotchar(confirmed and upMacd, "MACD crosses above signal", "M", location.bottom, color.orange)
// Independent rational calculation references; checked when fixture defaults run.
var expectedTsi = array.from(float(na), float(na), 100, 100, 100, 50.057803468208, 39.507901580316, 39.812478819144, 45.048155551517, 52.767717775522, 61.410550930297, 69.835923089941)
var expectedTsiSignal = array.from(float(na), float(na), 100, 100, 100, 75.028901734104, 57.26840165721, 48.540440238177, 46.794297894847, 49.781007835185, 55.595779382741, 62.715851236341)
var expectedMacd = array.from(0, 0, 0.66666666666667, 1.4444444444444, 2.1296296296296, 1.3364197530864, 1.0159465020576, 0.90646433470508, 0.88555955647005, 0.89766470431337, 0.91875563620891, 0.93932667413927)
var expectedMacdSignal = array.from(float(na), float(na), 0.66666666666667, 1.0555555555556, 1.5925925925926, 1.4645061728395, 1.2402263374486, 1.0733453360768, 0.97945244627343, 0.9385585752934, 0.92865710575116, 0.93399188994521)
same(float actual, float expected) =>
na(expected) ? na(actual) : not na(actual) and math.abs(actual - expected) < 0.00000001 * math.max(1.0, math.abs(expected))
isFixture = mode == "Fixture" and longLen == 5 and shortLen == 3 and fastLen == 3 and slowLen == 5 and signalLen == 3
if isFixture and bar_index < 12
ok = same(tsi, array.get(expectedTsi, bar_index)) and same(tsiSignal, array.get(expectedTsiSignal, bar_index)) and same(macd, scale * array.get(expectedMacd, bar_index)) and same(macdSignal, scale * array.get(expectedMacdSignal, bar_index))
if not ok
runtime.error("Fixture differs from independent reference")