Skip to content

View original

BtcTakerFlowConfirmedMomentumLS

Hypotheses

BTC Perp Taker-Flow-Confirmed Momentum (Single-Instrument USD-M, Long-Short, 1H, Aggressor-Imbalance Gated Trend, Flat on Flow Divergence)

Hypotheses

A long-SHORT, SINGLE-INSTRUMENT, single-venue directional strategy on BTCUSDT.BINANCE USD-M perpetual futures using 1-HOUR bars, that takes a directional position ONLY when the price trend is CONFIRMED by sustained TAKER AGGRESSOR FLOW in the same direction. This is the third member of the ONLY mechanism class with a promoted survivor in this factory (a single, price-creditable leg gated by a crypto-native confirmation signal — cf. the promoted ETH funding-confirmed trend), but it deliberately swaps to an ORTHOGONAL signal not used by its siblings: the taker buy/sell volume imbalance (which side is the aggressor lifting offers vs hitting bids), distinct from funding (ETH sibling) and open-interest change (SOL sibling). Core thesis: a price move accompanied by persistent taker-BUY dominance reflects real demand paying up through the book (genuine continuation), while a move on persistent taker-SELL dominance reflects real supply hitting bids (genuine downside continuation); when price direction and aggressor flow DISAGREE (e.g. price ticking up while sellers dominate the tape), the move is unsupported and likely to exhaust, so the strategy stands flat. CRITICAL DESIGN NOTES separating this from the closed families: (1) SINGLE creditable price leg — no delta-neutral pair, no funding/basis CARRY (funding is never booked as cash flow here), so it avoids the uncreditable-carry and sub-fee-basis traps; (2) taker flow is a SIGNAL only, the validated role for crypto-native data; (3) NOT cross-venue / HYPERLIQUID, NOT COIN-M, NOT spot-perp basis, NOT cross-sectional, NOT tick-dispatched (it reads aggregated per-bar taker volume, fully representable in the bar engine); (4) BTC has the deepest, longest taker-flow and price history of any crypto asset, so walk-forward windows are data-rich — no thin-data ceiling; (5) the gate fires CONTINUOUSLY across every trending stretch (not on rare events), so OOS windows are densely populated — the opposite of the OOS-all-zero event-sparsity signature that killed the drawdown-accumulation class. Intentionally minimal: 3 tunables (trend_lookback, taker_window, taker_threshold) to resist overfitting.

Hypotheses

Iteration 4 fix for the Layer-3 sandbox timeout (>300s wall-clock). The prior code's per-bar `_flow_over_window` rebuilt a slice `self._taker_ratio_vals[lo:hi]` and called `sum()` on every one of ~70k 1H bars — O(window) work that scaled up once the dense 5-min `metrics` stream (~525k rows since 2021) was merged in. The fix precomputes a cumulative PREFIX-SUM array ONCE in `_build_taker` (alongside the already-sorted timestamp list), so the windowed mean becomes `(prefix[hi]-prefix[lo])/(hi-lo)` — O(1), no per-bar allocation or summation. The fallback branch now reuses the existing `hi` bisect index (`j = hi - 1`) instead of recomputing a second `bisect_right`, shaving another per-bar O(log n) call. No signal logic, imports, entry/exit gates, or sizing changed, so Layers 1 and 2 (already passing) are untouched; only the per-bar compute cost is reduced. Venue remains BINANCE futures (shorts are used) with leverage=1.0 (sizing uses position_pct only, so no unused-leverage gate risk).

Hypotheses

No edge, and it is not a code bug the developer can fix — the strategy runs exactly as designed (2064 clean trades, full history, correct taker-flow gating) yet the taker-flow-confirmed momentum-continuation signal has negative expectancy across the ENTIRE 6.5-year sample: Sharpe -1.39 (CI fully negative), profit_factor 0.797, and a loss in every year post-2020 (2022 -5.9%, 2023 -10.5%, 2024 -3.8%, 2025 -7.1%), with information_ratio -0.78 vs its BTC benchmark. Optimization cannot rescue a signal that is uniformly negative — there is no positive parameter region to tune toward, so 2 hours of walk-forward optimization would be wasted. The persistent symmetric loss on both long and short legs is faintly consistent with an inverted-signal edge, but that is a hypothesis-level reframe for the Research Lead (mean-reversion on unsupported moves rather than continuation), not a parameter tweak — and it is not established here. Do not optimize.

Implementation

BTC USD-M perpetual 1H long-short momentum that opens a directional position ONLY when the trailing trend_lookback-hour price trend is confirmed by sustained taker aggressor flow in the same direction (mean taker buy/sell ratio over the trailing taker_window hours crossing a symmetric band around 1.0). Long on up-trend + buy-dominant flow, short on down-trend + sell-dominant flow. Exits flat on flow divergence (trend reversal or flow flipping to the opposite dominance band), a protective stop, or a max-holding backstop. Taker flow is a signal only, merged from the standalone taker_ratio stream and the metrics stream (taker_long_short_vol_ratio history back to ~2021) so the backtest spans full history.

Verification Results

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).

Backtest Review

Implementation is sound: 2064 trades fired cleanly (no size-zero/min-notional/cash drops), full 2020-2026 history covered via the merged taker_ratio+metrics streams, sane 41.6% exposure, no liquidation

Backtest Review

Signal is a genuine long-short with both directions active (1356 long / 708 short)

Backtest Review

NO EDGE: Sharpe -1.39 (CI entirely negative -2.27 to -0.59), Sortino -2.75, profit_factor 0.797, total_return -21.1%

