shared chart link: https://tos.mx/!J1JcPNpB MUST follow these instructions for loading shared links.
Hope you're enjoying your Memorial Day weekend! I'm incredibly excited to share my latest creation - an indicator that I believe will become the cornerstone of every serious trader's toolkit.
Think of this as assembling a council of expert advisors, each specializing in a different aspect of market psychology. Together, they reveal not just what a stock is doing, but why it's moving and whether that movement has staying power.
The Problem with Most Indicators
Most technical indicators are just different ways of slicing the same apple. They're all looking at price and volume through slightly different lenses, often telling you the same story multiple times. It's like having five people describe the same car accident - you get repetition, not clarity.
But there are actually six distinct market forces that drive price action, and most traders only look at 2-3 of them:
Here's where it gets interesting. Instead of trying to compare apples to oranges, I've normalized everything using Z-scores. This puts all our indicators on the same playing field - like translating different languages into a common tongue.
A Z-score tells us: "How unusual is this current reading compared to recent history?"
What Makes This Special
This indicator combines seven different market dimensions into one cohesive view:
Reading the Market's Mind
The stacked histogram shows you:
Why This Could Be Your Last Indicator
Because it doesn't just tell you what - it tells you why, how strong, and how sustainable. It's like having a team of specialists all weighing in on the same question: "Should I pay attention to this move?"
When all your advisors agree, you act with conviction. When they disagree, you wait for clarity. Simple as that.
This may very well be the evolution from looking at individual indicators to understanding market ecosystem dynamics.

