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.
9.3 KiB
VWAP (Volume-Weighted Average Price)
The volume-weighted mean of typical price; the institutional benchmark for "fair" intraday execution. Wickra ships both the unbounded cumulative session VWAP and a finite-window
RollingVwap.
This page documents two distinct public types — jump straight to
Vwap (cumulative) or
RollingVwap (finite window).
Quick reference
| Item | Value |
|---|---|
| Family | Volume |
| Input type | Candle (uses high, low, close, volume) |
| Output type | f64 |
| Output range | unbounded (price-units) |
| Default parameters | none for Vwap; period required for RollingVwap |
| Warmup period | 1 for Vwap, period for RollingVwap |
| Interpretation | intraday fair-price benchmark for execution |
Formula
Both variants use the typical price tp_t = (H_t + L_t + C_t) / 3
(see Candle::typical_price in crates/wickra-core/src/ohlcv.rs:104-108).
Cumulative VWAP:
VWAP_t = ( Σ_{i=1..t} tp_i * v_i ) / ( Σ_{i=1..t} v_i )
Rolling VWAP over the last period candles:
RollingVWAP_t = ( Σ_{i=t-period+1..t} tp_i * v_i ) / ( Σ_{i=t-period+1..t} v_i )
Both forms gate their output: when the relevant volume sum is 0.0, no
value is emitted (vwap.rs:50, 121).
Vwap (cumulative)
The session VWAP. State grows forever; call reset() at session
boundaries (e.g. the start of the trading day) to restart accumulation.
Parameters
Vwap::new() takes no parameters. Python: wickra.VWAP(). Node:
new w.VWAP().
Inputs / Outputs
impl Indicator for Vwap {
type Input = Candle;
type Output = f64;
fn update(&mut self, candle: Candle) -> Option<f64>;
fn warmup_period(&self) -> usize { 1 }
}
- Rust input. A full
Candle; the indicator multipliestypical_price() * volumeand accumulates. - Python batch.
VWAP.batch(high, low, close, volume)returns a 1-Dnp.ndarraywithNaNfor any prefix where the cumulative volume is still0. - Node batch.
vwap.batch(high, low, close, volume)returnsArray<number>withNaNfor the same prefix.
Warmup
warmup_period() == 1. Provided the first candle has positive volume,
the indicator emits on tick 1. If the first k candles all have
volume == 0, no output is emitted until the first candle with
non-zero volume — RollingVwap's warmup gating is independent of
this volume-gating logic and applies on top of it.
Edge cases
- Zero-volume bar. A candle with
volume == 0does not advance the running sums in any visible way and (if it is the first such bar the indicator has seen) keeps the output atNone. The implementation short-circuits withif self.sum_v == 0.0 { return None; }(vwap.rs:50). - Constant input. Identical candles produce a flat VWAP equal to their typical price.
- Session boundaries. There is no automatic reset; the caller is
responsible for invoking
reset()at the start of each new session. - NaN / infinity.
Candle::newrejects non-finite OHLCV values before they can reach the indicator. - Reset.
reset()zeroes both running sums and unsets thehas_emittedflag.
Examples
Rust
use wickra::{BatchExt, Candle, Indicator, Vwap};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let candles = vec![
Candle::new(10.0, 10.0, 10.0, 10.0, 1.0, 0)?, // tp = 10
Candle::new(20.0, 20.0, 20.0, 20.0, 3.0, 0)?, // tp = 20
Candle::new(30.0, 30.0, 30.0, 30.0, 1.0, 0)?, // tp = 30
Candle::new(40.0, 40.0, 40.0, 40.0, 2.0, 0)?, // tp = 40
];
let mut v = Vwap::new();
println!("{:?}", v.batch(&candles));
Ok(())
}
Output:
[Some(10.0), Some(17.5), Some(20.0), Some(25.714285714285715)]
Hand check at t = 2: (10*1 + 20*3) / (1+3) = 70/4 = 17.5.
At t = 4: (10*1 + 20*3 + 30*1 + 40*2) / (1+3+1+2) = 180/7 ≈ 25.7142857.
Python
import numpy as np
import wickra as ta
vw = ta.VWAP()
h = np.array([10.0, 20.0, 30.0, 40.0])
l = np.array([10.0, 20.0, 30.0, 40.0])
c = np.array([10.0, 20.0, 30.0, 40.0])
v = np.array([ 1.0, 3.0, 1.0, 2.0])
print(vw.batch(h, l, c, v))
Output:
[10. 17.5 20. 25.71428571]
Node
const w = require('wickra');
const vw = new w.VWAP();
console.log(vw.batch(
[10, 20, 30, 40],
[10, 20, 30, 40],
[10, 20, 30, 40],
[ 1, 3, 1, 2],
));
Output:
[ 10, 17.5, 20, 25.714285714285715 ]
RollingVwap (finite window)
A rolling-window variant for streaming bots that want a finite-memory fair-price benchmark instead of an unbounded session aggregate.
Parameters
| Name | Type | Default | Constraint | Source |
|---|---|---|---|---|
period |
usize |
(no default) | > 0 |
RollingVwap::new (vwap.rs:89) |
period == 0 returns Error::PeriodZero. RollingVwap is exposed in
Rust only — Python's VWAP / Node's VWAP correspond to the cumulative
form.
Inputs / Outputs
impl Indicator for RollingVwap {
type Input = Candle;
type Output = f64;
fn update(&mut self, candle: Candle) -> Option<f64>;
fn warmup_period(&self) -> usize { self.period }
}
The window stores (typical_price * volume, volume) pairs and runs
incremental sum_pv / sum_v aggregates, so each update is O(1).
Warmup
warmup_period() == period. The first period - 1 candles return
None; the period-th candle emits the first value provided the rolling
volume sum is positive. If the entire window has volume == 0, the
indicator stays at None.
Edge cases
- Window slides. Once
window.len() == period, the oldest(pv, v)pair is subtracted from the running sums before the new pair is added. - Zero-volume window. If every candle in the window has zero
volume,
sum_v == 0and the indicator suppresses output until a positive-volume candle is in scope. - Reset.
reset()clears the window and both running sums. is_ready(). Returnstrueonly when the window is full andsum_v > 0(vwap.rs:138).
Examples
Rust
use wickra::{BatchExt, Candle, Indicator, RollingVwap};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let candles = vec![
Candle::new(10.0, 10.0, 10.0, 10.0, 1.0, 0)?,
Candle::new(20.0, 20.0, 20.0, 20.0, 3.0, 0)?,
Candle::new(30.0, 30.0, 30.0, 30.0, 1.0, 0)?,
Candle::new(40.0, 40.0, 40.0, 40.0, 2.0, 0)?,
];
let mut rv = RollingVwap::new(3)?;
println!("{:?}", rv.batch(&candles));
Ok(())
}
Output:
[None, None, Some(20.0), Some(28.333333333333332)]
Hand check at t = 3 with window [10@1, 20@3, 30@1]:
(10 + 60 + 30) / (1+3+1) = 100/5 = 20.0.
At t = 4 with window [20@3, 30@1, 40@2]:
(60 + 30 + 80) / (3+1+2) = 170/6 ≈ 28.333.
(RollingVwap is currently exposed only in the Rust API; the Python
VWAP and Node VWAP classes correspond to the cumulative form.)
Interpretation
- Execution benchmark. "Beat VWAP" is the canonical buy-side execution mandate: an aggressive algo that ends up paying below VWAP on the day is considered to have earned alpha relative to a passive participation strategy.
- Mean reversion. Intraday strategies often fade extensions away from VWAP, treating the VWAP line as a magnet.
- Trend filter. Some systems trade only longs above VWAP and only shorts below it; the line acts as a session-aware bias toggle.
Common pitfalls
- Forgetting to reset. Call
reset()at session start (or on each new trading day) — otherwise you average yesterday's tape into today's signal and the line drifts permanently behind current price action. - Zero-volume warmup. Several common data sources include
pre-session candles with
volume = 0for "no print this minute". Cumulative VWAP returnsNoneuntil at least one positive-volume candle has been seen; downstream code should treatNone/NaN/nullas "not yet ready," not as "VWAP is zero." - Typical price vs close. Wickra uses typical price
(H + L + C) / 3, not close. A naive implementation that uses close will produce noticeably different numbers on bars with wide intraday ranges.
References
- The VWAP construct emerged in institutional execution literature in the late 1980s and early 1990s; it has no single attributed inventor. The textbook reference for its role as an execution benchmark is Bertsimas & Lo, "Optimal control of execution costs," Journal of Financial Markets, 1998.
See also
- OBV — cumulative signed-volume measure that pairs well with VWAP as a divergence flag.
- MFI — money-flow oscillator that also blends typical price with volume.
- Bollinger Bands — non-volume volatility envelope, often layered alongside VWAP on intraday charts.