Order flow
The pure trade-aggregation core behind every order-flow study — one buy/sell semantic, flow bars, CVD, footprint and volume profile folded from the trade tape, the book-fed microstructure studies beside them, and the parity discipline each builder is gated by.
vike-orderflow is the crate every order-flow study in Vike Trader is computed by. Its own header,
crates/vike-orderflow/src/lib.rs, states the contract in one line: a pure trade-aggregation core
that folds vike_model::TradeTick streams into orderflow primitives — no I/O, no rendering, no
threading. The manifest (crates/vike-orderflow/Cargo.toml) declares it at layer 20, tier
domain, "one hop over the vocabulary: a single-purpose pure core", and its only workspace
dependency is vike-model. The one crate beyond that is libm, pulled in for the standard-normal
CDF that VPIN's bulk volume classification needs — a pure-Rust FDLIBM
erf, deterministic across platforms, and already a workspace-pinned dependency rather than a
new supply-chain entry.
The input
Six of the nine modules read one type: crates/vike-marketdata/src/bar.rs's TradeTick, "one
executed trade: price + size, with the aggressor flag where available". Its fields are ts (epoch
milliseconds, UTC), local_ts (the machine receive time — 0 means not stamped, which is what
fixtures and backfill carry), price, size, is_buyer_maker and symbol. Two more, imbalance
and otr, read a vike_model::L2Book instead — the same reducer the
data model page describes. The ninth, p2, reads neither: its
push takes a bare f64, which is why the
streaming quantiles page calls it the one module that
folds nothing from the tape.
One semantic, nine modules
| module | symbols | what it is | page |
|---|---|---|---|
classify | Side, classify, signed | the load-bearing semantic: is_buyer_maker=false → Buy, true → Sell; delta = buy_vol − sell_vol everywhere below | classification |
bars | OrderflowBar, TickBarBuilder, VolumeBarBuilder, DollarBarBuilder, ImbalanceBarBuilder, RunsBarBuilder, FlowUnit | tick, volume and dollar bars with a buy/sell/delta split; the opt-in information-driven bars | flow bars |
cvd | CvdAccumulator | running Σ(buy − sell) | CVD |
footprint | FootprintBuilder, FootprintBar | a per-bar PriceBin grid | footprint |
profile | VolumeProfileBuilder, VolumeProfile, PriceBin | price-bucketed bins, POC, 70% value area | volume profile |
imbalance | depth_imbalance, weighted_depth_imbalance, ImbalanceTracker | depth-N and inverse-distance-weighted book pressure | depth imbalance |
otr | OtrTracker, OtrConfig, OtrSample | order-to-trade ratio from consecutive top-N snapshot diffs per event-time window | order-to-trade ratio |
vpin | Vpin, BvcVpin, VolumeClassifier | fixed-volume-bucket order-flow toxicity; the aggressor-free variant with bulk volume classification and a tick-rule option | VPIN |
p2 | P2Quantile | the Jain–Chlamtac P² single-quantile estimator in O(1) space, for future adaptive thresholds | streaming quantiles |
The header splits them into two families. The first five are "builders, one file each"; the last four are microstructure studies — mechanisms from the standard literature, implemented independently.
Two conventions every builder shares
Forming versus committed. Every bar builder carries a forming() read, documented identically
on each: "Snapshot of the OPEN (unclosed) bar — the chart's forming bar. Pure read." The closed
bar is what push returns; the open one is what the chart draws while it is still filling.
OtrTracker's forming() and last() "mirror the crate's forming/committed convention", so a
book-fed study reads the same way.
Zero-size trades are skipped. TickBarBuilder::push returns None for size <= 0,
CvdAccumulator::push, FootprintBuilder::push and VolumeProfileBuilder::push return without
touching state, and every batch from_trades filters on size > 0 before folding.
ImbalanceBarBuilder::push says it outright: "Zero/negative-size trades are skipped entirely
(never open or advance a bar)."
The gate discipline
The header states what every builder is tested against, and it is not the parity-fixture machinery the rest of the platform uses:
- hand-computed expected-value tests — "the real oracle — no CPython twin here";
- invariant and zero-skip tests;
- streaming ↔ batch bit-parity on
f64::to_bits, where "batch is a genuinely separate slice computation, notpushin disguise".
The book-fed studies, imbalance and otr, have no trade-slice batch twin, so they are gated as
pure functions over scripted snapshots instead. p2 is gated against an exact full-sort quantile
oracle plus the published paper example.
No Python twin, so no frozen fixture
crates/vike-orderflow/src/classify.rs says it "ports no Python twin (new native)". The
parity gate's frozen fixtures therefore do not reach this crate;
its oracle is hand computation checked into the tests beside each builder, and its parity claim is
the streaming-equals-batch one above.
Where it is consumed
The header closes with "SP2 renders this, SP3 backfills it — both out of scope here." The consumers name themselves in their own headers:
crates/vike-app-core/src/tickvol.rs— interval strings of the form"<n>t"and"<x>v"select the tick and volume aggregators;TickVolAggwraps one builder and converts each closedOrderflowBarto avike_model::Barfor the chart's normal sync path, while the fixed kline set passes through unchanged.crates/vike-app-core/src/orderflow.rs'sOrderflowAggbuckets the drained trade tape into the chart's bars by open time and retains per-bar footprint cells — "the substrate SP2 renders from".crates/vike-chart/src/orderflow.rsderives CVD from&[FootprintBar], "the single orderflow input — so the app feeds one structure and the renderer computes the three views"; the visible volume profile is this crate's ownVolumeProfile::from_footprints, which the chart reaches throughChartState::visible_profile_shared.
Which pane draws which study is the in the GUI page; the chart engine itself is under the chart.
Sizing, and zero-trade diagnosis
The swappable position-sizer model the simulator applies to opening entries, and the analyzer that turns a flat, zero-trade run into a ranked list of probable causes.
Buy/sell classification
The one load-bearing semantic of the order-flow crate — how a trade's aggressor side is read off the maker flag, and how every bar, delta, footprint and profile inherits it unchanged.