Strategies
Binance USD-M Intraday Volatility-Expansion Breakout (Majors, 15-Minute, ATR-Gated Large-Move Filter, ATR-Trailed, Long-Short)
Outcome: Abandoned
IntradayVolatilityExpansionBreakoutMajorsLS15m
Code↔hypothesis misalignment found by the semantic auditor — the code does NOT implement the hypothesis. Re-code the strategy to implement the hypothesis EXACTLY (instrument, timeframe, direction, the named…
Hypothesis
Repeat liquidation — not optimizable, and already abandoned once for the same cause. The account LIQUIDATED on the exact same date (2020-12-30) as iteration 1, again blowing up in year one (total_return -100%, max_drawdown 100%, then flat/dead for ~5.7 years), which proves the iteration-2 order-size-precision change was a red herring that never addressed the root cause. The mechanism is a 15m over-trading fee catastrophe: 15,962 trades with commission 20.23% of gross ($80k) plus $68k impact, avg_trade_return_pct -0.023% (net negative), profit_factor 0.70, Sharpe -1.06 (CI [-2.99, -0.86]), PSR 0.0, return_kurtosis 1982, negative in every vol regime — the ATR-expansion gate does not cut trade count enough to escape fee domination, and the risk sizing lets losses compound into a blow-up. This is the L18/L30 pure-OHLCV 15m fee graveyard; no parameter change rescues an account that went to zero. Failure pattern: risk_reject/fee_edge liquidated 15m over-trading breakout, repeat of the iteration-1 abandonment.
Implementation
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.
Backtest Review
- Sharpe
- -1.06
- Total return
- -100.00%
- Max drawdown
- 100.00%
- Trades
- 15962
- Win rate
- 33.9%
- Profit factor
- 0.70
Clean incremental ATR/Donchian engineering; the large trade count makes the negative result statistically decisive
Account LIQUIDATED again on the SAME date (2020-12-30) as iteration 1: total_return -100%, max_drawdown 100%, CAGR -100% — the precision fix did not touch the root cause
Fee/impact catastrophe: commission 20.23% of gross ($80k) plus $68k impact over 15,962 trades; avg_trade_return_pct -0.023% (negative), profit_factor 0.70
Decisively negative: Sharpe -1.06 (CI [-2.99, -0.86]), PSR 0.0, return_kurtosis 1982, 28 consecutive losses, negative in every vol regime
L18/L30 pure-OHLCV 15m over-trading fee graveyard; the ATR-expansion gate does not keep trade count low enough to escape fee domination
Analysis
Iteration History
Verification failed (Layer 2 — synthetic scenarios): Parameters used: ['assets', 'risk_frac', 'atr_period', 'trail_mult', 'min_notional', 'max_hold_bars', 'qty_precision', 'channel_length', 'gross_cap_frac', 'max_position_frac', 'expansion_atr_mult', 'default_qty_precision'] Check that __init__ sets all attributes from self.parameters.get(). - steady_uptrend: TypeError: super(type, obj): obj must be an instance or subtype of type (bar timestamp: 1735689600000) - steady_downtrend: TypeError: super(type, obj): obj must be an instance or subtype of type (bar timestamp: 1735689600000) - flat_ranging: TypeError: super(type, obj): obj must be an instance or subtype of type (bar timestamp: 1735689600000) - volatility_spike: TypeError: super(type, obj): obj must be an instance or subtype of type (bar timestamp: 1735689600000) - zero_volume: TypeError: super(type, obj): obj must be an instance or subtype of type (bar timestamp: 1735689600000) - price_gap: TypeError: super(type, obj): obj must be an instance or subtype of type (bar timestamp: 1735689600000)
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 and paper results are hypothetical. Trading involves risk of loss.