vike
Market makingCross-exchange

Cross-exchange market making

The xEMM — rest passively on one venue at prices derived from another's touch and hedge every fill there — its pure pricing core, its four safety layers, and the fact that no binary mounts it.

crates/vike-mm/src/xemm/mod.rs's XemmMaker is the cross-exchange market maker: rest passively on venue A, the maker venue, at prices derived from venue B's touch, and hedge every fill on B. Its pricing arithmetic is a port of an Apache-2.0 cross-exchange strategy; the risk half — the guards, the hedge ledger and the basis estimator — is Vike Trader's own.

Built, tested, and mounted by nothing

crates/vike-run/src/xemm.rs's build_live_xemm_core has no caller; its paper twin is called only from tests; crates/vike-strategy/src/registry.rs's strategy_by_name has no xemm arm, so a profile naming it is told it does not exist; there is no feature gate, flag, CLI verb or GUI surface. It has never quoted on a venue. Keeping the code rather than deleting it was a deliberate verdict, not an oversight — and registering "xemm" in that registry would be the wrong road anyway: it would produce a single-leg mount that never hedges. The event that flips it to mounted is one mount declaring a leg on a second venue — a non-empty MountSpec::legs, the shape xemm_mount_legs produces.

What it earns

xEMM earns the maker spread: it rests at reference ± (edge + fee) and offloads any fill on B, so it profits from being filled, not from a pre-existing price gap. The module doc adds why the distinction is load-bearing: the cross-venue dislocation this strategy is often mis-explained by does not survive a four-crossing cost floor on the pairs measured here.

The pure core

crates/vike-mm/src/xemm/pricing.rs is four functions and one value type, no state and no I/O. xemm_maker_quotes turns B's (bid, ask) into the pair to rest on A: maker_bid = taker_bid · (1 − min_profitability − total_fee) and maker_ask = taker_ask · (1 + min_profitability + total_fee), so a fill on A can always be hedged into B at a profit no smaller than the edge. Both terms only ever add, the spread widens monotonically in each, and with both at zero the maker quotes collapse onto the taker touch bit-for-bit. The header calls this the hedge identity, living here and nowhere else: every later stage may move a quote away from the reference touch, never toward it. hedge_qty sizes the hedge as net_filled_base · hedge_ratio.

passive_clamp holds each side strictly inside A's own touch — min(raw_bid, a_ask − standoff) and max(raw_ask, a_bid + standoff). min/max can only move a quote away from the reference, so the edge survives by construction, and the quote can never be marketable on A, which is the structural substitute for the post-only that no roster venue supports — vike_model::venue_caps pins supports_post_only: false on all 14 rows. It refuses rather than degrades — no maker touch, an insane touch, a non-finite price, a non-positive standoff or a crossed result all return None, and the caller pulls. snap_down and snap_up then put the two prices on A's grid directionally, because the crate's half-to-even round_to_step could round a clamped bid back up through the clamp.

The one hard problem: a persistent basis

Two venues quoting the "same" instrument sit at systematically different prices — the doc's measurement is that hyperliquid trades below the CEXes on some instruments in more than 99 % of minutes. A maker treating B's touch as fair value for A therefore quotes marketable on one side continuously, paying an unbudgeted taker fee — and paper and backtest book that as a maker fill (is_maker = kind == Limit at both fill sites), so the rehearsal looks profitable. The fix is placement, not a price term. passive_clamp's doc states the consequence so nobody reads it as a bug: on a pair whose basis exceeds the required edge, one side rests deep and inert while the other sits at A's touch and fills — the economic truth of the pair. The obvious alternative, rebasing the reference by an estimated basis, is refuted on the basis page.

Four independent safety layers

The doc lists them because none alone suffices: the passive clamp, structural and impossible to mis-tune; the basis halt band, which catches a decoupled pair, a wrong-instrument mount or a lying feed; the one-sided-fill breaker, which fires on the symptom regardless of whether any model is right; and the naked bands — soft suppression of the growing side, then a hard halt plus a taker-flatten impulse on the excess. The freshness bounds and the halt vocabulary are on guards; the inventory authority — a target, not a delta — is the hedge ledger. The maker reads no inventory through the broker seam anywhere, and a poisoned-broker test pins it.

XemmMaker::requote is the one quote funnel: a halted or not-yet-ready maker pulls both sides; then the hedge identity, the passive clamp against A's own touch — with min_edge_ticks floored at 1.0, because a sub-tick standoff rounds onto the touch — the directional snap, inventory skew on the sizes off the owned ledger, per-side suppression, and emission bid-then-ask. The hedge goes through Broker::submit_market, the only venue-routable verb — a tagged submit carries no symbol and the runtime resolves a leg by symbol alone — which is why the bound is HftBroker and why XemmMaker::new panics if the two symbols are equal.

Defaults that ship safety on

crates/vike-model/src/strategy/xemm_params.rs's header declares a knowing inversion of the workspace's neutral-default rule: xEMM has no existing behaviour to protect, and every guard's neutral value is unsafe. XemmParams::default sets both touch-age bounds to 2 s, the all-lanes-quiet gap to 5 s, a 3 s hedge timeout with 3 attempts, a 60 s basis half-life with a 0.05 clamp, resume_after_halt_ms = 0 (manual resume only) and qty = 0.0, so a bare default quotes nothing. total_fee must come from vike_model::fees::xemm_round_trip_fee, whose None is a refusal a caller may not default to 0.0: it refuses every fee shape a flat fraction of price cannot express or would understate, because a silent zero would price a fee-bearing round trip as free; its assume_taker_on_maker_leg defaults to false precisely because the clamp keeps the maker leg passive. The two symbols are identity, not config, held outside the params bag: XemmMaker::apply_params is one struct copy that can widen the edge or cut size but never repoint a leg mid-flight.

crates/vike-run/src/xemm.rs's header names the three feeds a live mount would need — the maker venue's L1/L2, the taker venue's L1 delivered to on_reference_quote through MountLeg::at, and a periodic LiveSchedule sweep, the one lane that still fires when both venues go silent — and that file's XemmMountConfig names the v1 pair: a hyperliquid maker leg on BTC against an okx taker leg on BTC-USDT-SWAP.

On this page