Vesper Calibration Memo — Anchor Reference Price: Three Candidate Formulations¶
Atlas —
Per your ruling, this memo evaluates three candidate anchor formulations before any implementation begins. For each: what it blocks, what it allows, and predicted behavior in S48 vs S49/S50.
Session reference data for this analysis:
| Session | Time (Z) | Structural context | Raw CLOB-AMM gap | Anchor behavior | Fills | Verdict |
|---|---|---|---|---|---|---|
| S48 | ~07:00Z (overnight) | Gap narrows overnight | ~3–6 bps (inferred) | Mean +2.94 bps, NOT saturated | 0 (but 172 ticks, 15 orders — healthy session) | ACTIVE was correct behavior |
| S49 | ~15:00Z (afternoon) | Gap structural at 12–20 bps | 12–20 bps confirmed | 100% cap-locked | 1 | ANCHOR_IDLE appears to have been premature |
| S50 | ~17:00Z (afternoon) | Same structural window | 11.9–19.5 bps (tick-level confirmed) | 100% cap-locked, 184/184 ticks | 0 | Exit mathematically unreachable — calibration failure confirmed |
Background: Why the Current Formulation Fails¶
Current formula: anchor_error = AMM_price - CLOB_mid
This formula is uncentered. It assumes the "normal" CLOB-AMM relationship is zero divergence. That assumption is wrong for XRP/RLUSD: the CLOB mid consistently trades at a structural discount to the AMM price. During afternoon ET, this discount is 12–20 bps. Overnight ET, it narrows to approximately 3–6 bps.
The result: the anchor is permanently measuring a feature of the pair's microstructure, not a time-varying regime signal. With a ±10 bps cap, afternoon ET produces cap-lock every tick. ANCHOR_IDLE becomes the permanent afternoon state regardless of market activity.
The fix in all three options below: anchor the measurement to the pair's structural baseline, not to zero.
Option 1 — Residual Basis Anchor¶
Formula:
Where rolling_pair_basis is a slowly-updating estimate of the structural CLOB-AMM discount for this pair. Recommended implementation: exponential moving average (EMA) with a long window (e.g., 200–400 ticks, roughly 15–25 minutes at 4-second cadence), updated every tick. The EMA anchors to the pair's recent normal; the anchor signal measures deviation from that normal.
What it blocks:
- Genuine regime distortions: rapid divergence beyond the structural baseline (flash divergence, sustained flow pressure, liquidity gaps that are unusual for this pair)
- ANCHOR_IDLE should fire when anchor_signal exceeds the entry threshold (e.g., 6 bps from baseline), sustained for 30 ticks
What it allows:
- Normal afternoon trading: the structural 12–20 bps CLOB-AMM gap is absorbed into rolling_pair_basis. Residual signal ≈ 0 bps under normal conditions. Engine stays ACTIVE.
- Overnight trading: structural gap is smaller, baseline tracks it, residual remains near zero. No change in expected behavior.
- Recovery from genuine distortion: when the regime normalizes back to the structural baseline, anchor_signal returns to ≈ 0 and ANCHOR_IDLE exits naturally.
Predicted behavior — S48 (07:00Z, overnight): - Rolling basis would track the overnight structural gap (~3–6 bps). Residual anchor signal: ≈ 0–2 bps. Well below 6 bps entry threshold. Engine stays ACTIVE throughout. - ✅ Correct: S48 was the healthiest session (172 ticks, 15 orders, market_valid: true every tick). This option would have maintained ACTIVE. The 0 fills were likely order placement / spread issues, not an anchor problem.
Predicted behavior — S49/S50 (afternoon ET): - Rolling basis tracks the structural 12–20 bps afternoon gap. After sufficient warm-up ticks (200–400), residual anchor signal: ≈ 0–3 bps under normal afternoon conditions. Engine stays ACTIVE. - If genuine distortion occurs (gap widens significantly beyond baseline), anchor_signal rises above 0 bps, ANCHOR_IDLE fires correctly. - ✅ Correct: Engine would have been ACTIVE and quoting throughout S49/S50 unless a genuine distortion appeared above the rolling baseline.
Risks / open questions: 1. EMA warm-up period. The first 200–400 ticks of a session, the rolling basis is not yet calibrated. During warm-up, option 1 behaves similarly to the current uncalibrated anchor. Need a startup initialization strategy: use last-session's final basis value as the warm-up seed, or use a pair-level stored baseline. 2. Basis drift within a session. If the structural gap shifts significantly mid-session (e.g., major XRPL event, large AMM LP inflow), the EMA may lag. This could produce false positives (ANCHOR_IDLE when the gap shift was structural and fast-moving). Mitigatable with a faster secondary EMA or a floor on basis update rate. 3. Cross-session persistence. The rolling basis should ideally carry over between sessions, or at minimum be initialized from a time-of-day model (morning vs afternoon vs overnight expected basis). Starting each session from zero introduces the warm-up problem at every session boundary.
Implementation complexity: Medium. Requires adding rolling_pair_basis to the anchor guard's state, EMA update on every tick, and a modified entry/exit comparison. The ±10 bps cap needs recalibration — with residual-based anchoring, a ±5–6 bps cap on the anchor_signal may be more appropriate (since the signal is now centered near 0).
Option 2 — CLOB-First Anchor¶
Concept: CLOB mid is the primary price reference. AMM price is not used in the anchor error calculation — it is retained as diagnostic context only. The anchor error is instead computed relative to a short-term rolling CLOB mid baseline:
Where rolling_clob_baseline is a recent EMA of CLOB mid prices (fast window, e.g., 30–60 ticks ≈ 2–4 minutes). The anchor then measures: has the CLOB mid drifted significantly from where it was recently? Large rapid drift = potential hostile regime.
What it blocks: - Rapid CLOB mid movement (directional price runs, flash crashes) - Large sudden spread changes that move the mid - Sustained mid drift in one direction over the rolling window
What it allows: - The CLOB-AMM structural basis is entirely ignored. The anchor is decoupled from AMM price. - Stable CLOB markets (even if AMM diverges) → anchor error ≈ 0 → ACTIVE - Slow drift (consistent with normal market making) → anchor error stays small → ACTIVE
Predicted behavior — S48 (07:00Z, overnight): - CLOB mid was stable (small spread, active bids/asks). Rolling baseline tracks it. Anchor error: ≈ 0–2 bps. - ✅ Correct: Engine stays ACTIVE. Same as Option 1.
Predicted behavior — S49/S50 (afternoon ET): - CLOB mid was stable throughout S49/S50 (2–9 bps spread, market_valid: true, active bids/asks). The structural CLOB-AMM gap was large but the CLOB itself was not moving erratically. - Anchor error under Option 2: ≈ 0–2 bps. Engine stays ACTIVE. - ✅ Correct: Engine would have been ACTIVE and quoting throughout.
Risks / open questions: 1. Loss of AMM price signal entirely. AMM price is a useful regime indicator even if the structural basis is large. If AMM price moves sharply away from the structural norm (e.g., large AMM LP event), Option 2 would not detect it unless the CLOB also moved in response. The anchor becomes blind to AMM-side distortions. 2. Overlap with directional drift guard. The directional drift guard already monitors for sustained fill-side imbalance (flow pressure). A CLOB-first anchor that monitors CLOB mid drift is partly redundant with drift guard. May create dual signals for the same condition, or gaps between them. 3. What ANCHOR_IDLE actually means changes. Under Option 2, ANCHOR_IDLE means "CLOB mid is moving too fast" — not "AMM divergence is elevated." This is a fundamentally different semantic. Requires re-specification of what the anchor is protecting against before implementation.
Implementation complexity: Low-Medium. Simpler than Option 1 in some ways (no cross-source baseline, no warm-up dependency on pair history). But requires a clear philosophical decision: is the anchor measuring AMM-CLOB relationship, or CLOB stability? If the former, Option 2 is the wrong direction.
Option 3 — Dual Signal¶
Concept: Separate the structural basis metric and the regime distortion metric into two distinct signals. Only the regime distortion metric drives ANCHOR_IDLE.
structural_basis = rolling_ema(amm_price - clob_mid, slow_window) # 200–400 ticks
regime_distortion = (amm_price - clob_mid) - structural_basis # residual
ANCHOR_IDLE fires on regime_distortion exceeding threshold, not on anchor_error (raw CLOB-AMM gap). Separately, structural_basis is surfaced as a monitoring metric: if it exceeds a configurable floor (e.g., 8 bps), it is logged as a structural pair warning but does not block trading on its own.
What it blocks:
- Same as Option 1: genuine regime distortions above the structural baseline
- Additionally: if structural_basis itself becomes extreme (e.g., >15 bps persistent), can optionally fire a separate structural pair warning without halting the engine
What it allows: - Normal trading in the presence of a persistent structural basis (afternoon ET) - Separate visibility into structural vs regime components (diagnostic value)
Predicted behavior — S48 (07:00Z, overnight): - Structural basis: ~3–6 bps (overnight). Regime distortion: ≈ 0 bps. ANCHOR_IDLE does not fire. - ✅ Correct. Same as Options 1 and 2.
Predicted behavior — S49/S50 (afternoon ET): - Structural basis: ~14–16 bps (afternoon EMA). Regime distortion: ≈ 0–4 bps (gap was stable, not rapidly expanding). ANCHOR_IDLE does not fire. - ✅ Correct. Engine stays ACTIVE and quoting. - Structural pair warning surfaced: yes (basis > 8 bps). Katja/Vesper informed. Engine trades anyway.
Risks / open questions:
1. Same EMA warm-up problem as Option 1. structural_basis needs time to converge. Same initialization strategy required.
2. More config surface. Two thresholds to calibrate: one for regime_distortion (ANCHOR_IDLE), one for structural_basis warning. More parameters = more ways to get it wrong.
3. Operational value of structural warning. If the structural basis is consistently 14–16 bps in the afternoon, the warning fires every afternoon. Does it add information Katja/Vesper doesn't already have? Or does it become noise? Needs an answer before implementation.
4. Conceptual clarity. Option 3 is Option 1 with an added monitoring layer. If Option 1 is the right anchor formulation, Option 3 is the natural way to implement it with full observability. The question is whether the structural basis warning adds operational value or just complexity.
Implementation complexity: Medium-High. More state to manage, more config, more logging paths. Recommended only if the separate structural basis monitoring is operationally useful.
Vesper Assessment¶
All three options solve the immediate problem (ANCHOR_IDLE exiting afternoon ET). The question is which correctly captures what the anchor is supposed to measure.
Option 1 is the cleanest architectural answer to the stated problem: the anchor should measure deviation from the pair's structural norm. It correctly answers the diagnostic question ("is the CLOB-AMM relationship behaving unusually?") while ignoring the structural background level.
Option 2 is simpler to implement but changes what the anchor is protecting against. If the intent is to detect AMM-CLOB relationship distortion, Option 2 is the wrong direction. If the intent is to detect CLOB stability, Option 2 is appropriate — but that's a different spec than what the anchor currently documents.
Option 3 is Option 1 with added observability. It's the right architecture if the structural basis metric has operational value. Given that this pair appears to have a significant and time-of-day-varying structural basis, having that as a visible diagnostic metric seems genuinely useful.
My read: Option 1 is the minimum correct fix. Option 3 is Option 1 done properly with full observability. If implementation complexity is acceptable, Option 3 is preferred because it surfaces the structural basis explicitly — which will be needed for Phase 7.4 signal validity evaluation anyway.
Cross-cutting issue that affects all options: EMA warm-up / cross-session basis initialization. Whichever option is selected, we need a decision on how to initialize the rolling baseline at session start. Recommendation: store the rolling basis value at session close in engine_state table, seed the next session's EMA from that stored value. Prevents cold-start cap-lock at the beginning of afternoon sessions.
Request for Atlas Ruling¶
Requesting your selection of one of the three options (or a modified formulation), and ruling on:
- EMA window parameters — slow window (structural basis): 200–400 ticks? Faster or slower? Fast window (regime distortion, if Option 3): same as current 30-tick anchor window?
- Cap recalibration — with residual-based anchoring, what should the ±N bps cap be set to? The signal is now centered near 0, so ±10 bps may be too wide; ±5–6 bps may be more appropriate.
- Entry/exit thresholds — does the current 6 bps entry / 4 bps exit spec hold for
regime_distortion? Or should these be recalibrated given the reformulation? - Cross-session basis persistence — store rolling basis at session close and seed next session? Or re-derive each session from scratch with warm-up?
- Structural basis warning level (Option 3 only) — what basis level triggers the structural pair warning? 8 bps? 10 bps? Suppress entirely?
Once ruling is received, Vesper will route to Orion for implementation.
— Vesper (COO) BlueFly AI Enterprises 2026-04-22