Pine Script Positive Volume Index (PVI)

Master this unique volume-based indicator in TradingView's Pine Script, designed to track "uninformed money" activity, particularly on high-volume days, to confirm trends and anticipate price movements.

Subscribe now @ $99/month

What is the Positive Volume Index (PVI)?

The Positive Volume Index (PVI) is a cumulative momentum indicator that focuses on periods of increasing volume. Developed by Paul Dysart and popularized by Norman Fosback, the underlying theory behind PVI is that "uninformed money" or the general public tends to be most active and influence price changes on high-volume days, reacting to news or trends. Therefore, changes in price action on high-volume days are considered significant.

The PVI essentially tracks a cumulative sum that is adjusted only when volume increases from the previous day. If volume increases, the PVI is adjusted by the percentage change in price. If volume decreases or stays the same, the PVI remains unchanged. A rising PVI suggests that public participation (high volume) is pushing the price higher, often confirming an uptrend. A falling PVI suggests public distribution. PVI is primarily used to:

In Pine Script, PVI offers a distinctive way to analyze market sentiment by focusing on periods of high trading activity, providing insight into the conviction of broader market participation.

Components and Calculation

The calculation of the Positive Volume Index is cumulative and depends on the relationship between current and previous volume:

  1. Initialize PVI: The starting value of PVI is usually set to 1000 (or some other arbitrary base value) to provide a convenient reference point.
  2. Conditional Update: For each period:
    • If Current Volume > Previous Volume: `PVI = Previous PVI + (Previous PVI * ((Close - Previous Close) / Previous Close))` Essentially, `PVI = Previous PVI * (1 + Price Percentage Change)` * Handle `Previous Close == 0` to avoid division by zero.
    • If Current Volume <= Previous Volume: `PVI = Previous PVI` (PVI remains unchanged)

PVI is often smoothed with an Exponential Moving Average (EMA) (e.g., 255-period EMA for annual trend) to reduce noise and identify its long-term trend.

Basic Positive Volume Index (PVI) Implementation in Pine Script

Pine Script v5 provides a built-in function `ta.pvi()` for calculating the Positive Volume Index.

//@version=5
indicator("My Positive Volume Index (PVI)", overlay=false) // overlay=false to plot in a separate pane

// Input for PVI starting value (arbitrary, but common to start at 1000)
pviStartValue = input.float(1000, title="PVI Start Value")

// Calculate PVI using the built-in function
// ta.pvi() uses 'close' for price comparison and 'volume' for volume comparison
pviValue = ta.pvi(pviStartValue, close, volume)

// Plot the PVI line
plot(pviValue, title="PVI", color=color.blue, linewidth=2)

// Optional: Add a Moving Average of PVI (often a long-term EMA) as a signal line
// A common length for the PVI MA is 255 (representing roughly a year of trading days)
pviMALength = input.int(255, title="PVI MA Length", minval=1)
pviMA = ta.ema(pviValue, pviMALength)

// Plot the PVI Moving Average
plot(pviMA, title="PVI MA", color=color.orange, linewidth=1)
Public Participation: PVI focuses on high-volume days, theorizing that these are driven by the broader, often less informed, public responding to market moves.

Practical PVI Trading Strategies

1. PVI and Moving Average Crossovers (Trend Confirmation)

The most common strategy with PVI involves comparing it to its own moving average (often a long-term EMA like a 255-period). This helps confirm the direction of the "public money" trend and potential market direction.

//@version=5
strategy("PVI Crossover Strategy", overlay=true)

pviStartValue = input.float(1000, title="PVI Start Value")
pviMALength = input.int(255, title="PVI MA Length", minval=1) // Long-term MA

pviValue = ta.pvi(pviStartValue, close, volume)
pviMA = ta.ema(pviValue, pviMALength)

plot(pviValue, "PVI", color.blue, display=display.pane_only)
plot(pviMA, "PVI MA", color.orange, display=display.pane_only)

// Long entry: PVI crosses above its MA
longCondition = ta.crossover(pviValue, pviMA)

// Short entry: PVI crosses below its MA
shortCondition = ta.crossunder(pviValue, pviMA)

if (longCondition)
    strategy.entry("Long PVI", strategy.long)

if (shortCondition)
    strategy.entry("Short PVI", strategy.short)

// Basic exit: opposite signal
strategy.close("Long PVI", when=shortCondition)
strategy.close("Short PVI", when=longCondition)

2. PVI Divergence (Key Reversal Signal)

Divergence between price and PVI can be a powerful signal, suggesting a weakening trend and potential reversal, as public money's actions are not confirming the current price trend.

//@version=5
strategy("PVI Divergence Strategy", overlay=true)

pviStartValue = input.float(1000, title="PVI Start Value")
pviValue = ta.pvi(pviStartValue, close, volume)
pviMALength = input.int(255, title="PVI MA Length", minval=1)
pviMA = ta.ema(pviValue, pviMALength)

