mod note:
Volume‑Validated Trend Color (VVTC) — How Traders Should Use It
VVTC identifies sustained trend conditions by requiring alignment between moving averages, slope, volume participation, momentum direction, and VWAP position. The study is designed to provide confirmation that a move has real participation behind it.
VVTC does not fire early and does not flip often; it waits for structure, volume, and momentum to agree before marking a trend. Once a trend is established, VVTC holds the state until an opposite trend is confirmed, which helps traders stay with strong moves and avoid reacting to drift. The colors show the strength of the active trend, while the arrows mark the moment a new trend is validated.
Trying something new. Please test it out. Need help since it's my very first custom indicator.
Volume‑Validated Trend Color (VVTC) — How Traders Should Use It
VVTC identifies sustained trend conditions by requiring alignment between moving averages, slope, volume participation, momentum direction, and VWAP position. The study is designed to provide confirmation that a move has real participation behind it.
VVTC does not fire early and does not flip often; it waits for structure, volume, and momentum to agree before marking a trend. Once a trend is established, VVTC holds the state until an opposite trend is confirmed, which helps traders stay with strong moves and avoid reacting to drift. The colors show the strength of the active trend, while the arrows mark the moment a new trend is validated.
Trying something new. Please test it out. Need help since it's my very first custom indicator.
| State | Requirements | What It Means |
|---|---|---|
| Bull | Price above both EMAs, EMAs aligned, slopes positive, volume above average, momentum positive, VWAP support | Trend is active and supported by participation |
| Bear | Price below both EMAs, EMAs aligned, slopes negative, volume above average, momentum negative, VWAP resistance | Trend is active and controlled by sellers |
| Hold | No opposite confirmation | Trend remains in effect until proven otherwise |
| Color | Condition | Use Case |
|---|---|---|
| Cyan / Magenta | Strong volume and strong momentum | Confirms trend continuation |
| Light Green / Bright Red | Strong volume | Confirms participation after a breakout |
| Green / Red | Significant volume | Confirms trend validity |
| Dark Green / Dark Red | Low volume | Trend intact but not expanding |
| Muted Tones | Candle against trend | Pullback inside an active trend |
| Gray | No trend | Standby until structure forms |
Code:
# ═══════════════════════════════════════════════════════════════════
# Volume-Validated Trend Color (VVTC) — 5-Minute Edition
# ═══════════════════════════════════════════════════════════════════
declare upper;
# ═══════════════════════════════════════════════════════════════════
# INPUTS
# ═══════════════════════════════════════════════════════════════════
input trendMaLen = 21;
input fastMaLen = 8;
input volLookback = 15;
input volMultiplier = 1.3;
input volStrongMult = 2.0;
input atrLen = 10;
input momentumLen = 5;
input showLabels = yes;
input useVwap = yes;
input strictMode = yes;
# ═══════════════════════════════════════════════════════════════════
# MOVING AVERAGES
# ═══════════════════════════════════════════════════════════════════
def trendMA = ExpAverage(close, trendMaLen);
def fastMA = ExpAverage(close, fastMaLen);
def trendSlope = trendMA - trendMA[2];
def fastSlope = fastMA - fastMA[1];
# ═══════════════════════════════════════════════════════════════════
# VWAP — using built-in to avoid recursive def issues
# ═══════════════════════════════════════════════════════════════════
def isNewDay = GetDay() != GetDay()[1];
def cumVolPrice = if isNewDay then close * volume
else cumVolPrice[1] + close * volume;
def cumVol = if isNewDay then volume
else cumVol[1] + volume;
def vwapLine = if !useVwap then close
else if cumVol > 0 then cumVolPrice / cumVol
else close;
def aboveVwap = close > vwapLine;
def belowVwap = close < vwapLine;
# ═══════════════════════════════════════════════════════════════════
# VOLUME
# ═══════════════════════════════════════════════════════════════════
def avgVol = Average(volume, volLookback);
def volRatio = if avgVol != 0 then volume / avgVol else 1;
def isSigVol = volRatio >= volMultiplier;
def isStrongVol = volRatio >= volStrongMult;
def isNormalVol = volRatio >= 1.0;
def recentSigVol = isSigVol or isSigVol[1] or isSigVol[2];
def recentStrongVol = isStrongVol or isStrongVol[1] or isStrongVol[2];
# ═══════════════════════════════════════════════════════════════════
# MOMENTUM
# ═══════════════════════════════════════════════════════════════════
def atrVal = ATR(atrLen);
def safeATR = if atrVal > 0 then atrVal else 0.0001;
def momentum = close - close[momentumLen];
def momStrength = AbsValue(momentum) / safeATR;
def strongMom = momStrength > 1.2;
def weakMom = momStrength < 0.4;
def bullMom = momentum > 0;
def bearMom = momentum < 0;
# ═══════════════════════════════════════════════════════════════════
# CANDLE BODY
# ═══════════════════════════════════════════════════════════════════
def bullCandle = close > open;
def bearCandle = close < open;
def candleRange = high - low;
def bodySize = AbsValue(close - open);
def bodyRatio = if candleRange != 0 then bodySize / candleRange else 0;
def strongCandle = bodyRatio > 0.5;
# ═══════════════════════════════════════════════════════════════════
# TREND CONDITIONS
# Price must be on correct side of both MAs,
# MAs must be aligned, slopes must agree,
# and VWAP must confirm (if enabled)
# ═══════════════════════════════════════════════════════════════════
def priceAboveBoth = close > trendMA and close > fastMA;
def priceBelowBoth = close < trendMA and close < fastMA;
def masAlignedBull = fastMA > trendMA;
def masAlignedBear = fastMA < trendMA;
def slopesBull = trendSlope > 0 and fastSlope > 0;
def slopesBear = trendSlope < 0 and fastSlope < 0;
def vwapBull = if useVwap then aboveVwap else 1;
def vwapBear = if useVwap then belowVwap else 1;
def rawBull = priceAboveBoth and masAlignedBull and slopesBull and vwapBull;
def rawBear = priceBelowBoth and masAlignedBear and slopesBear and vwapBear;
# ═══════════════════════════════════════════════════════════════════
# VOLUME VALIDATED TREND
# ═══════════════════════════════════════════════════════════════════
def volConfirmedBull = rawBull and recentSigVol and !weakMom and bullMom;
def volConfirmedBear = rawBear and recentSigVol and !weakMom and bearMom;
# ═══════════════════════════════════════════════════════════════════
# TREND STATE — persistent, sticky
# ═══════════════════════════════════════════════════════════════════
def trendState =
if volConfirmedBull then 1
else if volConfirmedBear then -1
else trendState[1];
def inBull = trendState == 1;
def inBear = trendState == -1;
def inNeutral = trendState == 0;
def newBullTrend = inBull and trendState[1] != 1;
def newBearTrend = inBear and trendState[1] != -1;
# ═══════════════════════════════════════════════════════════════════
# STRICT MODE — candle direction must agree with trend
# ═══════════════════════════════════════════════════════════════════
def candleAgrees = (inBull and bullCandle) or (inBear and bearCandle);
def candleOpposes = (inBull and bearCandle) or (inBear and bullCandle);
def showFull = if strictMode then candleAgrees else 1;
def showDim = if strictMode then candleOpposes else 0;
# ═══════════════════════════════════════════════════════════════════
# CANDLE COLOR
# ═══════════════════════════════════════════════════════════════════
AssignPriceColor(
if inBull and showFull and recentStrongVol and strongMom
then CreateColor(0, 255, 255) # Cyan - max bull
else if inBull and showFull and recentStrongVol
then CreateColor(0, 230, 130) # Light green - strong vol
else if inBull and showFull and recentSigVol
then CreateColor(0, 190, 90) # Green - sig vol
else if inBull and showFull
then CreateColor(0, 140, 55) # Dark green - low vol
else if inBull and showDim
then CreateColor(40, 80, 60) # Muted - pullback in uptrend
else if inBear and showFull and recentStrongVol and strongMom
then CreateColor(255, 0, 255) # Magenta - max bear
else if inBear and showFull and recentStrongVol
then CreateColor(230, 0, 80) # Bright red - strong vol
else if inBear and showFull and recentSigVol
then CreateColor(190, 0, 55) # Red - sig vol
else if inBear and showFull
then CreateColor(140, 0, 35) # Dark red - low vol
else if inBear and showDim
then CreateColor(80, 40, 50) # Muted - bounce in downtrend
else CreateColor(100, 100, 100) # Gray - no trend
);
# ═══════════════════════════════════════════════════════════════════
# MA + VWAP PLOTS
# ═══════════════════════════════════════════════════════════════════
plot TrendMAPlot = trendMA;
TrendMAPlot.SetLineWeight(2);
TrendMAPlot.AssignValueColor(
if inBull then CreateColor(0, 200, 100)
else if inBear then CreateColor(200, 0, 60)
else Color.GRAY
);
plot FastMAPlot = fastMA;
FastMAPlot.SetLineWeight(1);
FastMAPlot.SetStyle(Curve.SHORT_DASH);
FastMAPlot.AssignValueColor(
if inBull then CreateColor(0, 255, 150)
else if inBear then CreateColor(255, 80, 80)
else Color.DARK_GRAY
);
plot VwapPlot = if useVwap then vwapLine else Double.NaN;
VwapPlot.SetDefaultColor(CreateColor(255, 200, 0));
VwapPlot.SetLineWeight(2);
# ═══════════════════════════════════════════════════════════════════
# EMA CLOUD
# ═══════════════════════════════════════════════════════════════════
AddCloud(
if inBull then fastMA else Double.NaN,
if inBull then trendMA else Double.NaN,
CreateColor(0, 50, 25), CreateColor(0, 50, 25)
);
AddCloud(
if inBear then fastMA else Double.NaN,
if inBear then trendMA else Double.NaN,
CreateColor(50, 0, 15), CreateColor(50, 0, 15)
);
# ═══════════════════════════════════════════════════════════════════
# TREND CHANGE ARROWS
# ═══════════════════════════════════════════════════════════════════
plot BullArrow = if newBullTrend then low else Double.NaN;
BullArrow.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
BullArrow.SetDefaultColor(CreateColor(0, 255, 255));
BullArrow.SetLineWeight(4);
plot BearArrow = if newBearTrend then high else Double.NaN;
BearArrow.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
BearArrow.SetDefaultColor(CreateColor(255, 0, 255));
BearArrow.SetLineWeight(4);
# ═══════════════════════════════════════════════════════════════════
# LABELS
# ═══════════════════════════════════════════════════════════════════
AddLabel(showLabels,
"Trend: " + (if inBull then "BULL" else if inBear then "BEAR" else "NEUTRAL"),
if inBull then CreateColor(0, 230, 100)
else if inBear then CreateColor(230, 0, 60)
else Color.GRAY
);
AddLabel(showLabels,
"Vol: " + Round(volRatio, 1) + "x " +
(if isStrongVol then "STRONG" else if isSigVol then "SIG" else "WEAK"),
if isStrongVol then CreateColor(0, 255, 255)
else if isSigVol then CreateColor(0, 200, 100)
else Color.GRAY
);
AddLabel(showLabels and useVwap,
"VWAP: " + (if aboveVwap then "ABOVE" else "BELOW"),
if aboveVwap then CreateColor(0, 200, 100)
else CreateColor(200, 0, 60)
);
AddLabel(showLabels,
"Mom: " + Round(momStrength, 2) +
(if strongMom then " STRONG" else if weakMom then " WEAK" else " MOD"),
if strongMom then CreateColor(0, 230, 120)
else if weakMom then Color.GRAY
else Color.WHITE
);
Last edited by a moderator: