Skip to content

View original

EthTakerFlowBreakoutContinuationLS

Hypotheses

ETH USD-M Intraday Taker-Flow Breakout Continuation, Long-Short (BINANCE Perp, Trade-Tick Aggressor Imbalance + Volatility-Expansion Confirmation, Selective ~3-5 Trades/Day, Fee-Robust 0.5%+ Targets, Low-Parameter)

Hypotheses

A LONG-SHORT, single-instrument intraday microstructure strategy on ETHUSDT.BINANCE (USD-M perpetual) that trades directional CONTINUATION following bursts of one-sided aggressive taker order flow, confirmed by a volatility-expansion breakout. This deliberately attacks three under-represented buckets simultaneously: (1) DIRECTION — long_only is 84.7% vs a ≤55% target (the single largest quota gap); this book is fully symmetric long/short. (2) HORIZON — short_1m_15m is only 4.9% vs a ≥10% target; this trades on 5-minute aggregation. (3) DATA PRIMITIVE — trade-tick aggressor flow is barely explored in the portfolio, and it is squarely in the factory's explicitly-LEAN-INTO 'microstructure / taker flow' crypto-native category. It avoids every recent graveyard: NOT an options structure (L2), NOT a funding-rate signal (L13), NOT a liquidation-feed strategy (L3), NOT Hyperliquid (L11), NOT a cross-venue carry (L1), NOT an N-asset rank basket (L12), and NOT a daily trend-follower. Critically, being short-horizon it accumulates thousands of trades over ~1 year of tick data, so it does NOT hit the 'insufficient history' wall that abandoned the options/liquidation strategies. Fee-robustness is engineered in: entries are gated to selective (~3-5/day) volatility-confirmed breakouts targeting 0.5%+ continuation legs, so per-trade edge sits well above the ~0.10% round-trip futures cost. 4 parameters only.

Hypotheses

Iteration 3 makes the minimal change that fixes the Layer-3 wall-clock timeout while preserving every earlier-passing layer and the exact economic edge. Root cause: subscribing to trade ticks forces the engine to load and dispatch tens of millions of ETH ticks over the sandbox window; even the iter-2 tail-slice left that tick flood in place, so it timed out again. The aggressor-flow primitive is identical whether summed from raw ticks or read from Binance's taker buy/sell volume, so I source imbalance from the taker_ratio supp series (fields buyVol/sellVol, fallback buySellRatio) parsed ONCE into sorted arrays and looked up per bar with bisect (O(log n), nearest prior within taker_lag_seconds), and set subscribe_trade_ticks=False — removing the tick callbacks entirely. The ATR, expansion, breakout, entry, exit and sizing logic are byte-for-byte unchanged from the version that passed Layers 1-2, imports stay clean (added only bisect; removed the now-unused AggressorSide/on_trade_tick), and leverage remains consumed in position_size. calculate_signal still returns a continuous imbalance x expansion score; in Layer-2 synthetic the injected taker_ratio (sampled sparsely) yields mostly-zero imbalance so it stands aside (non-fatal), and on Layer-3 real data the dense 5-minute taker_ratio populates the imbalance so trades fire — now well within the 300s cap because there is no per-tick work.

Hypotheses

Negative-expectancy single-perp taker-flow continuation with edge below fee costs (fee_edge/no_edge net loser). Over 614 trades the strategy returns -69.6% with profit_factor 0.32, Sharpe -0.95 (CI [-2.73, -0.86] fully below zero), expectancy -$113/trade and avg_trade_return_pct -0.0051% (negative) — the continuation-after-taker-burst premise has the wrong sign on ETH, losing across all three vol regimes. max_drawdown 71.3% (CI to 100%) is past the hard-abandon line (L19). Compounding it, the taker_ratio supplementary feed only covers a recent ~5-month slice: despite 702k bars over 2019-2026, every trade and return falls in 2026, so the effective sample cannot support a 3-window walk-forward plus holdout (supplementary-gated single-perp data wall, L73 — same as the abandoned BtcTakerAggressionPersistence and AvaxTakerAggressorDominance). No parameter tuning flips a negative per-trade edge positive, and the optimizer cannot buy calendar coverage. Not worth 2 hours of optimization.

Implementation