plot(pviValue, "PVI", color.blue, display=display.pane_only)
plot(pviMA, "PVI MA", color.orange, display=display.pane_only)

// Simple divergence detection (conceptual, robust detection requires advanced pivot logic)
// This example looks for recent higher/lower swings in price and PVI.

// Bullish Divergence: Price lower low, PVI higher low
bullishDiv = close < close[1] and close[1] < close[2] and pviValue > pviValue[1] and pviValue[1] > pviValue[2]

// Bearish Divergence: Price higher high, PVI lower high
bearishDiv = close > close[1] and close[1] > close[2] and pviValue < pviValue[1] and pviValue[1] < pviValue[2]

// Plot shapes on the chart to indicate divergence
plotshape(bullishDiv, title="Bullish PVI Divergence", location=location.belowbar, color=color.green, style=shape.triangleup, size=size.small)
plotshape(bearishDiv, title="Bearish PVI Divergence", location=location.abovebar, color=color.red, style=shape.triangledown, size=size.small)

if (bullishDiv)
    strategy.entry("Long Divergence", strategy.long)
if (bearishDiv)
    strategy.entry("Short Divergence", strategy.short)

// Basic exit after a few bars or on opposite signal
strategy.exit("Long Divergence Exit", from_entry="Long Divergence", profit=close*0.02, loss=close*0.01)
strategy.exit("Short Divergence Exit", from_entry="Short Divergence", profit=close*0.02, loss=close*0.01)

3. PVI as a Long-Term Trend Filter (Opposite of NVI)

Given PVI's focus on public participation and its typically long-term smoothing, it can act as a filter for other trading strategies, particularly for confirming periods when the broader market is actively supporting a trend.

//@version=5
strategy("PVI Trend Filter Strategy", overlay=true)

pviStartValue = input.float(1000, title="PVI Start Value")
pviMALength = input.int(255, title="PVI MA Length", minval=1) // Long-term MA filter

pviValue = ta.pvi(pviStartValue, close, volume)
pviMA = ta.ema(pviValue, pviMALength)

plot(pviValue, "PVI", color.blue, display=display.pane_only)
plot(pviMA, "PVI MA", color.orange, display=display.pane_only)

// Define PVI trend direction
isPviUptrend = pviValue > pviMA
isPviDowntrend = pviValue < pviMA

// Example: Combine with a simple price EMA crossover strategy
fastPriceMALength = input.int(10, title="Fast Price MA Length", minval=1)
slowPriceMALength = input.int(20, title="Slow Price MA Length", minval=1)

fastPriceMA = ta.ema(close, fastPriceMALength)
slowPriceMA = ta.ema(close, slowPriceMALength)

longEntrySignal = ta.crossover(fastPriceMA, slowPriceMA)
shortEntrySignal = ta.crossunder(fastPriceMA, slowPriceMALength) // Typo in original: slowPriceMALength should be slowPriceMA

// Only take long entries if PVI confirms a bullish trend
if (longEntrySignal and isPviUptrend)
    strategy.entry("Filtered Long", strategy.long)

// Only take short entries if PVI confirms a bearish trend
if (shortEntrySignal and isPviDowntrend)
    strategy.entry("Filtered Short", strategy.short)

// Exit on opposite price MA crossover, regardless of PVI filter for simplicity
strategy.close("Filtered Long", when=ta.crossunder(fastPriceMA, slowPriceMA))
strategy.close("Filtered Short", when=ta.crossover(fastPriceMA, slowPriceMA))

// Optional: Color background based on PVI trend
bgcolor(isPviUptrend ? color.new(color.lime, 95) : na, title="PVI Bullish Bias")
bgcolor(isPviDowntrend ? color.new(color.maroon, 95) : na, title="PVI Bearish Bias")

Optimizing Positive Volume Index (PVI) Performance

To get the most from the Positive Volume Index in Pine Script:

Uninformed Money Insights: PVI helps you analyze how the broader market (often reacting to established trends or news) is influencing price, giving insight into public sentiment.

Common PVI Pitfalls

Conclusion

The Positive Volume Index (PVI) is a distinct and insightful technical indicator available in Pine Script for TradingView. By specifically focusing on price movements on high-volume days, it attempts to track the activity of the broader market participation ("uninformed money") and provide a unique perspective on underlying market sentiment. While its greatest strengths lie in confirming long-term trends and identifying powerful divergences with price (signaling potential trend reversals), it is most effective when smoothed with a moving average and integrated strategically with price action and other technical analysis tools. By understanding its calculation and thoughtfully utilizing its signals, you can leverage PVI to enhance your pine script strategies and gain a clearer understanding of market conviction, particularly from the perspective of widespread public activity.

Enhance Your Trading

Get a high-performance Pine Script analysis tool for actionable market insights, designed for traders on the move.

This strategy runs in live mode on TradingView, helping you identify potential opportunities.

Subscribe now @ $99/month