Pine Script Negative Volume Index (NVI)

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

Subscribe now @ $99/month

What is the Negative Volume Index (NVI)?

The Negative Volume Index (NVI) is a cumulative momentum indicator that focuses on periods of decreasing volume. Developed by Paul Dysart and popularized by Norman Fosback, the underlying theory behind NVI is that "smart money" (institutional or well-informed investors) tends to operate on low-volume days, while "uninformed money" operates on high-volume days. Therefore, changes in price action on low-volume days are considered more significant than changes on high-volume days.

The NVI essentially tracks a cumulative sum that is adjusted only when volume decreases from the previous day. If volume decreases, the NVI is adjusted by the percentage change in price. If volume increases, the NVI remains unchanged. A rising NVI suggests smart money is accumulating an asset, even on low volume, which often precedes price increases. A falling NVI suggests smart money is distributing. NVI is primarily used to:

In Pine Script, NVI offers a distinctive way to analyze market sentiment by focusing on the less obvious, but often more telling, periods of trading activity.

Components and Calculation

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

  1. Initialize NVI: The starting value of NVI 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: `NVI = Previous NVI + (Previous NVI * ((Close - Previous Close) / Previous Close))` Essentially, `NVI = Previous NVI * (1 + Price Percentage Change)` * Handle `Previous Close == 0` to avoid division by zero.
    • If Current Volume > Previous Volume: `NVI = Previous NVI` (NVI remains unchanged)
    • If Current Volume == Previous Volume: `NVI = Previous NVI` (NVI remains unchanged)

NVI 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 Negative Volume Index (NVI) Implementation in Pine Script

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

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

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

// Calculate NVI using the built-in function
// ta.nvi() uses 'close' for price comparison and 'volume' for volume comparison
nviValue = ta.nvi(nviStartValue, close, volume)

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

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

// Plot the NVI Moving Average
plot(nviMA, title="NVI MA", color=color.orange, linewidth=1)
Smart Money Focus: NVI specifically tracks activity on low-volume days, believing that these are the days when informed investors subtly position themselves.

Practical NVI Trading Strategies

1. NVI and Moving Average Crossovers (Trend Confirmation)

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

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

nviStartValue = input.float(1000, title="NVI Start Value")
nviMALength = input.int(255, title="NVI MA Length", minval=1) // Long-term MA

nviValue = ta.nvi(nviStartValue, close, volume)
nviMA = ta.ema(nviValue, nviMALength)

plot(nviValue, "NVI", color.blue, display=display.pane_only)
plot(nviMA, "NVI MA", color.orange, display=display.pane_only)

// Long entry: NVI crosses above its MA
longCondition = ta.crossover(nviValue, nviMA)

// Short entry: NVI crosses below its MA
shortCondition = ta.crossunder(nviValue, nviMA)

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

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

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

2. NVI Divergence (Key Reversal Signal)

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

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

nviStartValue = input.float(1000, title="NVI Start Value")
nviValue = ta.nvi(nviStartValue, close, volume)
nviMALength = input.int(255, title="NVI MA Length", minval=1)
nviMA = ta.ema(nviValue, nviMALength)

plot(nviValue, "NVI", color.blue, display=display.pane_only)
plot(nviMA, "NVI 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 NVI.

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

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

// Plot shapes on the chart to indicate divergence
plotshape(bullishDiv, title="Bullish NVI Divergence", location=location.belowbar, color=color.green, style=shape.triangleup, size=size.small)
plotshape(bearishDiv, title="Bearish NVI 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. NVI as a Long-Term Trend Filter

Given NVI's focus on smart money and its typically long-term smoothing, it can act as an excellent filter for other trading strategies, especially for confirming bull or bear markets.

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

nviStartValue = input.float(1000, title="NVI Start Value")
nviMALength = input.int(255, title="NVI MA Length", minval=1) // Long-term MA filter

nviValue = ta.nvi(nviStartValue, close, volume)
nviMA = ta.ema(nviValue, nviMALength)

plot(nviValue, "NVI", color.blue, display=display.pane_only)
plot(nviMA, "NVI MA", color.orange, display=display.pane_only)

// Define NVI trend direction
isNviUptrend = nviValue > nviMA
isNviDowntrend = nviValue < nviMA

// 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, slowPriceMA) // Corrected: was slowPriceMALength

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

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

// Exit on opposite price MA crossover, regardless of NVI filter for simplicity
strategy.close("Filtered Long", when=ta.crossunder(fastPriceMA, slowPriceMA))
strategy.close("Filtered Short", when=ta.crossover(fastPriceMA, slowMA)) // Corrected: was slowPriceMA for long exit

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

Optimizing Negative Volume Index (NVI) Performance

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

Unmasking Smart Money: NVI offers a rare glimpse into the actions of potentially more informed investors, as it attributes greater significance to price changes that occur on quiet, low-volume days.

Common NVI Pitfalls

Conclusion

The Negative Volume Index (NVI) is a unique and insightful technical indicator available in Pine Script for TradingView. By specifically focusing on price movements on low-volume days, it attempts to track the activity of "smart money" and provide a distinct 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 NVI to enhance your pine script strategies and gain a clearer understanding of market conviction, particularly from the perspective of informed investors.

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