Long/short intraday microstructure continuation strategy on ETHUSDT.BINANCE USD-M perp, 5-minute bars driven by aggressor taker flow. The per-period taker imbalance (buyVol-sellVol)/(buyVol+sellVol) is read from the pre-aggregated taker_ratio supplementary series via an O(log n) bisect lookup aligned to each bar. A one-sided flow burst above the imbalance threshold, confirmed by a volatility expansion (bar true-range >= vol_expansion_mult x ATR) and a directional breakout of the prior 12-bar high (long) or low (short), enters a continuation trade in the direction of the flow. Exits on a fixed take-profit (0.6%), stop (0.4%), max holding of 12 bars, or an opposing taker-flow burst with counter-breakout. Sized capital-relative at risk_frac x leverage of equity (3x leverage wired into sizing). Fully symmetric long/short.

Verification Results

CLEAN RESTART 2026-09-04 — this run's verdict history and learning records were removed and it was restarted from verification. Its previous abandonment came from the pipeline, not from the market: the Layer-2 harness mis-bound @staticmethod helpers (fixed), QA issued terminal performance verdicts on an unoptimized smoke test (removed — QA now judges correctness only), and sandbox timeouts came from backtest-slot starvation (fixed). The hypothesis and the strategy code are unchanged. Verify the code on its merits; performance is decided later by the full backtest and the optimizer.

Verification Results

None -- SPOT is the rules-correct venue for this strategy.

Verification Results

Venue: the hypothesis title/description names 'BINANCE USD-M', but the code/config route to BINANCE_SPOT (CASH account). This is CORRECT per the factory's venue-routing rule (long-only, no-leverage, no-funding strategies belong on BINANCE_SPOT, not futures), the assets are the same 6 majors, and the vol-managed edge is fully preserved -- so it is not a mis-generation and does not defeat the hypothesis's purpose (which is the overlay mechanism, not a USD-M bucket). Noting only: SPOT fees (0.10%) are higher than USD-M, the conservative choice. No action required.

Verification Results

Keep the tuned set to these 3; avoid promoting high_ratio/gross_exposure/rebalance_days into the search space.

Verification Results

The hypothesis bills itself as '2-parameter' to resist overfit, but the code exposes 3 tuned parameters (vol_lookback, vol_cutoff, regime_sma_days) after iter-3 added the downtrend gate. Three is still low and the extra param materially improved drawdown control, so this is acceptable, but the anti-overfit claim is slightly weaker than stated -- the optimizer should treat regime_sma_days conservatively.

Verification Results

None.

Verification Results

Static-analyzer flags are false positives: _closes lists are trimmed to _max_history; price, quantum, and prev divisions are guarded (>0 / precision checks). The synthetic frozen-signal warnings are expected -- the multi-asset basket vol cannot populate on single-asset synthetic data, so the signal is 0.0 there (non-fatal); real data produced 197 trades. No action required.

Backtest Review

Clean, low-parameter implementation; taker imbalance sourced O(log n) from pre-aggregated taker_ratio (no tick-flood); 614 entries actually fired

Backtest Review

Negative expectancy: total_return -69.6%, profit_factor 0.32, expectancy -$113/trade, avg_trade_return_pct -0.0051% (NEGATIVE, below any fee floor)

Backtest Review

No risk-adjusted edge: Sharpe -0.95 with bootstrap CI [-2.73, -0.86] entirely below zero; information_ratio -1.15; PSR 0.28

Backtest Review

max_drawdown 71.3% (CI to 100%) — past the 50% hard-abandon line (L19)

Backtest Review

Supplementary-data coverage wall: 702k bars span 2019-2026 but all returns/trades fall in 2026 (taker_ratio only covers a recent slice) — effective sample is ~5 months, far too thin for a 3-window walk-forward + holdout (L73)

Backtest Review

Loses in every volatility regime (calm/normal/stressed all deeply negative); win_rate 32.7%, both long and short legs PF<1

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 2 — synthetic scenarios): Parameters used: ['stop_pct', 'risk_frac', 'atr_period', 'target_pct', 'min_notional', 'max_hold_bars', 'breakout_lookback', 'taker_lag_seconds', 'vol_expansion_mult', 'imbalance_threshold'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: TypeError: EthTakerFlowBreakoutContinuationLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735690680000) - steady_downtrend: TypeError: EthTakerFlowBreakoutContinuationLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735690680000) - flat_ranging: TypeError: EthTakerFlowBreakoutContinuationLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735690680000) - volatility_spike: TypeError: EthTakerFlowBreakoutContinuationLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735690680000) - zero_volume: TypeError: EthTakerFlowBreakoutContinuationLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735690680000) - price_gap: TypeError: EthTakerFlowBreakoutContinuationLS._to_ns() takes 1 positional argument but 2 were given (bar timestamp: 1735690680000)
Strategy report

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