Skip to content

View translation

BtcTradeFlowImbalanceContinuation

Hypotheses

BTC USD-M Trade-Flow Imbalance Continuation, Long-Short (BINANCE Perp, TRADE-TICK Driven Order-Flow Aggression Signal Aggregated to a Rolling Window, Ride Sustained Taker Imbalance for ~15-60min, ATR Target/Stop, 3-Parameter)

Hypotheses

A LONG-SHORT, single-instrument microstructure strategy on BTCUSDT.BINANCE (USD-M perpetual) driven by the TRADE-TICK aggressor feed (data_requirements: trade_ticks) rather than OHLCV bars — a data primitive that <2% of the 1554-experiment portfolio uses, so it is structurally novel versus the bar-based reversion/momentum/rotation strategies that dominate the book. Mechanism: aggregate the raw trade feed into a rolling Order-Flow Imbalance (OFI = (buy-aggressor volume - sell-aggressor volume) / total volume) over a trailing window; when OFI is strongly and persistently one-sided AND price confirms with a fresh micro-extreme, take a position in the direction of the flow and ride the short continuation, exiting on an ATR-scaled target/stop or flow decay. This is deliberately CONTINUATION, not reversion (distinct from the SOL VWAP-reversion and ETH pivot-reversion siblings), and it is NOT bar-momentum (the signal is aggressor imbalance, invisible in OHLCV). It avoids every recent graveyard: no funding-level signal (L13), no liquidations feed (L3), no options (L23), no cross-sectional/dollar-neutral basket (L12), no cross-venue carry (L1), no Hyperliquid (L11), no majors rotation (L24), no 200-SMA regime timing. It fills the two most under-represented survivable buckets — LONG-SHORT (14.9% vs a book that is 85% long-only) and SHORT-horizon 1m-15m (5.6% vs >=10% target) — while introducing a fresh data source. Routed to BINANCE because its BTCUSDT aggregated-trade history is deep and full (multi-year) — the only venue whose tick feed supports proper short-horizon validation (Hyperliquid tick history is too shallow, L11).

Hypotheses

Fixes the reported Layer-3 'should_enter returned a side 0 times over 19,470 bars' with the two changes that can cause it, and nothing else. (1) Flow coverage: the entry gate required len(self._flow) >= min_ticks, so a sandbox window without trade-tick coverage pinned OFI at 0.0 and made an entry impossible. The strategy now falls back to Binance's published taker BUY/SELL volume (taker_ratio) -> OFI_supp = (buyVol - sellVol)/(buyVol + sellVol) over the SAME 15-minute window. That is the identical primitive the hypothesis specifies (taker aggressor imbalance), exchange-aggregated rather than tick-reconstructed — not a price-only proxy and not a different edge; if BOTH sources are empty the strategy stays flat rather than substituting anything. The lookup is point-in-time (observations at or before the bar), O(log n) via a once-built sorted timestamp array plus prefix sums, with a staleness guard, so it adds no per-bar history rescan and cannot re-trigger the earlier timeout class. (2) Gate width: |OFI| >= 0.18 AND a fresh 3-bar extreme is a conjunction that fires almost never on 5m BTC; defaults loosen to 0.12 and a fresh 2-bar extreme, keeping both conditions but at a firing rate that produces trades. Everything that already passed — tick handler, O(1) window maintenance, ATR stop/target with intrabar detection, the no-sub-fee-scratch decay gate, the fee-viable target gate, deterministic fixed-fraction sizing, imports and class structure — is unchanged. Config now also declares _param_bounds matching the hard clamps in __init__ so the optimizer cannot search values the code silently rewrites.

Hypotheses

Negative expectancy on a reliable 883-trade / 6.6-year sample: profit_factor 0.27, avg_trade_return_pct -0.011% (below zero), Sharpe -1.64 with a fully-negative CI, and consistent losses across every regime and month. The taker-imbalance continuation signal is gross-negative before fees (commission is 170% of gross profit), so optimization/threshold-tuning cannot lift an edge that does not exist. Not worth 2 hours of optimization.

Implementation

Long-short BTCUSDT.BINANCE USD-M perp continuation strategy on taker aggressor imbalance. Trade ticks are accumulated into a 15-minute trailing window of signed volume; OFI = (buy_vol - sell_vol) / total_vol in [-1,1]. On each 5-minute decision bar, a |OFI| >= 0.12 one-sided flow reading confirmed by a fresh 2-bar price extreme in the same direction opens a position WITH the flow. Exits: ATR-scaled stop (1.5xATR) and target (2.5R) detected intrabar on the bar low/high, a flow-decay exit gated on the trade already clearing the round-trip fee, and a 60-minute time stop. Sizing is a deterministic 10% of equity notional. If the tick feed carries no coverage the strategy reads the same aggressor primitive from Binance's published taker buy/sell volume (taker_ratio); with neither source it stays flat.

Verification Results

Verification failed (Layer 3 — sandbox backtest): No trades produced Bar type used: BTCUSDT.BINANCE-5-MINUTE-LAST-EXTERNAL, Bars processed: 19484 Diagnostics: should_enter() returned a side 0 times over 19470 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

