8.3 KiB
PVD: Price Volume Divergence
When price and volume disagree, one of them is lying.
| Property | Value |
|---|---|
| Category | Volume |
| Inputs | OHLCV bar (TBar) |
| Parameters | pricePeriod (default 14), volumePeriod (default 14), smoothingPeriod (default 3) |
| Outputs | Single series (Pvd) |
| Output range | Unbounded |
| Warmup | 1 bar |
| PineScript | pvd.pine |
- Price Volume Divergence (PVD) quantifies the disagreement between price momentum and volume momentum.
- Similar: PVI, NVI | Complementary: Volume | Trading note: Price-Volume Divergence; measures disagreement between price and volume trends.
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
Price Volume Divergence (PVD) quantifies the disagreement between price momentum and volume momentum. The indicator identifies situations where price movement lacks volume confirmation—a classic warning signal that the current trend may be weakening or about to reverse.
Historical Context
The relationship between price and volume has been a cornerstone of technical analysis since Charles Dow first articulated his theories in the late 1800s. The core principle: volume should confirm price movements. Rising prices on rising volume suggest strong conviction; rising prices on declining volume suggest weak hands.
PVD formalizes this intuition into a measurable oscillator. Unlike simple volume overlays or static divergence rules, PVD produces a continuous signal that can be smoothed and compared across different timeframes. The indicator combines Rate of Change (ROC) calculations for both price and volume, then measures the magnitude of their disagreement.
This implementation follows the design principles established in the QuanTAlib PineScript reference, with optimizations for streaming calculation and bar correction support.
Architecture & Physics
1. Rate of Change Calculation
Both price and volume momentum are measured using percentage Rate of Change:
ROC_{price,t} = \frac{C_t - C_{t-p}}{C_{t-p}} \times 100
ROC_{volume,t} = \frac{V_t - V_{t-v}}{V_{t-v}} \times 100
where:
C_t= Close price at timetV_t= Volume at timetp= Price lookback periodv= Volume lookback period
2. Momentum Sign Extraction
The direction of momentum is captured as a sign function:
M_{price} = \text{sign}(ROC_{price}) = \begin{cases}
+1 & \text{if } ROC_{price} > 0 \\
-1 & \text{if } ROC_{price} < 0 \\
0 & \text{if } ROC_{price} = 0
\end{cases}
M_{volume} = \text{sign}(ROC_{volume}) = \begin{cases}
+1 & \text{if } ROC_{volume} > 0 \\
-1 & \text{if } ROC_{volume} < 0 \\
0 & \text{if } ROC_{volume} = 0
\end{cases}
3. Divergence Calculation
The raw divergence combines direction disagreement with magnitude:
\text{Magnitude}_t = |ROC_{price,t}| + |ROC_{volume,t}|
D_{raw,t} = M_{price} \times (-M_{volume}) \times \text{Magnitude}_t
The negation of M_{volume} means:
- Positive PVD: Price and volume moving in opposite directions (divergence)
- Negative PVD: Price and volume moving in same direction (confirmation)
- Zero PVD: No momentum in price or volume
4. Smoothing Filter
Raw divergence is smoothed using a Simple Moving Average:
PVD_t = \frac{1}{s} \sum_{i=0}^{s-1} D_{raw,t-i}
where s = smoothing period.
Mathematical Foundation
Divergence Interpretation
| Price | Volume | M_p \times (-M_v) |
PVD Sign | Interpretation |
|---|---|---|---|---|
| ↑ | ↓ | +1 × +1 = +1 | Positive | Bearish divergence (price up on declining volume) |
| ↓ | ↑ | -1 × -1 = +1 | Positive | Bullish divergence (price down on rising volume) |
| ↑ | ↑ | +1 × -1 = -1 | Negative | Bullish confirmation |
| ↓ | ↓ | -1 × +1 = -1 | Negative | Bearish confirmation |
| — | — | 0 | Zero | No momentum |
Magnitude Weighting
The magnitude term ensures that small price/volume changes produce small PVD values, while large movements produce large signals. This prevents noise from creating false divergence signals when both price and volume are essentially flat.
Parameter Relationships
- pricePeriod: Lookback for price momentum (default: 14)
- volumePeriod: Lookback for volume momentum (default: 14)
- smoothingPeriod: SMA window for noise reduction (default: 3)
Asymmetric periods (different pricePeriod and volumePeriod) can be useful when price and volume have different characteristic timescales.
Performance Profile
Operation Count (Streaming Mode, Scalar)
| Operation | Count | Cost (cycles) | Subtotal |
|---|---|---|---|
| SUB | 4 | 1 | 4 |
| DIV | 2 | 15 | 30 |
| MUL | 3 | 3 | 9 |
| ABS | 2 | 1 | 2 |
| CMP | 4 | 1 | 4 |
| ADD (SMA sum) | s | 1 | s |
| DIV (SMA) | 1 | 15 | 15 |
| Total | — | — | ~64 + s cycles |
For default smoothingPeriod=3: ~67 cycles per bar.
Batch Mode (512 values, SIMD potential)
The ROC and magnitude calculations are SIMD-friendly. However, the sign extraction and multiplication introduce branching that limits vectorization benefits. The SMA smoothing pass is straightforward to vectorize.
| Mode | Cycles/bar | Total (512 bars) |
|---|---|---|
| Scalar streaming | ~67 | ~34,304 |
| Partial SIMD | ~45 | ~23,040 |
| Improvement | 33% | — |
Memory Footprint
| Component | Size |
|---|---|
| State record struct | 40 bytes |
| Price RingBuffer | (pricePeriod + 1) × 8 bytes |
| Volume RingBuffer | (volumePeriod + 1) × 8 bytes |
| Divergence RingBuffer | smoothingPeriod × 8 bytes |
| Total (default params) | ~320 bytes |
Quality Metrics
| Metric | Score | Notes |
|---|---|---|
| Accuracy | 9/10 | Direct ROC calculation, minimal approximation |
| Timeliness | 7/10 | SMA smoothing adds lag proportional to period |
| Overshoot | 8/10 | Magnitude weighting prevents wild swings |
| Smoothness | 7/10 | Configurable via smoothingPeriod |
| Interpretability | 9/10 | Clear positive/negative divergence meaning |
Validation
| Library | Status | Notes |
|---|---|---|
| TA-Lib | N/A | Not implemented |
| Skender | N/A | Not implemented |
| Tulip | N/A | Not implemented |
| Ooples | N/A | Not implemented |
| Self-consistency | ✅ | Streaming == Batch == Span |
| Math verification | ✅ | Manual calculation tests pass |
PVD is a custom indicator not found in standard technical analysis libraries. Validation is performed through:
- Self-consistency across all calculation modes
- Manual calculation verification with known inputs
- Edge case testing (zero volume, constant prices, etc.)
Common Pitfalls
-
Warmup Period: PVD requires
max(pricePeriod, volumePeriod) + smoothingPeriodbars before producing meaningful values. During warmup, the indicator returns zero. -
Interpretation Confusion: Positive PVD means divergence (price/volume disagreement), not necessarily bullish. A positive PVD with rising prices suggests bearish divergence (weak rally).
-
Smoothing Trade-off: Higher smoothingPeriod reduces noise but increases lag. For short-term trading, use smoothingPeriod=1-2. For position trading, 5-10 may be appropriate.
-
Zero Volume Handling: Zero volume produces zero volume ROC, which yields zero divergence. Markets with frequent zero-volume bars may produce misleading flat periods.
-
Asymmetric Periods: Using different pricePeriod and volumePeriod changes the warmup calculation. The effective warmup is
max(pricePeriod, volumePeriod) + smoothingPeriod. -
Bar Correction (isNew=false): When correcting a bar, internal state rolls back to the previous bar's state. Multiple corrections in sequence are supported but each uses the same rollback point.
References
- Dow, C. (1900-1902). Wall Street Journal editorials on price-volume relationships.
- Murphy, J. J. (1999). Technical Analysis of the Financial Markets. New York Institute of Finance.
- Achelis, S. B. (2001). Technical Analysis from A to Z. McGraw-Hill.