This script analyzes the market by comparing price movement with volume changes.
It identifies different market conditions like confirming trends, exhaustion (divergence), and absorption (large buyers or sellers), and visually marks those conditions with labels on the chart.
It adds labels to the chart to indicate the detected market conditions:
PNVI is a modified version of the
Price-Volume Trend (PVT) indicator, which combines price changes and volume data to give an indication of price movement relative to volume.
PNVI can be interpreted as a momentum indicator based on volume and price direction. The higher the PNVI, the more bullish the market, and the lower the PNVI, the more bearish the market.
The PEMA line is the average; essentially a smoothed version of PNVI, helping to reduce noise and make trends easier to spot.
AddLabel(PNVI crosses PEMA, "Absorption / Possible Reversal", Color.PLUM);
AddLabel(PNVI > PEMA and PNVI > PNVI[1], "Confirmed Uptrend", Color.BLUE);
AddLabel(PNVI < PEMA and PNVI < PNVI[1], "Potential Exhaustion", Color.ORANGE);
AddLabel(PNVI > PEMA and PNVI > PNVI[1], "Bullish Momentum", Color.GREEN);
AddLabel(PNVI < PEMA and PNVI < PNVI[1], "Bearish Momentum", Color.RED);
The lowest chart is without labels and the addition of combining a ROC price action and volume indicators.
Code:
# PNVI is a modified version of the Price-Volume Trend (PVT) indicator
# @antwerks 2/2/2025
declare lower;
input ma_length = 15;
def xROC = (close - close[1]) * 100 / close;
def nRes1 = if (volume < volume[1]) then nRes1[1] + xROC else nRes1[1];
def nRes2 = if (volume > volume[1]) then nRes2[1] + xROC else nRes2[1];
def nRes3 = nRes1 + nRes2;
def nResEMA3 = simpleMovingAvg(nRes1, ma_length) + simpleMovingAvg(nRes2, ma_length);
plot PNVI = nRes3;
plot PEMA = nResEMA3;
PNVI.SetDefaultColor(GetColor(1));
PNVI.DefineColor("Up Momentum", Color.BLUE);
PNVI.AssignValueColor(PNVI.color("Up Momentum"));
PEMA.SetDefaultColor(GetColor(1));
PEMA.DefineColor("Down Momentum", Color.RED);
PEMA.AssignValueColor(PEMA.color("Down Momentum"));
AddCloud(PNVI, PEMA, PNVI.color("Up Momentum"), PEMA.color("Down Momentum"));
# Define Trend Labels
# Define Trend Labels with Else Statements
AddLabel(PNVI crosses PEMA, "Absorption / Possible Reversal", Color.PLUM);
AddLabel(PNVI > PEMA and PNVI > PNVI[1], "Confirmed Uptrend", Color.BLUE);
AddLabel(PNVI < PEMA and PNVI < PNVI[1], "Potential Exhaustion", Color.ORANGE);
AddLabel(PNVI > PEMA and PNVI > PNVI[1], "Bullish Momentum", Color.GREEN);
AddLabel(PNVI < PEMA and PNVI < PNVI[1], "Bearish Momentum", Color.RED);
# Background Coloring
input paintCandles = yes ;
AssignPriceColor(
if !paintCandles then color.current else
if PNVI > PEMA then Color.GREEN else Color.RED);
Below is the script for the lowest chart is without labels and the addition of combining a ROC price action and volume indicators.
Code:
declare lower;
### INPUTS ###
input ma_length = 15;
input cvd_length = 15;
### PRICE RATE OF CHANGE ###
def xROC = (close - close[1]) * 100 / close;
### VOLUME RIBBON LOGIC ###
def nRes1 = if (volume < volume[1]) then nRes1[1] + xROC else nRes1[1];
def nRes2 = if (volume > volume[1]) then nRes2[1] + xROC else nRes2[1];
def nRes3 = nRes1 + nRes2;
def nResEMA3 = simpleMovingAvg(nRes1, ma_length) + simpleMovingAvg(nRes2, ma_length);
### CVD LOGIC ###
def buyVolume = if close > close[1] then volume else 0;
def sellVolume = if close < close[1] then volume else 0;
def CVD = CompoundValue(1, CVD[1] + buyVolume - sellVolume, 0);
def CVD_MA = Average(CVD, cvd_length);
### PLOTS ###
plot PNVI = nRes3;
plot PEMA = nResEMA3;
plot CVD_Plot = CVD;
plot CVD_MA_Plot = CVD_MA;
### COLOR CHANGES ###
PNVI.SetDefaultColor(GetColor(1));
PNVI.AssignValueColor(if PNVI > PEMA then Color.BLUE else Color.RED);
PEMA.SetDefaultColor(GetColor(7));
CVD_Plot.SetDefaultColor(GetColor(3));
CVD_Plot.AssignValueColor(if CVD > CVD_MA then Color.GREEN else Color.RED);
CVD_MA_Plot.SetDefaultColor(GetColor(5));
### CLOUDS & CROSS ALERTS ###
AddCloud(PNVI, PEMA, Color.BLUE, Color.RED);
AddCloud(CVD_Plot, CVD_MA_Plot, Color.GREEN, Color.RED);
Alert(CVD_Plot crosses above CVD_MA_Plot, "CVD Bullish Reversal!", Alert.BAR, Sound.Ring);
Alert(CVD_Plot crosses below CVD_MA_Plot, "CVD Bearish Reversal!", Alert.BAR, Sound.Bell);