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.
crates/vike-mm/src/refresh.rs's within_tolerance is the anti-churn gate of the
spread maker. Given what one side already has
resting — a (price, size) pair — and the target the current tick just computed, it answers
"close enough to leave alone". A true means the caller skips the modify and leaves the resting
order, and its venue queue position, untouched.
Why it exists
The crate header (crates/vike-mm/src/lib.rs) states the cost it removes: without the gate the
maker emits two venue modifies per book delta forever, which on a rate-limited CLOB reached over a
long-haul link is its biggest wire cost. SpreadMaker::from_params adds the second reason in its
reader comment — a quote that re-prices every tick forfeits its FIFO slot, so the tolerance is
load-bearing for a queue-position fill backtest: a quote that
never holds its place can never be hit by a taker trade.
The contract
Both axes are relative, measured in basis points of the resting value, held in
crates/vike-model/src/strategy/maker_params.rs's RefreshTolerance (price_bps, size_bps).
The header's reason for that unit is that it reads sanely on both a 0..1-priced prediction market
and a five-figure crypto book without the strategy knowing either venue's tick grid. A skip needs
both axes inside tolerance:
- price:
|target_px − resting_px| ≤ price_bps · 1e-4 · |resting_px| - size:
|target_sz − resting_sz| ≤ size_bps · 1e-4 · |resting_sz|
The per-axis helper drift_within carries the edge rules. An exactly unchanged value always
passes, whatever the threshold — there is nothing to send. A non-positive tol_bps therefore means
"no tolerance on this axis": only exact equality passes it. A zero or non-finite resting reference
has no relative scale to measure against, so it never passes, and NaN anywhere never skips — the
conservative direction is to re-price rather than silently strand a stale quote. The comparison is
multiplied through (delta · 10_000 ≤ tol_bps · scale) rather than divided: no reciprocal
rounding, and NaN falls out as false. The in-file tests pin the boundary as inclusive — 25 bp of
100 is 0.25, and a target of 100.25 is inside.
Off is the default. A None tolerance never reaches the module at all, and an all-zero bag —
including RefreshTolerance::default — returns false from every call, so an unconfigured maker
re-prices on every tick exactly as it did before the feature, byte-identical.
Where it may and may not be consulted
Only the re-price path is gated
crates/vike-mm/src/quote.rs's refresh_skips is reachable only from the modify arm of
requote_single_side. Placing a new quote and pulling a resting one — the fill-rate breaker's
suppression cancel — are never tolerance-gated: a quote that must come off the book always comes
off, whatever the tolerance is set to — crates/vike-mm/src/refresh.rs's header states it in
those words, paired with the other invariant the module keeps: a fully-inert bag must stay byte-identical to the
ungated maker.
There is a second refusal before the arithmetic runs. refresh_skips answers false immediately
when the side's snapshot is stale — SideState::refresh_stale, set by Strategy::on_fill
whenever a fill lands on that side. The reason is that SideState::own is the maker's intended
quote, not the venue-side remainder: after a partial fill the venue holds less than the intended
size, so an intended-versus-target comparison would read "no change" and the size top-up would be
silently lost. The flag forces the next tick through the modify arm exactly once, which re-issues
the full configured size. on_fill sets it before the breaker's early return, deliberately,
because it is independent of the breaker; and it is inert while the gate is off, since it is "read
ONLY by refresh_skips/reward_moas_holds (and the ladder's per-rung twin), which short-circuit
to 're-quote'". The ladder is that twin: requote_ladder_side
reads the flag directly rather than through either helper, and applies the same predicate per rung,
with the same stale short-circuit and the same rule that a pull is never gated.
Tuning it against the edge
RefreshTolerance's doc carries the ceiling. The tolerance is a fraction of the resting price,
while the edge the maker is paid for is half_spread away from mid; if price_bps · 1e-4 · price
approaches or exceeds half_spread, a market move that stays inside the tolerance — and therefore
sends nothing — can leave the resting quote at or through the new mid, quoting at zero or negative
edge and inviting exactly the adverse fill the spread exists to price. The doc's useful ceiling is
a small fraction, say a tenth, of half_spread / price · 1e4 basis points; past that the gate is no
longer only suppressing churn, it is silently widening the maker's fill risk.
SpreadMaker::with_refresh_tolerance adds the size axis's interaction with the
inventory skew. A size_bps of 0.0 demands bit-exact
size equality, so it only ever fires on a fixed-size maker; with skew active the sizes are
recomputed from a continuously varying position every tick, the size axis would essentially never
compare equal, and the gate would never fire — a non-zero size_bps is effectively required there,
sized to swallow the inventory jitter and still re-quote on a real re-size.
On a reward-bearing venue the tolerance also protects reward eligibility. The same doc quotes
the measurement: Polymarket's rewards program enforces a minimum order age of 30 s (moas: 30 on
GET /clob-markets/{condition_id}), so an order re-quoted more often than that scores zero. The
liquidity-rewards fold adds its own min-order-age hold,
reward_moas_holds, which composes with this gate — either may skip — rather than replacing it.
The TOML keys are refresh_price_bps and refresh_size_bps, both defaulting to 0.0 (off) in
SpreadMaker::from_params. The cross-exchange maker exposes the same
bag through XemmMaker::with_refresh_tolerance, with the same rule: consulted only on the re-price
path. The behaviour suite is crates/vike-mm/src/tests/refresh_tolerance.rs — sub-tolerance drift
skips the modify, supra-tolerance re-prices in place, a fill always forces the size top-up, and a
pull is never tolerance-gated.
Ladder quoting
The pure per-side rung builder behind the maker's N-orders-per-side mode — rung 0 is today's quote bit-for-bit, deeper rungs step outward, and the whole side is diffed to the minimal verb set each tick.
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.