CVD
Cumulative volume delta — the running sum of buy minus sell volume over the trade stream, the accumulator that computes it, and the per-bar form the chart derives from footprints instead.
crates/vike-orderflow/src/cvd.rs is, after classify, the shortest module in the crate, and its
header is its whole contract: "cumulative volume delta — running Σ(buy − sell) over the trade
stream". Buy and sell are the classification module's reading
of the aggressor flag, so a rising CVD means aggressive buying has exceeded aggressive selling
since the accumulator started, whatever price has done meanwhile.
The accumulator
pub struct CvdAccumulator { cvd: f64 }
impl CvdAccumulator {
pub fn new() -> Self;
pub fn push(&mut self, t: &TradeTick); // cvd += buy − sell; size <= 0 skipped
pub fn value(&self) -> f64;
pub fn from_trades(trades: &[TradeTick]) -> f64; // the batch twin
}push takes signed's (buy, sell) pair for the trade and adds buy − sell; a trade of zero or
negative size returns before touching the sum. value is a plain read. The sum is a naive
running += fold — there is no compensated summation, and the order of the trades is the order
of the sum.
from_trades is the batch form over a slice, and the module's parity test drives the same trades
through both and compares value().to_bits() to the batch result: streaming and batch are
bit-identical, not merely close. The zero-skip is pinned by the same file — +3 buy, −2 sell, skip 0, +1 buy → +2.
The per-bar form the chart draws
The accumulator is the trade-stream primitive. The chart does not run it. crates/vike-chart/src/orderflow.rs derives CVD from the per-bar
footprint substrate instead: its cvd_from_footprints is
"cumulative volume delta per bar: running Σ over bars of (Σ cell.buy − Σ cell.sell)", index-aligned
to the footprints and so to the chart's bars, and again a "naive fold (no compensation)". The
header's reason is architectural — CVD and the visible volume profile are both derived from
&[FootprintBar], "the single orderflow input — so the app feeds one structure and the renderer
computes the three views".
Two computations, one semantic
The trade-stream accumulator and the chart's per-bar derivation are separate code, but both read
buy and sell through the same signed split, and the footprint cells are themselves sums of that
split. Where the two would differ is what they start from and how the sum is grouped: the
accumulator from its construction, folding trade by trade in tape order; the chart from the first
bar it holds, folding each bar's cell totals and then accumulating those. Both folds are naive, and
no test compares them.
Where the CVD pane sits and what it is drawn against is the in the GUI page.
Flow bars
Tick, volume and dollar bars with a buy/sell/delta split, how each one treats the trade that crosses its boundary, and the opt-in imbalance and runs bars that sample by information rather than by count.
Footprint
The per-bar, per-price-bucket buy/sell volume grid — how trades are bucketed on the tick grid, why the bar boundary belongs to the caller, and how the app keeps a footprint for every chart bar without losing ticks.