vike
Market makingCross-exchange

Basis

The event-time EWMA of the maker-versus-reference basis — a diagnostic and a halt band, never a term in a quote price, folded from paired market touches only.

crates/vike-mm/src/xemm/basis.rs's BasisEwma is the cross-exchange maker's estimate of the observed basis between its two venues: an event-time EWMA of mid_A / mid_B − 1, where A is the maker venue and B the reference. Its header opens with the rule the whole file is built around.

Diagnostic and halt band only — never a term in a quote price

The obvious use for a basis estimate is to rebase the reference touch before pricing. crates/vike-mm/src/xemm/pricing.rs's passive_clamp carries the argument against it. Rebasing destroys the hedge identity: with A 10 bp below B and edge + fee also 10 bp, the rebased ask lands on ask_B, so selling on A and buying back on B is a guaranteed loss net of fees — and every such fill looks hedged. Flooring the rebase back against the raw quote restores the identity but pins the disadvantaged side at a price that can never fill, leaving a one-sided accumulator quoting off an estimate whose error between the fill and the hedge is unbounded. The clamp needs no estimate at all: venue A's own book is the ground truth about where A trades.

Two jobs, both honest for a point estimate

The header allows the estimator exactly two uses. First, publish — XemmMaker::basis exposes the value so an operator can size min_profitability against basis volatility rather than a point level; the volatility, not the level, is the real risk between the A-fill and the B-hedge. Second, BasisEwma::out_of_band, the halt band, which catches a decoupled pair, a wrong-instrument mount and a lying feed with one number, turning "this pair has no two-sided edge" into an operator-visible halt instead of a silent one-sided accumulation. In XemmMaker::detect_fault that verdict is HaltReason::BasisOutOfBand, evaluated last — after the freshness bounds and the exposure faults, in the order a diagnosis should read.

Three deliberate disciplines

  • Paired observations only. A fold needs both venues' mids, both sane. Folding one venue's move against the other's stale last price would measure feed latency, not basis. XemmMaker::observe_touch feeds the estimator only once both touches are known and both pass Touch::is_sane, stamping the fold with the later touch's event time.
  • Event-time half-life, never wall clock, so the estimate is deterministic under test and identical under replay — the same rule the rest of the crate's windows follow.
  • Never fed by own fills. Own fills are the adversely-selected sample: the maker is filled precisely when the basis moved against it, so folding them would bias the estimate toward the side already being picked off. The estimator sees market touches only.

The fold

BasisEwma::observe(mid_a, mid_b, ts, halflife_ms, clamp) folds one paired observation. The raw observation mid_a / mid_b − 1 is clamped to ±clamp when clamp > 0, so one garbage touch cannot move the estimate arbitrarily far — the estimator's job is to detect a persistent regime, and a single outlier is the opposite of that. The decay weight is 0.5^(dt / halflife) in event milliseconds, so one half-life exactly halves the weight of everything before it; the test one_halflife_halves_the_previous_weight pins that bit-for-bit, because the band's calibration depends on it. A non-positive dt — a same-timestamp or out-of-order tick — folds at full weight rather than being dropped: an out-of-order tick is still a real observation, and dropping it would make the estimate depend on arrival order. The fold is a no-op when halflife_ms <= 0, when either mid is not finite and strictly positive, or when the ratio comes out non-finite; insane inputs fold nothing rather than poisoning the estimate.

The estimator is cold — value() is None — until its first paired observation, and disabled means permanently cold, not merely quiet: with a non-positive half-life nothing downstream can read a stale or fabricated value out of it. The value is a fraction; −0.001 means venue A trades 10 bp below venue B.

out_of_band(max_bps) is true when the estimate has warmed and |value| · 10_000 exceeds max_bps. A non-positive max_bps disables the band, and a cold estimator never trips it — an absent estimate is not evidence of a wide basis; the freshness bounds on guards cover "I can't see anything". The band is on magnitude, in both directions.

The knobs

crates/vike-model/src/strategy/xemm_params.rs's XemmParams carries three: max_basis_bps, the halt band in basis points of the reference mid; basis_halflife_ms, the event-time half-life; and basis_clamp, the per-observation bound as a fraction. XemmParams::default sets the half-life to 60_000 ms and the clamp to 0.05 with the band off (0.0) — XemmMaker::with_basis_band's doc notes the estimator still warms and publishes in that state, it just never halts. The TOML keys under XemmMaker::from_params are the same three names.

The pure core is pinned across platforms

crates/vike-mm/src/platform_probe.rs's PINNED_STATEFUL carries a recorded cross-platform hash for observe — the fold reaches its pow through the libm crate rather than the platform — which is one of the concrete costs of deleting the stack. The estimator is dormant with the rest of the xEMM, but it is not inert in the tree.

On this page