Liquidity Map V2
(Out of the Rabbit Hole)
Chart Link
Liquidity all studies
Liquidity Map V2 is a full microstructure engine built around 17 liquidity zones, three institutional patterns, and four core intents. The study uses user‑controlled inputs to toggle visibility of structural footprints, pattern bubbles, and labels. These inputs allow traders to customize the map for:
Each bubble group corresponds to a specific microstructure footprint. Turning them on/off lets the operator isolate patterns, debug sequences, or focus on a single intent:
Dynamic Support/Resistance
I decided to use Mitigation Origins for S/R levels. They behave more like dynamic VWAP bands than static S/R lines — adapting to institutional defense, displacement origin, and mitigation flow.
Operator Cheat Sheet — Liquidity Map V2
Pattern A — Collection (Stop Grab & Reversal)
Goal: Harvest liquidity to enter positions Watch:
Pattern B — Escape (Displacement & Imbalance)
Goal: Push price away from fill zone Watch:
Pattern C — Defense (Mitigation & Refill)
Goal: Protect displacement origin Watch:
Study Link
Liquidity_Map_V2
(Out of the Rabbit Hole)
Chart Link
Liquidity all studies
Liquidity Map V2 is a full microstructure engine built around 17 liquidity zones, three institutional patterns, and four core intents. The study uses user‑controlled inputs to toggle visibility of structural footprints, pattern bubbles, and labels. These inputs allow traders to customize the map for:
- reversal detection
- displacement quality
- mitigation logic
- institutional flow visualization
- Labels: Top‑Right
- REV↑/REV↓ bubbles: Off
- Flow label: Off
- S/R Line: Yes
- HTF Mode: Yes (Quarterly aggregation)
- Event Bubbles: ALL
- User control: All / Off / Custom
Each bubble group corresponds to a specific microstructure footprint. Turning them on/off lets the operator isolate patterns, debug sequences, or focus on a single intent:
- StopGrab / Sweep / ICT Sweep — Collection intent
- FVG / ICT FVG / FVG Fill — Escape intent
- BPR / ICT BPR / Mitigation Origin — Defense intent
- Void / Refill — Imbalance structure
- InstRev / Exhaust / Climax — Reversal signals
- OB / BOS / CHoCH — Structural confirmation
- HFT Trap / Shelf / Churn — Microstructure context
- Clusters / Pivot Cluster — Institutional footprint density
Dynamic Support/Resistance
I decided to use Mitigation Origins for S/R levels. They behave more like dynamic VWAP bands than static S/R lines — adapting to institutional defense, displacement origin, and mitigation flow.
Operator Cheat Sheet — Liquidity Map V2
Pattern A — Collection (Stop Grab & Reversal)
Goal: Harvest liquidity to enter positions Watch:
- LIQ ↑/↓
- SWEEP ↑/↓
- ICT SWEEP
- SHELF
- MICROREJECT / MICROABSORB
- INST REV ↑/↓
Pattern B — Escape (Displacement & Imbalance)
Goal: Push price away from fill zone Watch:
- FVG ↑/↓
- ICT FVG ↑/↓
- VOID
- BPR ↑/↓
- OB BULL/BEAR
- BOS ↑/↓
Pattern C — Defense (Mitigation & Refill)
Goal: Protect displacement origin Watch:
Study Link
Liquidity_Map_V2
Ruby:
############################################
# LIQUIDITY MAP
# Version: 2.0 (Work In Progress)
# atcsam — 09/28/26
# Playing it Forward
# Description:
# A microstructure engine that maps liquidity behavior
# across 17 structural zones, directional reversal probability
# (REV↑/REV↓), RPM confluence scoring, volume pressure,
# and candle‑behavior micro‑footprints.
#
# Includes full Pattern & Sequence Detection:
# Pattern A (Collection), Pattern B (Escape),
# Pattern C (Defense), and Abandonment Logic.
############################################
#-----------------------------------------
# USER INPUTS
#-----------------------------------------
input LabelPos = {default "Top Right", "Top Left", "Bottom Left"};
input useRTH = no;
input shelfMode = {default "High", "Medium", "Institutional"};
input SR_Lines = yes;
input HTF_SR = yes;
input htfTimeFrame = AggregationPeriod.quarter;
input showREV_Bubbles = no;
input revBubbleThreshold = 2;
input EventBubbles = {default "All", "Off", "Custom"};
input BPR = no;
input Climax_Exhaust = no;
input Clusters = no;
input DP_Churn = yes;
input FVG = no;
input HFT_Trap = yes;
input Hidden_Absorption = yes;
input Inst_Rev = yes;
input Shelf = no;
input StopGrab = yes;
input Sweep = no;
input Voids = no;
input ICT_Sweep = yes;
input ICTFVG = no;
input ICTBPR = no;
input Mitigation = no;
input OB_B = no;
input BOS_B = no;
input showCandleArrow = no;
input showRPM = yes;
input showRevLabel = yes;
input showCandleLabels = yes;
input showFlowLabel = no;
input lookbackPeriod = 10;
input bodyMultiplier = 1.5;
input rvolExhaustThreshold = 0.8;
input seqLookback = 10;
#-----------------------------------------
# POSITION
#-----------------------------------------
def pos =
if LabelPos == LabelPos."Top Left" then 0
else if LabelPos == LabelPos."Top Right" then 1
else if LabelPos == LabelPos."Bottom Left" then 2
else 3;
def showAllBubbles = EventBubbles == EventBubbles.All;
def showNoBubbles = EventBubbles == EventBubbles.Off;
def showCustomBubble = EventBubbles == EventBubbles.Custom;
#-----------------------------------------
# GLOBAL COLORS
#-----------------------------------------
DefineGlobalColor("MagLt", CreateColor(237, 74, 213));
DefineGlobalColor("Amber", CreateColor(220, 170, 45));
DefineGlobalColor("Trap", CreateColor(220, 65, 145));
DefineGlobalColor("RPM_DownStrong", Color.RED);
DefineGlobalColor("RPM_Down",CreateColor(205, 70, 78));
DefineGlobalColor("RPM_Neutral",CreateColor(237, 226, 19));
DefineGlobalColor("RPM_Up", CreateColor(70, 175, 135));
DefineGlobalColor("RPM_UpStrong", CreateColor(0, 210, 120));
DefineGlobalColor("Info", CreateColor(0, 190, 220));
DefineGlobalColor("Paper", CreateColor(245, 240, 225));
DefineGlobalColor("Parchment", CreateColor(221, 204, 178));
DefineGlobalColor("FiberP", CreateColor(145, 121, 90));
DefineGlobalColor("DownTrend", CreateColor(255, 0, 128));
DefineGlobalColor("Fill", CreateColor(0, 128, 255));
DefineGlobalColor("UpTrend", CreateColor(0, 128, 255));
DefineGlobalColor("BearStrong", CreateColor(230, 70, 78));
#-----------------------------------------
# CORE METRICS / RTH FILTER
#-----------------------------------------
def isRTH =
SecondsFromTime(0930) >= 0 and
SecondsTillTime(1600) >= 0;
def rawVol = volume;
def volRTH = if useRTH and !isRTH then Double.NaN else rawVol;
def avgVol20 = Average(volRTH, 20);
def RVOL20 = if avgVol20 > 0 then rawVol / avgVol20 else 1;
def isIntraday = GetAggregationPeriod() < AggregationPeriod.DAY;
def volAvg10 = Average(volume, 10);
def price = close;
def candleRange = high - low;
def candleBody = AbsValue(close - open);
def upperWick = high - Max(open, close);
def lowerWick = Min(open, close) - low;
def atr20 = ATR(20);
def bn = BarNumber();
# ====================================================
# ZONE 1 — DARK POOL CHURN
# ====================================================
def _isChurn =
RVOL20 > 1.8 and
candleBody / candleRange < 0.35;
def isChurn = if IsNaN(_isChurn) then 0 else _isChurn;
# ====================================================
# ZONE 2 — SWEEPS & STOP GRABS
# ====================================================
def _isUpSweep = RVOL20 > 1.5 and candleBody > atr20 * 0.65 and close > open;
def isUpSweep = if IsNaN(_isUpSweep) then 0 else _isUpSweep;
def _isDnSweep = RVOL20 > 1.5 and candleBody > atr20 * 0.65 and close <= open;
def isDnSweep = if IsNaN(_isDnSweep) then 0 else _isDnSweep;
def _isUpStopGrab = RVOL20 > 1.5 and upperWick > candleRange * 0.45 and close < (high + low) / 2;
def isUpStopGrab = if IsNaN(_isUpStopGrab) then 0 else _isUpStopGrab;
def _isDnStopGrab = RVOL20 > 1.5 and lowerWick > candleRange * 0.45 and close > (high + low) / 2;
def isDnStopGrab = if IsNaN(_isDnStopGrab) then 0 else _isDnStopGrab;
# ====================================================
# ZONE 3 — VOIDS & REFILLS
# ====================================================
def prevHigh = high[1];
def prevLow = low[1];
def strongBody = candleBody > candleRange * 0.55;
def smallUpperWick = upperWick < candleRange * 0.35;
def smallLowerWick = lowerWick < candleRange * 0.35;
def normalVolume = RVOL20 > 0.8;
def voidUp = close > prevHigh and strongBody and smallUpperWick and normalVolume;
def voidDown = close < prevLow and strongBody and smallLowerWick and normalVolume;
def _refillUp = voidUp[1] and low <= prevHigh[1];
def refillUp = if IsNaN(_refillUp) then 0 else _refillUp;
def _refillDown = voidDown[1] and high >= prevLow[1];
def refillDown = if IsNaN(_refillDown) then 0 else _refillDown;
def isVoid = voidUp or voidDown;
def isVoidRefill = refillUp or refillDown;
def voidBN1 = CompoundValue(1, if isVoid then BarNumber() else voidBN1[1], 0);
# ====================================================
# ZONE 4 — HIDDEN ABSORPTION
# ====================================================
def _isHiddenAbsorb =
RVOL20 >= 1.80 and
candleBody <= atr20 * 0.30 and
candleRange >= atr20 * 0.40 and
(upperWick + lowerWick) >= candleBody * 0.25 and
(upperWick + lowerWick) <= candleBody * 0.75 and
!isUpSweep and !isDnSweep and
!isUpStopGrab and !isDnStopGrab and
!voidUp and !voidDown;
def isHiddenAbsorb = if IsNaN(_isHiddenAbsorb) then 0 else _isHiddenAbsorb;
# ====================================================
# ZONE 5 — VOLUME CLIMAX
# ====================================================
def _isVolClimax =
RVOL20 > 3.0 and
candleBody > atr20 * 0.8 and
(upperWick + lowerWick) < candleRange * 0.30;
def isVolClimax = if IsNaN(_isVolClimax) then 0 else _isVolClimax;
# ====================================================
# ZONE 6 — TREND EXHAUSTION
# ====================================================
def _effortHigh = RVOL20 > 1.5 and candleBody > atr20 * 0.5;
def effortHigh = if IsNaN(_effortHigh) then 0 else _effortHigh;
def _resultWeakUp = close < open and upperWick > candleRange * 0.4;
def resultWeakUp = if IsNaN(_resultWeakUp) then 0 else _resultWeakUp;
def _effortLow = RVOL20 > 1.5 and candleBody > atr20 * 0.5;
def effortLow = if IsNaN(_effortLow) then 0 else _effortLow;
def _resultWeakDown = close > open and lowerWick > candleRange * 0.4;
def resultWeakDown = if IsNaN(_resultWeakDown) then 0 else _resultWeakDown;
def _isTrendExhaustion = (effortHigh and resultWeakUp) or (effortLow and resultWeakDown);
def isTrendExhaustion = if IsNaN(_isTrendExhaustion) then 0 else _isTrendExhaustion;
# ====================================================
# ZONE 7 — LIQUIDITY SHELVES
# ====================================================
def tick = TickSize();
def shelfHigh_H =
high == Highest(high, 5) and
AbsValue(high[1] - high) <= (tick * 2) and
AbsValue(high[2] - high) <= (tick * 2);
def shelfLow_H =
low == Lowest(low, 5) and
low[1] == Lowest(low[1], 5) and
low[2] == Lowest(low[2], 5);
def shelfHigh_M =
shelfHigh_H and RVOL20 < 0.8 and candleRange < atr20 * 0.6;
def shelfLow_M =
shelfLow_H and RVOL20 < 0.8 and candleRange < atr20 * 0.6;
def shelfHigh_I =
shelfHigh_H and RVOL20 < 0.6 and candleBody < atr20 * 0.4 and upperWick < candleRange * 0.3;
def shelfLow_I =
shelfLow_H and RVOL20 < 0.6 and candleBody < atr20 * 0.4 and lowerWick < candleRange * 0.3;
def _isShelf =
if shelfMode == shelfMode."High" then (shelfHigh_H or shelfLow_H)
else if shelfMode == shelfMode."Medium" then (shelfHigh_M or shelfLow_M)
else (shelfHigh_I or shelfLow_I);
def isShelf = if IsNaN(_isShelf) then 0 else _isShelf;
def shelfLow = shelfLow_H or shelfLow_M or shelfLow_I;
def shelfHigh = shelfHigh_H or shelfHigh_M or shelfHigh_I;
# ====================================================
# ZONE 8 — PIVOT CLUSTER
# ====================================================
def pivotHigh20 = Highest(high, 20);
def pivotLow20 = Lowest(low, 20);
def _pivotHighCompression =
AbsValue(pivotHigh20 - pivotHigh20[5]) <= atr20 * 0.4;
def pivotHighCompression = if IsNaN(_pivotHighCompression) then 0 else _pivotHighCompression;
def _pivotLowCompression =
AbsValue(pivotLow20 - pivotLow20[5]) <= atr20 * 0.4;
def pivotLowCompression = if IsNaN(_pivotLowCompression) then 0 else _pivotLowCompression;
def pivotBandCompression = pivotHighCompression and pivotLowCompression;
def _rangeCompression =
candleRange < atr20 * 0.6 and candleRange < candleRange[1];
def rangeCompression = if IsNaN(_rangeCompression) then 0 else _rangeCompression;
def _volCompression =
RVOL20 < 0.8 and RVOL20 < RVOL20[1];
def volCompression = if IsNaN(_volCompression) then 0 else _volCompression;
def _pivotCluster =
pivotBandCompression and
rangeCompression and
volCompression and
(isShelf or isHiddenAbsorb or isUpStopGrab or isDnStopGrab or isVoid or isVoidRefill);
def pivotCluster = if IsNaN(_pivotCluster) then 0 else _pivotCluster;
def pivotClusterUp = pivotCluster and high == pivotHigh20;
def pivotClusterDown = pivotCluster and low == pivotLow20;
def pivotClusterMid = pivotCluster and !pivotClusterUp and !pivotClusterDown;
# ====================================================
# ZONE 9 — HFT VWAP TRAP
# ====================================================
def vwapValue = vwap;
def vwapDist = AbsValue(close - vwapValue);
def vwapStDev = StDev(vwapDist, 50);
def upperVwapBand = vwapValue + (2.0 * vwapStDev);
def lowerVwapBand = vwapValue - (2.0 * vwapStDev);
def _isHftVwapTrap =
(high > upperVwapBand and (isUpStopGrab or isVolClimax or isTrendExhaustion)) or
(low < lowerVwapBand and (isDnStopGrab or isVolClimax or isTrendExhaustion));
def isHftVwapTrap = if IsNaN(_isHftVwapTrap) then 0 else _isHftVwapTrap;
# ====================================================
# ZONE 10 — ICT LIQUIDITY SWEEPS
# ====================================================
def swingHigh = Highest(high[1], 5);
def swingLow = Lowest(low[1], 5);
def ictBuySideSweep =
high > swingHigh and
close < swingHigh and
close < open and
RVOL20 >= 1.25;
def ictSellSideSweep =
low < swingLow and
close > swingLow and
close > open and
RVOL20 >= 1.25;
def isICTSweep = ictBuySideSweep or ictSellSideSweep;
# ====================================================
# ZONE 11 — BPR
# ====================================================
def dispUp = close[1] - open[1] > (high[1] - low[1]) * 0.35;
def dispDn = open[1] - close[1] > (high[1] - low[1]) * 0.35;
def oppBull = dispDn[1] and dispUp;
def oppBear = dispUp[1] and dispDn;
def wickOverlap =
low[1] < high[2] and
high[1] > low[2];
def swingContext =
high[1] == Highest(high, 5) or
low[1] == Lowest(low, 5);
def bullBPR =
oppBull and wickOverlap and swingContext;
def bearBPR =
oppBear and wickOverlap and swingContext;
def bullBPRValid =
bullBPR and close > high[1];
def bearBPRValid =
bearBPR and close < low[1];
def isBPR = bullBPR or bearBPR;
def isBPRValid = bullBPRValid or bearBPRValid;
# ====================================================
# ZONE 12 — UNIFIED FVG ENGINE
# ====================================================
def body = AbsValue(close - open);
def avgBodySize = Average(body[1], lookbackPeriod);
def middleBody = AbsValue(close[1] - open[1]);
def bigMiddleBody = middleBody > avgBodySize * bodyMultiplier;
def prevBody = AbsValue(close[1] - open[1]);
def prevRange = high[1] - low[1];
def ictClassicBullFVG = high[2] < low;
def ictClassicBearFVG = low[2] > high;
def isICTClassicFVG = ictClassicBullFVG or ictClassicBearFVG;
def bullDispFVG =
bigMiddleBody and
high[2] < low;
def bearDispFVG =
bigMiddleBody and
low[2] > high;
def isDispFVG = bullDispFVG or bearDispFVG;
def isHQFVG = isDispFVG and (BarNumber()[1] - voidBN1 <= 3);
def bullHQFVG = bullDispFVG and (BarNumber()[1] - voidBN1 <= 3);
def bearHQFVG = bearDispFVG and (BarNumber()[1] - voidBN1 <= 3);
def ictDispUp =
isICTSweep and
close > high[1] and
body > prevBody and
RVOL20 > 1.2;
def ictDispDn =
isICTSweep and
close < low[1] and
body > prevBody and
RVOL20 > 1.2;
def ictBullFVG =
ictDispUp and
high[2] < low and
upperWick < candleRange * 0.35;
def ictBearFVG =
ictDispDn and
low[2] > high and
lowerWick < candleRange * 0.35;
def isICTDispFVG = ictBullFVG or ictBearFVG;
def isFVG =
isICTClassicFVG or
isDispFVG or
isICTDispFVG;
def middleBN =
if isFVG
then bn[1]
else middleBN[1];
def hasMiddle = middleBN > 0;
def fvgForwardWindow =
hasMiddle and
bn > middleBN and
bn <= middleBN + 5;
def bullFVGFill = fvgForwardWindow and bullDispFVG[1] and low <= high[3];
def bearFVGFill = fvgForwardWindow and bearDispFVG[1] and high >= low[3];
def isFVGFill = bullFVGFill or bearFVGFill;
def activeFVG = isFVG and fvgForwardWindow;
def activeFVGFill = isFVGFill and fvgForwardWindow;
def voidOnlyRefill = isVoidRefill and !isFVG;
# ====================================================
# ZONE 13 — INSTITUTIONAL REVERSAL SIGNATURE
# ====================================================
def rvolExhaust = RVOL20 < rvolExhaustThreshold;
def anySweep = isUpSweep or isDnSweep or isUpStopGrab or isDnStopGrab or isICTSweep;
def anyDispEvent = isVoid or isVoidRefill or isFVG or isFVGFill or isBPRValid;
def anyExhaust = isTrendExhaustion or isVolClimax or rvolExhaust;
def anyHtf = isChurn or isHiddenAbsorb or isShelf or pivotCluster;
def sweepCluster = Sum(anySweep, 2) >= 1;
def dispCluster = Highest(anyDispEvent, 2);
def exhaustCluster = Highest(anyExhaust, 2);
def htfCluster = Highest(anyHtf, 2);
def chainActive =
activeFVG or activeFVGFill or isHQFVG or voidOnlyRefill or isBPR;
def clusterScore =
(if sweepCluster then 1 else 0) +
(if dispCluster then 1 else 0) +
(if exhaustCluster then 1 else 0) +
(if htfCluster then 1 else 0);
def isInstRevUp =
clusterScore >= 3 and
!chainActive and
(low == Lowest(low, 5));
def isInstRevDn =
clusterScore >= 3 and
!chainActive and
(high == Highest(high, 5));
def isInstReversal = isInstRevUp or isInstRevDn;
# ====================================================
# ZONE 14 — ICT BPR (Overlapping FVGs)
# ====================================================
# 1. Define Standard Gaps (Evaluating the Current Bar)
def fvgBullGapHigh = low;
def fvgBullGapLow = high[2];
def fvgIsBull = fvgBullGapLow < fvgBullGapHigh;
def fvgBearGapHigh = low[2];
def fvgBearGapLow = high;
def fvgIsBear = fvgBearGapHigh > fvgBearGapLow;
# 2. Track the boundaries and timing of the most recent opposing FVGs
def lastBearFvgHigh = if fvgIsBear then fvgBearGapHigh else lastBearFvgHigh[1];
def lastBearFvgLow = if fvgIsBear then fvgBearGapLow else lastBearFvgLow[1];
def lastBearFvgBar = if fvgIsBear then bn else lastBearFvgBar[1];
def lastBullFvgHigh = if fvgIsBull then fvgBullGapHigh else lastBullFvgHigh[1];
def lastBullFvgLow = if fvgIsBull then fvgBullGapLow else lastBullFvgLow[1];
def lastBullFvgBar = if fvgIsBull then bn else lastBullFvgBar[1];
# 3. Identify the BPR Overlap
def ictBullBPR = fvgIsBull and
(bn - lastBearFvgBar <= 8) and
(fvgBullGapHigh >= lastBearFvgLow) and
(fvgBullGapLow <= lastBearFvgHigh);
def ictBearBPR = fvgIsBear and
(bn - lastBullFvgBar <= 8) and
(fvgBearGapHigh >= lastBullFvgLow) and
(fvgBearGapLow <= lastBullFvgHigh);
# 4. Validity and Signal Execution
def ictBullBPRValid = ictBullBPR and RVOL20 > 1.2 and close > high[1];
def ictBearBPRValid = ictBearBPR and RVOL20 > 1.2 and close < low[1];
def isICTBPR = ictBullBPR or ictBearBPR;
def isICTBPRValid = ictBullBPRValid or ictBearBPRValid;
# ====================================================
# Candle Behavior Engine
# ====================================================
def range = high - low;
def bodyPctOfRange =
if range != 0 then body / range else 0;
def upperWickPct =
if range != 0 then upperWick / range else 0;
def lowerWickPct =
if range != 0 then lowerWick / range else 0;
def isDispUp1 =
body > prevBody and
range > prevRange and
close > high[1];
def isDispDn1 =
body > prevBody and
range > prevRange and
close < low[1];
def tr1Up = close > close[1];
def tr1Dn = close < close[1];
def tr1 = if tr1Up then 1 else if tr1Dn then -1 else 0;
def isRejectUp =
lowerWickPct > 0.4 and
close > open and
close < high[1];
def isRejectDn =
upperWickPct > 0.4 and
close < open and
close > low[1];
def isAbsorb =
bodyPctOfRange < 0.25 and
range > prevRange * 0.75 and
RVOL20 > 1 and
rawVol > avgVol20 and
rawVol > volAvg10 and
(isShelf or isVoid or isHiddenAbsorb or isChurn);
def isCompression =
range < prevRange * 0.7 and
range < Average(range, 5) * 0.8 and
!isVoid and !isUpSweep and !isDnSweep;
# ====================================================
# ZONE 15 — BOS / CHoCH (Dynamic Swings)
# ====================================================
def localDispUp =
(candleBody > candleBody[1]) and
(candleRange > candleRange[1]) and
(close > high[1]) and
(RVOL20 > 1.0);
def localDispDn =
(candleBody > candleBody[1]) and
(candleRange > candleRange[1]) and
(close < low[1]) and
(RVOL20 > 1.0);
# --- Swing High / Low ---
input swingLength = 3;
def swingHigh1 = high[swingLength] == Highest(high, swingLength * 2 + 1);
def swingLow1 = low[swingLength] == Lowest(low, swingLength * 2 + 1);
# --- Dynamic swing levels ---
def swingHighLevel = if swingHigh1 then high[swingLength] else swingHighLevel[1];
def swingLowLevel = if swingLow1 then low[swingLength] else swingLowLevel[1];
# --- CHoCH (Reversal + break of opposite swing) ---
def chochUp = swingLow1[1] and close > swingHighLevel;
def chochDn = swingHigh1[1] and close < swingLowLevel;
def isCHoCH = chochUp or chochDn;
# --- BOS (Break of dynamic swing levels) ---
def bosUp = localDispUp and close > swingHighLevel;
def bosDn = localDispDn and close < swingLowLevel;
def isBOS = bosUp or bosDn;
# ====================================================
# ZONE 16 — Institutional Order Block (Corrected)
# ====================================================
def isDispUp =
body > prevBody and
range > prevRange and
close > high[1];
def isDispDn =
body > prevBody and
range > prevRange and
close < low[1];
def volValid = volume > Average(volume, 20);
# 2. Bullish OB: Displacement + FVG + Volume, AND the preceding candle must be a down candle
def obBull =
isDispUp and
(bullDispFVG or isHQFVG) and
volValid and
close[1] < open[1];
# 3. Bearish OB: Displacement + FVG + Volume, AND the preceding candle must be an up candle
def obBear =
isDispDn and
(bearDispFVG or isHQFVG) and
volValid and
close[1] > open[1];
def isOB = obBull or obBear;
# ====================================================
# ZONE 17 — MITIGATION ENGINE
# ====================================================
# 1. Mitigation Origins
def mitigBeginUp =
isUpSweep or
isInstRevUp or
bullHQFVG or
obBull or
bosUp or
chochUp;
def mitigBeginDn =
isDnSweep or
isInstRevDn or
bearHQFVG or
obBear or
bosDn or
chochDn;
# 2. Mitigation Terminations
def mitigEndUp =
refillUp or
bullFVGFill or
pivotClusterUp;
def mitigEndDn =
refillDown or
bearFVGFill or
pivotClusterDown;
def oppositeResetUp = mitigBeginDn;
def oppositeResetDn = mitigBeginUp;
# 3. Active State Tracking
def mitigIsActiveUp = CompoundValue(1,
if mitigBeginUp then 1
else if mitigEndUp or oppositeResetUp then 0
else mitigIsActiveUp[1], 0);
def mitigIsActiveDn = CompoundValue(1,
if mitigBeginDn then 1
else if mitigEndDn or oppositeResetDn then 0
else mitigIsActiveDn[1], 0);
def isMitigOriginUp =
mitigBeginUp and (mitigIsActiveUp[1] <= 0);
def isMitigOriginDn =
mitigBeginDn and (mitigIsActiveDn[1] <= 0);
# 4. Anchor Bar Memory
def mitigAnchorUp = CompoundValue(1,
if isMitigOriginUp then bn
else if mitigIsActiveUp then mitigAnchorUp[1]
else 0, 0);
def mitigAnchorDn = CompoundValue(1,
if isMitigOriginDn then bn
else if mitigIsActiveDn then mitigAnchorDn[1]
else 0, 0);
def mitigAgeUp =
if mitigAnchorUp > 0 then bn - mitigAnchorUp else 0;
def mitigAgeDn =
if mitigAnchorDn > 0 then bn - mitigAnchorDn else 0;
# 5. Age-Out Mechanism
def ageOutUp = mitigAgeUp > 50 and !mitigBeginUp;
def ageOutDn = mitigAgeDn > 50 and !mitigBeginDn;
def mitigIsClosedUp = mitigEndUp or ageOutUp;
def mitigIsClosedDn = mitigEndDn or ageOutDn;
# 6. Price Level Tracking (Clears out to NaN when closed to prevent endless line plotting)
def originUpPrice =
if isMitigOriginUp then low
else if mitigIsClosedUp then Double.NaN
else originUpPrice[1];
def originDnPrice =
if isMitigOriginDn then high
else if mitigIsClosedDn then Double.NaN
else originDnPrice[1];
# ====================================================
# EVENT BN MEMORY
# ====================================================
# 1. State Trackers
def churnBN = CompoundValue(1, if isChurn then bn else churnBN[1], 0);
def sweepUpBN = CompoundValue(1, if isUpSweep then bn else sweepUpBN[1], 0);
def sweepDnBN = CompoundValue(1, if isDnSweep then bn else sweepDnBN[1], 0);
def stopGrabUpBN = CompoundValue(1, if isUpStopGrab then bn else stopGrabUpBN[1], 0);
def stopGrabDnBN = CompoundValue(1, if isDnStopGrab then bn else stopGrabDnBN[1], 0);
def voidUpBN = CompoundValue(1, if voidUp then bn else voidUpBN[1], 0);
def voidDnBN = CompoundValue(1, if voidDown then bn else voidDnBN[1], 0);
def refillUpBN = CompoundValue(1, if refillUp then bn else refillUpBN[1], 0);
def refillDnBN = CompoundValue(1, if refillDown then bn else refillDnBN[1], 0);
def fvgBullBN = CompoundValue(1, if bullDispFVG then bn else fvgBullBN[1], 0);
def fvgBearBN = CompoundValue(1, if bearDispFVG then bn else fvgBearBN[1], 0);
def fvgFillBullBN = CompoundValue(1, if bullFVGFill then bn else fvgFillBullBN[1], 0);
def fvgFillBearBN = CompoundValue(1, if bearFVGFill then bn else fvgFillBearBN[1], 0);
def hqFvgBN = CompoundValue(1, if isHQFVG then bn else hqFvgBN[1], 0);
def bprBullBN = CompoundValue(1, if bullBPR then bn else bprBullBN[1], 0);
def bprBearBN = CompoundValue(1, if bearBPR then bn else bprBearBN[1], 0);
def instRevUpBN = CompoundValue(1, if isInstRevUp then bn else instRevUpBN[1], 0);
def instRevDnBN = CompoundValue(1, if isInstRevDn then bn else instRevDnBN[1], 0);
def ictSweepUpBN = CompoundValue(1, if ictBuySideSweep then bn else ictSweepUpBN[1], 0);
def ictSweepDnBN = CompoundValue(1, if ictSellSideSweep then bn else ictSweepDnBN[1], 0);
def hiddenAbsorbBN = CompoundValue(1, if isHiddenAbsorb then bn else hiddenAbsorbBN[1], 0);
def pivotClusterBN = CompoundValue(1, if pivotCluster then bn else pivotClusterBN[1], 0);
def shelfBN = CompoundValue(1, if isShelf then bn else shelfBN[1], 0);
def volClimaxBN = CompoundValue(1, if isVolClimax then bn else volClimaxBN[1], 0);
def hftTrapBN = CompoundValue(1, if isHftVwapTrap then bn else hftTrapBN[1], 0);
def bprValidBullBN = CompoundValue(1, if bullBPRValid then bn else bprValidBullBN[1], 0);
def bprValidBearBN = CompoundValue(1, if bearBPRValid then bn else bprValidBearBN[1], 0);
def trendExhaustUpBN = CompoundValue(1, if effortHigh and resultWeakUp then bn else trendExhaustUpBN[1], 0);
def trendExhaustDnBN = CompoundValue(1, if effortLow and resultWeakDown then bn else trendExhaustDnBN[1], 0);
def rejectUpBN = CompoundValue(1, if isRejectUp then bn else rejectUpBN[1], 0);
def rejectDnBN = CompoundValue(1, if isRejectDn then bn else rejectDnBN[1], 0);
def absorbBN = CompoundValue(1, if isAbsorb then bn else absorbBN[1], 0);
def compressBN = CompoundValue(1, if isCompression then bn else compressBN[1], 0);
# 2. Lookback Queries: foundational structure, and seqLookback triggers
def contextLookback = 30;
def hasShelf = bn - shelfBN <= contextLookback;
def hasChurn = bn - churnBN <= contextLookback;
def hasPivot = bn - pivotClusterBN <= contextLookback;
def hasClimax = bn - volClimaxBN <= contextLookback;
def hasVoid = (bn - voidUpBN <= contextLookback) or (bn - voidDnBN <= contextLookback);
def hasSweep = (bn - sweepUpBN <= seqLookback) or (bn - sweepDnBN <= seqLookback);
def hasICTSweep = (bn - ictSweepUpBN <= seqLookback) or (bn - ictSweepDnBN <= seqLookback);
def hasStopGrab = (bn - stopGrabUpBN <= seqLookback) or (bn - stopGrabDnBN <= seqLookback);
def hasInstRev = (bn - instRevUpBN <= seqLookback) or (bn - instRevDnBN <= seqLookback);
def hasTrendExhaust = (bn - trendExhaustUpBN <= seqLookback) or (bn - trendExhaustDnBN <= seqLookback);
def hasRefill = (bn - refillUpBN <= seqLookback) or (bn - refillDnBN <= seqLookback);
def hasFVG = (bn - fvgBullBN <= seqLookback) or (bn - fvgBearBN <= seqLookback);
def hasFVGFill = (bn - fvgFillBullBN <= seqLookback) or (bn - fvgFillBearBN <= seqLookback);
def hasBPR = (bn - bprBullBN <= seqLookback) or (bn - bprBearBN <= seqLookback);
def hasBPRValid = (bn - bprValidBullBN <= seqLookback) or (bn - bprValidBearBN <= seqLookback);
def hasHftTrap = bn - hftTrapBN <= seqLookback;
def hasHQFVG = bn - hqFvgBN <= seqLookback;
# 3. Sequences
def seq_LRT = (hasSweep or hasICTSweep) and hasStopGrab and hasHftTrap and hasInstRev;
def seq_SFD = hasShelf and hasChurn and hasPivot and (hasClimax or hasTrendExhaust) and hasInstRev;
def seq_IMB = hasVoid and (hasFVG or hasHQFVG) and (hasFVGFill or hasRefill) and hasBPR and hasInstRev;
def seq_ICT_Mitig = hasICTSweep and hasFVGFill;
def seq_ICT_Cont = hasICTSweep and hasBPRValid;
def seq_VoidChain = hasVoid and hasFVG and hasFVGFill;
def seq_SweepExhaust = hasSweep and hasTrendExhaust and hasInstRev;
def hasReject = (bn - rejectUpBN <= seqLookback) or (bn - rejectDnBN <= seqLookback);
def hasAbsorb = bn - absorbBN <= contextLookback;
def seq_MicroReject =
hasReject and hasSweep and hasStopGrab;
def seq_MicroAbsorb =
hasAbsorb and hasShelf and hasChurn;
def hasCompress = bn - compressBN <= contextLookback;
def seqID =
if seq_LRT then 1
else if seq_SFD then 2
else if seq_IMB then 3
else if seq_ICT_Mitig then 4
else if seq_ICT_Cont then 5
else if seq_VoidChain then 6
else if seq_SweepExhaust then 7
else if seq_MicroReject then 8
else if seq_MicroAbsorb then 9
else 0;
AddLabel(yes,
"SEQ " + seqID,
if seqID == 1 then Color.RED
else if seqID == 2 then Color.YELLOW
else if seqID == 3 then Color.GREEN
else if seqID == 4 then Color.CYAN
else if seqID == 5 then Color.MAGENTA
else if seqID == 6 then Color.ORANGE
else if seqID == 7 then Color.DARK_RED
else if seqID == 8 then Color.LIGHT_RED
else if seqID == 9 then Color.LIGHT_GREEN
else Color.GRAY,
pos);
# ====================================================
# FLOW LABEL
# ====================================================
AddLabel(
showFlowLabel,
"Flow: " +
(if isHftVwapTrap then "⚠️ HFT VWAP TRAP"
else if isInstReversal then "REVERSAL"
else if isICTSweep then "ICT SWEEP"
else if isMitigOriginUp then "MITIG ORIGIN ↑"
else if isMitigOriginDn then "MITIG ORIGIN ↓"
else if isBPRValid then "BPR✓"
else if isFVGFill then "FVG FILL"
else if isHQFVG then "FVG✓"
else if isBPR then "BPR"
else if isFVG then "FVG"
else if isVoidRefill then "REFILL"
else if isVoid then "VOID"
else if isUpStopGrab then "LIQ GRAB ↑"
else if isDnStopGrab then "LIQ GRAB ↓"
else if isUpSweep then "SWEEP ↑"
else if isDnSweep then "SWEEP ↓"
else if isHiddenAbsorb then "HIDDEN ABSORB"
else if isVolClimax then "CLIMAX"
else if isTrendExhaustion then "EXHAUSTION"
else if isShelf then "SHELF"
else if pivotCluster then "PIVOT CLUSTER"
else if isChurn then "DP CHURN"
else "Standard Flow"),
if isHftVwapTrap then Color.MAGENTA else Color.WHITE,
pos
);
# ====================================================
# CHART BUBBLES (TIERS)
# ====================================================
AddChartBubble(
(showAllBubbles or (showCustomBubble and DP_Churn))
and isChurn,
low,
"DP CHURN",
GlobalColor("DownTrend"),
no
);
# --- Shelves ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and Shelf))
and isShelf,
if shelfHigh then high else low,
"SHELF",
if shelfHigh_I or shelfLow_I then Color.WHITE
else if shelfHigh_M or shelfLow_M then GlobalColor("Parchment")
else GlobalColor("FiberP"),
shelfHigh
);
# --- Absorption ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and Hidden_Absorption))
and isHiddenAbsorb,
low,
"ABSORB",
Color.CYAN,
no
);
# --- StopGrab Grab ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and StopGrab))
and (isUpStopGrab or isDnStopGrab),
if isUpStopGrab then high else low,
"LIQ " + (if isUpStopGrab then "↑" else "↓"),
if isUpStopGrab then Color.YELLOW else Color.LIME,
if isUpStopGrab then yes else no
);
# --- Sweep ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and Sweep))
and (isUpSweep or isDnSweep),
if isUpSweep then high else low,
"SWEEP " + (if isUpSweep then "↑" else "↓"),
if isUpSweep then Color.CYAN else Color.LIGHT_RED,
if isUpSweep then yes else no
);
# --- Voids ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and Voids))
and isVoid,
if close > open then high else low,
"VOID",
if !isVoidRefill and !isFVGFill and !isFVG
then Color.DARK_GREEN
else Color.LIGHT_GRAY,
close > open
);
# --- Refill ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and Voids))
and isVoidRefill and !isFVGFill,
low,
"REFILL",
GlobalColor("Fill"),
no
);
# --- Climax Exhaustion ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and Climax_Exhaust))
and (isVolClimax or isTrendExhaustion),
if upperWick > lowerWick then high else low,
(if isVolClimax then "CLIMAX" else "EXHAUST"),
if isVolClimax then GlobalColor("Amber") else Color.RED,
if upperWick > lowerWick then yes else no
);
# --- Clusters ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and Clusters))
and (pivotClusterUp or pivotClusterDown or pivotClusterMid),
if pivotClusterUp then high
else if pivotClusterDown then low
else close,
"PIVOT CLUSTER" +
(if pivotClusterUp then " ↑"
else if pivotClusterDown then " ↓"
else ""),
if pivotClusterMid then Color.LIGHT_GRAY else Color.ORANGE,
if pivotClusterUp then yes
else if pivotClusterDown then no
else yes
);
# --- ICT_Sweep FVG ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and ICTFVG))
and isICTDispFVG,
if ictBullFVG then low else high,
"ICT FVG " + (if ictBullFVG then "↑" else "↓"),
Color.CYAN,
if ictBullFVG then no else yes
);
# --- ICT_Sweep BPR ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and ICTBPR))
and (isICTBPR or isICTBPRValid),
if ictBullBPR or ictBullBPRValid then low else high,
"ICT BPR " +
(if ictBullBPR or ictBullBPRValid then "↑" else "↓") +
(if isICTBPRValid then "✓" else ""),
if isICTBPRValid then
(if ictBullBPRValid then Color.GREEN else Color.RED)
else
(if ictBullBPR then Color.MAGENTA else Color.DARK_ORANGE),
if ictBullBPR or ictBullBPRValid then no else yes
);
# --- ICT_Sweep Sweep ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and ICT_Sweep))
and (ictBuySideSweep or ictSellSideSweep),
if ictSellSideSweep then low else high,
"ICT SWEEP " + (if ictSellSideSweep then "↑" else "↓"),
Color.MAGENTA,
if ictSellSideSweep then no else yes
);
# --- HFT Trap ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and HFT_Trap))
and isHftVwapTrap,
if close > vwapValue then high else low,
"⚠️ HFT TRAP",
Color.MAGENTA,
close > vwapValue
);
# --- Inst Rev ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and Inst_Rev))
and (isInstRevUp or isInstRevDn),
if isInstRevUp then low else high,
"INST REV " + (if isInstRevUp then "↑" else "↓"),
Color.WHITE,
if isInstRevUp then no else yes
);
# --- FVG ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and FVG))
and (bullDispFVG or bearDispFVG),
if bullDispFVG then low else high,
"FVG " +
(if bullDispFVG then "↑" else "↓") +
(if isHQFVG then "✓" else ""),
if isHQFVG then
(if bullDispFVG then Color.GREEN else Color.RED)
else
(if bullDispFVG then Color.CYAN else Color.ORANGE),
if bullDispFVG then no else yes
);
# --- Fill ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and FVG))
and isFVGFill,
if bullFVGFill then low else high,
"FVG FILL",
GlobalColor("Info"),
if bullFVGFill then no else yes
);
# --- BRP ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and BPR))
and isBPR,
if bullBPR then low else high,
"BPR " + (if bullBPR then "↑" else "↓") +
(if isBPRValid then "✓" else ""),
if isBPRValid then (if bullBPR then Color.GREEN else Color.RED)
else (if bullBPR then Color.CYAN else Color.DARK_ORANGE),
if bullBPR then no else yes
);
# --- CHoCH Bubbles ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and BOS_B))
and (chochUp or chochDn),
if chochUp then low else high,
"CHoCH " + (if chochUp then "↑" else "↓"),
if chochUp then Color.GREEN else Color.RED,
if chochUp then no else yes
);
# --- BOS Bubbles ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and BOS_B))
and (bosUp or bosDn),
if bosUp then low else high,
"BOS " + (if bosUp then "↑" else "↓"),
if bosUp then Color.CYAN else Color.ORANGE,
if bosUp then no else yes
);
# --- OB Bubbles ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and OB_B))
and (obBull or obBear),
if obBull then low else high,
"OB " + (if obBull then "BULL" else "BEAR"),
if obBull then Color.CYAN else Color.MAGENTA,
if obBull then no else yes
);
# --- Mitigation ---
AddChartBubble(
(showAllBubbles or (showCustomBubble and Mitigation))
and (isMitigOriginUp or isMitigOriginDn),
if isMitigOriginUp then low else high,
"MITIG ORIGIN " + (if isMitigOriginUp then "↑" else "↓"),
if isMitigOriginUp then Color.GREEN else Color.RED,
if isMitigOriginUp then no else yes
);
# ====================================================
# DECAY SETTINGS
# ====================================================
def dirDecay = 0.50;
def seqDecay = 0.70;
# ====================================================
# DIRECTIONAL STATE VARIABLES (1 = Bullish, -1 = Bearish, 0 = None)
# ====================================================
def sweepDir = if isUpSweep then 1 else if isDnSweep then -1 else 0;
def ictSweepDir = if ictSellSideSweep then 1 else if ictBuySideSweep then -1 else 0;
def stopGrabDir = if isUpStopGrab then 1 else if isDnStopGrab then -1 else 0;
def voidDir = if voidUp then 1 else if voidDown then -1 else 0;
def refillDir = if refillUp then 1 else if refillDown then -1 else 0;
def fvgDir = if bullDispFVG then 1 else if bearDispFVG then -1 else 0;
def fvgFillDir = if bullFVGFill then 1 else if bearFVGFill then -1 else 0;
def bprDir = if bullBPR then 1 else if bearBPR then -1 else 0;
def bprValidDir = if bullBPRValid then 1 else if bearBPRValid then -1 else 0;
def trendExhaustDir = if (effortLow and resultWeakDown) then 1 else if (effortHigh and resultWeakUp) then -1 else 0;
def instRevDir = if isInstRevUp then 1 else if isInstRevDn then -1 else 0;
def sweepDirMem = CompoundValue(1,
if isUpSweep then 1
else if isDnSweep then -1
else sweepDirMem[1] * dirDecay, 0);
def ictSweepDirMem = CompoundValue(1,
if ictSellSideSweep then 1 # Swept lows -> Bullish reaction
else if ictBuySideSweep then -1 # Swept highs -> Bearish reaction
else ictSweepDirMem[1] * dirDecay, 0);
def voidDirMem = CompoundValue(1,
if voidUp then 1
else if voidDown then -1
else voidDirMem[1] * dirDecay, 0);
def refillDirMem = CompoundValue(1,
if refillUp then 1
else if refillDown then -1
else refillDirMem[1] * dirDecay, 0);
def fvgDirMem = CompoundValue(1,
if bullDispFVG then 1
else if bearDispFVG then -1
else fvgDirMem[1] * dirDecay, 0);
def fvgFillDirMem = CompoundValue(1,
if bullFVGFill then 1
else if bearFVGFill then -1
else fvgFillDirMem[1] * dirDecay, 0);
def bprDirMem = CompoundValue(1,
if bullBPR then 1
else if bearBPR then -1
else bprDirMem[1] * dirDecay, 0);
def bprValidDirMem = CompoundValue(1,
if bullBPRValid then 1
else if bearBPRValid then -1
else bprValidDirMem[1] * dirDecay, 0);
def trendExhaustDirMem = CompoundValue(1,
if effortLow and resultWeakDown then 1 # Sellers exhausted -> Bullish
else if effortHigh and resultWeakUp then -1 # Buyers exhausted -> Bearish
else trendExhaustDirMem[1] * dirDecay, 0);
def instRevDirMem = CompoundValue(1,
if isInstRevUp then 1
else if isInstRevDn then -1
else instRevDirMem[1] * dirDecay, 0);
# ====================================================
# SEQUENCE BOOSTERS (Decay)
# ====================================================
def seq_LRT_mem =
if seq_LRT then 1 else seq_LRT_mem[1] * seqDecay;
def seq_IMB_mem =
if seq_IMB then 1 else seq_IMB_mem[1] * seqDecay;
def seq_ICT_Mitig_mem =
if seq_ICT_Mitig then 1 else seq_ICT_Mitig_mem[1] * seqDecay;
def seq_SweepExhaust_mem =
if seq_SweepExhaust then 1 else seq_SweepExhaust_mem[1] * seqDecay;
def seq_MicroAbsorb_mem =
if seq_MicroAbsorb then 1 else seq_MicroAbsorb_mem[1] * seqDecay;
def seq_MicroReject_mem =
if seq_MicroReject then 1 else seq_MicroReject_mem[1] * seqDecay;
# ====================================================
# TREND BOOSTERS
# ====================================================
def revTrendUpBoost = if tr1 == 1 then 3 else 0;
def revTrendDnBoost = if tr1 == -1 then 3 else 0;
# ====================================================
# RPM V2 — Reversal Pressure Meter
# ====================================================
def rpmEventCore =
(hasSweep * 2)
+ (hasICTSweep * 3)
+ (hasStopGrab * 3)
+ (hasVoid * 2)
+ (hasRefill * 2)
+ (hasFVG * 1)
+ (hasHQFVG * 2)
+ (hasFVGFill * 3)
+ (hasBPR * 2)
+ (hasBPRValid * 4)
+ (hasTrendExhaust * 3)
+ (hasClimax * 3)
+ (hasHftTrap * 4)
+ (hasShelf * 1)
+ (hasChurn * 1)
+ (hasPivot * 2)
+ (hasAbsorb * 1)
+ (hasReject * 1)
+ (hasCompress * 1);
def rpmSeqBonus =
(seq_LRT_mem * 8)
+ (seq_SFD * 7)
+ (seq_IMB_mem * 9)
+ (seq_ICT_Mitig_mem * 6)
+ (seq_ICT_Cont * 6)
+ (seq_VoidChain * 5)
+ (seq_SweepExhaust_mem * 6)
+ (seq_MicroReject_mem * 3)
+ (seq_MicroAbsorb_mem * 3);
def rpmBiasUp =
((sweepDirMem == -1) * 3)
+ ((ictSweepDirMem == -1) * 3)
+ ((voidDirMem == -1) * 2)
+ ((refillDirMem == 1) * 2)
+ ((fvgDirMem == -1) * 1)
+ ((fvgFillDirMem == 1) * 2)
+ ((bprDirMem == 1) * 2)
+ ((bprValidDirMem == 1) * 3)
+ ((trendExhaustDirMem == -1) * 3)
+ ((instRevDirMem == 1) * 4);
def rpmBiasDn =
((sweepDirMem == 1) * 3)
+ ((ictSweepDirMem == 1) * 3)
+ ((voidDirMem == 1) * 2)
+ ((refillDirMem == -1) * 2)
+ ((fvgDirMem == 1) * 1)
+ ((fvgFillDirMem == -1) * 2)
+ ((bprDirMem == -1) * 2)
+ ((bprValidDirMem == -1) * 3)
+ ((trendExhaustDirMem == 1) * 3)
+ ((instRevDirMem == -1) * 4);
def rpmScoreRaw =
rpmEventCore
+ rpmSeqBonus
+ rpmBiasUp
+ rpmBiasDn;
def maxRpmRaw = 84;
def rpmPercent = (rpmScoreRaw / maxRpmRaw) * 100;
AddLabel(
showRPM,
"RPM " + Round(rpmPercent, 0) + "% " ,
if rpmPercent >= 80 then GlobalColor("RPM_UpStrong")
else if rpmPercent >= 60 then GlobalColor("RPM_Up")
else if rpmPercent >= 39 then Color.Light_Gray
else if rpmPercent >= 20 then GlobalColor("DownTrend")
else GlobalColor("RPM_DownStrong"),
pos
);
# ====================================================
# REV V2 — Directional Reversal Pressure
# ====================================================
def revUpScore =
((stopGrabDir == -1) * 3)
+ ((voidDirMem == -1) * 2)
+ ((refillDirMem == 1) * 3)
+ ((trendExhaustDirMem == -1) * 3)
+ ((instRevDirMem == 1) * 5)
+ (hasAbsorb * 2)
+ (hasReject * 2)
+ (hasShelf * 1)
+ (hasPivot * 2)
+ ((hasICTSweep and ictSweepDirMem == -1) * 3)
+ ((hasFVG and fvgDirMem == -1) * 1)
+ ((hasHQFVG and fvgDirMem == -1) * 2)
+ ((hasFVGFill and fvgFillDirMem == 1) * 3)
+ ((hasBPR and bprDirMem == 1) * 2)
+ ((hasBPRValid and bprValidDirMem == 1) * 4);
def revDnScore =
((stopGrabDir == 1) * 3)
+ ((voidDirMem == 1) * 2)
+ ((refillDirMem == -1) * 3)
+ ((trendExhaustDirMem == 1) * 3)
+ ((instRevDirMem == -1) * 5)
+ (hasAbsorb * 2)
+ (hasReject * 2)
+ (hasShelf * 1)
+ (hasPivot * 2)
+ ((hasICTSweep and ictSweepDirMem == 1) * 3)
+ ((hasFVG and fvgDirMem == 1) * 1)
+ ((hasHQFVG and fvgDirMem == 1) * 2)
+ ((hasFVGFill and fvgFillDirMem == -1) * 3)
+ ((hasBPR and bprDirMem == -1) * 2)
+ ((hasBPRValid and bprValidDirMem == -1) * 4);
def revUpScore1 =
revUpScore
+ (seq_LRT_mem * 4)
+ (seq_IMB_mem * 5)
+ (seq_ICT_Mitig_mem * 3)
+ (seq_SweepExhaust_mem * 4)
+ (seq_MicroAbsorb_mem * 2)
+ revTrendUpBoost
- revTrendDnBoost;
def revDnScore1 =
revDnScore
+ (seq_LRT_mem * 4)
+ (seq_IMB_mem * 5)
+ (seq_ICT_Mitig_mem * 3)
+ (seq_SweepExhaust_mem * 4)
+ (seq_MicroReject_mem * 2)
+ revTrendDnBoost
- revTrendUpBoost;
AddLabel(
showRevLabel,
"REV↓ " + Round(revDnScore1,0),
if revDnScore1 >= 24 then Color.RED
else if revDnScore1 >= 18 then Color.Pink
else if revDnScore1 >= 10 then Color.ORANGE
else Color.GRAY,
pos
);
AddLabel(
showRevLabel,
"REV↑ " + Round(revUpScore1,0),
if revUpScore1 >= 24 then Color.GREEN
else if revUpScore1 >= 18 then Color.Light_GREEN
else if revUpScore1 >= 10 then Color.YELLOW
else Color.GRAY,
pos
);
AddChartBubble(
showREV_Bubbles and Round(revUpScore1,0) >= revBubbleThreshold,
low,
"REV↑ " + Round(revUpScore1,0),
Color.Light_GREEN,
no
);
AddChartBubble(
showREV_Bubbles and Round(revDnScore1,0) >= revBubbleThreshold,
high,
"REV↓ " + Round(revDnScore1,0),
GlobalColor("RPM_Down"),
yes
);
#-----------------------------------------
# DISPLACEMENT ARROWS
#-----------------------------------------
plot cb_DispUp =
if showCandleArrow and isDispUp and tr1 == 1
then high
else Double.NaN;
cb_DispUp.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
cb_DispUp.SetLineWeight(1);
cb_DispUp.AssignValueColor(Color.GREEN);
plot cb_DispDn =
if showCandleArrow and isDispDn and tr1 == -1
then low
else Double.NaN;
cb_DispDn.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
cb_DispDn.SetLineWeight(1);
cb_DispDn.AssignValueColor(Color.RED);
plot cb_RejectUp =
if isRejectUp then low else Double.NaN;
cb_RejectUp.SetPaintingStrategy(PaintingStrategy.POINTS);
cb_RejectUp.SetLineWeight(2);
cb_RejectUp.AssignValueColor(Color.CYAN);
plot cb_RejectDn =
if isRejectDn then high else Double.NaN;
cb_RejectDn.SetPaintingStrategy(PaintingStrategy.POINTS);
cb_RejectDn.SetLineWeight(2);
cb_RejectDn.AssignValueColor(Color.CYAN);
plot cb_Absorb =
if isAbsorb then MidBodyVal() else Double.NaN;
cb_Absorb.SetPaintingStrategy(PaintingStrategy.POINTS);
cb_Absorb.SetLineWeight(2);
cb_Absorb.AssignValueColor(Color.YELLOW);
plot cb_Compress =
if isCompression then MidBodyVal() else Double.NaN;
cb_Compress.SetPaintingStrategy(PaintingStrategy.SQUARES);
cb_Compress.SetLineWeight(1);
cb_Compress.AssignValueColor(Color.LIGHT_GRAY);
#-----------------------------------------
# CANDLE NARRATIVE LABEL
#-----------------------------------------
AddLabel(
showCandleLabels,
if isDispUp then "Disp ↑"
else if isDispDn then "Disp ↓"
else if isRejectUp then "Reject ↑"
else if isRejectDn then "Reject ↓"
else if isAbsorb then "Absorb"
else if isCompression then "Compress"
else "Candle Neutral",
if isDispUp then Color.GREEN
else if isDispDn then Color.RED
else if isRejectUp or isRejectDn then Color.CYAN
else if isAbsorb then Color.YELLOW
else if isCompression then Color.LIGHT_GRAY
else Color.GRAY,
pos
);
# ====================================================
# PATTERN ENGINE v4
# ====================================================
def patternA_up =
isHiddenAbsorb or
(hasShelf and shelfLow) or
hasChurn or
(hasVoid and voidDir == 1) or
(hasHQFVG and fvgDir == 1) or
isMitigOriginUp or
chochUp or
bosUp;
def patternA_dn =
isHiddenAbsorb or
(hasShelf and shelfHigh) or
hasChurn or
(hasVoid and voidDir == -1) or
(hasHQFVG and fvgDir == -1) or
isMitigOriginDn or
chochDn or
bosDn;
def patternA = patternA_up or patternA_dn;
def patternB_up =
(hasFVG and fvgDir == 1) or
(hasHQFVG and fvgDir == 1) or
(hasVoid and voidDir == 1) or
hasBPRValid or
(isICTDispFVG and ictBullFVG) or
(isICTBPRValid and ictBullBPRValid);
def patternB_dn =
(hasFVG and fvgDir == -1) or
(hasHQFVG and fvgDir == -1) or
(hasVoid and voidDir == -1) or
hasBPRValid or
(isICTDispFVG and ictBearFVG) or
(isICTBPRValid and ictBearBPRValid);
def patternB = patternB_up or patternB_dn;
def patternC_up =
hasFVGFill or
hasRefill or
isMitigOriginUp or
isInstRevUp or
hasTrendExhaust or
chochUp or
bosUp;
def patternC_dn =
hasFVGFill or
hasRefill or
isMitigOriginDn or
isInstRevDn or
hasTrendExhaust or
chochDn or
bosDn;
def patternC = patternC_up or patternC_dn;
def patternID =
if patternA then 1
else if patternB then 2
else if patternC then 3
else 0;
AddLabel(
yes,
" "
+ (if patternID == 1 then
(if patternA_up then "Pattern A ↑ (Accumulation)"
else "Pattern A ↓ (Distribution)")
else if patternID == 2 then
(if patternB_up then "Pattern B ↑ (Bull Displacement)"
else "Pattern B ↓ (Bear Displacement)")
else if patternID == 3 then
(if patternC_up then "Pattern C ↑ (Bull Defense)"
else "Pattern C ↓ (Bear Defense)")
else "None"),
if patternID == 1 then
(if patternA_up then Color.GREEN else Color.PINK)
else if patternID == 2 then Color.CYAN
else if patternID == 3 then Color.ORANGE
else Color.GRAY,
pos
);
# ====================================================
# DISPLACEMENT QUALITY V2
# ====================================================
def dispSponsored =
hasHQFVG or
(hasVoid and voidDir != 0) or
hasBPRValid or
isICTDispFVG or
isICTBPRValid;
def dispModerate =
hasFVG and !dispSponsored;
def dispWeak =
!hasFVG and !hasHQFVG and !hasVoid;
def dispQualityCode =
if dispSponsored then 1
else if dispModerate then 2
else 3;
AddLabel(
yes,
" "
+ (if dispQualityCode == 1 then "Sponsored"
else if dispQualityCode == 2 then "Moderate"
else "Weak"),
if dispQualityCode == 1 then Color.GREEN
else if dispQualityCode == 2 then Color.YELLOW
else Color.GRAY,
pos
);
# ====================================================
# FAILURE ENGINE V2
# ====================================================
def failMitigation =
hasFVGFill and !hasInstRev;
def failDisplacement =
(hasVoid and !hasHQFVG) or
(hasFVG and fvgDir == 0);
def failDefense =
hasTrendExhaust and !hasInstRev;
def failAbandon =
failMitigation and failDisplacement and failDefense;
def failStateCode =
if failAbandon then 4
else if failDefense then 3
else if failMitigation then 2
else if failDisplacement then 1
else 0;
AddLabel(
yes,
" "
+ (if failStateCode == 4 then "Full Abandonment"
else if failStateCode == 3 then "Defense Failure"
else if failStateCode == 2 then "Mitigation Failure"
else if failStateCode == 1 then "Displacement Weakening"
else "Stable"),
if failStateCode == 4 then Color.RED
else if failStateCode == 3 then Color.ORANGE
else if failStateCode == 2 then Color.YELLOW
else if failStateCode == 1 then Color.LIGHT_GRAY
else Color.GRAY,
pos
);
# ====================================================
# FLOW BIAS / PRESSURE
# ====================================================
def flowBiasCode =
if revUpScore > revDnScore then 1
else if revDnScore > revUpScore then -1
else 0;
AddLabel(
yes,
" "
+ (if flowBiasCode == 1 then "Pressure Up"
else if flowBiasCode == -1 then "Pressure Dn"
else "Mixed Pressure"),
if flowBiasCode == -1 then Color.RED
else if flowBiasCode == 1 then Color.LIGHT_GREEN
else Color.LIGHT_GRAY,
pos
);
# ====================================================
# SEQUENCE LABEL
# ====================================================
def seqCode = seqID;
AddLabel(
yes,
" "
+ (if seqCode == 1 then "LRT"
else if seqCode == 2 then "SFD"
else if seqCode == 3 then "IMB"
else if seqCode == 4 then "ICT-Mitig"
else if seqCode == 5 then "ICT-Cont"
else if seqCode == 6 then "VoidChain"
else if seqCode == 7 then "SweepExhaust"
else if seqCode == 8 then "MicroReject"
else if seqCode == 9 then "MicroAbsorb"
else "None"),
Color.LIGHT_GRAY,
pos
);
# ====================================================
# NEXT PHASE
# ====================================================
def nextPhaseCode =
if failStateCode == 4 then -2
else if failStateCode == 3 then -1
else if failStateCode == 2 then 0
else if failStateCode == 1 then 2
else if patternID == 1 then 1
else if patternID == 2 then 2
else if patternID == 3 then 3
else 0;
AddLabel(
yes,
"NEXT: "
+ (if nextPhaseCode == 1 then " B (Displacement)"
else if nextPhaseCode == 2 then " C (Defense)"
else if nextPhaseCode == 3 then " B Continuation"
else if nextPhaseCode == 0 then " A Continuation"
else if nextPhaseCode == -1 then "Reversal Forming"
else if nextPhaseCode == -2 then "Opposite Pattern A (New Collection)"
else "Unknown"),
if nextPhaseCode == -1 or nextPhaseCode == -2 then GlobalColor("DownTrend")
else if nextPhaseCode == 1 then Color.GREEN
else if nextPhaseCode == 2 then Color.YELLOW
else Color.GRAY,
pos
);
# ====================================================
# DYNAMIC SR LINES (Unmitigated vs Mitigated State)
# ====================================================
# 1. Bullish Price Tracking
def curOrigPriceUp = CompoundValue(1,
if isMitigOriginUp then low
else curOrigPriceUp[1],
Double.NaN
);
def hasGreenLevel = if !IsNaN(curOrigPriceUp) then 1 else 0;
# Detect when price closes below the support level, officially mitigating it
def isMitigatedUp = close < curOrigPriceUp;
# 1 = Unmitigated (Solid), 0 = Mitigated (Dashed)
def greenRegime = CompoundValue(1,
if isMitigOriginUp then 1
else if isMitigatedUp then 0
else greenRegime[1], 1
);
plot GreenSolid = if SR_Lines and hasGreenLevel and greenRegime == 1 then curOrigPriceUp else Double.NaN;
GreenSolid.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
GreenSolid.SetDefaultColor(Color.GREEN);
GreenSolid.SetLineWeight(2);
plot GreenDashed = if SR_Lines and hasGreenLevel and greenRegime == 0 then curOrigPriceUp else Double.NaN;
GreenDashed.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
GreenDashed.SetStyle(Curve.POINTS);
GreenDashed.SetDefaultColor(Color.DARK_GREEN); # Slightly darker to fade it to the background
GreenDashed.SetLineWeight(1);
# 2. Bearish Price Tracking
def curOrigPriceDn = CompoundValue(1,
if isMitigOriginDn then high
else curOrigPriceDn[1],
Double.NaN
);
def hasRedLevel = if !IsNaN(curOrigPriceDn) then 1 else 0;
# Detect when price closes above the resistance level, officially mitigating it
def isMitigatedDn = close > curOrigPriceDn;
# 1 = Unmitigated (Solid), 0 = Mitigated (Dashed)
def redRegime = CompoundValue(1,
if isMitigOriginDn then 1
else if isMitigatedDn then 0
else redRegime[1], 1
);
plot RedSolid = if SR_Lines and hasRedLevel and redRegime == 1 then curOrigPriceDn else Double.NaN;
RedSolid.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
RedSolid.SetDefaultColor(Color.RED);
RedSolid.SetLineWeight(2);
plot RedDashed = if SR_Lines and hasRedLevel and redRegime == 0 then curOrigPriceDn else Double.NaN;
RedDashed.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
RedDashed.SetStyle(Curve.POINTS);
RedDashed.SetDefaultColor(Color.DARK_RED);
RedDashed.SetLineWeight(1);
input enableAlerts = yes;
input alertType = Alert.BAR;
input alertSound = Sound.NoSound;
Alert(enableAlerts and isMitigOriginUp, "Bullish Mitigation Origin Active",alertType, alertSound);
Alert(enableAlerts and isMitigOriginDn, "Bearish Mitigation Origin Active",alertType, alertSound);
# ====================================================
# HTF MITIGATION / HTF S/R
# ====================================================
input HTF_rt = no; # HTF real time. Shhh... Secret repainter switch (No Admin)
def localOriginUp =
if isMitigOriginUp then low
else if IsNaN(localOriginUp[1]) then low
else localOriginUp[1];
def localOriginDn =
if isMitigOriginDn then high
else if IsNaN(localOriginDn[1]) then high
else localOriginDn[1];
def isHigherTf = htfTimeFrame > GetAggregationPeriod();
def htfL_raw = low(period = htfTimeFrame);
def htfH_raw = high(period = htfTimeFrame);
def htfL = if HTF_rt then htfL_raw else htfL_raw[1];
def htfH = if HTF_rt then htfH_raw else htfH_raw[1];
def htfRawUp = CompoundValue(1,
if IsNaN(htfRawUp[1]) then htfL
else if HTF_rt then htfL_raw
else if htfL != htfL[1] then htfL
else htfRawUp[1],
htfL
);
def htfRawDn = CompoundValue(1,
if IsNaN(htfRawDn[1]) then htfH
else if HTF_rt then htfH_raw
else if htfH != htfH[1] then htfH
else htfRawDn[1],
htfH
);
def activeUp =
if !isHigherTf then localOriginUp
else if HTF_rt then htfL_raw
else htfRawUp;
def activeDn =
if !isHigherTf then localOriginDn
else if HTF_rt then htfH_raw
else htfRawDn;
def htfExtUp = CompoundValue(1,
if IsNaN(close) then htfExtUp[1] else activeUp,
activeUp
);
def htfExtDn = CompoundValue(1,
if IsNaN(close) then htfExtDn[1] else activeDn,
activeDn
);
plot HTFLineUp = if HTF_SR and !IsNaN(htfExtUp) then htfExtUp else Double.NaN;
HTFLineUp.SetPaintingStrategy(PaintingStrategy.DASHES);
HTFLineUp.SetDefaultColor(Color.CYAN);
HTFLineUp.SetLineWeight(1);
plot HTFLineDn = if HTF_SR and !IsNaN(htfExtDn) then htfExtDn else Double.NaN;
HTFLineDn.SetPaintingStrategy(PaintingStrategy.DASHES);
HTFLineDn.SetDefaultColor(Color.MAGENTA);
HTFLineDn.SetLineWeight(1);
Last edited: