Skip to content

View translation

BtcOrderFlowImbalanceContinuationTickDriven

Hypotheses

BTC Order-Flow Imbalance Continuation, Long-Short (Single-Instrument BTCUSDT.BINANCE Perp, TRADE-TICK Driven — Cumulative Volume Delta / Taker-Aggression Imbalance, Enter WITH Extreme Sustained Aggressive Flow, Fee-Aware High Threshold, Minutes-to-Hour Holds, 3-Parameter)

Hypotheses

A LONG-SHORT, single-instrument strategy on BTCUSDT.BINANCE USD-M perpetual that trades from TRADE-TICK order flow — a fundamentally different data primitive (trade_ticks) than every bar-based strategy this session, which have all died. The evidence forces this shift: the dual-timeframe momentum-confluence family — the factory's supposed flagship — is now conclusively dead (BTC-HL PF 0.954, ETH-Binance Sharpe 0.433 over 719 trades, BNB/DOGE PF ~1.19, 3-major basket Sharpe 0.319 over 2148 trades — ALL abandoned this session; the BTC-Binance Sharpe 1.99 was a lucky single fit). OHLCV bars simply do not carry a tradeable directional edge on majors net of fees. This strategy instead reads the MICROSTRUCTURE the anti-pattern guide explicitly steers toward: it computes a rolling CUMULATIVE VOLUME DELTA (signed taker volume = aggressive-buy minus aggressive-sell volume) from the raw trade tape, and enters in the direction of EXTREME, SUSTAINED aggressive flow — the footprint of informed/urgent participants whose order flow tends to precede short-term price continuation before liquidity replenishes. It is crypto-native (this order-flow signal does not exist in OHLCV), and it is deliberately distinct from the dead bar-aggregated taker strategies (TakerFlowPriceDivergence, which FADED flow and had inverted RR): this goes WITH strong flow, not against it. The single most important design choice is FEE-AWARENESS: order-flow edges are tiny per event, so the strategy uses a HIGH imbalance threshold to fire ONLY on the rare extreme-flow events that historically precede a continuation move larger than the ~0.10% round-trip cost, holding minutes-to-an-hour for a target that clears fees — trading infrequently by design rather than scalping every tick (the classic microstructure fee-death). Fills the under-represented SHORT horizon (8.9% vs 10% target) and long_short direction (13.6%), and introduces the trade-tick data primitive absent from the portfolio. Single instrument, single venue (no cross-venue infra trap). BTC has the deepest, cleanest tick tape on Binance with multi-year history → high, statistically-measurable trade count. I acknowledge it adds to the over-represented BINANCE venue; tick-data depth and quality are the reason, and this is an exploratory bet into the one encouraged niche the factory has not tested.

Hypotheses

Fixes exactly the reported Layer-3 failure — should_enter() returned a side 0 times over 40,575 bars — and nothing else. Two causes, both diagnosed against the actual catalog. First, the signal source was empty: BTCUSDT's trade_tick tape in this catalog is a single day (2026-05-06), outside the sandbox window (~2026-08-05 to 09-02), so _volume_sum was 0 on every bar and the stand-aside guard correctly returned None. The strategy now falls back to the `taker_ratio` supplementary feed, which is the SAME primitive (aggressive taker buy vs sell VOLUME, signed by aggressor side) pre-aggregated by the exchange into 5-minute buckets to 2026-08-02 and hourly buckets after — not a price-derived proxy and not a different edge mechanism; the strategy still goes WITH extreme aggression, never fades it, and stands aside entirely when neither source has data. Reads are point-in-time (a bucket becomes usable only when the next bucket opens, since the timestamp is the period open) and aggregated over a fixed wall-clock window so the 5-minute and hourly eras yield the same quantity. Second, the 0.35 absolute threshold was uncrossable on aggregated flow: measured on the real BTCUSDT taker feed in the sandbox window, hourly imbalance has std 0.11, a 90th percentile of 0.18 and a maximum of 0.35, while the 5-minute era's 90th percentile is 0.40 — one constant cannot serve both. The gate is now a rolling percentile of the strategy's own |flow| history (lesson: scale-invariant thresholds, not fixed constants), which preserves the hypothesis's central fee-aware design ('fire only on rare extreme flow') while making the firing rate predictable. Replaying the real feed over the sandbox window, the gate fires on 1,846 of 40,320 bars across 31 distinct episodes, so the run will produce a measurable trade sample instead of zero. Everything that already passed is untouched: imports stay clean (numpy only), the tick handler, CVD math, exits, sizing and the 3-parameter surface are unchanged in structure; the instrument returns to BTCUSDT.BINANCE as the hypothesis of record specifies.

Hypotheses

