Multi-Factor Trend Resumption Filter is a non-repainting lower study designed primarily for 5-minute ES charts. It evaluates the prior completed bar using normalized trend displacement, momentum, VWAP position, volume pressure, range expansion, and confirmed higher-timeframe context.
Rather than chasing an initial move, it identifies qualified pullbacks within established bullish or bearish conditions, then flags potential trend resumption when momentum and propagation speed re-accelerate. Signals and alerts appear on the next bar using completed data only, with no future-bar references or historical backfilling.
This is a market-context and setup filter—not a complete trading system. Use defined entry, exit, and risk rules, and validate settings independently for each ticker and timeframe.
Rather than chasing an initial move, it identifies qualified pullbacks within established bullish or bearish conditions, then flags potential trend resumption when momentum and propagation speed re-accelerate. Signals and alerts appear on the next bar using completed data only, with no future-bar references or historical backfilling.
This is a market-context and setup filter—not a complete trading system. Use defined entry, exit, and risk rules, and validate settings independently for each ticker and timeframe.
- candidates: ES,
-
Code:
# ============================================================ # ES Propagation Osccilator V3 — NON-REPAINTING # Designed primarily for: ES 5-minute chart # # NON-REPAINTING DESIGN: # - All indicator inputs use the PREVIOUS completed primary bar [1] # - Session VWAP uses the PREVIOUS completed bar's VWAP # - Higher-timeframe data uses the PREVIOUS closed HTF bar # - No future offsets or forward references are used # - Signals and alerts occur on the first update of the next bar, # using only completed data from the prior bar # # Trade-off: Signals appear 1 bar later than a current-bar version, # but do not backfill or disappear once printed. # ============================================================ declare lower; # ============================================================ # GENERAL SETTINGS # ============================================================ input setupMode = {default Balanced, Conservative, Aggressive}; input sourceType = {default HLC3, Close, OHLC4}; input showDashboard = yes; input showSignals = yes; input showWaveBackground = yes; input paintPriceBars = no; # ============================================================ # MARKET STATE ENGINE # ============================================================ input meanLength = 34; input momentumLength = 8; input normalizationLength = 50; input volumeLength = 20; input atrLength = 14; input useVWAP = yes; input useVolume = yes; input useRangeExpansion = yes; input weightMean = 1.10; input weightVWAP = 1.00; input weightMomentum = 1.20; input weightVolume = 0.65; input weightRange = 0.55; # ============================================================ # HIGHER-TIMEFRAME CONTEXT # ============================================================ input useHTF = yes; input htfAggregation = AggregationPeriod.FIFTEEN_MIN; input htfFastLength = 21; input htfSlowLength = 50; input weightHTF = 0.75; # ============================================================ # NONLINEAR DIFFUSION ENGINE # ============================================================ input diffusionM = 1.35; input diffusionP = 2.20; input diffusionGain = 0.18; input reactionGain = 0.16; input anchorGain = 0.22; # ============================================================ # PROPAGATION SPEED ENGINE # ============================================================ input speedLength = 4; input criticalLength = 40; input criticalMultiplierInput = 1.25; input speedSmoothLength = 3; input bullStateInput = 0.62; input bearStateInput = 0.38; # ============================================================ # RETRACEMENT / RESUMPTION ENGINE # ============================================================ input retraceWindow = 12; input minimumPullbackBars = 1; input requireVWAPAlignment = yes; input requireHTFAlignment = yes; input signalCooldown = 6; # ============================================================ # EXHAUSTION ENGINE # ============================================================ input showExhaustion = yes; input exhaustionState = 0.72; input exhaustionBars = 3; # ============================================================ # DISPLAY SETTINGS # ============================================================ input showRawState = yes; input showThresholdClouds = yes; input showSpeedLabel = yes; input showStateLabels = yes; input showSetupLabel = yes; input showActionLabel = yes; # ============================================================ # HELPER SCRIPTS # ============================================================ script Clamp { input value = 0.0; input minimum = 0.0; input maximum = 1.0; plot result = Max(minimum, Min(maximum, value)); } script SafeZScore { input value = 0.0; input length = 50; def average = Average(value, length); def deviation = StDev(value, length); plot result = if deviation > 0 then (value - average) / deviation else 0; } script Logistic { input value = 0.0; def limitedValue = Max(-10.0, Min(10.0, value)); plot result = 1.0 / (1.0 + Exp(-limitedValue)); } script SignedPower { input value = 0.0; input exponent = 1.0; plot result = if value > 0 then Power(value, exponent) else if value < 0 then -Power(AbsValue(value), exponent) else 0; } # ============================================================ # SOURCE — PREVIOUS CONFIRMED BAR # ============================================================ def srcRaw = if sourceType == sourceType.Close then close else if sourceType == sourceType.OHLC4 then (open + high + low + close) / 4 else (high + low + close) / 3; # Gate to previous confirmed bar — eliminates intrabar repaint def src = srcRaw[1]; # ============================================================ # NON-REPAINT TIMING # ============================================================ # # Every signal dependency below is based on the prior completed # primary bar or prior completed higher-timeframe bar. Do not use # a forward-looking bar reference as a confirmation proxy: it # causes backfilling onto the previous bar. # ============================================================ # MODE ADJUSTMENTS # ============================================================ def modeCriticalAdjustment = if setupMode == setupMode.Conservative then 1.20 else if setupMode == setupMode.Aggressive then 0.82 else 1.00; def modeStateAdjustment = if setupMode == setupMode.Conservative then 0.025 else if setupMode == setupMode.Aggressive then -0.025 else 0.0; def criticalMultiplier = criticalMultiplierInput * modeCriticalAdjustment; def bullStateThreshold = Max( 0.51, Min( 0.90, bullStateInput + modeStateAdjustment ) ); def bearStateThreshold = Max( 0.10, Min( 0.49, bearStateInput - modeStateAdjustment ) ); # ============================================================ # BASE MARKET MEASUREMENTS — PREVIOUS BAR # ============================================================ def trueRangeValue = TrueRange(high, close, low)[1]; def atr = Average(trueRangeValue, atrLength); def safeATR = Max(atr, TickSize()); def adaptiveMean = ExpAverage(src, meanLength); def meanDisplacement = (src - adaptiveMean) / safeATR; # ============================================================ # STABLE SESSION VWAP — PREVIOUS BAR # ============================================================ # reference VWAP() recalculates on every tick. Taking [1] # gives us the previous confirmed bar's VWAP, which is # stable and non-repainting. def sessionVWAP = if useVWAP then reference VWAP().VWAP[1] else Double.NaN; def vwapDisplacement = if useVWAP and !IsNaN(sessionVWAP) then (src - sessionVWAP) / safeATR else 0; def momentum = if !IsNaN(src[momentumLength]) then (src - src[momentumLength]) / safeATR else 0; def barRange = high[1] - low[1]; def averageRange = Average(high - low, atrLength)[1]; def rangeExpansion = if averageRange > 0 then barRange / averageRange - 1.0 else 0; def averageVolume = Average(volume, volumeLength)[1]; def relativeVolume = if averageVolume > 0 then volume[1] / averageVolume else 1.0; def candleEfficiency = if barRange > 0 then (close[1] - open[1]) / barRange else 0; def volumePressure = candleEfficiency * Max(relativeVolume - 1.0, 0); # ============================================================ # HIGHER-TIMEFRAME BIAS — PREVIOUS CLOSED HTF BAR # ============================================================ # close(period = ...) returns the forming HTF bar's close. # Taking [1] ensures we only use the PREVIOUS CLOSED HTF bar, # which is stable and non-repainting. def htfClose = close(period = htfAggregation)[1]; def htfHigh = high(period = htfAggregation)[1]; def htfLow = low(period = htfAggregation)[1]; def htfFast = ExpAverage(htfClose, htfFastLength); def htfSlow = ExpAverage(htfClose, htfSlowLength); def htfTrueRange = TrueRange(htfHigh, htfClose, htfLow); def htfATR = Average(htfTrueRange, atrLength); def htfBiasRaw = if htfATR > 0 then (htfFast - htfSlow) / htfATR else 0; def htfBias = Max(-2.0, Min(2.0, htfBiasRaw)); def htfBull = htfFast > htfSlow; def htfBear = htfFast < htfSlow; # ============================================================ # NORMALIZED COMPONENTS # ============================================================ def meanComponent = Max( -3.0, Min( 3.0, SafeZScore( meanDisplacement, normalizationLength ) ) ); def vwapComponent = Max( -3.0, Min( 3.0, SafeZScore( vwapDisplacement, normalizationLength ) ) ); def momentumComponent = Max( -3.0, Min( 3.0, SafeZScore( momentum, normalizationLength ) ) ); def volumeComponent = if useVolume then Max( -3.0, Min( 3.0, SafeZScore( volumePressure, normalizationLength ) ) ) else 0; def rangeDirection = if close[1] > open[1] then 1 else if close[1] < open[1] then -1 else 0; def rangeComponent = if useRangeExpansion then Max( -3.0, Min( 3.0, SafeZScore( rangeExpansion, normalizationLength ) ) ) * rangeDirection else 0; # ============================================================ # ACTIVE WEIGHT # ============================================================ def activeWeight = weightMean + weightMomentum + (if useVWAP then weightVWAP else 0) + (if useVolume then weightVolume else 0) + (if useRangeExpansion then weightRange else 0) + (if useHTF then weightHTF else 0); def weightedScore = weightMean * meanComponent + weightMomentum * momentumComponent + (if useVWAP then weightVWAP * vwapComponent else 0) + (if useVolume then weightVolume * volumeComponent else 0) + (if useRangeExpansion then weightRange * rangeComponent else 0) + (if useHTF then weightHTF * htfBias else 0); def normalizedScore = if activeWeight > 0 then weightedScore / activeWeight else 0; # ============================================================ # RAW BOUNDED MARKET STATE # ============================================================ def rawState = Logistic(normalizedScore * 2.25); # ============================================================ # REACTION IMPULSE # ============================================================ def impulseDirection = Max( -2.0, Min( 2.0, 0.45 * momentumComponent + 0.30 * volumeComponent + 0.25 * rangeComponent ) ); def impulseStrength = Max( 0.0, Min( 2.0, AbsValue(momentumComponent) * 0.40 + AbsValue(volumeComponent) * 0.30 + AbsValue(rangeComponent) * 0.30 ) ); def directionalImpulse = if impulseDirection > 0 then impulseStrength else if impulseDirection < 0 then -impulseStrength else 0; def reactionTerm = rawState * (1.0 - rawState) * directionalImpulse; # ============================================================ # DOUBLY NONLINEAR DIFFUSION APPROXIMATION # ============================================================ def safeRawState = Max(0.0001, Min(1.0, rawState)); def densityNow = Power(safeRawState, diffusionM); def densityPrevious = Power( Max( 0.0001, Min( 1.0, if IsNaN(rawState[1]) then rawState else rawState[1] ) ), diffusionM ); def densityTwoBarsAgo = Power( Max( 0.0001, Min( 1.0, if IsNaN(rawState[2]) then rawState else rawState[2] ) ), diffusionM ); def densityCurvature = densityNow - 2.0 * densityPrevious + densityTwoBarsAgo; def nonlinearDiffusion = SignedPower( densityCurvature, diffusionP - 1.0 ); # ============================================================ # RECURSIVE WAVE STATE # ============================================================ rec waveState = if BarNumber() == 1 then 0.50 else Max( 0.0, Min( 1.0, waveState[1] + diffusionGain * nonlinearDiffusion + reactionGain * reactionTerm + anchorGain * (rawState - waveState[1]) ) ); # ============================================================ # PROPAGATION SPEED # ============================================================ def rawWaveSpeed = if BarNumber() > speedLength then (waveState - waveState[speedLength]) / speedLength else 0; def waveSpeed = ExpAverage(rawWaveSpeed, speedSmoothLength); def stateChange = if BarNumber() > 1 then waveState - waveState[1] else 0; def speedNoise = StDev(stateChange, criticalLength); def criticalSpeed = Max( speedNoise * criticalMultiplier, 0.00001 ); def normalizedSpeed = waveSpeed / criticalSpeed; # ============================================================ # WAVE CLASSIFICATION # ============================================================ def bullState = waveState >= bullStateThreshold; def bearState = waveState <= bearStateThreshold; def equilibriumState = !bullState and !bearState; def bullWave = bullState and waveSpeed > criticalSpeed; def bearWave = bearState and waveSpeed < -criticalSpeed; def subcriticalBull = bullState and !bullWave; def subcriticalBear = bearState and !bearWave; def stalled = AbsValue(waveSpeed) < criticalSpeed * 0.35; # ============================================================ # RECENT WAVE MEMORY # ============================================================ rec barsSinceBullWave = if BarNumber() == 1 then retraceWindow + 100 else if bullWave then 0 else Min( barsSinceBullWave[1] + 1, retraceWindow + 100 ); rec barsSinceBearWave = if BarNumber() == 1 then retraceWindow + 100 else if bearWave then 0 else Min( barsSinceBearWave[1] + 1, retraceWindow + 100 ); def recentBullWave = barsSinceBullWave <= retraceWindow; def recentBearWave = barsSinceBearWave <= retraceWindow; # ============================================================ # RETRACEMENT STATE # ============================================================ def bullPullback = recentBullWave and bullState and waveSpeed <= criticalSpeed; def bearPullback = recentBearWave and bearState and waveSpeed >= -criticalSpeed; rec bullPullbackBars = if BarNumber() == 1 then 0 else if bullPullback then bullPullbackBars[1] + 1 else 0; rec bearPullbackBars = if BarNumber() == 1 then 0 else if bearPullback then bearPullbackBars[1] + 1 else 0; # ============================================================ # ALIGNMENT FILTERS — PREVIOUS BAR # ============================================================ def vwapLongOK = !requireVWAPAlignment or !useVWAP or close[1] > sessionVWAP; def vwapShortOK = !requireVWAPAlignment or !useVWAP or close[1] < sessionVWAP; def htfLongOK = !requireHTFAlignment or !useHTF or htfBull; def htfShortOK = !requireHTFAlignment or !useHTF or htfBear; # ============================================================ # SPEED CROSSINGS # ============================================================ def bullSpeedResume = waveSpeed > criticalSpeed and waveSpeed[1] <= criticalSpeed[1]; def bearSpeedResume = waveSpeed < -criticalSpeed and waveSpeed[1] >= -criticalSpeed[1]; # ============================================================ # ARMED RETRACEMENT SETUPS # ============================================================ rec bullResumeArmed = if BarNumber() == 1 then no else if !recentBullWave or !bullState then no else if bullSpeedResume and bullResumeArmed[1] then no else if bullPullback and bullPullbackBars >= minimumPullbackBars then yes else bullResumeArmed[1]; rec bearResumeArmed = if BarNumber() == 1 then no else if !recentBearWave or !bearState then no else if bearSpeedResume and bearResumeArmed[1] then no else if bearPullback and bearPullbackBars >= minimumPullbackBars then yes else bearResumeArmed[1]; # ============================================================ # PRELIMINARY RESUME SIGNALS # ============================================================ def preliminaryLongResume = bullSpeedResume and bullResumeArmed[1] and recentBullWave and bullState and vwapLongOK and htfLongOK; def preliminaryShortResume = bearSpeedResume and bearResumeArmed[1] and recentBearWave and bearState and vwapShortOK and htfShortOK; # ============================================================ # SIGNAL COOLDOWN # ============================================================ rec barsSinceLongSignal = if BarNumber() == 1 then signalCooldown + 1 else if preliminaryLongResume and barsSinceLongSignal[1] > signalCooldown then 0 else barsSinceLongSignal[1] + 1; rec barsSinceShortSignal = if BarNumber() == 1 then signalCooldown + 1 else if preliminaryShortResume and barsSinceShortSignal[1] > signalCooldown then 0 else barsSinceShortSignal[1] + 1; def longCooldownOK = barsSinceLongSignal[1] > signalCooldown; def shortCooldownOK = barsSinceShortSignal[1] > signalCooldown; # ============================================================ # FINAL SIGNALS — PAST-ONLY, NO FORWARD OFFSET # ============================================================ def longResumeSignal = preliminaryLongResume and longCooldownOK; def shortResumeSignal = preliminaryShortResume and shortCooldownOK; # ============================================================ # EXHAUSTION CONDITIONS # ============================================================ def speedFalling = Sum( waveSpeed < waveSpeed[1], exhaustionBars ) == exhaustionBars; def speedRising = Sum( waveSpeed > waveSpeed[1], exhaustionBars ) == exhaustionBars; def bullExhaustionCondition = waveState >= exhaustionState and waveSpeed > 0 and speedFalling and close[1] >= Highest(close, exhaustionBars)[1]; def bearExhaustionCondition = waveState <= 1.0 - exhaustionState and waveSpeed < 0 and speedRising and close[1] <= Lowest(close, exhaustionBars)[1]; def bullExhaustion = bullExhaustionCondition and !bullExhaustionCondition[1]; def bearExhaustion = bearExhaustionCondition and !bearExhaustionCondition[1]; # ============================================================ # GLOBAL COLORS # ============================================================ DefineGlobalColor( "BullWave", CreateColor(0, 220, 120) ); DefineGlobalColor( "BearWave", CreateColor(235, 70, 70) ); DefineGlobalColor( "BullRetrace", CreateColor(70, 165, 255) ); DefineGlobalColor( "BearRetrace", CreateColor(255, 170, 50) ); DefineGlobalColor( "BullStalled", CreateColor(70, 150, 110) ); DefineGlobalColor( "BearStalled", CreateColor(160, 90, 90) ); DefineGlobalColor( "Neutral", CreateColor(160, 160, 160) ); # ============================================================ # MAIN STATE PLOT # ============================================================ plot Wave = waveState; Wave.SetLineWeight(3); Wave.AssignValueColor( if bullWave then GlobalColor("BullWave") else if bearWave then GlobalColor("BearWave") else if bullPullback then GlobalColor("BullRetrace") else if bearPullback then GlobalColor("BearRetrace") else if subcriticalBull then GlobalColor("BullStalled") else if subcriticalBear then GlobalColor("BearStalled") else GlobalColor("Neutral") ); # ============================================================ # RAW STATE # ============================================================ plot RawMarketState = if showRawState then rawState else Double.NaN; RawMarketState.SetDefaultColor(Color.DARK_GRAY); RawMarketState.SetLineWeight(1); RawMarketState.HideBubble(); # ============================================================ # THRESHOLDS # ============================================================ plot BullThreshold = bullStateThreshold; BullThreshold.SetDefaultColor(Color.DARK_GREEN); BullThreshold.SetStyle(Curve.SHORT_DASH); BullThreshold.HideBubble(); plot BearThreshold = bearStateThreshold; BearThreshold.SetDefaultColor(Color.DARK_RED); BearThreshold.SetStyle(Curve.SHORT_DASH); BearThreshold.HideBubble(); plot Equilibrium = 0.50; Equilibrium.SetDefaultColor(Color.YELLOW); Equilibrium.SetStyle(Curve.SHORT_DASH); Equilibrium.HideBubble(); plot UpperBoundary = 1.0; UpperBoundary.SetDefaultColor(Color.BLACK); UpperBoundary.HideBubble(); UpperBoundary.HideTitle(); plot LowerBoundary = 0.0; LowerBoundary.SetDefaultColor(Color.BLACK); LowerBoundary.HideBubble(); LowerBoundary.HideTitle(); # ============================================================ # THRESHOLD CLOUDS # ============================================================ AddCloud( if showThresholdClouds then UpperBoundary else Double.NaN, if showThresholdClouds then BullThreshold else Double.NaN, Color.DARK_GREEN, Color.DARK_GREEN ); AddCloud( if showThresholdClouds then BearThreshold else Double.NaN, if showThresholdClouds then LowerBoundary else Double.NaN, Color.DARK_RED, Color.DARK_RED ); # ============================================================ # REGIME BACKGROUND # ============================================================ AssignBackgroundColor( if !showWaveBackground then Color.CURRENT else if bullWave then CreateColor(0, 35, 20) else if bearWave then CreateColor(40, 10, 10) else if bullPullback then CreateColor(10, 25, 45) else if bearPullback then CreateColor(45, 25, 5) else Color.CURRENT ); # ============================================================ # SIGNAL MARKERS # ============================================================ plot LongResume = if showSignals and longResumeSignal then 0.04 else Double.NaN; LongResume.SetPaintingStrategy( PaintingStrategy.ARROW_UP ); LongResume.SetDefaultColor(Color.GREEN); LongResume.SetLineWeight(4); LongResume.HideBubble(); LongResume.HideTitle(); plot ShortResume = if showSignals and shortResumeSignal then 0.96 else Double.NaN; ShortResume.SetPaintingStrategy( PaintingStrategy.ARROW_DOWN ); ShortResume.SetDefaultColor(Color.RED); ShortResume.SetLineWeight(4); ShortResume.HideBubble(); ShortResume.HideTitle(); # ============================================================ # EXHAUSTION MARKERS # ============================================================ plot BullExhaustionMarker = if showExhaustion and bullExhaustion then 0.96 else Double.NaN; BullExhaustionMarker.SetPaintingStrategy( PaintingStrategy.POINTS ); BullExhaustionMarker.SetDefaultColor(Color.ORANGE); BullExhaustionMarker.SetLineWeight(5); BullExhaustionMarker.HideBubble(); BullExhaustionMarker.HideTitle(); plot BearExhaustionMarker = if showExhaustion and bearExhaustion then 0.04 else Double.NaN; BearExhaustionMarker.SetPaintingStrategy( PaintingStrategy.POINTS ); BearExhaustionMarker.SetDefaultColor(Color.ORANGE); BearExhaustionMarker.SetLineWeight(5); BearExhaustionMarker.HideBubble(); BearExhaustionMarker.HideTitle(); # ============================================================ # OPTIONAL PRICE-BAR COLORING # ============================================================ AssignPriceColor( if !paintPriceBars then Color.CURRENT else if bullWave then GlobalColor("BullWave") else if bearWave then GlobalColor("BearWave") else if bullPullback then GlobalColor("BullRetrace") else if bearPullback then GlobalColor("BearRetrace") else Color.CURRENT ); # ============================================================ # DASHBOARD LABELS # ============================================================ AddLabel( showDashboard, "KPP PROPAGATION | " + (if setupMode == setupMode.Conservative then "CONSERVATIVE" else if setupMode == setupMode.Aggressive then "AGGRESSIVE" else "BALANCED"), Color.WHITE ); AddLabel( showDashboard and showStateLabels, if bullWave then "REGIME: BULL WAVE" else if bearWave then "REGIME: BEAR WAVE" else if bullPullback then "REGIME: BULL RETRACE" else if bearPullback then "REGIME: BEAR RETRACE" else if subcriticalBull then "REGIME: BULL STALLED" else if subcriticalBear then "REGIME: BEAR STALLED" else if stalled then "REGIME: NO PROPAGATION" else "REGIME: TRANSITION", if bullWave then GlobalColor("BullWave") else if bearWave then GlobalColor("BearWave") else if bullPullback then GlobalColor("BullRetrace") else if bearPullback then GlobalColor("BearRetrace") else if subcriticalBull then GlobalColor("BullStalled") else if subcriticalBear then GlobalColor("BearStalled") else GlobalColor("Neutral") ); AddLabel( showDashboard and showStateLabels, "STATE: " + AsText(Round(waveState * 100, 1)) + "%", if bullState then GlobalColor("BullWave") else if bearState then GlobalColor("BearWave") else Color.GRAY ); AddLabel( showDashboard and showSpeedLabel, "SPEED: " + AsText(Round(normalizedSpeed, 2)) + "x", if normalizedSpeed > 1 then Color.GREEN else if normalizedSpeed < -1 then Color.RED else Color.GRAY ); AddLabel( showDashboard, "VWAP: " + (if !useVWAP then "OFF" else if close[1] > sessionVWAP then "ABOVE" else if close[1] < sessionVWAP then "BELOW" else "AT"), if !useVWAP then Color.GRAY else if close[1] > sessionVWAP then Color.GREEN else if close[1] < sessionVWAP then Color.RED else Color.GRAY ); AddLabel( showDashboard, "HTF: " + (if !useHTF then "OFF" else if htfBull then "BULL" else if htfBear then "BEAR" else "FLAT"), if !useHTF then Color.GRAY else if htfBull then Color.GREEN else if htfBear then Color.RED else Color.GRAY ); # ============================================================ # SETUP STATUS # ============================================================ AddLabel( showDashboard and showSetupLabel, if bullResumeArmed then "SETUP: LONG ARMED | " + AsText(bullPullbackBars) + " BARS" else if bearResumeArmed then "SETUP: SHORT ARMED | " + AsText(bearPullbackBars) + " BARS" else if bullPullback then "SETUP: LONG RETRACE | " + AsText(bullPullbackBars) + " BARS" else if bearPullback then "SETUP: SHORT RETRACE | " + AsText(bearPullbackBars) + " BARS" else "SETUP: NOT ARMED", if bullResumeArmed then Color.GREEN else if bearResumeArmed then Color.RED else if bullPullback then GlobalColor("BullRetrace") else if bearPullback then GlobalColor("BearRetrace") else Color.GRAY ); # ============================================================ # ACTION STATUS # ============================================================ AddLabel( showDashboard and showActionLabel, if longResumeSignal then "ACTION: LONG RESUME" else if shortResumeSignal then "ACTION: SHORT RESUME" else if bullExhaustion then "ACTION: BULL EXHAUSTION" else if bearExhaustion then "ACTION: BEAR EXHAUSTION" else if bullResumeArmed or bearResumeArmed then "ACTION: WAIT FOR RESTART" else if bullPullback then "ACTION: BUILDING LONG SETUP" else if bearPullback then "ACTION: BUILDING SHORT SETUP" else if bullWave then "ACTION: HOLD LONG BIAS" else if bearWave then "ACTION: HOLD SHORT BIAS" else "ACTION: WAIT", if longResumeSignal then Color.GREEN else if shortResumeSignal then Color.RED else if bullExhaustion or bearExhaustion then Color.ORANGE else if bullResumeArmed then Color.GREEN else if bearResumeArmed then Color.RED else if bullWave then GlobalColor("BullWave") else if bearWave then GlobalColor("BearWave") else Color.GRAY ); # ============================================================ # CHART BUBBLES # ============================================================ AddChartBubble( showSignals and longResumeSignal, 0.04, "GO", Color.GREEN, no ); AddChartBubble( showSignals and shortResumeSignal, 0.96, "GO", Color.RED, yes ); # ============================================================ # ALERTS — fire once on the next bar using completed prior-bar data # ============================================================ Alert( longResumeSignal, "KPP bullish propagation resumed after a qualified retracement", Alert.BAR, Sound.Ding ); Alert( shortResumeSignal, "KPP bearish propagation resumed after a qualified retracement", Alert.BAR, Sound.Ding ); Alert( bullResumeArmed and !bullResumeArmed[1], "KPP bullish retracement qualified and armed", Alert.BAR, Sound.Chimes ); Alert( bearResumeArmed and !bearResumeArmed[1], "KPP bearish retracement qualified and armed", Alert.BAR, Sound.Chimes ); Alert( bullExhaustion, "KPP bullish propagation exhaustion", Alert.BAR, Sound.Ring ); Alert( bearExhaustion, "KPP bearish propagation exhaustion", Alert.BAR, Sound.Ring ); - NQ, RTY, YM, and liquid index ETFs such as SPY/QQQ.
- Test separately: individual stocks; earnings gaps and regular-hours settings can materially change behavior.
- Avoid initially: thin stocks and individual options, where spread/volume noise can overwhelm the signal.
- Treat forex cautiously: its volume/VWAP behavior is not comparable to centralized futures volume.