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)
نص برمجي محمي
تم نشر هذا النص البرمجي كمصدر مغلق. ومع ذلك، يمكنك استخدامه بحرية ودون أي قيود - تعرف على المزيد هنا.
إخلاء المسؤولية
لا يُقصد بالمعلومات والمنشورات أن تكون، أو تشكل، أي نصيحة مالية أو استثمارية أو تجارية أو أنواع أخرى من النصائح أو التوصيات المقدمة أو المعتمدة من TradingView. اقرأ المزيد في شروط الاستخدام.
نص برمجي محمي
تم نشر هذا النص البرمجي كمصدر مغلق. ومع ذلك، يمكنك استخدامه بحرية ودون أي قيود - تعرف على المزيد هنا.
إخلاء المسؤولية
لا يُقصد بالمعلومات والمنشورات أن تكون، أو تشكل، أي نصيحة مالية أو استثمارية أو تجارية أو أنواع أخرى من النصائح أو التوصيات المقدمة أو المعتمدة من TradingView. اقرأ المزيد في شروط الاستخدام.