negative expectancy on an adequate sample: profit_factor 0.10, total_return -36.1%, avg_trade_return_pct -0.0105% (negative, well below the fee floor), Sharpe -0.71 across 648 trades with every active month negative. The QA edge concern is confirmed on full history — the ~6x loss/win asymmetry (avg_loss 93.8 vs avg_win 17.4) under a symmetric bracket is adverse selection: going WITH extreme taker aggression buys exhaustion tops and sells capitulation lows. This falsifies the CONTINUATION direction of the mechanism, not its parameters. Optimizing 3 params (flow_window, percentile, target) cannot invert a wrong-signed edge, so this is not worth the 3-phase run. (Research Lead note: the FADE variant of the same flow signal is the reframe implied by this result, but that is a new premise, not a tuning of this one.)

Implementation

Long-short taker-aggression continuation on BTCUSDT.BINANCE USD-M perp, decisions on 1-minute bars. Signal = normalized aggressive-flow imbalance (buy volume minus sell volume over total taker volume, in [-1,+1]) measured over a fixed 1-hour wall-clock window, read from the raw trade tape when it is live and otherwise from Binance's taker buy/sell volume buckets (the same statistic, exchange-aggregated, read point-in-time so a still-forming bucket is never used). The strategy enters WITH the flow — long on extreme aggressive buying, short on extreme aggressive selling — where 'extreme' is a rolling percentile (top 4%) of the strategy's own recent |flow| distribution rather than a fixed constant. Exits are fee-aware and time-boxed: a 0.25% profit target (2.5x the ~0.10% round-trip taker cost), a symmetric stop, and a hard 60-minute hold cap anchored to bar timestamps. Fixed 25%-of-equity notional, leverage 1.0, BTCUSDT's 100 USDT minimum notional enforced.

Verification Results

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

Verification Results

Analyst: evaluate over the flow-covered window (2026-03-23 onward via taker_ratio); do not treat the multi-year backtest span as measurable trading history. No code change required for correctness.

Verification Results

The hypothesis is titled/justified as 'TRADE-TICK Driven' and claims BTC's multi-year tick tape as its novelty, but the catalog's BTCUSDT trade_tick tape is one day (2026-05-06). In practice the strategy executes on the taker_ratio bucket fallback, not raw ticks. The fallback IS the same signed-taker-volume primitive (buy_vol-sell_vol / total), read point-in-time, so the EDGE mechanism is faithful -- this is a data-source substitution of the same statistic, not a different strategy -- but the claimed tick-primitive contribution is essentially unexercised.

Verification Results

Advisory: if the mechanism shows promise on full history, consider bracket/stop-market orders so the stated stop is honored intra-bar rather than at the next 1-minute close.

Verification Results

avg_holding_bars reports 0.0 with symmetric 0.25% brackets on 1-minute bars, and avg_loss is ~6x avg_win. Exits are checked at bar close, so a >0.25% adverse move between bars is realized well past the stop level (slippage-through), while wins are capped near target -- an inherent limitation of bar-close bracketing on a fast microstructure signal, not a bug. use_bracket_orders is not set, so intra-bar stop protection is absent.

Verification Results

Two doubts for the analyst to weigh on full history (neither blocks): (1) The sandbox signature is extreme-negative (Sharpe -10.9, PF 0.052, win_rate 0.24, avg_loss 93.7 vs avg_win 15.5 = ~6x asymmetry DESPITE symmetric 0.25%/0.25% brackets). I verified this is NOT a unit/exit bug: get_position_pnl_pct returns percent (x100) so `pnl_pct >= profit_target_pct*100` is correct, polarity goes WITH flow as the hypothesis states, sizing is linear/non-inverse. The asymmetry is adverse selection: entering WITH extreme taker aggression tends to buy exhaustion tops / sell capitulation lows, so losses gap past the stop harder than wins reach target. If this persists on full history, the mechanism's DIRECTION (continuation vs fade) is falsified rather than mis-parameterized. (2) The hypothesis's defining premise -- a 'deepest, multi-year tick tape' introducing the trade-tick primitive -- is false against the actual catalog: the BTCUSDT trade_tick tape is a SINGLE day (2026-05-06). The code therefore runs almost entirely on the taker_ratio fallback (same signed-taker-volume statistic, legitimately, and read point-in-time), which only begins 2026-03-23. Effective active-trading window is ~5.5 months; the tick handler is dormant across the backtest and most of the multi-year window is flat/stand-aside. Trade count is still likely measurable (~50 trades/28d in sandbox -> ~275 over the live window), but the analyst should judge edge only over the flow-covered span, not the full flat history.

Backtest Review

