This is the second indicator in my next gen series.
(first one: https://usethinkscript.com/threads/eliteperformers-for-thinkorswim.20982/)
It does what we always want our indicators to do, it takes volume into consideration, adapts to market changes and gives labels for quick action.
VWMO Momentum + Compression Zones Indicator ā Explained for Traders
This indicator tracks where volume is flowing ā into up days or down days ā and combines that with volatility compression to identify high-probability setups before they move.
What It Measures:
What Makes It Unique:
How to Use It:
This tool may help determine the direction bollinger band squeezes. When bands are compressed watch for volume to be on the top half of the oscillator for a potential breakout. I am not familiar with any tools that currently do a good job predicting squeeze directions
In the following picture I actually took this trade when the dashed lines converged and the volume line stayed steady above it. Note it is the first time ive traded with it
mod note:
classified with Buy Sell Volume Pressure Indicators
(first one: https://usethinkscript.com/threads/eliteperformers-for-thinkorswim.20982/)
It does what we always want our indicators to do, it takes volume into consideration, adapts to market changes and gives labels for quick action.

This indicator tracks where volume is flowing ā into up days or down days ā and combines that with volatility compression to identify high-probability setups before they move.

- VWMO stands for Volume-Weighted Momentum Oscillator. It looks at recent volume and checks if more of it is coming in on up days vs down days.
- The line moves from 0 to 100:
- Above 50 = volume favoring up moves (bullish bias)
- Below 50 = volume favoring down moves (bearish bias)

- It doesnāt just look at price ā it tracks where the smart money is pushing volume.
- It adapts based on volatility:
- During a tight Bollinger Band squeeze, the indicator pulls the overbought/oversold zones closer to center, helping you catch early reversals before they run.

- VWMO > upper red dashed band = possibly overbought, but if the trend is up, it could mean strength continuation.
- VWMO < lower green dashed band = possibly oversold, but if price is holding, could be absorption or reversal brewing.
- Watch for "Squeeze Bias" labels ā when price is compressed and volume starts leaning one way, the spring is coiling.
- The dynamic labelsgive real-time context:
- āMomentum Upā = trending and strong.
- āOverbought Exhaustionā or āCapitulation Riskā = fading moves.
- āAbsorption Zoneā = price holding while volume recovers (bullish potential).
- āEarly Bull Reversalā = first uptick from deep oversold with rising slope.
- āBear Divergenceā = volume rising but price stalling ā risk of pullback.
This tool may help determine the direction bollinger band squeezes. When bands are compressed watch for volume to be on the top half of the oscillator for a potential breakout. I am not familiar with any tools that currently do a good job predicting squeeze directions
In the following picture I actually took this trade when the dashed lines converged and the volume line stayed steady above it. Note it is the first time ive traded with it

Code:
declare lower;
input length = 14;
input percentileLookback = 63; # VWMO percentile window
input volatilityLookback = 63; # BBW percentile window
input bbLength = 20;
input bbNumDev = 2.0;
# --- VWMO Core Calculation ---
def upVol = if close > close[1] then volume else 0;
def downVol = if close < close[1] then volume else 0;
def upVolSum = Sum(upVol, length);
def downVolSum = Sum(downVol, length);
def totalVol = upVolSum + downVolSum;
def VWMO = if totalVol != 0 then 100 * upVolSum / totalVol else 50;
plot VWMO_Line = VWMO;
VWMO_Line.SetDefaultColor(Color.CYAN);
# --- Percentile Approximation for VWMO ---
def maxVWMO = Highest(VWMO, percentileLookback);
def minVWMO = Lowest(VWMO, percentileLookback);
def rangeVWMO = maxVWMO - minVWMO;
def OB_raw = minVWMO + rangeVWMO * 0.75;
def OS_raw = minVWMO + rangeVWMO * 0.25;
# --- Bollinger Band Width for Volatility ---
def bbBasis = Average(close, bbLength);
def bbDev = StDev(close, bbLength);
def bbUpper = bbBasis + bbNumDev * bbDev;
def bbLower = bbBasis - bbNumDev * bbDev;
def BBW = (bbUpper - bbLower) / bbBasis;
def maxBBW = Highest(BBW, volatilityLookback);
def minBBW = Lowest(BBW, volatilityLookback);
def rangeBBW = maxBBW - minBBW;
def BBWPercentile = if rangeBBW != 0 then (BBW - minBBW) / rangeBBW else 0;
# --- Compression Logic ---
def compressionFactor = if BBWPercentile < 0.25 then (0.25 - BBWPercentile) / 0.25 else 0;
def OB_dynamic = OB_raw - (OB_raw - 50) * compressionFactor;
def OS_dynamic = OS_raw + (50 - OS_raw) * compressionFactor;
plot OB_Band = OB_dynamic;
OB_Band.SetDefaultColor(Color.RED);
OB_Band.SetStyle(Curve.SHORT_DASH);
plot OS_Band = OS_dynamic;
OS_Band.SetDefaultColor(Color.GREEN);
OS_Band.SetStyle(Curve.SHORT_DASH);
# --- Label Logic with Smart Absorption and Trend Filters ---
def overbought = maxVWMO;
def oversold = minVWMO;
def priceSlope = LinearRegressionSlope(close, 5);
def absorptionCondition = VWMO < oversold and (close > close[1] or priceSlope > 0);
AddLabel(yes,
if VWMO > overbought and priceSlope > 0 then
"VWMO: " + Round(VWMO, 1) + " | Momentum Up"
else if VWMO > overbought and priceSlope <= 0 then
"VWMO: " + Round(VWMO, 1) + " | Overbought Exhaustion"
else if VWMO < oversold and priceSlope < 0 then
"VWMO: " + Round(VWMO, 1) + " | Capitulation Risk"
else if absorptionCondition then
"VWMO: " + Round(VWMO, 1) + " | Absorption Zone"
else if VWMO > VWMO[1] and VWMO[1] < oversold and priceSlope >= 0 then
"VWMO: " + Round(VWMO, 1) + " | Early Bull Reversal"
else if VWMO < VWMO[1] and priceSlope > 0 then
"VWMO: " + Round(VWMO, 1) + " | Bear Divergence"
else if VWMO >= 45 and VWMO <= 55 then
"VWMO: " + Round(VWMO, 1) + " | Neutral Volume"
else
"VWMO: " + Round(VWMO, 1),
if VWMO > overbought and priceSlope > 0 then Color.GREEN
else if VWMO > overbought and priceSlope <= 0 then Color.RED
else if VWMO < oversold and priceSlope < 0 then Color.DARK_RED
else if absorptionCondition then Color.LIGHT_GREEN
else if VWMO > VWMO[1] and VWMO[1] < oversold and priceSlope >= 0 then Color.CYAN
else if VWMO < VWMO[1] and priceSlope > 0 then Color.ORANGE
else if VWMO >= 45 and VWMO <= 55 then Color.GRAY
else Color.WHITE
);
def isSqueezing = compressionFactor > 0;
AddLabel(isSqueezing and VWMO > 55, "Squeeze Bias: Bullish", Color.GREEN);
AddLabel(isSqueezing and VWMO < 45, "Squeeze Bias: Bearish", Color.RED);
classified with Buy Sell Volume Pressure Indicators
Last edited by a moderator: