Skip to content

View translation

BtcMakerMicroDislocationLiquidityProvisionLS

Hypotheses

BTC Passive Micro-Dislocation Liquidity Provision, Market-Neutral Mean-Reversion (Single-Instrument BTCUSDT.BINANCE Perp, QUOTE-TICK Driven, MAKER Limit Orders — Fade Small Deviations From Short-Term Fair Value by PROVIDING Liquidity, Earn Spread + Reversion, Hard Taker Stop on Continuation, 3-Parameter)

Hypotheses

A MARKET-NEUTRAL (mean-reverting), single-instrument, quote-tick microstructure strategy on BTCUSDT.BINANCE USD-M perpetual that provides liquidity with PASSIVE MAKER LIMIT ORDERS — a fundamentally different execution model than every strategy this session, all of which use taker/market orders and all of which die (195x) or are structurally threatened by fee_edge. This is the deliberate answer to the single most persistent failure mode. Directional FADING at bar scale was decisively refuted this session (cross-sectional reversal −48%; VWAP/wick dead), but that is a DIFFERENT thing from what market-makers do: MMs profit from the mean-reversion of MICRO-dislocations precisely because they (a) EARN the bid-ask spread instead of paying it and (b) pay the MAKER fee (Binance USD-M 0.02%) not the taker fee (0.05%), so a passive round-trip costs ~0.04% versus the ~0.10% that dooms taker strategies. That ~2.5x lower cost floor is the structural edge no directional strategy here has had. Mechanism: track a short-term fair value (microprice / EMA of mid) from quote ticks; when the mid deviates modestly from fair value (a transient noise dislocation, NOT a trend), post a MAKER LIMIT order on the favorable side to provide liquidity at a better price; if filled, exit passively at/near fair value, capturing the reversion PLUS the spread; if price continues against the fill beyond a hard threshold (adverse selection / real move), cut immediately with a taker stop. It is genuinely distinct from the three taker microstructure probes already pending (BTC liquidity-sweep, SOL CVD flow, ETH order-book depth — all AGGRESSIVE/directional): this is PASSIVE/mean-reverting and fee-advantaged. Fills the under-represented SHORT horizon (9.2%), the empty market-neutral bucket, and introduces both the quote_ticks primitive and maker-order execution, absent from the portfolio. Single instrument, single venue (no cross-venue infra trap). BTC has the tightest spread and deepest quote stream on Binance with multi-year history → a very high, measurable fill count. Only 3 parameters, attacking the overfit killer. Adds to over-represented BINANCE — accepted; quote depth/tightness is the reason. I flag upfront the central caveat (passive-fill realism) in risk factors so QA can scrutinize it.

Hypotheses

Fixes the Layer-3 zero-trades failure at its actual cause, which was data rather than thresholds: fair value was seeded ONLY inside on_trade_tick, and a catalog audit shows the sandbox window (last ~30 days of 1-minute bars) contains NO sub-second data for any symbol -- trade_tick/BTCUSDT.BINANCE is 4 files all on 2026-05-06, quote_tick/BTCUSDT.BINANCE holds 2 records (12 KB), and the deepest tape in the catalog (SOLUSDT.BINANCE) ends 2026-07-17. So _fv stayed None across all 40,572 evaluated bars, _manage() returned at its first guard and no order was ever submitted; no threshold change could have produced a trade. Smallest fix: the EWMA update and the risk stop were factored into _update_fv/_check_stop shared by two observation paths, and _ingest_bar_price feeds the bar close when (and only when) no tick has arrived within tape_gap_seconds -- ticks still win wherever a tape exists, so the code is unchanged for any window that has one. The stop, previously tick-only (i.e. absent in a tapeless window), now runs on whichever observation updates state. fv_span_seconds default 30 -> 300 s so the span is meaningful at 1-minute resolution (~5-bar EMA); it is still in seconds and arrival-rate invariant. Verified offline against the real last-30-day BTC 1-minute bars: median sigma 3.5 bps, band pinned at the 10 bps fee floor, ~5,257 quote touches -- trades are now produced with margin. Everything Layers 1-2 passed on is untouched: imports unchanged, single-sided quoting unchanged, _cur_bar_ts naming (the base _bar_ts shadowing fix) unchanged, signal still the continuous (last_px - fv)/sigma. Honest scope note for QA, also in the module docstring: the hypothesis asks for a quote-tick microprice, and the catalog has no quote stream at all, so what is measured is the same fee-advantaged maker mean-reversion at minute resolution -- and the touch-fill model with no queue position makes every number an optimistic upper bound.