Mechanism is faithfully implemented and matches the hypothesis: enters WITH flow (continuation), long_short, point-in-time flow reads, fee-aware brackets.

Backtest Review

Sample is measurable (648 trades over the ~5.5-month flow-covered window; ~152 daily obs), so the result is a real read on the edge, not noise.

Backtest Review

Negative expectancy on a reliable sample: profit_factor 0.10, total_return -36.1%, avg_trade_return_pct -0.0105% (NEGATIVE, below any fee floor), Sharpe -0.71.

Backtest Review

Severe adverse-selection asymmetry: avg_loss 93.8 vs avg_win 17.4 (~6x) DESPITE a symmetric 0.25%/0.25% bracket, with return_skew -3.07 and win_rate 0.36. Entering with extreme taker aggression buys exhaustion tops / sells capitulation lows.

Backtest Review

Every month in the active window is negative (Mar -2.2% through Aug -4.4%); loss is consistent, not window-specific — the CONTINUATION direction is falsified, not mis-tuned.

Backtest Review

The hypothesis's defining premise (deep multi-year tick tape) is false against the catalog (one day of ticks); the strategy actually runs on the taker_ratio fallback over ~5.5 months and stands aside for the rest of the multi-year window.

Iteration History

Verification failed (Layer 4 — QA review): - DATA STARVATION — the strategy's required primitive (trade_tick) is absent, so it cannot be validated. The developer checked before writing logic and found BTCUSDT.BINANCE trade_tick coverage is exactly ONE DAY (2026-05-06): the tape is present for ~0.3% of the 365-day sandbox and effectively nothing of a multi-year backtest. Systemic, not symbol-specific (4,046 trade_tick dirs, only 316 MB total, sampled ones empty), and src/data/on_demand.py has NO tick-collection path — so unlike missing bars the tape will NOT be auto-fetched; it needs a Data Engineer aggTrades->trade_tick backfill. The sandbox confirms it: 34 trades, ALL from the single 2026-05-06 day, with degenerate metrics that are artifacts of ~1 day of data (PF 0.18, Sharpe -1.07, skew -16.7, kurtosis 294, PSR 0.0024), not a real edge. No parameterization or code change fixes this. - The code is CORRECT and faithfully implements the hypothesis, with the RIGHT integrity choices. on_trade_tick signs each print by aggressor side (BUYER -> +size) into a rolling CVD with O(1) running sums and timestamp eviction; imbalance = signed_sum/volume_sum in [-1,1]; entry fires at |imbalance| >= threshold WITH the flow (continuation, correctly distinct from the dead taker-divergence FADE); fee-aware exits (0.25% target ~2.5x round-trip, symmetric stop, 60-min bar-ts-anchored cap); fixed-fraction sizing with min-notional. Critically, subscribe_trade_ticks=true correctly matches the on_trade_tick override (handler will be called), and the developer deliberately added NO OHLCV-proxy fallback — it stands aside when the tape is absent rather than fabricating a signal from bars, exactly the silent-substitution failure the guidelines forbid. NO code defect.

Iteration History

Verification failed (Layer 4 — QA review): - DATA STARVATION persists — the strategy still cannot be validated, now EXHAUSTIVELY confirmed. The developer audited every repo source that could carry aggressor-signed volume: trade_tick = 1 day (2026-05-06); agg_trades (the tape's upstream) = 29 days; taker_ratio supplementary = 4.3 months at HOURLY resolution only; and Binance Vision klines drop the taker-volume column on Bar conversion. None supplies the tick-level signed flow at usable length, and on_demand.py has no tick-collection path so it will not self-heal. The sandbox is unchanged from iteration 1: 34 trades ALL from the single 2026-05-06 day, with degenerate one-day artifacts (PF 0.18, Sharpe -1.07, skew -16.7, kurtosis 294, PSR 0.0024), not an edge. No code change resolves this; it requires a Data Engineer aggTrades->trade_tick backfill. - The code is CORRECT (unchanged from the iteration-1 version QA confirmed) and the developer's integrity choices are exemplary. Aggressor-signed rolling CVD with O(1) eviction; continuation-WITH-flow entry (correct polarity, distinct from the dead taker-divergence fade); fee-aware time-boxed exits; subscribe_trade_ticks=true correctly matching the on_trade_tick handler; NO OHLCV-proxy fallback. The developer did NOT switch to taker_ratio (only 4.3 months, hourly resolution collapses the tick primitive — a different, weaker experiment), did NOT add a price-derived proxy (silent substitution), and did NOT re-tune the threshold to manufacture a trade count from one unrepresentative day. The exhaustive audit is itself valuable so no one repeats it. NO code defect.

Iteration History

SolOrderFlowImbalanceContinuationTickDriven

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.