Volume Price Confirmation Indicator: components and limits
The Volume Price Confirmation Indicator (VPCI) multiplies a long-window VWMA-minus-SMA difference by a short-window price ratio and a volume ratio. It describes how volume weights relate to price levels. It does not measure buying orders or establish a profitable entry rule.
VPCI = VPC × VPR × VM
The same closes, 10 → 12 → 14 → 16, give VPCI +1.3778, -0.6667 or 0 in the example below. Only the volume distribution changes.
What each factor measures
Buff Dormeier's presentation defines VPC, VPR and VM. Here, S and L mean short and long lookback lengths in bars, with S < L. Every price average uses close. VWMA(N) = Σ(close × volume, N) / Σ(volume, N).
| Factor | Calculation | Meaning and units |
|---|---|---|
| VPC | VWMA(close, L) - SMA(close, L) | A price-unit difference. Positive means heavier volume weights favor higher price levels within L bars. |
| VPR | VWMA(close, S) / SMA(close, S) | A dimensionless ratio. Above 1 amplifies the signed VPC; below 1 reduces its magnitude when prices are positive. |
| VM | SMA(volume, S) / SMA(volume, L) | A dimensionless ratio. Above 1 means recent average volume exceeds the longer average. |
With positive closes and positive volume totals, VPR and VM are positive. VPC therefore determines the sign. An increase in VM makes a negative VPC more negative; it does not turn that reading positive. VPC compares two averages, not the current close with its VWMA.
Smoothing is a separate choice. Dormeier's slides describe a VWMA of VPCI. The AIQ implementation also documents SMA variants. The script below labels its signal as an SMA and adds optional standard-deviation bands; neither is part of the three-factor definition.
Same prices, different volume: a four-bar example
These are hypothetical inputs, not a backtest. Read left to right from oldest to newest; S = 2 and L = 4. Price is in arbitrary price units and volume uses a consistent unit. Calculate at bar 4 using the last two bars for S and all four for L.
| Series | Bar 1 | Bar 2 | Bar 3 | Bar 4 |
|---|---|---|---|---|
| Close in every case | 10 | 12 | 14 | 16 |
| A: heavier at higher prices | 10 | 10 | 10 | 30 |
| B: heavier at lower prices | 30 | 10 | 10 | 10 |
| C: equal weights | 15 | 15 | 15 | 15 |
All cases have SMA(close, 4) = 13, SMA(close, 2) = 15 and average long volume = 15. In A, long VWMA = (100 + 120 + 140 + 480) / 60 = 14. Short VWMA = (140 + 480) / 40 = 15.5. Thus VPCI = (14 - 13) × (15.5 / 15) × (20 / 15) = 1.3778, rounded.
| Case | VWMA L | VWMA S | VPC | VPR | VM | VPCI |
|---|---|---|---|---|---|---|
| A | 14 | 15.5 | +1 | 1.0333 | 1.3333 | +1.3778 |
| B | 12 | 15 | -1 | 1 | 0.6667 | -0.6667 |
| C | 13 | 15 | 0 | 1 | 1 | 0 |
Prices rise in all three cases. B still has negative VPCI because the large volume weight belongs to the lowest price. C has zero VPCI despite the same advance: equal positive volumes make VWMA equal SMA. If every close is identical, VPC is also zero regardless of how valid volume is distributed.
Multiplying every volume by 100 leaves all three factors unchanged. Multiplying every price by 2 doubles VPC and VPCI while leaving VPR and VM unchanged. Raw VPCI therefore retains price units and is not a comparable percentage score across instruments with different price scales.
Data failures and misleading signals
- Missing volume is unknown, not zero. TradingView reports that some feeds supply no volume and others supply tick counts rather than traded quantity. Check the exact symbol, provider and timeframe before interpreting VM.
- One zero-volume bar contributes no VWMA weight but still counts in the price SMA. If the entire short window has zero volume, its VWMA is undefined even when the long window has positive volume. Both volume totals must be positive.
- A zero short price SMA makes VPR undefined. Negative prices also break the usual positive-factor sign interpretation. This example deliberately rejects any nonpositive close in the long window.
- A high-volume bar can dominate until it leaves the rolling window. The resulting change can reflect an old observation dropping out rather than new activity. Intraday session patterns and contract rolls can alter the volume comparison.
- A positive value, an SMA cross or a band touch does not specify an entry, exit or position size. Standard-deviation bands on VPCI are descriptive overlays, not calibrated reversal probabilities. With zero dispersion, a touch can occur without an unusual move.
TradingView's volume-feed explanation and chart-data documentation describe those input constraints. Different venues can supply different volume distributions. A consistent unit conversion cancels out mathematically; a change of feed, session or coverage need not.
Educational information, not investment advice. This calculation and script provide no evidence of future returns. To test a trading hypothesis, define the price condition, closed-bar timing, exits, sizing and costs, then evaluate it on data excluded from parameter selection.
Pine Script v6 with explicit data guards
Paste the complete indicator into TradingView's Pine Editor and add it to a standard candle chart. Settings expose the two lookbacks, SMA signal and bands. Inspect VPC, VPR, VM and the valid-window flag in the Data Window. The default 5/20 lengths are starting inputs, not a recommendation for a particular market.
//@version=6
indicator("VPCI component audit", overlay=false)
shortLength = input.int(5, "Short length", minval=1, maxval=500)
longLength = input.int(20, "Long length", minval=2, maxval=500)
maLength = input.int(8, "SMA signal length", minval=1, maxval=500)
bbLength = input.int(20, "Band length", minval=2, maxval=500)
bbMult = input.float(3.0, "Band standard deviations", minval=0.1)
showBands = input.bool(false, "Show bands")
if shortLength >= longLength
runtime.error("Short length must be less than long length.")
// Strict policy: positive closes, known nonnegative volume on every bar.
validBar = not na(close) and close > 0 and not na(volume) and volume >= 0
validCount = math.sum(validBar ? 1.0 : 0.0, longLength)
price = validBar ? close : 0.0
vol = validBar ? volume : 0.0
shortVol = math.sum(vol, shortLength)
longVol = math.sum(vol, longLength)
shortPrice = math.sum(price, shortLength) / shortLength
longPrice = math.sum(price, longLength) / longLength
shortWeighted = math.sum(price * vol, shortLength)
longWeighted = math.sum(price * vol, longLength)
ready = bar_index >= longLength - 1 and validCount == longLength and shortVol > 0 and longVol > 0 and shortPrice > 0
vpc = ready ? longWeighted / longVol - longPrice : na
vpr = ready ? (shortWeighted / shortVol) / shortPrice : na
vm = ready ? (shortVol / shortLength) / (longVol / longLength) : na
vpci = vpc * vpr * vm
// SMA and bands are optional overlays, not additional VPCI factors.
maReady = math.sum(ready ? 1.0 : 0.0, maLength) == maLength
bandReady = math.sum(ready ? 1.0 : 0.0, bbLength) == bbLength
signalSum = math.sum(nz(vpci), maLength)
bandSum = math.sum(nz(vpci), bbLength)
signal = maReady ? signalSum / maLength : na
basis = bandReady ? bandSum / bbLength : na
spread = bbMult * ta.stdev(vpci, bbLength)
upper = bandReady ? basis + spread : na
lower = bandReady ? basis - spread : na
upperBreach = bandReady and vpci >= upper
lowerBreach = bandReady and vpci <= lower
crossedUp = ta.crossover(vpci, signal)
confirmedCross = barstate.isconfirmed and ready and maReady and not na(signal[1]) and crossedUp
plot(vpci, "VPCI", color=color.blue, linewidth=2, style=plot.style_linebr)
plot(signal, "SMA signal (variant)", color=color.orange, style=plot.style_linebr)
hline(0, "Zero", color=color.gray)
plot(showBands ? upper : na, "Upper band", color=color.gray, style=plot.style_linebr)
plot(showBands ? lower : na, "Lower band", color=color.gray, style=plot.style_linebr)
plot(upperBreach or lowerBreach ? vpci : na, "Band touch or breach", color=color.purple, style=plot.style_cross)
plot(vpc, "VPC", display=display.data_window)
plot(vpr, "VPR", display=display.data_window)
plot(vm, "VM", display=display.data_window)
plot(ready ? 1 : 0, "Valid window (1=yes)", display=display.data_window)
alertcondition(confirmedCross, "VPCI above SMA on close", "VPCI crossed above its SMA on a closed bar. This is not a trade instruction.")Copy code
Invalid windows stay blank instead of silently substituting missing volume. The SMA requires consecutive valid VPCI values; bands require their own full window. With complete data and default inputs, raw VPCI first becomes available on bar 20, the SMA on bar 27 and bands on bar 39, counting the first loaded bar as 1.
The plotted values and band markers update during the open bar. The alert condition waits for barstate.isconfirmed and a valid previous signal value. Create an alert from that named condition in TradingView; copying the script does not create an active alert. A syntax check verifies code syntax, not the formula's profitability or the quality of the feed.
VPCI, VWMA and PVT answer different questions
VWMA is a rolling price average. VPCI uses its difference from an SMA plus two ratios. Price Volume Trend (PVT) instead accumulates volume times fractional price changes. PVT's running total depends on prior history; raw VPCI depends on its current long and short windows. A signal average adds another lookback.
Specify a custom VPCI rule in Pineify
The Pine Script AI Coding Agent can help draft or edit a script from a stated rule. Start with the component definitions and the missing-data policy above. Ask explicitly for a syntax check, then inspect the generated output on your intended TradingView feed. A generated script does not establish whether the feed is complete or the rule is profitable.
Use close-based VPCI with short length 5 and long length 20. Require known nonnegative volume, positive closes and positive volume totals. Expose VPC, VPR and VM in the Data Window. Keep the 8-bar SMA signal explicitly labeled as a variant. Add a closed-bar cross alert and check the final Pine Script syntax.Explore Pine Script AI Coding Agent
This opens the product overview. It does not import this script or start a backtest automatically.
VPCI questions
Sources and scope
Reviewed October 17, 2026. The numerical examples and strict-data policy are this page's demonstrations; the linked sources establish the indicator components and platform behavior.
- Buff Dormeier: VPCI components and smoothing, PDF slides 12 and 15
- AIQ: published close-based implementation and SMA smoothing variant
- TradingView: missing volume and tick-volume feeds
- TradingView: chart prices and volume units
- TradingView: barstate.isconfirmed
- TradingView: Price Volume Trend calculation