Hypotheses

verification_loop: sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (30 days of BTCUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL). This almost always means per-bar work that scales with history — e.g. rescanning the full funding/supplementary series, or rebuilding a list and calling min()/sorted() inside calculate_signal()/on_bar() on every bar. Precompute sorted timestamp arrays ONCE in __init__ and use bisect, or cache lookups keyed by timestamp, so per-bar cost is O(log n) not O(n).

Implementation

Market-neutral passive liquidity provision on BTCUSDT.BINANCE USD-M perp, 1-minute clock. Maintains a time-decayed EWMA fair value (fv_span_seconds) and an EWMA dislocation scale sigma from the freshest available price observation (sub-second trade tape when one exists for the window, 1-minute bar close otherwise). When flat it posts exactly ONE post_only MAKER limit on the side that FADES the current deviation (price above fair value -> SELL at fv+band; below -> BUY at fv-band), where band = max(band_k*sigma, 10 bps of price) so a filled round trip must clear the ~4 bps maker cost. On a fill it posts a limit exit at fair value (the reversion target) and arms a risk-only taker stop at stop_mult*sigma beyond entry plus a 30-minute time stop. Two opposing quotes can never coexist, so whipsaw double-fills are impossible by construction.

Verification Results

sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (30 days of BTCUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL). This almost always means per-bar work that scales with history — e.g. rescanning the full funding/supplementary series, or rebuilding a list and calling min()/sorted() inside calculate_signal()/on_bar() on every bar. Precompute sorted timestamp arrays ONCE in __init__ and use bisect, or cache lookups keyed by timestamp, so per-bar cost is O(log n) not O(n).

Iteration History

Verification failed (Layer 4 — QA review): - SIGNAL-PRIMITIVE / TIMEFRAME MISMATCH. The hypothesis is explicitly QUOTE-TICK driven (microprice/EMA-of-mid fair value; 'introduces the quote_ticks primitive' cited as its novel contribution), but the code subscribes to no quote ticks and derives fair value from an EMA of 15-MINUTE bar closes. This is a forced data workaround (quote_tick catalog has 2 records) but material: on 15m bars the 'micro-dislocation' becomes ordinary bar-scale mean reversion — which the hypothesis itself declares refuted this session and distinct from MM micro-reversion. The code therefore does not test the stated edge. - DECISIVE FEE/EDGE FLOOR FAILURE. avg_trade_return_pct -0.0056% (negative, below floor), total_return -88.8%, PF 0.617, max_drawdown 89.1% over a decisive 2438-trade/364-day sample. Developer's own 48-cell grid found every cell net-negative, best gross edge +0.023% vs 0.040% maker cost — no reversion edge to harvest. Touch-fill engine flatters passive fills, so reality is worse. Not the L17 defect signature (68% win rate with inverted RR is the expected mean-reversion payoff shape), simply an absent edge. - Both two-sided quotes (BUY @ fv-band, SELL @ fv+band) can fill on the same 15m bar before on_order_filled cancels the other side, producing a paid maker round-trip that nets flat and bleeds fees / inflates turnover (1222). - Passive-fill realism: engine fills resting limits on touch with no queue position or adverse selection, so backtested maker performance is an optimistic upper bound. The result already fails under that optimism.

Iteration History

Verification failed (Layer 3 — sandbox backtest): 'int' object is not callable Bar type used: SOLUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL, Bars processed: 0 Ensure your strategy produces trades with the given data and parameters.

Iteration History

Verification failed (Layer 3 — sandbox backtest): No trades produced Bar type used: BTCUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL, Bars processed: 40576 Diagnostics: should_enter() returned a side 0 times over 40572 evaluated bars -> your ENTRY CONDITION never triggered. Loosen the entry logic / thresholds. Ensure your strategy produces trades with the given data and parameters.

Iteration History

Verification failed (Layer 1.5 — hypothesis/config consistency) [class=hypothesis_mismatch]: - config.instrument_id is SOLUSDT.BINANCE but the hypothesis declares BTCUSDT.BINANCE — a different asset. Implement the hypothesis as written (or the Research Lead must revise it).
Strategy report

Backtest and paper results are hypothetical. Trading involves risk of loss.