Inventory skew
The pure size-shaping multipliers that lean the maker toward a target inventory, and the round-trip netting behind the per-side fill-rate breaker that pulls a side being picked off.
crates/vike-mm/src/skew.rs holds the two pure risk helpers of the
spread maker: skew_multipliers, which shapes the
two quote sizes from inventory, and net_signed_fills, the round-trip netting the fill-rate
circuit breaker trips on. Both were moved out of the crate root verbatim and are isolated so they
unit-test without a runtime. Neither touches a price: prices come from the style or the
Avellaneda–Stoikov layer, the skew decides sizes, and
the breaker decides which sides quote at all.
Size shaping
skew_multipliers(position, target, max_inventory, skew) returns a (bid_mult, ask_mult) pair
applied to the base quote size. With imbalance = clamp((position − target) / max_inventory, −1, 1):
bid_mult = max(1 − skew · imbalance, 0)
ask_mult = max(1 + skew · imbalance, 0)Its doc lists the five properties the skew_sizing tests cover. Neutral: skew <= 0, or a
degenerate max_inventory <= 0, yields exactly (1.0, 1.0) for any position, reproducing the
fixed-size path bit-for-bit — and guarding the division. Directional: long (position > target)
shrinks the bid and grows the ask, leaning to sell the position down; short mirrors.
Symmetric about the target. Monotonic: the bid is non-increasing and the ask
non-decreasing as position rises. Clamped: beyond ±max_inventory the multipliers saturate at
1 ∓ skew, floored at zero so an over-unit skew can never request a negative size. The crate
header adds where the position comes from: the maker reads its own signed position off the broker
through HftBroker::position, and the default target of 0 means stay flat.
SpreadMaker::with_skew(target_inventory, max_inventory, skew) is the builder; the TOML keys of
the same names default to 0.0 / 1.0 / 0.0, which SpreadMaker::from_params notes are
exactly the constructor's neutral values, so a keyless table is byte-identical with skew off. The
shaped size is the base every ladder rung multiplies, and
the reward min_size floor is applied after it.
Round-trip netting
net_signed_fills(fills, now, window_ms) sums the signed fill size within [now − window_ms, now]: +size per bid (buy) fill, −size per ask (sell) fill. The sign is the round-trip
cancellation — a bid fill later offset by an equal ask fill sums back toward zero, which is a
completed, inventory-neutral round trip, the desired market-making outcome, and must not trip the
guard. Only net one-directional accumulation survives the sum: a result at or above +threshold
means bids are being repeatedly hit without offsetting asks — adverse selection on the bid, a
falling market lifting it — and suppresses the bid; at or below −threshold, the mirror
suppresses the ask. Every timestamp in the window is a fill or quote event stamp
(FillRec::ts); wall-clock is never read, matching the runtime's event-clock determinism.
The breaker
SpreadMaker::with_fill_breaker(window_ms, net_fill_threshold, cooldown_ms) arms it, and
SpreadMaker::breaker_enabled is the single gate every breaker path checks: all three knobs must
be positive, and any non-positive value leaves it off, so the strategy reduces exactly to the
skew-only maker with no fill tracking and no suppression. Strategy::on_fill in
crates/vike-mm/src/strategy_impl.rs records each fill at its event timestamp, evicts everything
older than the window — the window rides the latest fill — nets, and arms the over-hit side's
cooldown from the fill's timestamp. The threshold it compares against is
net_fill_threshold / pull_accel_mult(fill.ts), the settlement
acceleration, which is exactly 1.0 unless a resolution is known, so the default comparison is
bit-for-bit the unchanged threshold; the pure netting is untouched.
The arm is acted on by requote, from either lane: a side is suppressed while the triggering
event's timestamp is still before its suppressed_until deadline, its resting quote is pulled
through HftBroker::cancel_tagged, and it is not re-quoted until the cooldown expires, while the
other side keeps quoting and re-skewing normally. The crate header calls this the adverse-selection
guard the plain maker lacked.
A pull is never tolerance-gated
The refresh tolerance is consulted only on the re-price path, so it can never suppress the breaker's suppression cancel — a quote that must come off the book always comes off. A laddered side pulls every rung.
In the cross-exchange maker
The xEMM reuses both helpers with two deliberate differences.
XemmMaker::with_skew shapes the maker leg's sizes off the owned hedge ledger's maker_pos,
never a broker read, for the reasons the hedge ledger page
carries. And XemmMaker::record_maker_fill folds maker-leg fills only into the breaker window:
hedge-leg fills are the strategy's own mechanical offset, not market flow, and netting them would
cancel every real one-sided signal to exactly zero. Its module doc ranks the breaker as the third
of four independent safety layers — the one that fires on the symptom regardless of whether
any pricing model is right, so a wrong assumption costs bounded one-sided flow.
The end-to-end suite is crates/vike-mm/src/tests/breaker.rs: round-trip netting, per-side
suppression and cooldown expiry, the accelerated pull near a binary resolution, the OFI-to-toxicity
synthesis that feeds the same guard, and the breaker-off reduction.
Refresh tolerance
The pure "is this re-quote worth the wire?" predicate — a relative basis-point band on the resting price and size that skips a modify, gates only the re-price path, and is off by default.
Taker flatten
The Guilbaud–Pham impulse-control leg — a pure decision that crosses the book with a market order when inventory breaches a hard band, cutting only the excess over the band.