Liquidity Mirage Detection: Cancel-Trade Divergence Slippage Playbook

2026-02-26 · finance

Liquidity Mirage Detection: Cancel-Trade Divergence Slippage Playbook

Date: 2026-02-26
Category: Research (Execution / Slippage Modeling)
Scope: Intraday equity execution (KR-first, portable to other lit venues)


Why this model exists

Top-of-book depth can look healthy right before execution cost blows up.

The failure mode is a liquidity mirage:

If the router trusts displayed depth as if it were durable inventory, it over-allocates passive risk and pays late-stage slippage.

This playbook introduces a production-first detector for that failure mode and links it to live execution controls.


Core concept

Model displayed liquidity as two components:

  1. Durable liquidity: survives long enough to be meaningfully interactable.
  2. Ephemeral liquidity: frequently canceled/repriced before interaction.

Define latent mirage state:

[ M_t \in {\text{Normal}, \text{Watch}, \text{Mirage}} ]

The controller switches policy by mirage probability, not by naive visible size.


Signal stack

1) Cancel-Trade Divergence (CTD)

Within short rolling window (w):

Define:

[ CTD_t = \frac{C_t - \alpha X_t}{\epsilon + X_t + \beta A_t} ]

Interpretation:

Bucket-normalize by symbol × time-of-day:

[ Z^{CTD}t = \frac{CTD_t - \mu{bucket}}{\sigma_{bucket}} ]


2) Queue Half-Life (QHL)

Track resting volume cohorts and estimate survival function (S(\tau)) under cancellations/executions.

Define queue half-life:

[ QHL_t = \inf{\tau : S(\tau) \le 0.5} ]

Very short QHL means the queue decays fast (ephemeral book).

Use robust transformed feature:

[ Z^{QHL}t = -\frac{\log(QHL_t) - \mu{\log QHL,bucket}}{\sigma_{\log QHL,bucket}} ]

(negative sign so higher = worse durability)


3) Refill Quality Ratio (RQR)

Not all replenishment helps. Distinguish refill that survives vs instantly cancels.

[ RQR_t = \frac{\text{added volume surviving }\ge \tau_s}{\epsilon + \text{total added volume}} ]

Low RQR + high CTD is a strong mirage signature.


4) Touch Stability Drift (TSD)

Measure how often best quotes mutate without meaningful trade conversion.

[ TSD_t = \frac{\text{touch updates without conversion}}{\epsilon + \text{total touch updates}} ]

This catches "visual churn" where quotes refresh but executable quality degrades.


Composite Mirage Score

[ MS_t = w_1 Z^{CTD}_t + w_2 Z^{QHL}t + w_3 (1-RQR_t) + w_4 TSD_t + w_5 \Delta s_t + w_6 \hat{\sigma}{short,t} ]

where:

Do not hard-threshold (MS_t) directly. Feed it to probabilistic state modeling.


Modeling architecture

A) Fast state model (classification)

Train calibrated classifier for (M_t):

Output:

[ P_t = (P(Normal), P(Watch), P(Mirage)) ]

B) Tail-risk model (quantile)

Separately estimate conditional slippage quantiles for short horizons (e.g., 30s/60s/180s):

This model handles cost severity if Mirage is true.

C) Sticky transition filter

Use hysteresis / HMM smoothing to avoid mode flapping:


Labeling design

Target future implementation shortfall over horizon (h):

[ Y_{t,h} = IS_{t\to t+h} ]

Regime labels can be built from forward outcomes + microstructure context:

Use purged time splits to avoid leakage from overlapping windows.


Execution controller mapping

Let (B_t) be remaining slippage budget (bps).

Mode 1: Normal

Mode 2: Watch

Mode 3: Mirage

Budget breach trigger example:

[ \Pr(\text{budget breach} \mid P_t, q95_t, remain_qty) > \theta_B \Rightarrow \text{defensive mode} ]


Production feature minimum


Evaluation protocol

Offline

Primary objective:

Secondary:

Use day-block bootstrap by liquidity cohorts.

Shadow to staged rollout

  1. Shadow decisions only (no capital impact).
  2. Small-capital rollout in liquid names.
  3. Expand universe with hard stop guardrails.

Hard stop examples:


Reliability & drift guards

Never run Mirage controller on stale queue-survival inputs.


Practical KR deployment notes


Pseudocode

for t in decision_ticks:
    x = build_features(ctd, qhl, rqr, tsd, spread, vol, own_exec)
    p = state_model.predict_proba(x)      # Normal/Watch/Mirage
    q95 = tail_model.predict(x, q=0.95)

    state = sticky_filter.update(p)
    breach = breach_prob(slippage_budget, q95, remain_qty, state)

    if breach > THETA_B:
        mode = "MIRAGE_DEFENSIVE"
    else:
        mode = policy_map(state)

    action = execution_policy(mode, market_state, remain_qty)
    send(action)

What this improves

If implemented well:


Next experiments

  1. Cross-venue mirage transfer: does one venue’s mirage predict another’s shortly after?
  2. Conformal mirage probability bands for stronger online risk coverage.
  3. Metaorder interaction term: mirage sensitivity as function of own participation and slicing cadence.
  4. Joint optimization of slippage tail + underfill with explicit constraints.

One-line takeaway

Displayed depth is not liquidity; it is a hypothesis. Mirage detection tests that hypothesis before your slippage budget pays the tuition.