Hope you're enjoying your Memorial Day weekend! I'm incredibly excited to share my latest creation - an indicator that I believe will become the cornerstone of every serious trader's toolkit.
Think of this as assembling a council of expert advisors, each specializing in a different aspect of market psychology. Together, they reveal not just what a stock is doing, but why it's moving and whether that movement has staying power.
The Problem with Most Indicators
Most technical indicators are just different ways of slicing the same apple. They're all looking at price and volume through slightly different lenses, often telling you the same story multiple times. It's like having five people describe the same car accident - you get repetition, not clarity.
But there are actually six distinct market forces that drive price action, and most traders only look at 2-3 of them:
- Momentum (Where is energy building?)
- Volatility (How much uncertainty exists?)
- Money Flows (Where is smart money positioning?)
- Volume (Who's participating?)
- Strength (How sustainable is this move?)
- Trend vs Chop (What regime are we in?)
Here's where it gets interesting. Instead of trying to compare apples to oranges, I've normalized everything using Z-scores. This puts all our indicators on the same playing field - like translating different languages into a common tongue.
A Z-score tells us: "How unusual is this current reading compared to recent history?"
- Z-Score of +2 = This is happening 2 standard deviations above normal (97.5th percentile)
- Z-Score of -2 = This is 2 standard deviations below normal (2.5th percentile)
- Z-Score near 0 = Nothing unusual happening
What Makes This Special
This indicator combines seven different market dimensions into one cohesive view:
- VWAP Distance Z - Price positioning relative to institutional levels
- Volume Z - Participation strength (adjusted for direction)
- OBV Z - Money flow momentum
- CMF Z - Chaikin Money Flow intensity
- RSI Z - Momentum oscillator extremes
- MACD Z - Trend momentum shifts
- Percentage Gain Z - Daily performance context
Reading the Market's Mind
The stacked histogram shows you:
- Height = Strength of conviction across all market forces
- Direction = Bullish vs bearish confluence
- Wave patterns = Sustainable trends vs unsustainable spikes
- Regime labels = Plain English translation of what's happening
Why This Could Be Your Last Indicator
Because it doesn't just tell you what - it tells you why, how strong, and how sustainable. It's like having a team of specialists all weighing in on the same question: "Should I pay attention to this move?"
When all your advisors agree, you act with conviction. When they disagree, you wait for clarity. Simple as that.
This may very well be the evolution from looking at individual indicators to understanding market ecosystem dynamics.
Code:
declare lower;
# === Inputs ===
input length = 14; # For RSI/CMF lookback
input zLength = 20; # For z-score normalization
input macdFastLen = 12;
input macdSlowLen = 26;
input macdSigLen = 9;
input emaLength = 9; # EMA window for the moving average
input upperExtreme = 7.5; # Threshold for highest bullish color
input upperModerate = 2.0; # Threshold for moderate bullish color
input lowerExtreme = -7.5; # Threshold for highest bearish color
input lowerModerate = -2.0; # Threshold for moderate bearish color
# === Wave Smoothing Parameters ===
input TripleSmoothing = yes; # Enable triple exponential smoothing
input SmoothingFactor = 3; # Smoothing factor (lower = smoother)
# === VWAP Distance Z ===
def vwap = (high + low + close) / 3;
def vwapDist = close - vwap;
def vwapMean = Average(vwapDist, zLength);
def vwapStdev = StDev(vwapDist, zLength);
def vwapZ = if vwapStdev != 0 then (vwapDist - vwapMean) / vwapStdev else 0;
# === Relative Volume Z ===
def volMean = Average(volume, zLength);
def volStdev = StDev(volume, zLength);
def volumeZ = if volStdev != 0 then (volume - volMean) / volStdev else 0;
def adjVolumeZ = if close < close[1] then -volumeZ else volumeZ;
# === OBV Z ===
def obv = TotalSum(
if close > close[1] then volume
else if close < close[1] then -volume
else 0
);
def obvChange = obv - obv[1];
def obvMean = Average(obvChange, zLength);
def obvStdev = StDev(obvChange, zLength);
def obvZ = if obvStdev != 0 then (obvChange - obvMean) / obvStdev else 0;
# === CMF Z ===
def mfMultiplier = if (high - low) == 0 then 0 else ((close - low) - (high - close)) / (high - low);
def mfVolume = mfMultiplier * volume;
def cmfRaw = if Sum(volume, length) == 0 then 0 else Sum(mfVolume, length) / Sum(volume, length);
def cmfMean = Average(cmfRaw, zLength);
def cmfStdev = StDev(cmfRaw, zLength);
def cmfZ = if cmfStdev != 0 then (cmfRaw - cmfMean) / cmfStdev else 0;
# === RSI Z ===
def rsi = RSI(length = length);
def rsiMean = Average(rsi, zLength);
def rsiStdev = StDev(rsi, zLength);
def rsiZ = if rsiStdev != 0 then (rsi - rsiMean) / rsiStdev else 0;
# === MACD Histogram Z ===
def macdValue = ExpAverage(close, macdFastLen) - ExpAverage(close, macdSlowLen);
def macdSignal = ExpAverage(macdValue, macdSigLen);
def macdHist = macdValue - macdSignal;
def macdMean = Average(macdHist, zLength);
def macdStdev = StDev(macdHist, zLength);
def macdZ = if macdStdev != 0 then (macdHist - macdMean) / macdStdev else 0;
# === Percentage Gain Z ===
def pctGain = (close - open) / open * 100;
def pctGainMean = Average(pctGain, zLength);
def pctGainStdev = StDev(pctGain, zLength);
def pctGainZ = if pctGainStdev != 0 then (pctGain - pctGainMean) / pctGainStdev else 0;
# === Triple Exponential Smoothing for Wave Effect ===
def vwapZSmooth = if TripleSmoothing then ExpAverage(ExpAverage(ExpAverage(vwapZ, SmoothingFactor), SmoothingFactor), SmoothingFactor) else vwapZ;
def adjVolumeZSmooth = if TripleSmoothing then ExpAverage(ExpAverage(ExpAverage(adjVolumeZ, SmoothingFactor), SmoothingFactor), SmoothingFactor) else adjVolumeZ;
def obvZSmooth = if TripleSmoothing then ExpAverage(ExpAverage(ExpAverage(obvZ, SmoothingFactor), SmoothingFactor), SmoothingFactor) else obvZ;
def cmfZSmooth = if TripleSmoothing then ExpAverage(ExpAverage(ExpAverage(cmfZ, SmoothingFactor), SmoothingFactor), SmoothingFactor) else cmfZ;
def rsiZSmooth = if TripleSmoothing then ExpAverage(ExpAverage(ExpAverage(rsiZ, SmoothingFactor), SmoothingFactor), SmoothingFactor) else rsiZ;
def macdZSmooth = if TripleSmoothing then ExpAverage(ExpAverage(ExpAverage(macdZ, SmoothingFactor), SmoothingFactor), SmoothingFactor) else macdZ;
def pctGainZSmooth = if TripleSmoothing then ExpAverage(ExpAverage(ExpAverage(pctGainZ, SmoothingFactor), SmoothingFactor), SmoothingFactor) else pctGainZ;
# === Wave-Like Stackable Histogram Bars ===
plot vwapStack = vwapZSmooth;
vwapStack.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
vwapStack.SetLineWeight(4);
vwapStack.AssignValueColor(Color.LIGHT_ORANGE);
plot volStack = vwapZSmooth + adjVolumeZSmooth;
volStack.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
volStack.SetLineWeight(4);
volStack.AssignValueColor(Color.MAGENTA);
plot obvStack = vwapZSmooth + adjVolumeZSmooth + obvZSmooth;
obvStack.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
obvStack.SetLineWeight(4);
obvStack.AssignValueColor(Color.YELLOW);
plot cmfStack = vwapZSmooth + adjVolumeZSmooth + obvZSmooth + cmfZSmooth;
cmfStack.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
cmfStack.SetLineWeight(4);
cmfStack.AssignValueColor(Color.LIGHT_GREEN);
plot rsiStack = vwapZSmooth + adjVolumeZSmooth + obvZSmooth + cmfZSmooth + rsiZSmooth;
rsiStack.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
rsiStack.SetLineWeight(4);
rsiStack.AssignValueColor(Color.CYAN);
plot macdStack = vwapZSmooth + adjVolumeZSmooth + obvZSmooth + cmfZSmooth + rsiZSmooth + macdZSmooth;
macdStack.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
macdStack.SetLineWeight(4);
macdStack.AssignValueColor(Color.VIOLET);
plot pctGainStack = vwapZSmooth + adjVolumeZSmooth + obvZSmooth + cmfZSmooth + rsiZSmooth + macdZSmooth + pctGainZSmooth;
pctGainStack.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
pctGainStack.SetLineWeight(4);
pctGainStack.AssignValueColor(Color.WHITE);
# === Threshold Lines ===
plot zeroLine = 0;
zeroLine.SetDefaultColor(Color.GRAY);
zeroLine.SetStyle(Curve.SHORT_DASH);
plot upperThresh = 1.5;
upperThresh.SetDefaultColor(Color.DARK_GRAY);
upperThresh.SetStyle(Curve.LONG_DASH);
plot lowerThresh = -1.5;
lowerThresh.SetDefaultColor(Color.DARK_GRAY);
lowerThresh.SetStyle(Curve.LONG_DASH);
# === Update sumZ calculation ===
def sumZ = vwapZSmooth + adjVolumeZSmooth + obvZSmooth + cmfZSmooth + rsiZSmooth + macdZSmooth + pctGainZSmooth;
# === EMA of sumZ ===
def sumZema = ExpAverage(sumZ, emaLength);
plot sumZemaPlot = sumZema;
sumZemaPlot.SetLineWeight(3);
sumZemaPlot.AssignValueColor(
if sumZema >= upperExtreme then Color.ORANGE
else if sumZema >= upperModerate then Color.GREEN
else if sumZema <= lowerExtreme then Color.CYAN
else if sumZema <= lowerModerate then Color.DARK_RED
else Color.LIGHT_GRAY
);
# === Keep your existing labels but use smoothed values ===
AddLabel(yes, "VWAP_Z: " + Round(vwapZSmooth, 2), Color.LIGHT_ORANGE);
AddLabel(yes, "VOL_Z: " + Round(adjVolumeZSmooth, 2), Color.MAGENTA);
AddLabel(yes, "OBV_Z: " + Round(obvZSmooth, 2), Color.YELLOW);
AddLabel(yes, "CMF_Z: " + Round(cmfZSmooth, 2), Color.LIGHT_GREEN);
AddLabel(yes, "RSI_Z: " + Round(rsiZSmooth, 2), Color.CYAN);
AddLabel(yes, "MACD_Z: " + Round(macdZSmooth, 2), Color.VIOLET);
AddLabel(yes, "PCT_GAIN_Z: " + Round(pctGainZSmooth, 2), Color.WHITE);
# === Z-Score of the Z-Scores (using smoothed values) ===
def sumZmean = Average(sumZ, zLength);
def sumZstdev = StDev(sumZ, zLength);
def sumZZ = if sumZstdev != 0 then (sumZ - sumZmean) / sumZstdev else 0;
AddLabel(yes, "sumZZ: " + Round(sumZZ, 2),
if sumZZ >= 2 then Color.ORANGE
else if sumZZ <= -2 then Color.CYAN
else Color.LIGHT_GRAY
);
# === Diagnostic Scenario Threshold Inputs ===
input cmfPos = 1.0;
input cmfNeg = -1.0;
input obvPos = 1.0;
input obvNeg = -1.0;
input volSpike = 2.0;
input volPos = 1.0;
input volNeg = -1.0;
input rsiPos = 2.0;
input rsiNeg = -2.0;
input macdPos = 1.5;
input macdNeg = -1.5;
input vwapStretch = 2.0;
input sumZZpos = 2.0;
input sumZZneg = -2.0;
input chop = 0.5;
# === Market Regime Classification ===
def regime =
if sumZZ > sumZZpos and cmfZ > cmfPos and obvZ > obvPos and adjVolumeZ > volPos and pctGainZ > 1.0 then 1
else if sumZZ < sumZZneg and cmfZ < cmfNeg and obvZ < obvNeg and pctGainZ < -1.0 then 2
else if vwapZ > vwapStretch and sumZZ > sumZZpos and pctGainZ > 1.5 then 3
else if vwapZ < -vwapStretch and sumZZ < sumZZneg and pctGainZ < -1.5 then 4
else if adjVolumeZ > volSpike and cmfZ < cmfPos/2 and obvZ < obvPos/2 and pctGainZ > 0 then 5
else if rsiZ > rsiPos and macdZ > macdPos and adjVolumeZ > volPos and pctGainZ > 1.0 then 6
else if obvZ > obvPos*1.5 and cmfZ > cmfPos and adjVolumeZ < volPos/2 and pctGainZ < 0.5 then 7
else if adjVolumeZ > volPos and obvZ < obvNeg and cmfZ < cmfNeg and pctGainZ > 0 then 8
else if adjVolumeZ > volPos and obvZ > obvPos and cmfZ > cmfPos and pctGainZ < 0 then 9
else if pctGainZ > 2.0 and sumZZ > sumZZpos and adjVolumeZ > volSpike then 10
else if pctGainZ < -2.0 and sumZZ < sumZZneg and adjVolumeZ > volSpike then 11
else 0;
# === Primary Market Regime Label ===
AddLabel(yes,
if regime == 1 then "BREAKOUT CONFIRMED"
else if regime == 2 then "BREAKDOWN CONFIRMED"
else if regime == 3 then "PARABOLIC MOVE"
else if regime == 4 then "CAPITULATION"
else if regime == 5 then "RETAIL FOMO"
else if regime == 6 then "MOMENTUM CLIMAX"
else if regime == 7 then "STEALTH ACCUMULATION"
else if regime == 8 then "BULL TRAP"
else if regime == 9 then "BEAR TRAP"
else if regime == 10 then "HELICOPTER MONEY"
else if regime == 11 then "FIRE SALE"
else if sumZZ > 1 then "UPTREND"
else if sumZZ < -1 then "DOWNTREND"
else "RANGE BOUND",
if sumZZ > sumZZpos then Color.ORANGE
else if sumZZ < sumZZneg then Color.CYAN
else Color.LIGHT_GRAY
);
# === Action Guidance Label ===
AddLabel(yes,
if regime == 1 then "All Systems Green"
else if regime == 2 then "Distribution Active"
else if regime == 3 then "Exit Zone"
else if regime == 4 then "Reversal Watch"
else if regime == 5 then "Fade Setup"
else if regime == 6 then "Blowoff Risk"
else if regime == 7 then "Smart Money Building"
else if regime == 8 then "Price Up, Flow Down"
else if regime == 9 then "Flow Up, Price Down"
else if regime == 10 then "Massive Bull Move"
else if regime == 11 then "Massive Bear Move"
else if sumZZ > 1 then "Trend Following"
else if sumZZ < -1 then "Trend Following"
else "Wait for Setup",
Color.LIGHT_GRAY
);
# === Trend Strength Label ===
AddLabel(yes,
if AbsValue(sumZZ) > 3 then "EXTREME"
else if AbsValue(sumZZ) > 2 then "STRONG"
else if AbsValue(sumZZ) > 1 then "MODERATE"
else if AbsValue(sumZZ) > 0.5 then "WEAK"
else "NEUTRAL",
if AbsValue(sumZZ) > 2 then Color.ORANGE
else if AbsValue(sumZZ) > 1 then Color.YELLOW
else Color.GRAY
);
# === Volume Participation Label ===
AddLabel(yes,
if adjVolumeZ > volSpike then "HIGH VOL"
else if adjVolumeZ > volPos then "ABOVE AVG VOL"
else if adjVolumeZ < volNeg then "LOW VOL"
else "NORMAL VOL",
if adjVolumeZ > volSpike then Color.MAGENTA
else if adjVolumeZ > volPos then Color.LIGHT_GRAY
else if adjVolumeZ < volNeg then Color.DARK_GRAY
else Color.GRAY
);
# Pseudo-code logic for ThinkScript (you'll need to implement using recursive variables)
def adaptiveMean = Average(sumZZ, zLength);
def adaptiveStdev = StDev(sumZZ, zLength);
def adaptiveUpper = adaptiveMean + adaptiveStdev;
def adaptiveLower = adaptiveMean - adaptiveStdev;
plot unusualExtreme = sumZZ > adaptiveUpper or sumZZ < adaptiveLower;
Last edited by a moderator: