EthCoinMRangingBollingerReversionLS
Hypotheses
COIN-M ETH Inverse-Perp Regime-Gated Bollinger Mean Reversion, Long-Short (Single-Instrument BINANCE_CM, 1H, Fade Band Extremes ONLY in Ranging/Low-ADX Regime, Mid-Band Take-Profit, Failed-Reversion Stop, Pure OHLCV, Low-Parameter, Cheapest-Fee Venue)
Hypotheses
A LONG-SHORT, SINGLE-INSTRUMENT, pure-OHLCV counter-trend MEAN-REVERSION strategy on ETHUSD_PERP.BINANCE_CM (Binance COIN-M inverse perpetual, ETH-margined, 1-HOUR bars). It deliberately fills the two most under-target buckets at once: BINANCE_CM venue (only 1.7% of the portfolio vs the >=5% quota — the single most starved venue, and barely explored) and long_short direction (14.5%). COIN-M also carries the cheapest round-trip taker fee in the entire venue set (~0.06% RT), which widens the post-fee edge headroom for a reversion strategy whose per-trade targets are modest. Critically, this is a MECHANISM the factory has not validated — it is NOT momentum/breakout/continuation (the squeeze-breakout, opening-range-breakout, impulse-bar-continuation, Donchian, and time-series-momentum families already in the book) but its orthogonal counterpart: fading short-term overextension back to the mean. The well-known failure mode of classic Bollinger/RSI mean reversion in crypto (trends run over the fade and stop you out) is addressed structurally with an ADX ranging-regime GATE: the strategy only fades band extremes when ADX(14) confirms a low-trend / range-bound regime, and stands aside entirely when ADX shows a strong trend. Pure OHLCV means zero supplementary-data dependency (sidestepping the funding/option-settlement data failures that abandoned the recent families). Kept intentionally low-parameter (4 core params) to resist the overfitting that has been the recurring abandonment cause.
Hypotheses
This is the smallest change that addresses the specific defect QA identified, and it is a structural fix rather than a parameter tweak. QA accepted that the reversion effect is real (win_rate 0.717, positive gross per trade) and located the expectancy leak precisely: the failed-reversion stop was evaluated on the bar CLOSE, so fast adverse moves blew through it, leaving largest_loss -$5,289 against avg_loss $762 - a ~7x tail. The arithmetic makes the fix worth attempting: expectancy is 0.717*$289 - 0.283*avg_loss, which is -$8.2 at avg_loss $762 and turns POSITIVE once the average loss drops below ~$732, i.e. a ~4% reduction. Capping a 7x tail intra-bar should exceed that comfortably, so unlike a threshold sweep this has a mechanical reason to change the result rather than reshuffle noise. Implementation: use_bracket_orders is enabled with stop_loss_pct=2.0%, and the z-based stop is REMOVED from should_exit so the position cannot be double-exited (the base template cancels the resting legs when the mid-band signal exit fires). I picked 2.0% by measuring the OLD dynamic stop distance, sigma*(stop_z-|z|)/price, on this instrument's real 1h history at entry-zone z values: median 2.12%, p25 1.27%, p75 3.54%. So the stop sits essentially where it always sat - only WHEN it fires changed - which is what keeps this a fix to the tail rather than a re-tuning of the edge. Sizing now measures risk against that same bracket distance, keeping _risk_pct semantically true. Everything else is untouched: imports, the ADX state machine, the arm/re-entry logic, the continuous z-score signal and the inverse-contract sizing are as they were through Layers 1-3. I want to be straight about the residual risk: QA measured the gross per-trade edge at roughly 0.11% against a ~0.10% COIN-M round trip, so even with the tail capped the margin is thin and the take-profit side is unchanged - if this run still shows profit_factor near 1.0 with a normalised loss distribution, the honest conclusion is that the mechanism has no room on this venue and it should be abandoned rather than tuned further.
Hypotheses
Negative-expectancy single-name mean-reversion — no edge to optimize. Over 781 measured trades: profit_factor 0.907 (<1), avg_trade_return_pct -0.059% (negative), expectancy -$14.74/trade, total_return -19.6% over 5.8 years, Sharpe -0.019 with bootstrap CI [-0.85, 0.76] straddling zero (PSR 0.48). The iteration-2 intra-bar bracket stop worked as designed (win_rate rose to 64.3%) but the reward:risk stays inverted (avg_win $224 < avg_loss $444, ~0.5), so at that win rate expectancy is still ~-$17/trade — the classic small-wins/large-losses mean-reversion signature the fix could not flip. It is fee-fragile (commission 17.34% of gross at the 1H cadence), loses in most years (2022 -8.3%, 2024 -3.0%, 2026 -2.6%) with almost all stress windows negative (china-ban -3.3, FTX -2.7, SVB -5.2) and max_drawdown 35% (CI to 76.5%). This is the L55 single-name fade/reversion family (0/174 survivors), where re-tuning entry/exit thresholds has never lifted the class over costs. No parameter change flips a sub-1-PF, negative-per-trade, RR-inverted reversion. Failure pattern: no_edge/fee_edge single-name mean-reversion, RR-inverted (L55).
Implementation
Long-short ADX-gated Bollinger band fade on the ETH COIN-M inverse perpetual (ETHUSD_PERP.BINANCE_CM, 1-hour bars, pure OHLCV). It computes the close's Bollinger z-score over 20 bars, arms a fade when z reaches a band extreme (+/-2.0), and enters only once price starts reverting back inside the band while Wilder ADX(14) confirms a ranging regime below 20. The mid-band (z crossing the SMA) is the take-profit and a 48-bar time stop bounds the hold. Iteration 2 moves the failed-reversion stop from a bar-close z check to a VENUE-MANAGED bracket leg at 2.0% that triggers intra-bar, so a fast adverse move is cut at the level instead of at the next close. Sizing risks 0.5% of equity over that bracket stop distance, capped at 0.75x equity of gross notional, floored to WHOLE $10-face inverse contracts.
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
Analyst to decide abandon vs optimize on full history; if PF stays ~1.0 after walk-forward, abandon per the developer's stated condition rather than burning a 3-phase optimization.
Verification Results
Fee-viability is marginal by the developer's own measurement (gross per-trade edge ~0.11% vs ~0.10% CM round trip), realized as breakeven-to-negative (PF 1.0001, avg_trade_return_pct ~0). Classic mean-reversion fee-graveyard tension: the mid-band TP caps wins small while the 2% bracket stop makes losses ~2x larger, so almost no post-fee headroom. Not a code defect — the mechanism, gate, and exits are correctly implemented.
Backtest Review
Well-measured (781 trades over 5.8 years); clean 4-parameter pure-OHLCV construction with an ADX regime gate and correct inverse-contract sizing
Backtest Review
Iteration-2 intra-bar bracket stop worked mechanically (win_rate up to 64%); no blow-up, contained per-trade risk
Backtest Review
Negative expectancy: PF 0.907, avg_trade_return_pct -0.059%, expectancy -$14.74/trade, total_return -19.6%, Sharpe -0.019 (CI [-0.85, 0.76])
Backtest Review
RR still inverted (avg_win $224 < avg_loss $444, ~0.5) — the high win rate does not overcome the loss asymmetry; the stop fix lifted win-rate but not expectancy
Backtest Review
Fee-fragile: commission 17.34% of gross at the 1H reversion cadence
Backtest Review
L55 single-name fade/reversion family (0/174 survivors); loses in most years; stress windows almost all negative; max_drawdown 35% (CI to 76.5%)
Iteration History
Verification failed (Layer 4 — QA review) [class=no_edge]:
- FEE-NONVIABLE / NEGATIVE EXPECTANCY. The mean-reversion effect is real (win_rate 0.717, positive gross per-trade edge) but too small to survive fees plus fat-tailed failed-reversion losses. Sandbox: profit_factor 0.962 (<1), avg_trade_pnl -$8.21 (negative expectancy), total_return -11.9%, alpha -0.0338 over 750 days / 265 trades. Classic asymmetric reversion trap: small mid-band take-profits (avg_win $289) outweighed by large failed-reversion stops (avg_loss $762, largest_loss -$5,289) when a trend runs through the fade despite the ADX gate. The developer's honest measurement matches: gross per-trade edge ~0.11% ~= one round-trip of COIN-M fees, and the ADX gate is already at its best setting (ungated -0.12%/trade, adx_max=25 -0.03%, adx_max=20 +0.013% gross) yet still can't clear the 0.10% floor. No parameter change rescues an edge that structurally equals its trading cost.
- The failed-reversion stop is checked on z at bar CLOSE (stop_z=3.5), so a fast adverse move blows past it before the check fires — largest_loss -$5,289 vs avg_loss $762 (~7x tail). Design behavior, not a bug, but it's why the high win rate doesn't yield positive expectancy.
Iteration History
Verification failed (Layer 4 — QA review) [class=no_edge]:
- The iteration-2 fix is correct and worked mechanically, but it revealed the mechanism is fee-nonviable with no room to recover. The intra-bar bracket stop capped the tail exactly as intended (largest_loss -$5,289 -> -$525, avg_loss $762 -> $414, max_drawdown 31% -> 6.78%, kurtosis normalized to 3.4) and lifted expectancy from -$9 to -$0.40 — but the result is now break-even/slightly negative: profit_factor 0.997, expectancy -$0.40, avg_trade_return_pct -0.0016% (below the 0.10% CM floor), total_return -4.04%, Sharpe 0.072 (CI [-1.14, 1.18] straddling zero), over 271 trades. The tail cap also cut win_rate (0.717 -> 0.672) and avg_win ($289 -> $202) because the 2% intra-bar stop closes trades that dipped then recovered, so the ~0.11% gross edge nets to zero against the ~0.10% round-trip cost. The developer stated the criterion up front: 'if this run still shows profit_factor near 1.0 with a normalised loss distribution, it should be abandoned rather than tuned further' — that condition is exactly met (PF 0.997, normalized losses). No parameter change closes a gap this structural.
- Credit where due (not a defect): the bracket conversion is implemented correctly per check 16 — use_bracket_orders with both stop_loss_pct and take_profit_pct > 0, the z-stop removed from should_exit so there is no double-exit, only signal-based exits (mid-band TP, time stop) remain, and sizing measures risk against the actual bracket stop distance. Exactly the fix QA asked for; it exposed the absence of edge rather than creating one.
Backtest and paper results are hypothetical. Trading involves risk of loss.