Backtest Review

Loses money in EVERY year post-2020 (2022 -5.9%, 2023 -10.5%, 2024 -3.8%, 2025 -7.1%) — not a regime artifact, a persistent negative expectancy

Backtest Review

win_rate 23.8% with both legs poor (long 24.6% / short 22.3%); information_ratio -0.78 vs a meaningful BTC benchmark — strictly worse than buy-and-hold

Backtest Review

commission_pct_of_gross 22.4% — the 1H rebalance frequency bleeds fees on top of a losing gross signal

Analysis

Do NOT optimize — only 62 trades, all in the last ~2 months (2026); 2020-2025 produced zero trades, so walk-forward OOS windows and the holdout would be empty. The dominant cause is taker-data coverage, not (yet provably) the signal. Investigate in this order: (1) PRINT THE TAKER COVERAGE SPAN: in _build_taker, log len(self._taker_ts) and min/max(self._taker_ts) after parsing supplementary_data['taker_ratio'] for BTCUSDT. Determine whether taker rows exist before 2026 at all. (2) IF ROWS EXIST but don't align: the bug is parsing/format. _parse_taker_ratio guesses across key names (buySellRatio/buy_sell_ratio/ratio/...) and timestamp scales (ms vs ns via the <10^15 heuristic) and a buyVol/sellVol fallback — verify the ACTUAL Binance Vision 'metrics' taker schema delivered to the strategy matches one of those and that timestamps convert correctly; a units mismatch would strand all but recent rows. (3) IF TAKER HISTORY GENUINELY STARTS ~2026: Binance's live takerlongshortRatio endpoint only serves ~30 days, but data.binance.vision 'metrics' archives taker buy/sell volume back to ~2021 — confirm the collector backfilled BTCUSDT taker metrics to the full backtest start; if that data does not exist far enough back, the multi-year premise is unviable and the hypothesis should be ABANDONED (data wall), or re-scoped only to a period long enough for a 3-window walk-forward + holdout (>= ~18 months). (4) SECONDARY (watch after the data fix, do not ignore): even in the 2026 window the strategy loses hard (PF 0.50, win 25.8%, 13 consecutive losses) with 37.6% commission drag at 1H. A 26% win rate on a momentum-CONFIRMATION signal suggests the flow-divergence exit is cutting winners / holding losers — re-examine the should_exit logic (exiting the instant flow crosses 1.0 may be too twitchy). If, after full taker coverage, the edge stays negative or 1H fees dominate, abandon rather than iterate again. Keep the no-price-fallback fail-loud design — it is exactly why this surfaced as zero trades rather than silently testing a price-only momentum edge.

Outcome Summary

BtcTakerFlowConfirmedMomentumLS ran exactly as designed — 2064 trades across the full 2019-2026 BTC history, both long and short legs active, sane 41.6% exposure and no liquidation — but the taker-flow-confirmed continuation thesis simply had no edge. The backtest returned -21.1% with a Sharpe of -1.39 (confidence interval entirely negative), a profit factor of 0.797, and losses in every year after 2020, while 1H rebalancing bled 22.4% of gross to commissions. Because the signal was negative everywhere and offered no positive region to optimize toward, the analyst abandoned it at the backtest-review gate rather than spending hours on walk-forward optimization; no optimization or post-optimization analysis stage was reached. The record notes the symmetric two-sided loss faintly suggests an inverted mean-reversion reframe, but that is left as a future hypothesis, not a fix to this strategy.

Outcome Summary

A clean, correctly-implemented crypto-native confirmation signal can still carry persistent negative expectancy, so taker-flow-confirmed momentum-continuation on BTC 1H should not be re-attempted as-is — the symmetric loss on both legs hints a mean-reversion reframe would be a Research-Lead-level hypothesis, not a parameter tweak.

Outcome Summary

It was abandoned at the pre-optimization backtest-review gate, where the analyst issued an 'abandon' verdict: the signal was uniformly negative across the entire 6.5-year sample and lost money every year post-2020 (2022 -5.9%, 2023 -10.5%, 2024 -3.8%, 2025 -7.1%), so optimization had no positive parameter region to tune toward.

Outcome Summary

It took long or short positions on BTCUSDT USD-M perpetual (1H bars) only when the price trend was confirmed by sustained taker aggressor-flow in the same direction, standing flat when price and taker buy/sell imbalance disagreed.

Outcome Summary

Over ~1600 days (2019-2026) it fired 2064 clean trades (1356 long / 708 short) but had no edge: Sharpe -1.39 (CI fully negative, -2.27 to -0.59), total return -21.1%, profit factor 0.797, win rate 23.8%, and information ratio -0.78 versus its BTC benchmark, with commissions eating 22.4% of gross.

Iteration History

Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['min_notional', 'position_pct', 'taker_window', 'stop_loss_pct', 'trend_lookback', 'taker_threshold', 'max_holding_bars'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: TypeError: BtcTakerFlowConfirmedMomentumLS._ts_to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735691100000) - steady_downtrend: TypeError: BtcTakerFlowConfirmedMomentumLS._ts_to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735691100000) - flat_ranging: TypeError: BtcTakerFlowConfirmedMomentumLS._ts_to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735691100000) - volatility_spike: TypeError: BtcTakerFlowConfirmedMomentumLS._ts_to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735691100000) - zero_volume: TypeError: BtcTakerFlowConfirmedMomentumLS._ts_to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735691100000) - price_gap: TypeError: BtcTakerFlowConfirmedMomentumLS._ts_to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735691100000)
Strategy report

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