PROTECTED SOURCE SCRIPT
Institutions order spikes spotter

//version=5
indicator("Volume Spike — QuickFire (TF-Adaptive)", overlay=true, max_labels_count=500)
//––– Helpers –––
barsFromMinutes(mins, avgBarMs) =>
ms = mins * 60000.0
int(math.max(2, math.round(ms / math.max(1.0, nz(avgBarMs, 60000.0)))))
alphaFromLen(lenBarsFloat) =>
lb = math.max(2.0, lenBarsFloat)
2.0 / (lb + 1.0) // EMA alpha
//––– Inputs –––
useMinutesHorizon = input.bool(true, "Use Minutes Horizon (TF-adaptive)")
presetMinutes = input.string("120","Horizon Preset (min)", options=["30","60","120","240","480"])
horizonMinutes = input.int(240, "Custom Horizon (min) if preset OFF", minval=10, maxval=24*60)
usePresetMins = input.bool(true, "Use Preset")
// Sensitivity (LOOSE defaults)
multK = input.float(2.2, "K: vol > baseline × K", minval=1.1, step=0.1)
zThresh = input.float(2.5, "Z: vol > mean + Z·stdev", minval=1.5, step=0.1)
requireBoth = input.bool(false, "Require BOTH (K & Z). If OFF → EITHER")
// Optional filters (OFF by default)
useNewExtreme = input.bool(false, "Require New Extreme vs Prior Max (OFF)")
priorWinBarsInp = input.int(100, "Prior-Max Window (bars)", minval=20, maxval=5000)
priorFactor = input.float(1.20, "New Extreme ≥ priorMax ×", minval=1.0, step=0.05)
minDollarVol = input.float(0.0, "Min Dollar-Volume (price×vol×mult) — 0=off", step=1.0)
contractMult = input.float(1.0, "Contract/Dollar Multiplier (e.g., NQ 20, MNQ 2)", step=0.1)
sessionOnly = input.bool(false, "Restrict to Session (OFF)")
sess = input.session("0830-1600", "Session (exchange tz)")
earlyDetect = input.bool(true, "Early Intrabar Detection")
cooldownMins = input.int(10, "Cooldown Minutes", minval=0, maxval=24*60)
markerSize = input.string("normal", "Marker Size", options=["tiny","small","normal","large","huge"])
showLabel = input.bool(false, "Show ratio label")
shadeNear = input.bool(true, "Shade near-misses (only one condition)")
colUp = color.new(color.teal, 0)
colDn = color.new(color.red, 0)
colBgHit = color.new(color.yellow, 80)
colBgNear = color.new(color.silver, 88)
//––– Derived (minutes → bars → alphas) –––
avgBarMs = ta.sma(time - time[1], 50)
useMin = usePresetMins ? str.tonumber(presetMinutes) : horizonMinutes
lenEffBars = useMinutesHorizon ? barsFromMinutes(useMin, avgBarMs) : useMin
lenEffF = float(lenEffBars)
alphaVol = alphaFromLen(lenEffF)
alphaATR = alphaFromLen(math.max(10.0, lenEffF/2.0))
cooldownBars = useMinutesHorizon ? barsFromMinutes(cooldownMins, avgBarMs) : cooldownMins
//––– Guards –––
inSess = sessionOnly ? not na(time(timeframe.period, sess)) : true
//––– EW stats (no series-int) –––
vol = volume
var float vMean = na
var float vVar = na
vMeanPrev = nz(vMean[1], vol)
vMean := na(vMean[1]) ? vol : vMeanPrev + alphaVol * (vol - vMeanPrev)
delta = vol - vMeanPrev
vVar := na(vVar[1]) ? 0.0 : (1.0 - alphaVol) * (nz(vVar[1]) + alphaVol * delta * delta)
vStd = math.sqrt(math.max(vVar, 0.0))
// EW ATR (for optional anatomy later if you want)
trueRange = math.max(high - low, math.max(math.abs(high - close[1]), math.abs(low - close[1])))
var float atrEW = na
atrEW := na(atrEW[1]) ? trueRange : atrEW[1] + alphaATR * (trueRange - atrEW[1])
// Intrabar scaling
elapsedMs = barstate.isrealtime ? (timenow - time) : nz(avgBarMs, 0)
frac = earlyDetect ? math.max(0.0, math.min(1.0, elapsedMs / math.max(1.0, nz(avgBarMs, 1)))) : 1.0
// Thresholds
thMult = nz(vMean, 0) * multK
thZ = nz(vMean, 0) + zThresh * vStd
thMultEf = thMult * frac
thZEf = thZ * frac
condMult = vol > thMultEf
condZ = vol > thZEf
condCore = requireBoth ? (condMult and condZ) : (condMult or condZ)
// Optional filters (default OFF)
priorMax = ta.highest(vol[1], priorWinBarsInp)
condNewMax = not useNewExtreme or (vol >= priorMax * priorFactor)
dollarVol = close * vol * contractMult
condDVol = (minDollarVol <= 0) or (dollarVol >= minDollarVol)
// Cooldown
var int lastSpikeBar = -1000000000
coolOK = (bar_index - lastSpikeBar) > cooldownBars
// Final event (minimal gates)
isSpike = inSess and condCore and condNewMax and condDVol and coolOK
// Near-miss shading (only one condition true)
nearMiss = shadeNear and inSess and not isSpike and (condMult != condZ) and (condMult or condZ)
// Severity
ratio = nz(vol) / nz(vMean, 1.0)
dirUp = close >= open
// Update cooldown stamp
if isSpike
lastSpikeBar := bar_index
//––– Plotting –––
bgcolor(isSpike ? colBgHit : nearMiss ? colBgNear : na)
isUp = isSpike and dirUp
isDn = isSpike and not dirUp
// const-size markers
plotshape(markerSize == "tiny" and isUp, title="Spike Up tiny", style=shape.triangleup, color=colUp, location=location.belowbar, size=size.tiny)
plotshape(markerSize == "small" and isUp, title="Spike Up small", style=shape.triangleup, color=colUp, location=location.belowbar, size=size.small)
plotshape(markerSize == "normal" and isUp, title="Spike Up normal", style=shape.triangleup, color=colUp, location=location.belowbar, size=size.normal)
plotshape(markerSize == "large" and isUp, title="Spike Up large", style=shape.triangleup, color=colUp, location=location.belowbar, size=size.large)
plotshape(markerSize == "huge" and isUp, title="Spike Up huge", style=shape.triangleup, color=colUp, location=location.belowbar, size=size.huge)
plotshape(markerSize == "tiny" and isDn, title="Spike Dn tiny", style=shape.triangledown, color=colDn, location=location.abovebar, size=size.tiny)
plotshape(markerSize == "small" and isDn, title="Spike Dn small", style=shape.triangledown, color=colDn, location=location.abovebar, size=size.small)
plotshape(markerSize == "normal" and isDn, title="Spike Dn normal", style=shape.triangledown, color=colDn, location=location.abovebar, size=size.normal)
plotshape(markerSize == "large" and isDn, title="Spike Dn large", style=shape.triangledown, color=colDn, location=location.abovebar, size=size.large)
plotshape(markerSize == "huge" and isDn, title="Spike Dn huge", style=shape.triangledown, color=colDn, location=location.abovebar, size=size.huge)
// Optional label
if showLabel and isSpike
y = dirUp ? low : high
st = dirUp ? label.style_label_down : label.style_label_up
c = dirUp ? colUp : colDn
label.new(bar_index, y, str.tostring(ratio, "#.##x"), xloc=xloc.bar_index, style=st, textcolor=color.white, color=c)
// Alerts
alertcondition(isSpike, title="Volume Spike (Any)", message="Volume spike detected.")
alertcondition(isSpike and isUp, title="Volume Spike Up", message="UP volume spike.")
alertcondition(isSpike and isDn, title="Volume Spike Down", message="DOWN volume spike.")
// Hidden refs (optional)
plot(ratio, title="Severity Ratio", display=display.none)
plot(dollarVol, title="Dollar Volume", display=display.none)
plot(atrEW, title="EW ATR", display=display.none)
indicator("Volume Spike — QuickFire (TF-Adaptive)", overlay=true, max_labels_count=500)
//––– Helpers –––
barsFromMinutes(mins, avgBarMs) =>
ms = mins * 60000.0
int(math.max(2, math.round(ms / math.max(1.0, nz(avgBarMs, 60000.0)))))
alphaFromLen(lenBarsFloat) =>
lb = math.max(2.0, lenBarsFloat)
2.0 / (lb + 1.0) // EMA alpha
//––– Inputs –––
useMinutesHorizon = input.bool(true, "Use Minutes Horizon (TF-adaptive)")
presetMinutes = input.string("120","Horizon Preset (min)", options=["30","60","120","240","480"])
horizonMinutes = input.int(240, "Custom Horizon (min) if preset OFF", minval=10, maxval=24*60)
usePresetMins = input.bool(true, "Use Preset")
// Sensitivity (LOOSE defaults)
multK = input.float(2.2, "K: vol > baseline × K", minval=1.1, step=0.1)
zThresh = input.float(2.5, "Z: vol > mean + Z·stdev", minval=1.5, step=0.1)
requireBoth = input.bool(false, "Require BOTH (K & Z). If OFF → EITHER")
// Optional filters (OFF by default)
useNewExtreme = input.bool(false, "Require New Extreme vs Prior Max (OFF)")
priorWinBarsInp = input.int(100, "Prior-Max Window (bars)", minval=20, maxval=5000)
priorFactor = input.float(1.20, "New Extreme ≥ priorMax ×", minval=1.0, step=0.05)
minDollarVol = input.float(0.0, "Min Dollar-Volume (price×vol×mult) — 0=off", step=1.0)
contractMult = input.float(1.0, "Contract/Dollar Multiplier (e.g., NQ 20, MNQ 2)", step=0.1)
sessionOnly = input.bool(false, "Restrict to Session (OFF)")
sess = input.session("0830-1600", "Session (exchange tz)")
earlyDetect = input.bool(true, "Early Intrabar Detection")
cooldownMins = input.int(10, "Cooldown Minutes", minval=0, maxval=24*60)
markerSize = input.string("normal", "Marker Size", options=["tiny","small","normal","large","huge"])
showLabel = input.bool(false, "Show ratio label")
shadeNear = input.bool(true, "Shade near-misses (only one condition)")
colUp = color.new(color.teal, 0)
colDn = color.new(color.red, 0)
colBgHit = color.new(color.yellow, 80)
colBgNear = color.new(color.silver, 88)
//––– Derived (minutes → bars → alphas) –––
avgBarMs = ta.sma(time - time[1], 50)
useMin = usePresetMins ? str.tonumber(presetMinutes) : horizonMinutes
lenEffBars = useMinutesHorizon ? barsFromMinutes(useMin, avgBarMs) : useMin
lenEffF = float(lenEffBars)
alphaVol = alphaFromLen(lenEffF)
alphaATR = alphaFromLen(math.max(10.0, lenEffF/2.0))
cooldownBars = useMinutesHorizon ? barsFromMinutes(cooldownMins, avgBarMs) : cooldownMins
//––– Guards –––
inSess = sessionOnly ? not na(time(timeframe.period, sess)) : true
//––– EW stats (no series-int) –––
vol = volume
var float vMean = na
var float vVar = na
vMeanPrev = nz(vMean[1], vol)
vMean := na(vMean[1]) ? vol : vMeanPrev + alphaVol * (vol - vMeanPrev)
delta = vol - vMeanPrev
vVar := na(vVar[1]) ? 0.0 : (1.0 - alphaVol) * (nz(vVar[1]) + alphaVol * delta * delta)
vStd = math.sqrt(math.max(vVar, 0.0))
// EW ATR (for optional anatomy later if you want)
trueRange = math.max(high - low, math.max(math.abs(high - close[1]), math.abs(low - close[1])))
var float atrEW = na
atrEW := na(atrEW[1]) ? trueRange : atrEW[1] + alphaATR * (trueRange - atrEW[1])
// Intrabar scaling
elapsedMs = barstate.isrealtime ? (timenow - time) : nz(avgBarMs, 0)
frac = earlyDetect ? math.max(0.0, math.min(1.0, elapsedMs / math.max(1.0, nz(avgBarMs, 1)))) : 1.0
// Thresholds
thMult = nz(vMean, 0) * multK
thZ = nz(vMean, 0) + zThresh * vStd
thMultEf = thMult * frac
thZEf = thZ * frac
condMult = vol > thMultEf
condZ = vol > thZEf
condCore = requireBoth ? (condMult and condZ) : (condMult or condZ)
// Optional filters (default OFF)
priorMax = ta.highest(vol[1], priorWinBarsInp)
condNewMax = not useNewExtreme or (vol >= priorMax * priorFactor)
dollarVol = close * vol * contractMult
condDVol = (minDollarVol <= 0) or (dollarVol >= minDollarVol)
// Cooldown
var int lastSpikeBar = -1000000000
coolOK = (bar_index - lastSpikeBar) > cooldownBars
// Final event (minimal gates)
isSpike = inSess and condCore and condNewMax and condDVol and coolOK
// Near-miss shading (only one condition true)
nearMiss = shadeNear and inSess and not isSpike and (condMult != condZ) and (condMult or condZ)
// Severity
ratio = nz(vol) / nz(vMean, 1.0)
dirUp = close >= open
// Update cooldown stamp
if isSpike
lastSpikeBar := bar_index
//––– Plotting –––
bgcolor(isSpike ? colBgHit : nearMiss ? colBgNear : na)
isUp = isSpike and dirUp
isDn = isSpike and not dirUp
// const-size markers
plotshape(markerSize == "tiny" and isUp, title="Spike Up tiny", style=shape.triangleup, color=colUp, location=location.belowbar, size=size.tiny)
plotshape(markerSize == "small" and isUp, title="Spike Up small", style=shape.triangleup, color=colUp, location=location.belowbar, size=size.small)
plotshape(markerSize == "normal" and isUp, title="Spike Up normal", style=shape.triangleup, color=colUp, location=location.belowbar, size=size.normal)
plotshape(markerSize == "large" and isUp, title="Spike Up large", style=shape.triangleup, color=colUp, location=location.belowbar, size=size.large)
plotshape(markerSize == "huge" and isUp, title="Spike Up huge", style=shape.triangleup, color=colUp, location=location.belowbar, size=size.huge)
plotshape(markerSize == "tiny" and isDn, title="Spike Dn tiny", style=shape.triangledown, color=colDn, location=location.abovebar, size=size.tiny)
plotshape(markerSize == "small" and isDn, title="Spike Dn small", style=shape.triangledown, color=colDn, location=location.abovebar, size=size.small)
plotshape(markerSize == "normal" and isDn, title="Spike Dn normal", style=shape.triangledown, color=colDn, location=location.abovebar, size=size.normal)
plotshape(markerSize == "large" and isDn, title="Spike Dn large", style=shape.triangledown, color=colDn, location=location.abovebar, size=size.large)
plotshape(markerSize == "huge" and isDn, title="Spike Dn huge", style=shape.triangledown, color=colDn, location=location.abovebar, size=size.huge)
// Optional label
if showLabel and isSpike
y = dirUp ? low : high
st = dirUp ? label.style_label_down : label.style_label_up
c = dirUp ? colUp : colDn
label.new(bar_index, y, str.tostring(ratio, "#.##x"), xloc=xloc.bar_index, style=st, textcolor=color.white, color=c)
// Alerts
alertcondition(isSpike, title="Volume Spike (Any)", message="Volume spike detected.")
alertcondition(isSpike and isUp, title="Volume Spike Up", message="UP volume spike.")
alertcondition(isSpike and isDn, title="Volume Spike Down", message="DOWN volume spike.")
// Hidden refs (optional)
plot(ratio, title="Severity Ratio", display=display.none)
plot(dollarVol, title="Dollar Volume", display=display.none)
plot(atrEW, title="EW ATR", display=display.none)
Skrip dilindungi
Skrip ini diterbitkan sebagai sumber tertutup. Akan tetapi, anda boleh menggunakannya dengan percuma dan tanpa had – ketahui lebih lanjut di sini.
Penafian
Maklumat dan penerbitan adalah tidak dimaksudkan untuk menjadi, dan tidak membentuk, nasihat untuk kewangan, pelaburan, perdagangan dan jenis-jenis lain atau cadangan yang dibekalkan atau disahkan oleh TradingView. Baca dengan lebih lanjut di Terma Penggunaan.
Skrip dilindungi
Skrip ini diterbitkan sebagai sumber tertutup. Akan tetapi, anda boleh menggunakannya dengan percuma dan tanpa had – ketahui lebih lanjut di sini.
Penafian
Maklumat dan penerbitan adalah tidak dimaksudkan untuk menjadi, dan tidak membentuk, nasihat untuk kewangan, pelaburan, perdagangan dan jenis-jenis lain atau cadangan yang dibekalkan atau disahkan oleh TradingView. Baca dengan lebih lanjut di Terma Penggunaan.