At optimization, cut trade frequency and lift per-trade capture: raise ofi_threshold, lengthen hold/raise tp_rr, gate the flow-decay exit harder. Abandon if avg_trade_return_pct can't exceed 0.15%.

Verification Results

High turnover (934 trades/67d, commissions 141.8% of gross) fee-death — the recurring continuation pattern (L6/L16), not a code bug. Avg holding 34m matches the thesis but per-trade capture is 0.033% vs 0.10% round-trip cost.

Verification Results

Confirm the tick feed drives the signal over the full window so the microstructure edge is what's measured.

Verification Results

taker_ratio fallback (used only when tick window empty) is the same aggressor-imbalance primitive, exchange-aggregated, read point-in-time with a staleness guard — faithful substitute, not a different edge. Sandbox used the tick path (934 trades fired).

Backtest Review

Faithful, well-instrumented implementation: 883 entries fired over 702k bars (6.6yr span), so the 'no trades' problem from earlier iterations is fixed and the sample is statistically ample.

Backtest Review

Deterministic fixed-fraction sizing, ATR stop/target, and a point-in-time supplementary fallback are cleanly built.

Backtest Review

Negative expectancy on a large, reliable sample: profit_factor 0.27, avg_trade_return_pct -0.011% (below zero, not just below the 0.15% fee floor), win_rate 37.9%, expectancy -$14.90/trade.

Backtest Review

Sharpe -1.64 (CI [-2.51, -1.40], entirely negative), Sortino -0.29, total_return -13.2%, information_ratio -0.93, alpha -2.1%.

Backtest Review

Losses are consistent across regimes (calm -8.0%, normal -9.8%) and every month shown is negative — this is not a curve-fit window, the continuation edge simply does not exist as coded.

Backtest Review

Commission is 170% of gross profit — the strategy is gross-negative, so no fee reduction or threshold retune can rescue it.

Iteration History

Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['tp_rr', 'risk_pct', 'min_ticks', 'atr_period', 'decay_frac', 'max_hold_sec', 'min_notional', 'atr_stop_mult', 'ofi_threshold', 'max_gross_frac', 'ofi_window_sec', 'size_precision', 'confirm_lookback'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: TypeError: BtcTradeFlowImbalanceContinuation._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690440000) - steady_downtrend: TypeError: BtcTradeFlowImbalanceContinuation._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690440000) - flat_ranging: TypeError: BtcTradeFlowImbalanceContinuation._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690440000) - volatility_spike: TypeError: BtcTradeFlowImbalanceContinuation._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690440000) - zero_volume: TypeError: BtcTradeFlowImbalanceContinuation._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690440000) - price_gap: TypeError: BtcTradeFlowImbalanceContinuation._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735690440000)

Iteration History

Verification failed (Layer 4 — QA review): - STRUCTURAL FEE-DEATH. commission_pct_of_gross 677.34% — fees ~6.8x gross P&L (1192 commission vs ~176 gross). Not a sample artifact: avg_win $29.34 is smaller than the ~$49.7/trade commission (1192/24), so a WINNING trade doesn't cover its own round-trip fee. On ~$50k notional, winners capture ~0.06% and losers ~0.28% — the 5m ATR-target moves are below the ~0.10% round-trip taker cost. PF 0.07, win_rate 0.25, avg_trade_return_pct -0.0157%. The tick-continuation-gated-on-5m churn (turnover 6006% in one day) can't clear fees (L6/L16). - NON-DIAGNOSTIC / UNMEASURABLE BACKTEST. Sandbox ran over data_days=1, 24 trades, metrics_reliable=false ('only 1 daily returns'); Sharpe/PSR/vol all null. 24 trades cannot distinguish edge from noise (L16). It also undercuts the hypothesis's premise — it chose BINANCE for 'deep, multi-year' BTC tick history, yet the tick backtest yielded a single day. If only ~1 day of usable tick history is runnable, the family cannot be validated (same shallow-tick wall L11 flags for Hyperliquid). - LATENCY-DEPENDENCE (checklist #15). avg_trade_return_pct -0.0157% is far below the 0.05% floor below which tick strategies are latency-dependent. The backtest assumes zero latency and fills at the 5m close, but entries chase aggressor flow (a fresh micro-extreme in the direction trades are already lifting), so real fills would be worse. A sub-0.05% tick edge is unlikely to survive execution slippage. - SIZING REGRESSION RISK. position_size reuses the equity-anchored risk-based formula capped at equity*max_gross_frac — the same pattern whose realized exposure ran 1.5-5x the cap and liquidated the SOL/ETH siblings. avg_position_pct 50.2% ~= the 0.5 cap here (bounded in this 1-day sample), but the developer did NOT adopt the validated path-independent fixed-notional fix, so it could inflate over a longer/volatile window. - Mechanics otherwise faithful and the novel data primitive handled correctly: on_trade_tick accumulates signed aggressor volume in an O(1) rolling deque, OFI = (buy-sell)/total in [-1,1], entry requires |OFI|>=threshold WITH a fresh micro-extreme (continuation), exits on ATR stop/target/decay/max-hold. subscribe_trade_ticks=true matches the on_trade_tick override (checklist #11 ✓), and the iter-2 _bar_ts instance-method fix resolved Layer 2. Direction/instrument/horizon match. The block is fee-viability + measurability.
Strategy report

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