This overlay indicator marks CALLS and PUTS labels on the price chart when a strict boolean gate of price structure, momentum, volatility, breadth, and candle confirmation all pass.
// ============================================================================
// SPY 0DTE Scalper
// Timeframe: 1-minute
// Version: 1.0.0
// Author: Chris Thomas
// ============================================================================
// Purpose-built overlay for scalping SPY 0DTE options on the 1-minute chart.
// Targets rapid momentum scalps with 1-5 minute hold times. The 1-minute
// chart produces ~390 RTH bars per session, so the signal engine uses strict
// AND-gate logic (all conditions must pass) to suppress noise and surface
// only high-confluence setups as CALLS or PUTS labels.
//
// No scoring engine — pure boolean gating across price structure, momentum,
// volatility, breadth, and candlestick confirmation. All thresholds are
// configurable. The indicator does not auto-trade.
//
// Components:
// - EMA ribbon (9/21/50) with dynamic trend cloud fill
// - Session-anchored VWAP with standard deviation bands
// - RSI momentum filter (neutral-zone gating)
// - ADX / DMI trend strength filter
// - ATR realized volatility
// - TTM Squeeze detection (BB/KC compression) with optional signal filter
// - NYSE TICK Index breadth (6-tier classification, optional signal filter)
// - Volume Footprint via request.footprint() (dashboard-only, no signal
// coupling). Requires TradingView Premium/Ultimate.
// - Candle pattern detection (engulfing, strong close, hammer, shooting star)
// - Key levels: Prior Day H/L/C, Pre-Market H/L, Opening Range, HOD/LOD
// - Regime classifier (BULLISH / BEARISH / RANGING / NO TRADE)
// - VWAP cross markers (diamond shapes)
// - Signal cooldown (configurable bar count)
// - 20-row heads-up dashboard
// - Dual alert system: 9 alertcondition + 4 dynamic alert() calls
// ============================================================================
// ============================================================================
// TradingView Pine Script v6
// ============================================================================
//@version=6
indicator(
title = "SPY 0DTE Scalper - 1m",
shorttitle = "SPY-0-1min",
overlay = true,
max_labels_count = 500,
max_lines_count = 500,
max_boxes_count = 200,
max_bars_back = 5000
)
// ============================================================================
// CONSTANTS
// ============================================================================
var string GP_EMA = "EMA Ribbon"
var string GP_VWAP = "VWAP"
var string GP_RSI = "RSI"
var string GP_ADX = "ADX"
var string GP_ATR = "ATR"
var string GP_SQUEEZE = "TTM Squeeze"
var string GP_TICK = "NYSE TICK"
var string GP_LEVELS = "Key Levels"
var string GP_SESSION = "Session & Time"
var string GP_SIGNALS = "Signal Logic"
var string GP_DASH = "Dashboard"
// Colors — vibrant, dark-theme optimized
var color C_VWAP = #FFFFFF
var color C_VWAP_BAND = #00BCD4
var color C_EMA_FAST = #FFD600
var color C_EMA_MID = #FF9100
var color C_EMA_SLOW = #FF1744
var color C_CLOUD_BULL = color.new(#00E676, 85)
var color C_CLOUD_BEAR = color.new(#FF1744, 85)
var color C_CLOUD_MIXED = color.new(#FFD600, 90)
var color C_PM_HIGH = #FF5252
var color C_PM_LOW = #69F0AE
var color C_PDH = #FF6E40
var color C_PDL = #64FFDA
var color C_PDC = #B0BEC5
var color C_OR_HIGH = #E040FB
var color C_OR_LOW = #B388FF
var color C_CALLS = #00E676
var color C_PUTS = #FF1744
var color C_BG_CALLS = color.new(#00E676, 92)
var color C_BG_PUTS = color.new(#FF1744, 92)
var color C_DASH_BG = color.new(#1A1A2E, 5)
var color C_DASH_HEADER = #7C4DFF
var color C_DASH_TEXT = #E0E0E0
var color C_GREEN = #00E676
var color C_RED = #FF1744
var color C_YELLOW = #FFD600
var color C_ORANGE = #FF9100
var color C_GRAY = #616161
var color C_NEUTRAL = #B0BEC5
// Footprint colors
var string GP_FOOTPRINT = "Volume Footprint"
var color C_FP_POC = #E040FB
var color C_FP_DELTA_P = #00E676
var color C_FP_DELTA_N = #FF1744
// ============================================================================
// INPUTS
// ============================================================================
// --- EMA Ribbon ---
i_emaFastLen = input.int(8, "Fast EMA Length", minval=2, group=GP_EMA)
i_emaMidLen = input.int(13, "Mid EMA Length", minval=2, group=GP_EMA)
i_emaSlowLen = input.int(21, "Slow EMA Length", minval=2, group=GP_EMA)
i_showEmaCloud = input.bool(true, "Show EMA Cloud Fill", group=GP_EMA)
// --- VWAP ---
i_showVwap = input.bool(true, "Show VWAP", group=GP_VWAP)
i_showVwapBands = input.bool(true, "Show VWAP +/- 1 StdDev", group=GP_VWAP)
i_vwapBandMult = input.float(1.0, "VWAP Band Multiplier", minval=0.5, maxval=3.0, step=0.25, group=GP_VWAP)
// --- RSI ---
i_rsiLen = input.int(14, "RSI Length", minval=2, group=GP_RSI)
i_rsiOB = input.int(70, "RSI Overbought", minval=50, maxval=95, group=GP_RSI)
i_rsiOS = input.int(30, "RSI Oversold", minval=5, maxval=50, group=GP_RSI)
// --- ADX ---
i_adxLen = input.int(14, "ADX Length", minval=2, group=GP_ADX)
i_adxNoTrend = input.int(15, "ADX No-Trend Threshold", minval=5, maxval=30, group=GP_ADX)
i_adxTrend = input.int(25, "ADX Trending Threshold", minval=15, maxval=50, group=GP_ADX)
i_adxStrong = input.int(40, "ADX Strong Trend Threshold", minval=25, maxval=60, group=GP_ADX)
// --- ATR ---
i_atrLen = input.int(14, "ATR Length", minval=2, group=GP_ATR)
// --- TTM Squeeze ---
i_useSqueeze = input.bool(true, "Enable TTM Squeeze Detection", group=GP_SQUEEZE,
tooltip="Detects Bollinger Band compression inside Keltner Channels — volatility squeeze precedes breakouts.")
i_sqzBBLen = input.int(20, "BB Length", minval=5, maxval=50, group=GP_SQUEEZE)
i_sqzBBMult = input.float(2.0, "BB Multiplier", minval=0.5, maxval=4.0, step=0.25, group=GP_SQUEEZE)
i_sqzKCLen = input.int(20, "KC Length", minval=5, maxval=50, group=GP_SQUEEZE)
i_sqzKCMult = input.float(1.5, "KC Multiplier", minval=0.5, maxval=4.0, step=0.25, group=GP_SQUEEZE)
// --- NYSE TICK ---
i_useTick = input.bool(true, "Enable NYSE TICK Index", group=GP_TICK,
tooltip="Pulls NYSE TICK (USI:TICK) for market breadth confirmation. Requires RTH data.")
i_tickSymbol = input.string("USI:TICK", "TICK Symbol", group=GP_TICK,
options=["USI:TICK", "USI:TICK.NQ"])
i_tickBull = input.int(500, "TICK Bullish Threshold", minval=100, maxval=1000, step=50, group=GP_TICK)
i_tickBear = input.int(-500, "TICK Bearish Threshold", minval=-1000, maxval=-100, step=50, group=GP_TICK)
i_tickExtreme = input.int(800, "TICK Extreme Threshold", minval=500, maxval=1500, step=50, group=GP_TICK)
// --- Volume Footprint ---
i_useFootprint = input.bool(true, "Enable Volume Footprint", group=GP_FOOTPRINT,
tooltip="Requests volume footprint data for the current bar. Requires TradingView Premium or Ultimate. Displays buy/sell volume, delta, and POC in the dashboard. Does NOT affect signal generation — informational only. Footprint data repaints by design.")
i_fpTicksPerRow = input.int(10, "Ticks Per Footprint Row", minval=1, maxval=200, group=GP_FOOTPRINT,
tooltip="Number of price ticks per row. For SPY ($0.01 mintick), 10 = $0.10 per row. On 1-min bars with typical $0.20-$0.80 ranges, this gives 2-8 rows per bar.")
i_fpVaPct = input.int(70, "Value Area Percentage", minval=50, maxval=95, step=5, group=GP_FOOTPRINT)
i_fpShowPOC = input.bool(true, "Show POC Level", group=GP_FOOTPRINT,
tooltip="Plots the Point of Control as a step line. Visual reference only — not used in signal logic.")
// --- Key Levels ---
i_showPM = input.bool(true, "Show Pre-Market High/Low", group=GP_LEVELS)
i_showPD = input.bool(true, "Show Prior Day H/L/C", group=GP_LEVELS)
i_showOR = input.bool(true, "Show Opening Range", group=GP_LEVELS)
i_orMinutes = input.int(5, "Opening Range Minutes", minval=1, maxval=30, group=GP_LEVELS)
i_showHODLOD = input.bool(true, "Show Current Session HOD/LOD", group=GP_LEVELS)
// --- Session ---
i_pmSession = input.session("0400-0930", "Pre-Market Session", group=GP_SESSION)
i_rthSession = input.session("0930-1600", "Regular Trading Hours", group=GP_SESSION)
i_tz = input.string("America/New_York", "Timezone", group=GP_SESSION,
options=["America/New_York", "America/Chicago", "America/Los_Angeles", "UTC"])
// --- Signal Logic ---
i_showSignals = input.bool(true, "Show CALLS / PUTS Signals", group=GP_SIGNALS)
i_cooldownBars = input.int(5, "Signal Cooldown (bars)", minval=1, maxval=30, group=GP_SIGNALS)
i_signalStart = input.session("0935-1545", "Signal Time Window", group=GP_SIGNALS)
i_requireADX = input.bool(true, "Require ADX Above No-Trend", group=GP_SIGNALS)
i_showVwapCross = input.bool(true, "Show VWAP Cross Markers", group=GP_SIGNALS)
i_vwapExtFilter = input.float(1.5, "Max VWAP Distance (ATR multiples)", minval=0.5, maxval=5.0, step=0.25, group=GP_SIGNALS)
i_requireSqueeze = input.bool(false, "Require Squeeze Fired (filter)", group=GP_SIGNALS,
tooltip="When enabled, signals are suppressed during active squeeze. Only fires when volatility is expanding (squeeze OFF or just FIRED).")
i_requireTick = input.bool(false, "Require TICK Alignment (filter)", group=GP_SIGNALS,
tooltip="When enabled, CALLS require TICK > 0, PUTS require TICK < 0. Light directional breadth filter.")
// --- Dashboard ---
i_showDash = input.bool(true, "Show Dashboard", group=GP_DASH)
i_dashSize = input.string("small", "Dashboard Text Size", options=["tiny", "small", "normal", "large"], group=GP_DASH)
// ============================================================================
// UTILITY FUNCTIONS
// ============================================================================
// Map dashboard size string to size constant
getDashSize(string s) =>
switch s
"tiny" => size.tiny
"small" => size.small
"large" => size.large
=> size.normal
// Check if current bar falls within a given session
inSession(string sess) =>
not na(time(timeframe.period, sess, i_tz))
// Format a float to 2 decimal places
f2(float val) =>
str.tostring(val, "#.##")
// Return green for positive, red for negative
posnegColor(float val) =>
val >= 0 ? C_GREEN : C_RED
// ============================================================================
// CORE INDICATOR CALCULATIONS
// ============================================================================
// --- EMA Ribbon ---
emaFast = ta.ema(close, i_emaFastLen)
emaMid = ta.ema(close, i_emaMidLen)
emaSlow = ta.ema(close, i_emaSlowLen)
bool emaBullish = emaFast > emaMid and emaMid > emaSlow
bool emaBearish = emaFast < emaMid and emaMid < emaSlow
color emaCloudColor = emaBullish ? C_CLOUD_BULL : emaBearish ? C_CLOUD_BEAR : C_CLOUD_MIXED
// --- VWAP + Standard Deviation Bands ---
float vwapValue = ta.vwap(hlc3)
float vwapCumVol = ta.cum(volume)
float vwapCumPV = ta.cum(hlc3 * volume)
float vwapCumPV2 = ta.cum(hlc3 * hlc3 * volume)
float vwapMean = vwapCumPV / vwapCumVol
float vwapVar = math.max(vwapCumPV2 / vwapCumVol - vwapMean * vwapMean, 0)
float vwapStdev = math.sqrt(vwapVar)
float vwapUpper = vwapValue + vwapStdev * i_vwapBandMult
float vwapLower = vwapValue - vwapStdev * i_vwapBandMult
float vwapDist = close - vwapValue
// --- RSI ---
float rsiValue = ta.rsi(close, i_rsiLen)
getRsiLabel() =>
if rsiValue > i_rsiOB
"OVERBOUGHT"
else if rsiValue < i_rsiOS
"OVERSOLD"
else
"NEUTRAL"
getRsiColor() =>
if rsiValue > i_rsiOB
C_RED
else if rsiValue < i_rsiOS
C_GREEN
else
C_NEUTRAL
// --- ADX with DI+/DI- ---
[diPlus, diMinus, adxValue] = ta.dmi(i_adxLen, i_adxLen)
getAdxLabel() =>
if adxValue >= i_adxStrong
"STRONG TREND"
else if adxValue >= i_adxTrend
"TRENDING"
else if adxValue >= i_adxNoTrend
"WEAK/RANGING"
else
"NO TREND"
getAdxColor() =>
if adxValue >= i_adxTrend
C_GREEN
else if adxValue >= i_adxNoTrend
C_YELLOW
else
C_RED
// --- ATR ---
float atrValue = ta.atr(i_atrLen)
// ============================================================================
// TTM SQUEEZE DETECTION
// ============================================================================
// Bollinger Bands
float sqzBBBasis = ta.sma(close, i_sqzBBLen)
float sqzBBDev = ta.stdev(close, i_sqzBBLen) * i_sqzBBMult
float sqzBBUpper = sqzBBBasis + sqzBBDev
float sqzBBLower = sqzBBBasis - sqzBBDev
// Keltner Channels
float sqzKCBasis = ta.ema(close, i_sqzKCLen)
float sqzKCRange = ta.atr(i_sqzKCLen) * i_sqzKCMult
float sqzKCUpper = sqzKCBasis + sqzKCRange
float sqzKCLower = sqzKCBasis - sqzKCRange
// Squeeze state: BB inside KC = squeeze ON (compression)
bool squeezeOn = sqzBBUpper < sqzKCUpper and sqzBBLower > sqzKCLower
bool squeezeFired = not squeezeOn and squeezeOn[1]
// Track bars since last squeeze fired for recency context
var int sqzBarsSinceFire = 999
if squeezeFired
sqzBarsSinceFire := 0
else
sqzBarsSinceFire += 1
// Squeeze momentum histogram (linear regression of midline delta)
// Measures directional energy during/after squeeze
float sqzMomSource = close - math.avg(sqzBBBasis, sqzKCBasis)
float sqzMomentum = ta.linreg(sqzMomSource, i_sqzBBLen, 0)
// ============================================================================
// NYSE TICK INDEX
// ============================================================================
float tickValue = i_useTick ? request.security(i_tickSymbol, "1", close, lookahead=barmerge.lookahead_off) : na
// ============================================================================
// VOLUME FOOTPRINT DATA
// ============================================================================
// Dashboard-only integration. No signal coupling.
// request.footprint() counts toward the 40-call request.*() budget.
// Total request.*() calls after tuple consolidation: 3
// 1x "1" (TICK, same-TF), 1x "D" (daily tuple), 1x footprint
footprint fpData = i_useFootprint ? request.footprint(i_fpTicksPerRow, i_fpVaPct) : na
// Bar-level metrics
float fpBuyVol = not na(fpData) ? fpData.buy_volume() : na
float fpSellVol = not na(fpData) ? fpData.sell_volume() : na
float fpDelta = not na(fpData) ? fpData.delta() : na
// POC midpoint price
float fpPocPrice = na
if not na(fpData)
volume_row pocRow = fpData.poc()
if not na(pocRow)
fpPocPrice := (pocRow.up_price() + pocRow.down_price()) / 2.0
// Derived
float fpTotalVol = nz(fpBuyVol) + nz(fpSellVol)
float fpDeltaPct = fpTotalVol > 0 ? (fpDelta / fpTotalVol) * 100.0 : na
bool fpAvailable = not na(fpData)
// Delta strength classification for dashboard
fpDeltaLabel() =>
if na(fpDelta)
"N/A"
else if math.abs(nz(fpDeltaPct)) > 40
fpDelta > 0 ? "STRONG BUY" : "STRONG SELL"
else if math.abs(nz(fpDeltaPct)) > 20
fpDelta > 0 ? "BUY LEAN" : "SELL LEAN"
else
"BALANCED"
fpDeltaColor() =>
if na(fpDelta)
C_GRAY
else if math.abs(nz(fpDeltaPct)) > 40
fpDelta > 0 ? C_FP_DELTA_P : C_FP_DELTA_N
else if math.abs(nz(fpDeltaPct)) > 20
fpDelta > 0 ? color.new(C_FP_DELTA_P, 30) : color.new(C_FP_DELTA_N, 30)
else
C_NEUTRAL
// ============================================================================
// SESSION DETECTION & KEY LEVELS
// ============================================================================
bool isRTH = inSession(i_rthSession)
bool isPM = inSession(i_pmSession)
bool rthStart = isRTH and not isRTH[1]
// --- Pre-Market High / Low ---
var float pmHigh = na
var float pmLow = na
if isPM
if na(pmHigh) or not isPM[1]
pmHigh := high
pmLow := low
else
pmHigh := math.max(pmHigh, high)
pmLow := math.min(pmLow, low)
// --- Prior Day High / Low / Close + Current Day Open ---
// Consolidated into a single request.security() tuple — 1 pass through daily data instead of 4
[pdHigh, pdLow, pdClose, dayOpen] = request.security(
syminfo.tickerid, "D",
[high[1], low[1], close[1], open],
lookahead=barmerge.lookahead_on)
// --- Opening Range ---
var float orHigh = na
var float orLow = na
var bool orComplete = false
var int orBars = 0
if rthStart
orHigh := high
orLow := low
orComplete := false
orBars := 1
else if isRTH and not orComplete
orBars += 1
orHigh := math.max(orHigh, high)
orLow := math.min(orLow, low)
if orBars >= i_orMinutes
orComplete := true
// --- Current Session HOD / LOD ---
var float sessionHigh = na
var float sessionLow = na
if rthStart
sessionHigh := high
sessionLow := low
else if isRTH
sessionHigh := math.max(nz(sessionHigh, high), high)
sessionLow := math.min(nz(sessionLow, low), low)
// ============================================================================
// REGIME / MODE ENGINE
// ============================================================================
getMode() =>
if adxValue < i_adxNoTrend and math.abs(vwapDist) < atrValue * 0.5
"NO TRADE"
else if adxValue < i_adxNoTrend
"RANGING"
else if adxValue >= i_adxNoTrend and emaBullish and close > vwapValue
"BULLISH"
else if adxValue >= i_adxNoTrend and emaBearish and close < vwapValue
"BEARISH"
else if adxValue >= i_adxTrend
"TRANSITION"
else
"RANGING"
string currentMode = getMode()
getModeColor() =>
switch currentMode
"BULLISH" => C_GREEN
"BEARISH" => C_RED
"RANGING" => C_YELLOW
"TRANSITION" => C_ORANGE
"NO TRADE" => C_GRAY
=> C_NEUTRAL
// ============================================================================
// SIGNAL LOGIC
// ============================================================================
// --- Shared filter conditions ---
bool inSignalWindow = inSession(i_signalStart)
bool adxFilter = not i_requireADX or adxValue >= i_adxNoTrend
bool vwapExtended = math.abs(vwapDist) > atrValue * i_vwapExtFilter
bool barConfirmed = barstate.isconfirmed
// --- Squeeze filter: when enabled, suppress signals during active squeeze ---
bool squeezeFilter = not i_requireSqueeze or not squeezeOn
// --- TICK filter: when enabled, require directional alignment ---
bool tickFilterCalls = not i_requireTick or (not na(tickValue) and tickValue > 0)
bool tickFilterPuts = not i_requireTick or (not na(tickValue) and tickValue < 0)
// --- Cooldown tracking ---
var int barsSinceSignal = 999
barsSinceSignal += 1
// --- Candle pattern detection ---
bool bullishEngulfing = close > open and close > high[1] and open <= low[1]
bool bearishEngulfing = close < open and close < low[1] and open >= high[1]
bool strongBullClose = close > open and (close - open) > (high - low) * 0.5
bool strongBearClose = close < open and (open - close) > (high - low) * 0.5
bool hammer = close > open and (open - low) > (close - open) * 2 and (high - close) < (close - open) * 0.5
bool shootingStar = close < open and (high - open) > (open - close) * 2 and (close - low) < (open - close) * 0.5
// --- CALLS (bullish entry) conditions ---
bool callsBase = barConfirmed and inSignalWindow and adxFilter and not vwapExtended and squeezeFilter and tickFilterCalls and barsSinceSignal >= i_cooldownBars
bool callsVwapOk = close > vwapValue or (close > vwapValue - atrValue * 0.3 and close[1] < vwapValue)
bool callsEmaOk = emaFast > emaSlow or (close > emaSlow and close[1] < emaSlow)
bool callsRsiOk = rsiValue > i_rsiOS and rsiValue < i_rsiOB
bool callsCandle = bullishEngulfing or strongBullClose or hammer
bool callsSignal = callsBase and callsVwapOk and callsEmaOk and callsRsiOk and callsCandle
// --- PUTS (bearish entry) conditions ---
bool putsBase = barConfirmed and inSignalWindow and adxFilter and not vwapExtended and squeezeFilter and tickFilterPuts and barsSinceSignal >= i_cooldownBars
bool putsVwapOk = close < vwapValue or (close < vwapValue + atrValue * 0.3 and close[1] > vwapValue)
bool putsEmaOk = emaFast < emaSlow or (close < emaSlow and close[1] > emaSlow)
bool putsRsiOk = rsiValue > i_rsiOS and rsiValue < i_rsiOB
bool putsCandle = bearishEngulfing or strongBearClose or shootingStar
bool putsSignal = putsBase and putsVwapOk and putsEmaOk and putsRsiOk and putsCandle
// Reset cooldown on signal fire
if callsSignal or putsSignal
barsSinceSignal := 0
// --- VWAP cross detection ---
bool vwapCrossUp = ta.crossover(close, vwapValue)
bool vwapCrossDown = ta.crossunder(close, vwapValue)
// ============================================================================
// PLOTS — EMA RIBBON
// ============================================================================
pFast = plot(emaFast, "EMA Fast", C_EMA_FAST, linewidth=1)
pMid = plot(emaMid, "EMA Mid", C_EMA_MID, linewidth=1)
pSlow = plot(emaSlow, "EMA Slow", C_EMA_SLOW, linewidth=1)
fill(pFast, pSlow, color=i_showEmaCloud ? emaCloudColor : color.new(color.white, 100), title="EMA Cloud")
// ============================================================================
// PLOTS — VWAP + BANDS
// ============================================================================
plot(i_showVwap ? vwapValue : na, "VWAP", C_VWAP, linewidth=2)
plot(i_showVwapBands ? vwapUpper : na, "VWAP +1 SD", C_VWAP_BAND, linewidth=1, style=plot.style_circles)
plot(i_showVwapBands ? vwapLower : na, "VWAP -1 SD", C_VWAP_BAND, linewidth=1, style=plot.style_circles)
// --- Footprint POC Level ---
plot(i_useFootprint and i_fpShowPOC ? fpPocPrice : na,
"Footprint POC", C_FP_POC, linewidth=2, style=plot.style_stepline)
// ============================================================================
// KEY LEVELS — HORIZONTAL LINES WITH LABELS
// ============================================================================
// --- Pre-Market High / Low ---
var line pmHighLine = na
var line pmLowLine = na
var label pmHighLbl = na
var label pmLowLbl = na
if barstate.islast and i_showPM and not na(pmHigh) and isRTH
if not na(pmHighLine)
line.delete(pmHighLine)
line.delete(pmLowLine)
label.delete(pmHighLbl)
label.delete(pmLowLbl)
pmHighLine := line.new(bar_index - 300, pmHigh, bar_index + 20, pmHigh,
color=C_PM_HIGH, style=line.style_dashed, width=1)
pmLowLine := line.new(bar_index - 300, pmLow, bar_index + 20, pmLow,
color=C_PM_LOW, style=line.style_dashed, width=1)
pmHighLbl := label.new(bar_index + 22, pmHigh, "PM HIGH " + f2(pmHigh),
style=label.style_label_left, color=color.new(C_PM_HIGH, 80),
textcolor=C_PM_HIGH, size=size.small)
pmLowLbl := label.new(bar_index + 22, pmLow, "PM LOW " + f2(pmLow),
style=label.style_label_left, color=color.new(C_PM_LOW, 80),
textcolor=C_PM_LOW, size=size.small)
// --- Prior Day High / Low / Close ---
var line pdhLine = na
var line pdlLine = na
var line pdcLine = na
var label pdhLbl = na
var label pdlLbl = na
var label pdcLbl = na
if barstate.islast and i_showPD and not na(pdHigh)
if not na(pdhLine)
line.delete(pdhLine)
line.delete(pdlLine)
line.delete(pdcLine)
label.delete(pdhLbl)
label.delete(pdlLbl)
label.delete(pdcLbl)
pdhLine := line.new(bar_index - 300, pdHigh, bar_index + 20, pdHigh,
color=C_PDH, style=line.style_dotted, width=1)
pdlLine := line.new(bar_index - 300, pdLow, bar_index + 20, pdLow,
color=C_PDL, style=line.style_dotted, width=1)
pdcLine := line.new(bar_index - 300, pdClose, bar_index + 20, pdClose,
color=C_PDC, style=line.style_dotted, width=1)
pdhLbl := label.new(bar_index + 22, pdHigh, "PDH " + f2(pdHigh),
style=label.style_label_left, color=color.new(C_PDH, 80),
textcolor=C_PDH, size=size.small)
pdlLbl := label.new(bar_index + 22, pdLow, "PDL " + f2(pdLow),
style=label.style_label_left, color=color.new(C_PDL, 80),
textcolor=C_PDL, size=size.small)
pdcLbl := label.new(bar_index + 22, pdClose, "PDC " + f2(pdClose),
style=label.style_label_left, color=color.new(C_PDC, 80),
textcolor=C_PDC, size=size.small)
// --- Opening Range ---
var line orHighLine = na
var line orLowLine = na
var label orHighLbl = na
var label orLowLbl = na
if barstate.islast and i_showOR and orComplete and not na(orHigh)
if not na(orHighLine)
line.delete(orHighLine)
line.delete(orLowLine)
label.delete(orHighLbl)
label.delete(orLowLbl)
orHighLine := line.new(bar_index - 300, orHigh, bar_index + 20, orHigh,
color=C_OR_HIGH, style=line.style_dashed, width=1)
orLowLine := line.new(bar_index - 300, orLow, bar_index + 20, orLow,
color=C_OR_LOW, style=line.style_dashed, width=1)
orHighLbl := label.new(bar_index + 22, orHigh, "OR HIGH " + f2(orHigh),
style=label.style_label_left, color=color.new(C_OR_HIGH, 80),
textcolor=C_OR_HIGH, size=size.small)
orLowLbl := label.new(bar_index + 22, orLow, "OR LOW " + f2(orLow),
style=label.style_label_left, color=color.new(C_OR_LOW, 80),
textcolor=C_OR_LOW, size=size.small)
// --- Current Session HOD / LOD ---
var line hodLine = na
var line lodLine = na
var label hodLbl = na
var label lodLbl = na
if barstate.islast and i_showHODLOD and isRTH and not na(sessionHigh)
if not na(hodLine)
line.delete(hodLine)
line.delete(lodLine)
label.delete(hodLbl)
label.delete(lodLbl)
hodLine := line.new(bar_index - 300, sessionHigh, bar_index + 20, sessionHigh,
color=C_GREEN, style=line.style_solid, width=1)
lodLine := line.new(bar_index - 300, sessionLow, bar_index + 20, sessionLow,
color=C_RED, style=line.style_solid, width=1)
hodLbl := label.new(bar_index + 22, sessionHigh, "HOD " + f2(sessionHigh),
style=label.style_label_left, color=color.new(C_GREEN, 80),
textcolor=C_GREEN, size=size.small)
lodLbl := label.new(bar_index + 22, sessionLow, "LOD " + f2(sessionLow),
style=label.style_label_left, color=color.new(C_RED, 80),
textcolor=C_RED, size=size.small)
// ============================================================================
// SIGNAL VISUAL CUES
// ============================================================================
// Background highlight on signal bars
bgcolor(i_showSignals and callsSignal ? C_BG_CALLS : na, title="CALLS Background Flash")
bgcolor(i_showSignals and putsSignal ? C_BG_PUTS : na, title="PUTS Background Flash")
// Arrow shapes for fast scanning
plotshape(i_showSignals and callsSignal, title="CALLS Arrow", style=shape.triangleup,
location=location.belowbar, color=C_CALLS, size=size.tiny)
plotshape(i_showSignals and putsSignal, title="PUTS Arrow", style=shape.triangledown,
location=location.abovebar, color=C_PUTS, size=size.tiny)
// Detailed text labels with hover tooltip
if i_showSignals and callsSignal
string sqzTip = i_useSqueeze ? "\nSqueeze: " + (squeezeOn ? "ON" : squeezeFired ? "FIRED" : "OFF") : ""
string tickTip = i_useTick and not na(tickValue) ? "\nTICK: " + str.tostring(math.round(tickValue)) : ""
string tip = "RSI: " + f2(rsiValue) + " | ADX: " + f2(adxValue) +
"\nVWAP Dist: " + f2(vwapDist) + " | Mode: " + currentMode +
"\nATR: " + f2(atrValue) + " | EMA: " + (emaBullish ? "BULL" : emaBearish ? "BEAR" : "MIXED") +
sqzTip + tickTip
label.new(bar_index, low, "CALLS",
style=label.style_label_up, color=C_CALLS,
textcolor=color.black, size=size.small, tooltip=tip)
if i_showSignals and putsSignal
string sqzTip = i_useSqueeze ? "\nSqueeze: " + (squeezeOn ? "ON" : squeezeFired ? "FIRED" : "OFF") : ""
string tickTip = i_useTick and not na(tickValue) ? "\nTICK: " + str.tostring(math.round(tickValue)) : ""
string tip = "RSI: " + f2(rsiValue) + " | ADX: " + f2(adxValue) +
"\nVWAP Dist: " + f2(vwapDist) + " | Mode: " + currentMode +
"\nATR: " + f2(atrValue) + " | EMA: " + (emaBullish ? "BULL" : emaBearish ? "BEAR" : "MIXED") +
sqzTip + tickTip
label.new(bar_index, high, "PUTS",
style=label.style_label_down, color=C_PUTS,
textcolor=color.white, size=size.small, tooltip=tip)
// VWAP cross markers
plotshape(i_showVwapCross and vwapCrossUp and barConfirmed, title="VWAP Cross Bullish",
style=shape.diamond, location=location.belowbar, color=#76FF03, size=size.tiny)
plotshape(i_showVwapCross and vwapCrossDown and barConfirmed, title="VWAP Cross Bearish",
style=shape.diamond, location=location.abovebar, color=C_PUTS, size=size.tiny)
// ============================================================================
// DASHBOARD TABLE
// ============================================================================
var table dash = table.new(position.bottom_right, 3, 20,
bgcolor = C_DASH_BG,
border_width = 0,
border_color = color.new(#FFFFFF, 85),
frame_width = 1,
frame_color = color.new(#FFFFFF, 80))
// dayOpen already fetched in the consolidated daily tuple above
float avgVol = ta.sma(volume, 20)
if barstate.islast and i_showDash
string sz = i_dashSize
// Helper to resolve size constant
cellSize = getDashSize(sz)
// --- Row 0: Header ---
table.cell(dash, 0, 0, " SPY 0DTE Scalper - 1m ", text_color=#FFFFFF,
bgcolor=C_DASH_HEADER, text_size=cellSize, text_halign=text.align_center)
table.cell(dash, 1, 0, "", bgcolor=C_DASH_HEADER, text_size=cellSize)
table.cell(dash, 2, 0, "", bgcolor=C_DASH_HEADER, text_size=cellSize)
table.merge_cells(dash, 0, 0, 2, 0)
// --- Row 1: Price ---
color priceClr = close >= open ? C_GREEN : C_RED
string dayType = close >= open ? "Green Day" : "Red Day"
table.cell(dash, 0, 1, "Price", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 1, f2(close), text_color=priceClr, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 1, dayType, text_color=priceClr, text_size=cellSize, text_halign=text.align_right)
// --- Row 2: Mode ---
string mAdvice = currentMode == "NO TRADE" ? "AVOID" : currentMode == "RANGING" ? "CAUTION" : "ACTIVE"
table.cell(dash, 0, 2, "Mode", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 2, currentMode, text_color=getModeColor(), text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 2, mAdvice, text_color=getModeColor(), text_size=cellSize, text_halign=text.align_right)
// --- Row 3: RSI ---
table.cell(dash, 0, 3, "RSI (" + str.tostring(i_rsiLen) + ")",
text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 3, f2(rsiValue), text_color=getRsiColor(), text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 3, getRsiLabel(), text_color=getRsiColor(), text_size=cellSize, text_halign=text.align_right)
// --- Row 4: ADX ---
table.cell(dash, 0, 4, "ADX", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 4, f2(adxValue), text_color=getAdxColor(), text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 4, getAdxLabel(), text_color=getAdxColor(), text_size=cellSize, text_halign=text.align_right)
// --- Row 5: VWAP Distance ---
float absVD = math.abs(vwapDist)
color vdClr = absVD > atrValue ? C_RED : absVD > atrValue * 0.5 ? C_YELLOW : C_GREEN
string vdLbl = absVD > atrValue ? "EXTENDED" : "NEAR VWAP"
table.cell(dash, 0, 5, "VWAP Dist", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 5, f2(vwapDist), text_color=vdClr, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 5, vdLbl, text_color=vdClr, text_size=cellSize, text_halign=text.align_right)
// --- Row 6: PM High ---
if not na(pmHigh)
float pmhD = close - pmHigh
string pmhLbl = close < pmHigh ? "RESISTANCE" : "CLEARED"
color pmhClr = close < pmHigh ? C_RED : C_GREEN
table.cell(dash, 0, 6, "PM High", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 6, f2(pmhD), text_color=pmhClr, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 6, pmhLbl, text_color=pmhClr, text_size=cellSize, text_halign=text.align_right)
else
table.cell(dash, 0, 6, "PM High", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 6, "N/A", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 6, "", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_right)
// --- Row 7: PM Low ---
if not na(pmLow)
float pmlD = close - pmLow
string pmlLbl = close > pmLow ? "SUPPORT" : "BROKEN"
color pmlClr = close > pmLow ? C_GREEN : C_RED
table.cell(dash, 0, 7, "PM Low", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 7, f2(pmlD), text_color=pmlClr, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 7, pmlLbl, text_color=pmlClr, text_size=cellSize, text_halign=text.align_right)
else
table.cell(dash, 0, 7, "PM Low", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 7, "N/A", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 7, "", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_right)
// --- Row 8: ATR ---
table.cell(dash, 0, 8, "ATR (" + str.tostring(i_atrLen) + ")",
text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 8, f2(atrValue), text_color=C_NEUTRAL, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 8, "", text_size=cellSize)
// --- Row 9: EMA Trend ---
string emaTrStr = emaBullish ? "BULLISH" : emaBearish ? "BEARISH" : "MIXED"
color emaTrClr = emaBullish ? C_GREEN : emaBearish ? C_RED : C_YELLOW
table.cell(dash, 0, 9, "EMA Trend", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 9, emaTrStr, text_color=emaTrClr, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 9, "", text_size=cellSize)
// --- Row 10: Last Signal ---
string sigStr = callsSignal ? "CALLS" : putsSignal ? "PUTS" : "—"
color sigClr = callsSignal ? C_GREEN : putsSignal ? C_RED : C_GRAY
table.cell(dash, 0, 10, "Signal", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 10, sigStr, text_color=sigClr, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 10, "", text_size=cellSize)
// --- Row 11: Day Change % ---
float dayChg = not na(dayOpen) and dayOpen != 0 ? ((close - dayOpen) / dayOpen) * 100 : 0.0
string dcStr = (dayChg >= 0 ? "+" : "") + f2(dayChg) + "%"
table.cell(dash, 0, 11, "Day Chg", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 11, dcStr, text_color=posnegColor(dayChg), text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 11, "", text_size=cellSize)
// --- Row 12: Relative Volume ---
float rVol = avgVol > 0 ? volume / avgVol : 0.0
string rvStr = f2(rVol) + "x"
color rvClr = rVol > 1.5 ? C_GREEN : rVol > 1.0 ? C_YELLOW : C_GRAY
string rvLbl = rVol > 1.5 ? "SPIKE" : rVol > 1.0 ? "ABOVE AVG" : "BELOW AVG"
table.cell(dash, 0, 12, "Rel Vol", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 12, rvStr, text_color=rvClr, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 12, rvLbl, text_color=rvClr, text_size=cellSize, text_halign=text.align_right)
// --- Row 13: DI+/DI- Spread ---
float diSpread = diPlus - diMinus
string diStr = "+" + f2(diPlus) + " / -" + f2(diMinus)
color diClr = diSpread > 0 ? C_GREEN : C_RED
string diLbl = diSpread > 0 ? "BULLS" : "BEARS"
table.cell(dash, 0, 13, "DI Spread", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 13, diStr, text_color=diClr, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 13, diLbl, text_color=diClr, text_size=cellSize, text_halign=text.align_right)
// --- Row 14: TTM Squeeze ---
if i_useSqueeze
string sqzStr = squeezeOn ? "ON" : squeezeFired ? "FIRED" : "OFF"
color sqzClr = squeezeOn ? C_ORANGE : squeezeFired ? C_GREEN : sqzBarsSinceFire <= 5 ? C_GREEN : C_GRAY
string sqzLbl = squeezeOn ? "BUILDING" : squeezeFired ? "BREAKOUT" : sqzBarsSinceFire <= 5 ? str.tostring(sqzBarsSinceFire) + " bars ago" : "NORMAL"
string sqzMomStr = sqzMomentum > 0 ? "+" : ""
table.cell(dash, 0, 14, "Squeeze", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 14, sqzStr, text_color=sqzClr, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 14, sqzLbl, text_color=sqzClr, text_size=cellSize, text_halign=text.align_right)
else
table.cell(dash, 0, 14, "Squeeze", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 14, "OFF", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 14, "", text_size=cellSize)
// --- Row 15: NYSE TICK ---
if i_useTick and not na(tickValue)
float tv = tickValue
int tvRnd = math.round(tv)
string tvStr = str.tostring(tvRnd)
color tvClr = tv > i_tickExtreme ? C_GREEN : tv > i_tickBull ? C_GREEN : tv > 0 ? C_NEUTRAL : tv < -i_tickExtreme ? C_RED : tv < i_tickBear ? C_RED : tv < 0 ? C_NEUTRAL : C_GRAY
string tvLbl = tv > i_tickExtreme ? "EXTREME BULL" : tv > i_tickBull ? "BULLISH" : tv > 0 ? "MILD BULL" : tv < -i_tickExtreme ? "EXTREME BEAR" : tv < i_tickBear ? "BEARISH" : tv < 0 ? "MILD BEAR" : "FLAT"
table.cell(dash, 0, 15, "TICK", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 15, tvStr, text_color=tvClr, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 15, tvLbl, text_color=tvClr, text_size=cellSize, text_halign=text.align_right)
else
table.cell(dash, 0, 15, "TICK", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 15, i_useTick ? "N/A" : "OFF", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 15, "", text_size=cellSize)
// --- Row 16: Footprint Status ---
if i_useFootprint
table.cell(dash, 0, 16, "FP Status", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 16, fpAvailable ? "ACTIVE" : "N/A",
text_color=fpAvailable ? C_GREEN : C_GRAY, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 16, "INFO ONLY", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_right)
else
table.cell(dash, 0, 16, "FP Status", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 16, "OFF", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 16, "", text_size=cellSize)
// --- Row 17: Footprint Delta ---
if i_useFootprint and fpAvailable
string fpDStr = fpDeltaLabel() + " | " + str.tostring(math.round(nz(fpDelta))) + " (" + f2(nz(fpDeltaPct)) + "%)"
table.cell(dash, 0, 17, "FP Delta", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 17, fpDStr, text_color=fpDeltaColor(), text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 17, "", text_size=cellSize)
else
table.cell(dash, 0, 17, "FP Delta", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 17, i_useFootprint ? "N/A" : "OFF", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 17, "", text_size=cellSize)
// --- Row 18: Footprint Buy/Sell ---
if i_useFootprint and not na(fpBuyVol)
string bsStr = str.tostring(fpBuyVol, format.volume) + " / " + str.tostring(fpSellVol, format.volume)
color bsClr = fpBuyVol > fpSellVol ? C_FP_DELTA_P : C_FP_DELTA_N
table.cell(dash, 0, 18, "FP Buy/Sell", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 18, bsStr, text_color=bsClr, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 18, "", text_size=cellSize)
else
table.cell(dash, 0, 18, "FP Buy/Sell", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 18, i_useFootprint ? "N/A" : "OFF", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 18, "", text_size=cellSize)
// --- Row 19: Footprint POC ---
if i_useFootprint and not na(fpPocPrice)
table.cell(dash, 0, 19, "FP POC", text_color=C_DASH_TEXT, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 19, f2(fpPocPrice), text_color=C_FP_POC, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 19, "", text_size=cellSize)
else
table.cell(dash, 0, 19, "FP POC", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_left)
table.cell(dash, 1, 19, i_useFootprint ? "N/A" : "OFF", text_color=C_GRAY, text_size=cellSize, text_halign=text.align_right)
table.cell(dash, 2, 19, "", text_size=cellSize)
// ============================================================================
// ALERTS — STANDARD (alertcondition) + DYNAMIC (alert)
// ============================================================================
// alertcondition() — appears in TradingView "Create Alert" dropdown
alertcondition(callsSignal, title="0DTE: CALLS Signal",
message="CALLS signal fired on SPY — bullish confluence detected")
alertcondition(putsSignal, title="0DTE: PUTS Signal",
message="PUTS signal fired on SPY — bearish confluence detected")
alertcondition(vwapCrossUp, title="0DTE: VWAP Cross Bullish",
message="SPY price crossed above VWAP")
alertcondition(vwapCrossDown, title="0DTE: VWAP Cross Bearish",
message="SPY price crossed below VWAP")
alertcondition(currentMode != currentMode[1], title="0DTE: Regime Mode Change",
message="SPY regime mode has changed")
alertcondition(i_useSqueeze and squeezeFired, title="0DTE: Squeeze Fired",
message="TTM Squeeze has fired — volatility expansion detected")
// alert() — dynamic messages with interpolated context
if callsSignal
string sqzCtx = i_useSqueeze ? " | Sqz: " + (squeezeOn ? "ON" : "OFF") : ""
string tickCtx = i_useTick and not na(tickValue) ? " | TICK: " + str.tostring(math.round(tickValue)) : ""
string fpCtx = i_useFootprint and not na(fpDelta) ? " | FP: " + fpDeltaLabel() + " (d:" + str.tostring(math.round(fpDelta)) + ")" + (not na(fpPocPrice) ? " POC:" + f2(fpPocPrice) : "") : ""
alert("0DTE CALLS | SPY " + f2(close) +
" | RSI " + f2(rsiValue) +
" | ADX " + f2(adxValue) +
" | VWAP Dist " + f2(vwapDist) +
" | Mode: " + currentMode +
sqzCtx + tickCtx + fpCtx,
alert.freq_once_per_bar_close)
if putsSignal
string sqzCtx = i_useSqueeze ? " | Sqz: " + (squeezeOn ? "ON" : "OFF") : ""
string tickCtx = i_useTick and not na(tickValue) ? " | TICK: " + str.tostring(math.round(tickValue)) : ""
string fpCtx = i_useFootprint and not na(fpDelta) ? " | FP: " + fpDeltaLabel() + " (d:" + str.tostring(math.round(fpDelta)) + ")" + (not na(fpPocPrice) ? " POC:" + f2(fpPocPrice) : "") : ""
alert("0DTE PUTS | SPY " + f2(close) +
" | RSI " + f2(rsiValue) +
" | ADX " + f2(adxValue) +
" | VWAP Dist " + f2(vwapDist) +
" | Mode: " + currentMode +
sqzCtx + tickCtx + fpCtx,
alert.freq_once_per_bar_close)
if currentMode != currentMode[1]
alert("0DTE MODE SHIFT | " + str.tostring(currentMode[1]) + " -> " + currentMode +
" | SPY " + f2(close),
alert.freq_once_per_bar)
if i_useSqueeze and squeezeFired
alert("0DTE SQUEEZE FIRED | SPY " + f2(close) +
" | Momentum: " + (sqzMomentum > 0 ? "BULLISH" : "BEARISH") +
" | ADX " + f2(adxValue) +
" | Mode: " + currentMode,
alert.freq_once_per_bar_close)
// Footprint delta alert conditions
alertcondition(
i_useFootprint and not na(fpDelta) and fpDelta > 0 and nz(fpDeltaPct) > 40,
title="0DTE: Strong Positive FP Delta (>40%)",
message="SPY 1m: Strong positive footprint delta — aggressive buying dominant")
alertcondition(
i_useFootprint and not na(fpDelta) and fpDelta < 0 and nz(fpDeltaPct) < -40,
title="0DTE: Strong Negative FP Delta (>40%)",
message="SPY 1m: Strong negative footprint delta — aggressive selling dominant")
// ============================================================================
// END OF SCRIPT
// ============================================================================
Overview
SPY 0DTE Scalper - 1m plots an EMA ribbon with cloud fill, session-anchored VWAP and standard-deviation bands, prior-day and pre-market highs and lows, the opening range, and high and low of day. Settings change EMA, RSI, ADX, ATR, squeeze, TICK, and footprint thresholds, plus signal cooldown. A regime label and dashboard summarize context. It does not place trades or define exits.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Fast EMA Length
int
8
i_emaFastLen
Mid EMA Length
int
13
i_emaMidLen
Slow EMA Length
int
21
i_emaSlowLen
Show EMA Cloud Fill
bool
true
i_showEmaCloud
Show VWAP
bool
true
i_showVwap
Show VWAP +/- 1 StdDev
bool
true
i_showVwapBands
VWAP Band Multiplier
float
1.0
i_vwapBandMult
RSI Length
int
14
i_rsiLen
RSI Overbought
int
70
i_rsiOB
RSI Oversold
int
30
i_rsiOS
ADX Length
int
14
i_adxLen
ADX No-Trend Threshold
int
15
i_adxNoTrend
Show all 40 settings
Setting
Type
Default
Variable
ADX Trending Threshold
int
25
i_adxTrend
ADX Strong Trend Threshold
int
40
i_adxStrong
ATR Length
int
14
i_atrLen
Enable TTM Squeeze Detection
bool
true
i_useSqueeze
BB Length
int
20
i_sqzBBLen
BB Multiplier
float
2.0
i_sqzBBMult
KC Length
int
20
i_sqzKCLen
KC Multiplier
float
1.5
i_sqzKCMult
Enable NYSE TICK Index
bool
true
i_useTick
TICK Symbol
string
USI:TICK
i_tickSymbol
TICK Bullish Threshold
int
500
i_tickBull
TICK Bearish Threshold
int
-500
i_tickBear
TICK Extreme Threshold
int
800
i_tickExtreme
Enable Volume Footprint
bool
true
i_useFootprint
Ticks Per Footprint Row
int
10
i_fpTicksPerRow
Value Area Percentage
int
70
i_fpVaPct
Show POC Level
bool
true
i_fpShowPOC
Show Pre-Market High/Low
bool
true
i_showPM
Show Prior Day H/L/C
bool
true
i_showPD
Show Opening Range
bool
true
i_showOR
Opening Range Minutes
int
5
i_orMinutes
Show Current Session HOD/LOD
bool
true
i_showHODLOD
Pre-Market Session
session
0400-0930
i_pmSession
Regular Trading Hours
session
0930-1600
i_rthSession
Timezone
string
America/New_York
i_tz
Show CALLS / PUTS Signals
bool
true
i_showSignals
Signal Cooldown (bars)
int
5
i_cooldownBars
Signal Time Window
session
0935-1545
i_signalStart
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.
This indicator scans NSE-listed stocks for momentum signals using Supertrend, multiple EMAs, MACD, and stochastic oscillator. It supports continuous or flip signal modes and displays matching setups in a customizable table at the bottom left of the chart. The
This indicator calculates pivot high and pivot low points on the price chart based on configurable left and right bar counts. Confirmed pivot highs and lows are plotted with negative bar offsets directly on the price chart using line and cross styles. Addition
This overlay indicator marks call and put setups from EMAs, RSI, MACD, and a SPY volume ratio. A call needs higher highs, RSI above its minimum, rising MACD, above-average proxy volume, and a rising trend EMA; a put reverses those tests. Early markers use an E
The Hedge Scalp indicator calculates an Exponential Moving Average (EMA) and generates four long grid levels and one hedged short grid level at user-defined percentage distances below the EMA. It models grid entry execution and average entry take-profit levels
This indicator collection calculates and plots previous daily high and low price levels on the chart to identify potential supply and demand zones. It includes real-time intraday high and low calculations, RSI divergence detection across a customizable period
This script provides an indicator-based backtesting engine framework that simulates trade entries, exits, and filtering directly on the price chart. It evaluates selected entry rules and multi-layered filters, including moving average trends, volume increases,