Skip to content

View translation

BtcAggressiveTakerFlowExhaustionFadeLS1H

Hypotheses

BTC Taker Aggression Flow Reversal: Counter-Trade BTCUSDT.BINANCE 1H Bars When 4H Rolling Taker Buy-Sell Ratio Z-Score Exceeds ±2.5

Hypotheses

A long-short mean-reversion strategy on BTCUSDT.BINANCE USD-M perpetual futures that fades EXTREME aggressive-flow imbalances. Uses BINANCE USD-M perp bars (proven clean) + taker_ratio supplementary data (PostgreSQL — confirmed available, completely unused across 464 prior experiments). The hypothesis: when aggressive taker BUY volume dominates the 4h rolling window by >2.5 standard deviations vs the 30-day baseline, retail FOMO buying has exhausted — the marginal buyer who was willing to pay-up has been satisfied, and price reverts as natural sellers and short-side liquidity-providers step in. Symmetric on the SHORT side: when aggressive taker SELL volume dominates by ≤-2.5 SD, panic-selling has exhausted and a reversion follows. This mechanism is STRUCTURALLY DISTINCT from the recently-documented 'BTC funding-extreme mean-reversion decay post-2023' failure pattern: funding-rate extremes are POSITIONING-state lagging indicators that institutional capital can preempt; taker-flow extremes are REAL-TIME AGGRESSION-flow measurements that can only be observed AFTER the flow has happened, making them harder to arbitrage and more durable across regimes. Fills FIVE under-represented buckets: long-short direction (14.0% → toward 45%), taker_ratio-data-driven mechanism (zero of 464 experiments use this stream), aggressive-flow-microstructure edge (distinct from positioning, funding, liquidations, L/S), mid-term hold (8-24h cycles), and BINANCE-USD-M-only (clean data, avoiding all BINANCE_SPOT failure modes). Position sizing: 15% of equity per direction. Risk per trade: 1.5% of equity capped by stop-loss.

Hypotheses

Iteration 3 feedback was purely a naming collision: the previous class name belonged to another hypothesis (cbc45d1f), so the code could not be adopted as an implementation of THIS hypothesis. The smallest fix is a rename to a unique, hypothesis-specific class name (BtcAggressiveTakerFlowExhaustionFadeLS1H) with the docstring updated to match; the signal, entry/exit and sizing logic that already passed the earlier verification layers is unchanged, so no passing layer is regressed. The mechanism implements the hypothesis directly: taker-flow aggression extremes (real-time, observable only after the flow) are faded symmetrically long and short on 1H bars with an 8-24h hold, using rolling z-scores rather than absolute thresholds so signal frequency stays scale-invariant across regimes.

Hypotheses

verification_loop: sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (833 days of BTCUSDT.BINANCE-1-HOUR-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

Long-short mean reversion on BTCUSDT.BINANCE USD-M perp 1H bars driven purely by the taker_ratio supplementary stream. Each bar samples the nearest taker buy/sell observation, converts it to log(buyVol/sellVol), smooths it over ~4h and z-scores that smoothed reading against a ~30-day rolling distribution of the same smoothed series. z >= +entry_z (aggressive buying exhausted) -> SHORT; z <= -entry_z (panic selling exhausted) -> LONG. Exits on z reverting inside +/- exit_z, a 3% stop, a 4% take-profit, or a 24-bar time stop. Sizing is 15% of equity per direction, capped by 1.5% equity risk over the stop distance. With no taker data the strategy stays flat (no price-only fallback edge).

Verification Results

sandbox_timeout: Verification failed (Layer 3 — sandbox backtest): smoke test exceeded the 300s wall-clock limit on a ~20000-bar window (833 days of BTCUSDT.BINANCE-1-HOUR-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

BtcTakerAggressionFlowReversalZScore1H

Iteration History

Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['z_min', 'exit_z', 'tp_pct', 'entry_z', 'risk_pct', 'stop_pct', 'smooth_bars', 'window_bars', 'min_notional', 'notional_pct', 'max_hold_bars', 'taker_tolerance_s'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - steady_downtrend: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - flat_ranging: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - volatility_spike: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - zero_volume: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - price_gap: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000)

Iteration History

Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['z_min', 'exit_z', 'tp_pct', 'entry_z', 'risk_pct', 'stop_pct', 'smooth_bars', 'window_bars', 'min_notional', 'notional_pct', 'max_hold_bars', 'taker_tolerance_s'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: TypeError: BtcTakerAggressionFlowReversalZScore1H._bar_ts_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - steady_downtrend: TypeError: BtcTakerAggressionFlowReversalZScore1H._bar_ts_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - flat_ranging: TypeError: BtcTakerAggressionFlowReversalZScore1H._bar_ts_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - volatility_spike: TypeError: BtcTakerAggressionFlowReversalZScore1H._bar_ts_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - zero_volume: TypeError: BtcTakerAggressionFlowReversalZScore1H._bar_ts_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000) - price_gap: TypeError: BtcTakerAggressionFlowReversalZScore1H._bar_ts_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735689840000)

Iteration History

Verification failed (Layer 3 — sandbox backtest): No trades produced Bar type used: BTCUSDT.BINANCE-1-HOUR-LAST-EXTERNAL, Bars processed: 56856 Diagnostics: should_enter() returned a side 0 times over 56852 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 — static analysis): - Look-ahead: a supplementary observation is selected by ABSOLUTE distance to the bar timestamp, which returns the NEXT observation when it is closer than the previous one. Use self.supp_as_of(key) (latest at or before the bar) or an explicit `ts <= bar.ts_init` filter — never abs(). (line None)
Strategy report

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