Skip to content

View original

BtcOrderFlowImbalanceContinuationLS

Hypotheses

BTC Trade-Tick Order-Flow Imbalance Continuation (Intraday, Long-Short, Binance USD-M Futures, Sustained Taker-Aggression Signal, Fee-Clearing Targets, Capital-Capped)

Hypotheses

The FIRST microstructure / trade-tick strategy in the 1,174-experiment portfolio (short-horizon bucket 2.4% vs >=10% quota; order-flow class entirely absent). A LONG-SHORT, SINGLE-INSTRUMENT intraday strategy on BTCUSDT.BINANCE USD-M perpetual that trades SHORT-HORIZON CONTINUATION driven by ORDER-FLOW IMBALANCE (OFI) -- the net of aggressive taker-buy vs taker-sell volume -- computed from TRADE TICKS (aggTrades), a crypto-native edge invisible in OHLCV bars. Thesis: bursts of sustained one-sided AGGRESSIVE flow (informed/forced order flow lifting the offer or hitting the bid) precede short continuation in the same direction before the book refills; entering with that flow and exiting on a fee-clearing move captures the continuation. EVERY design choice respects this session's binding lessons: (1) TRADE_TICKS as the data source -- aggTrades have FULL Binance Vision history (NOT the thin-history supplementary 'taker_ratio'/OI/liquidation streams that died 0-for-7 with final-window trade-clustering); the data-coverage wall does not apply to core tick data. (2) CONTINUATION direction, not fade -- crypto intraday CONTINUES (every intraday-fade/VWAP-reversion died: SOL -80%, BTC -90.5%); OFI-continuation aligns with the validated direction. (3) FEE-AWARE BY CONSTRUCTION -- enters only on STRONG sustained aggression and targets a ~0.4% move (~0.3% net after ~0.10% RT taker), well above the 0.15% futures floor, holding MINUTES; this is explicitly NOT scalping (sub-0.15% tick-chasing is the banned anti-pattern) and NOT 100+ tiny-PnL trades/day. (4) BTC -- deepest book, tightest microstructure -> best OFI signal-to-noise and lowest slippage. (5) LONG-SHORT (under-target 13% direction), FUTURES (clean discrete sizing, can short; the right venue, NOT engine-blocked like options/COIN-M and NOT data-starved like HL). (6) CAPITAL-CAPPED sizing against STABLE realized equity, hard-capped <=100% -- the explicit fix for the recurring >100%-notional inflation bug. Intentionally minimal: 3 tunables (ofi_window, ofi_threshold, take_profit_pct). HONEST: this is high-novelty/high-quota-value but survival-uncertain (fee drag and tick-data sandbox availability are the two failure modes), priced at priority 3.

Hypotheses

Iteration 3 restores the PRE-REGISTERED data path that QA flagged as substituted: OFI is derived only from trade ticks and config.subscribe_trade_ticks is now TRUE, so on_trade_tick actually runs; the 5-minute taker_ratio/metrics mirror is gone entirely, with no fallback mechanism (missing ticks -> flat OFI -> no trades, fail loud). To address the fee-graveyard evidence (98% commission/gross, 0.025% avg trade), selectivity and targets were raised: ofi_threshold 0.35 -> 0.45, min_ticks 10 -> 300, take_profit 0.4% -> 0.6% (~0.5% net), stop 0.3% -> 0.35%, hold cap 30 -> 20 bars, and min_notional set to BTCUSDT's real 100 USDT floor. Only parameter values and the subscription flag changed - the signal, tick hot path, sizing and exit structure that passed Layers 1-3 are untouched. HONEST CAVEAT (see recommendation): the catalog currently holds BTCUSDT.BINANCE trade ticks for a single day, 2026-05-06, while ~29 days of raw aggTrades sit unconverted in data/supplementary/agg_trades/BTCUSDT (2026-05-06..2026-06-03). Because check_catalog_availability applies its min_days span test to bars only, the millions of stale 2026-05-06 ticks count as 'sufficient', so pipeline auto-collection will not refresh them, and the recent sandbox window will receive zero ticks in range - the same structural cause as iteration 1's zero-trade failure. Even if the window did align, ~90M BTC aggTrades over a 30-day window are unlikely to replay inside the 300s Layer-3 wall clock.

Hypotheses

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

Implementation

BTCUSDT USD-M perpetual, long-short intraday continuation on trade-tick order-flow imbalance. OFI = (taker-buy volume - taker-sell volume) / total aggressive volume over a trailing 60-second window, computed exclusively from aggTrades TRADE TICKS in on_trade_tick() using per-second buckets with O(1) incremental aggregates. Decisions are taken once per 1-minute bar: OFI >= +0.45 with >= 300 aggressive ticks in the window enters LONG, OFI <= -0.45 enters SHORT. Exits on a 0.6% take-profit (~0.5% net of ~0.10% round-trip taker), a 0.35% stop, or a 20-bar time stop. Sizing is 20% of realized equity, hard-capped at 100% notional, leverage 1.0. If no trade ticks arrive, OFI stays 0 and the strategy stands aside - there is no supplementary-stream or OHLCV fallback.

Verification Results

Verification failed (Layer 3 — sandbox backtest): No trades produced Bar type used: BTCUSDT.BINANCE-1-MINUTE-LAST-EXTERNAL, Bars processed: 40279 Diagnostics: should_enter() returned a side 0 times over 40277 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 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit. 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) [class=hypothesis_mismatch]: - [edge_concern] Supporting evidence for the mismatch, not an independent verdict: the backtested 5-minute-mirror artifact degenerated into exactly the scalping fee-graveyard the hypothesis promised NOT to be. Commission is 98.03% of gross, avg_trade_return_pct 0.025% (vs the 0.15% floor and the claimed ~0.3% net target), Sharpe -6.6, PF 0.425, 612 trades / 67 days, turnover 1275. Even if re-registered as a 5-minute taker-flow strategy it is fee-dead here and belongs to the taker-flow family the hypothesis itself cites as 0-for-7. If the tick-level hypothesis is pursued instead, the aggTrades history must first be collected so the actual mechanism can be tested. - DATA-SOURCE / MECHANISM SUBSTITUTION vs the pre-registered hypothesis. The hypothesis's #1 binding design choice and its entire novelty ('FIRST microstructure / trade-tick strategy') is that OFI comes from aggTrades TRADE TICKS, and it EXPLICITLY excludes the supplementary taker streams ('NOT the thin-history supplementary taker_ratio/OI/liquidation streams that died 0-for-7'). Iteration 2 does exactly what the hypothesis excludes: _ensure_flow_series() reads OFI from the 5-minute taker_ratio and metrics mirrors, and config.subscribe_trade_ticks is FALSE, so on_trade_tick never runs in the backtest. The tested artifact is a 5-minute aggregated taker-flow strategy -- the exact family the hypothesis names as dead -- not the tick-level edge that was pre-registered. A unilateral in-code data-source reformulation made to escape iteration 1's zero-trade failure. - Subscription-flag inconsistency (check 12): the strategy overrides on_trade_tick() but subscribe_trade_ticks is false, so the tick handler is never called and the tick OFI path is dead in every backtest. Deliberate (1-day tick history fails the data-sufficiency gate), but it is the mechanical confirmation that the hypothesis's core data path is disabled.

Iteration History

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

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