The original taxonomy was four classical families plus a statistics group, with the F1-F12 expansion slotted in as sub-categories. This regroups the whole 71-indicator catalogue into eight top-level families, each with at least five members: Moving Averages (12), Momentum Oscillators (13), Trend & Directional (9), Price Oscillators (5), Volatility & Bands (12), Trailing Stops (5), Volume (9), Price Statistics (7). - Wiki: docs/wiki/indicators/ reorganised into eight family folders; all 71 indicator pages moved with `git mv`. Every internal cross-link is normalised to `../<family>/Indicator-X.md`, each page's `Family` field is set to its new family, and two pre-existing `../Indicator-Chaining.md` links (should have been `../../`) are corrected. A link check confirms every relative wiki link resolves. - Indicators-Overview.md fully rewritten around the eight families; Home.md indicator reference and the README family table follow suit. - Warmup-Periods.md gains the eight F13 indicators; CHANGELOG records the 46-indicator expansion (25 -> 71) and the eight-family taxonomy. - Tests: Node indicators.test.js and Python test_new_indicators.py cover all eight new indicators (Node 91/91, Python 117/117 green). cargo fmt + clippy (core/wickra/data/wasm/node) clean; 508 core tests, 25 data tests and 74 doctests green.
4.7 KiB
VolumePriceTrend
Volume-Price Trend (VPT) — a cumulative volume line where each bar's contribution is scaled by its percentage price change.
Quick reference
| Field | Value |
|---|---|
| Family | Volume |
| Input type | Candle (uses close, volume) |
| Output type | f64 |
| Output range | unbounded (drifts with cumulative volume) |
| Default parameters | none (no parameters) |
| Warmup period | 1 |
| Interpretation | Running volume flow; slope and divergence matter. |
Formula
VPT_t = VPT_{t−1} + volume_t · (close_t − close_{t−1}) / close_{t−1}
VPT is a close relative of Obv. Where OBV adds the
entire bar volume on any up-close, VPT adds volume scaled by the size
of the move: a 2 % gain on a given volume moves the line twice as far as a
1 % gain on the same volume. That makes VPT more sensitive to the
conviction behind a move. The first bar establishes the baseline at 0.
Parameters
VolumePriceTrend takes no parameters — VolumePriceTrend::new() in
Rust, wickra.VolumePriceTrend() in Python, new ta.VolumePriceTrend()
in Node.
Inputs / Outputs
From crates/wickra-core/src/indicators/vpt.rs:
impl Indicator for VolumePriceTrend {
type Input = Candle;
type Output = f64;
// update(&mut self, input: Candle) -> Option<f64>
}
VolumePriceTrend is a candle-input indicator: it reads close and
volume. In Python the streaming update accepts a 6-tuple or a dict;
the batch helper takes close and volume numpy arrays. Node and WASM
expose update(close, volume) and batch(close, volume).
Warmup
warmup_period() == 1. VPT is cumulative — it emits the baseline 0 from
the first candle, then accumulates from the second onward.
Edge cases
- Constant close. With no price change every bar contributes
0, so the line stays flat regardless of volume (constant_close_keeps_line_flatpins this). - First bar. The first candle has no previous close; VPT emits the
baseline
0.0(emits_from_first_candle_at_zeropins this). - Zero previous close. A percentage change against a
0.0prior close is undefined and is treated as0. - Candle validation.
Candle::newrejects invalid bars upstream. - Reset.
vpt.reset()returns the running total to0.
Examples
Rust
use wickra::{BatchExt, Candle, Indicator, VolumePriceTrend};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut vpt = VolumePriceTrend::new();
// closes 10 -> 11 -> 9, volumes 100, 200, 300.
let out = vpt.batch(&[
Candle::new(10.0, 10.0, 10.0, 10.0, 100.0, 0)?,
Candle::new(11.0, 11.0, 11.0, 11.0, 200.0, 1)?,
Candle::new(9.0, 9.0, 9.0, 9.0, 300.0, 2)?,
]);
println!("{:?}", out);
Ok(())
}
Output:
[Some(0.0), Some(20.0), Some(-34.54545454545455)]
Bar 1 is the baseline 0. Bar 2 adds 200 · (11−10)/10 = 20. Bar 3 adds
300 · (9−11)/11 = −600/11, leaving 20 − 600/11 ≈ −34.545. This matches
the reference_values test in crates/wickra-core/src/indicators/vpt.rs.
Python
import numpy as np
import wickra as ta
vpt = ta.VolumePriceTrend()
close = np.array([10.0, 11.0, 9.0])
volume = np.array([100.0, 200.0, 300.0])
print(vpt.batch(close, volume))
Output:
[ 0. 20. -34.54545455]
Node
const ta = require('wickra');
const vpt = new ta.VolumePriceTrend();
console.log(vpt.batch([10, 11, 9], [100, 200, 300]));
Output:
[ 0, 20, -34.54545454545455 ]
Interpretation
VolumePriceTrend is read like OBV — by slope and by divergence,
never by absolute level. A VPT rising in step with price confirms the
trend is volume-supported; VPT flattening or falling while price climbs
is a bearish divergence warning that the move lacks participation. Versus
OBV, VPT gives proportionally more weight to large moves and less to a
string of tiny up-closes, so it tracks the magnitude of conviction, not
just its direction.
Common pitfalls
- Reading the absolute value. Only slope and divergences carry meaning; the level depends on the stream's start point.
- Expecting OBV-identical behaviour. VPT scales by percentage change, so the two lines diverge — especially across large single-bar moves.
References
The Volume-Price Trend (also "Price-Volume Trend") is a standard
cumulative volume study; the volume · ROC accumulation here matches the
common definition.
See also
- Indicator-Obv.md — cumulative signed volume, the closest relative.
- Indicator-Adl.md — cumulative range-weighted volume.
- Indicators-Overview.md — the full taxonomy.