Skip to content
All strategies

Strategies

SOL USD-M Intraday VWAP-Reversion, Long-Short (Single-Instrument BINANCE Perp, 15m Bars, Fade MODERATE Deviations from Rolling VWAP, Trend-Regime Gated OFF, Frequently-Firing, Low-Parameter)

Outcome: Abandoned

SolIntradayVwapReversionLS

Backtest gate: - metrics unreliable: Incoherent: Sharpe 0.37 disagrees in sign with total_return -88.82% — the Sharpe is computed from the mtm_equity_curve series while the return comes from the equity curve. Judge on…

Hypothesis

[RESTORED 2026-07-10] Original hypothesis text lost to a cascade delete during test-vehicle cleanup (the HL fill-test vehicle shared this hypothesis). Fade moderate z-score deviations from rolling VWAP on SOL USD-M 15m; see experiment config rationale for the full strategy reasoning.

Implements the hypothesis directly: fade MODERATE deviations from a rolling intraday VWAP on SOL USD-M 15m, long+short, trend-regime gated OFF, few parameters. Iteration 4 is a clean restart with correctness-only edits and no change to the signal or entry logic that already passed the earlier layers: (1) the time-stop's bar interval is now measured from consecutive bar timestamps (seeded by bar_seconds) instead of a hardcoded 15-minute nanosecond constant, so max_hold_bars really means bars for whatever bar type is configured; (2) the broad try/except around the time-stop is removed -- bar.ts_event and position.ts_opened are guaranteed ints, so the handler could only mask a real defect; (3) parameters now declare _param_bounds for the stop_rr clamp the constructor enforces (min(stop_rr, 0.9)) plus the other active knobs, so the optimizer never reports a best value the code silently rewrites. Venue stays BINANCE USD-M because the strategy takes short positions; leverage stays 1.0 and sizing does not reference leverage beyond the identity multiplier, so no leverage_set_but_unused risk.

Negative expectancy on a reliable, decisive 3313-trade / 6-year sample: avg_trade_return_pct -0.0798% (below ZERO), profit_factor 0.68, total_return -87.1%, Sharpe -0.40, expectancy -$26.35/trade. The VWAP-reversion fade loses in EVERY calendar year and EVERY vol regime (calm -100%, normal -40.6%, stressed -42.9%), so the mean-reversion premise is measurably absent — this is a statement about the entry/direction, which IS the hypothesis, not a parameter cliff. The stated reward:risk ~1.43 does not manifest (avg_loss 179.97 > avg_win 103.57), the classic bar-close-stop overshoot signature QA flagged, now confirmed on full history. Commission is only 15.5% of gross, so this is not fee-fragility — the signal is gross-negative, and the 5 optimizable knobs cannot invert a PF-0.68 fade. Matches L55 (single-name fade, PF < 1.15, negative return → abandon). QA's edge concern is borne out. Not worth 2 hours of optimization.

Implementation

Intraday VWAP mean-reversion on SOL USD-M perpetual, 15-minute bars, long and short. Every bar it computes a continuous z-score of the close's deviation from a 32-bar (~8h) volume-weighted average price, scaled by RMS dispersion of closes around that anchor. It fades stretched deviations (|z| > 2.2) back toward VWAP -- short above, long below -- but only when the absolute deviation also exceeds a 1.2% fee floor and a loose 24h trend gate (|24h move| < 6%) says the market is oscillating rather than trending. Exits are derived from the same deviation: profit target = capture_frac * entry deviation (capture_frac = (entry_z - exit_z)/entry_z ~ 0.86), stop = 0.7x that target (capped at 1.5%), plus a z-back-inside-0.3 reversion exit and a 24-bar (~6h) time stop. Sizing is 15% of account equity in notional at leverage 1.

Verification Results

Verify FactoryStrategy uses the subclass's min_bars_required() for the warmup gate; if not, guard the -(trend_window+1) access explicitly.

min_bars_required() overrides a framework method (base_shadow warning from static analysis). Here it is deliberate — it raises the warmup to max(vwap_window, trend_window)+2 = 98 bars so the trend_window lookback index -(trend_window+1) is always in range — but confirm the base template honors the override for its warmup gate rather than using its own value, otherwise entries could fire before 98 bars accumulate.

If the hypothesis's reward:risk depends on the stop holding intrabar, implement the stop as a bracket/stop_market order at entry rather than bar-close logic; otherwise document that the effective stop is bar-close only.

The hard stop (pnl_pct <= -stop_pct, ~0.73% of notional) is only evaluated at bar close in should_exit(). On 15m bars a single bar can traverse well past the stop level intrabar, which explains largest_loss -527 vs largest_win 284 and avg_loss > avg_win despite the designed 1.43 reward:risk. This is realistic backtest behavior, not a defect, but the stated risk geometry is not actually enforced intrabar.

Sandbox is deeply negative on a reliable 227-trade / 205-day sample: total_return -8.34%, Sharpe -5.07 (CI [-7.56,-2.81]), profit_factor 0.61, avg_trade_return_pct -0.104% (below zero, roughly the round-trip fee), commission 25.4% of gross, and every vol tercile negative (calm/normal/stressed all lose). Crucially the claimed payoff geometry (reward:risk ~1.43) does NOT manifest: avg_loss 179.9 > avg_win 118.2, i.e. losers are larger than winners. This is consistent with (a) the stop being checked only at bar close, so 15m bars overshoot the derived ~0.73% stop before it can fire, and (b) the z-inside-exit and 24-bar time-stop closing most trades before the ~1.04% target is reached — so the VWAP-reversion edge is not clearing costs on SOL 15m. Not a correctness verdict (this is an unoptimized single draw), but the analyst should verify on full history whether captured deviation actually clears the ~0.10% round-trip and whether an intrabar/bracket stop is needed to make the stated reward:risk real, before spending optimization time.

Backtest Review

Sharpe
-0.40
Total return
-87.10%
Max drawdown
87.17%
Trades
3313
Win rate
54.2%
Profit factor
0.68

Well-formed, frequently-firing strategy with a large, statistically decisive sample (3313 trades over ~6 years)

Trades correctly implement the hypothesis (fades deviations from rolling VWAP, balanced 1638 long / 1675 short), so this is a fair test of the VWAP-reversion premise

Negative expectancy: avg_trade_return_pct -0.0798% (BELOW ZERO, roughly the ~0.10% round-trip cost), profit_factor 0.68, expectancy -$26.35/trade, total_return -87.1%

Sharpe -0.40 (CI [-1.30, +0.45]), Sortino -0.45, information_ratio -1.33 vs buy-hold

Premise falsified across the board: losing in every calendar year (2020 through 2026) and every vol regime (calm/normal/stressed all negative), so it is not a regime-selection or cliff problem

Inverted payoff geometry: the claimed reward:risk ~1.43 does not manifest (avg_loss 179.97 > avg_win 103.57) — losers are larger than winners, consistent with bar-close stops overshooting on 15m bars

Commission is only 15.48% of gross, so this is NOT fee-fragility — the raw fade signal is gross-negative; there is no positive edge for a fee/threshold tweak to rescue

Analysis

Backtest gate: - metrics unreliable: Incoherent: Sharpe 0.37 disagrees in sign with total_return -88.82% — the Sharpe is computed from the mtm_equity_curve series while the return comes from the equity curve. Judge on the equity curve.

Iteration History

Verification failed (Layer 4 — QA review): - FEE-VIABILITY FAILURE (checklist #7): the VWAP-fade mechanism does not clear round-trip trading costs. Over a decisive 1660-trade / 363-day sandbox sample the realized avg_trade_return_pct is -0.016% — net-negative and an order of magnitude below the ~0.10% BINANCE USD-M round-trip taker cost and the 0.15% futures floor. Turnover 297x, avg_holding 2h22m. The exit_z=0.3 reversion band banks tiny sub-fee reversions while the 1.5% stop lets losers run, producing an……Show moreShow less

Verification failed (Layer 4 — QA review): - FEE-VIABILITY FAILURE (checklist #7): the VWAP-fade mechanism does not clear round-trip trading costs. Over a decisive 1660-trade / 363-day sandbox sample the realized avg_trade_return_pct is -0.016% — net-negative and an order of magnitude below the ~0.10% BINANCE USD-M round-trip taker cost and the 0.15% futures floor. Turnover 297x, avg_holding 2h22m. The exit_z=0.3 reversion band banks tiny sub-fee reversions while the 1.5% stop lets losers run, producing an INVERTED reward:risk despite a 58% win rate: avg_win $75.81 vs avg_loss $156.52 (~2x). Result: total_return -36.1%, PF 0.67, Sharpe -2.19 (CI [-4.07, -0.64] entirely below zero). The rationale's claim that '~0.4-0.6% reversions clear the round-trip' is contradicted by the data — the exit_z quick-bank fires long before. Saturated single-name VWAP-fade class (zero survivors; cf. the 9158-trade SOL VWAP fade at -88%). - Signal polarity and logic are CORRECT and faithfully implement the hypothesis (z>entry_z -> SELL; z<-entry_z -> BUY; trend-off gate; stop/TP/exit_z/time-stop exits; capital-relative sizing). Noted so the developer does not chase a phantom code bug — the failure is economic, not a coding defect.

Verification failed (Layer 4 — QA review): - FEE/EDGE FAILURE PERSISTS (checklist #7, L6) — the iteration-2 fee-viability fixes did NOT create edge. Over a DECISIVE 755-trade / 363-day sample the realized avg_trade_return_pct is -0.064% (still net-negative and below the 0.15% futures floor), total_return -21.9%, profit_factor 0.61, Sharpe -2.45 with CI [-4.14, -0.85] ENTIRELY below zero (probabilistic_sharpe 0.001). The min_dev_pct=0.6% floor cut turnover (297x -> 143x) and halved trades (1660 -> 755), but the……Show moreShow less

Verification failed (Layer 4 — QA review): - FEE/EDGE FAILURE PERSISTS (checklist #7, L6) — the iteration-2 fee-viability fixes did NOT create edge. Over a DECISIVE 755-trade / 363-day sample the realized avg_trade_return_pct is -0.064% (still net-negative and below the 0.15% futures floor), total_return -21.9%, profit_factor 0.61, Sharpe -2.45 with CI [-4.14, -0.85] ENTIRELY below zero (probabilistic_sharpe 0.001). The min_dev_pct=0.6% floor cut turnover (297x -> 143x) and halved trades (1660 -> 755), but the single-name VWAP-fade has no directional edge net of costs — the saturated zero-survivor class the developer's own caveat concedes 'may simply not exist'. - INVERTED REWARD:RISK IS BUILT INTO THE PARAMETERS. The reversion target captures ~(entry_z-exit_z)/entry_z = (2.2-0.5)/2.2 = 0.77x the entry deviation (~0.46% at the 0.6% floor). The stop = min(stop_mult*dev, stop_loss_pct) = 1.2*0.6% = 0.72%, LARGER than the 0.46% target -> reward:risk ~0.64 and break-even win rate ~61% vs the realized 53%. The rationale's 'risking ~1.2x what the reversion is worth' is a math error: the reversion is worth only 0.77x the deviation, so stop_mult=1.2 risks ~1.56x the reward — which is why avg_loss $159.66 is still ~1.86x avg_win $85.70. A favorable payoff requires stop_mult BELOW the capture fraction (~0.77), not above it. - Signal polarity and mechanics are CORRECT and faithfully implement the hypothesis and the iteration-2 changes (z>entry_z -> SELL, z<-entry_z -> BUY; min_dev_pct percent gate; deviation-latched stop; trend-off gate; exit ladder; capital-relative sizing). NO L17 code-defect signature (win_rate 0.53, |Sharpe| 2.45 < 5, PF 0.61). Noted so the developer does not chase a phantom coding bug — the failure is economic, not a code error.

Verification failed (Layer 4 — QA review): - MECHANISM HAS NO EDGE — now demonstrated DECISIVELY with the payoff geometry corrected. Iteration 3 correctly implemented the required fix (computed _capture_frac, target = capture_frac x entry_deviation, stop_rr=0.7 clamped <1, min_dev_pct raised 0.6->1.2%), and realized reward:risk improved (avg_win $121 vs avg_loss $167, ratio 1.38, up from iter-2's 0.54). Yet over a DECISIVE 499-trade sample it is still a clear loser: avg_trade_return_pct -0.089% (below the 0.15%……Show moreShow less

Verification failed (Layer 4 — QA review): - MECHANISM HAS NO EDGE — now demonstrated DECISIVELY with the payoff geometry corrected. Iteration 3 correctly implemented the required fix (computed _capture_frac, target = capture_frac x entry_deviation, stop_rr=0.7 clamped <1, min_dev_pct raised 0.6->1.2%), and realized reward:risk improved (avg_win $121 vs avg_loss $167, ratio 1.38, up from iter-2's 0.54). Yet over a DECISIVE 499-trade sample it is still a clear loser: avg_trade_return_pct -0.089% (below the 0.15% floor), total_return -16.2%, PF 0.63, win_rate 0.467, Sharpe -2.69 with CI [-4.54, -1.01] ENTIRELY below zero (probabilistic_sharpe 0.0011). The 1.2% deviation floor selects more extreme stretches that trend rather than revert, dropping the win rate to 46.7% — below the ~58% break-even implied by the realized geometry. Fixing the geometry did not create edge because the reversion signal has none net of costs. - The developer's OWN pre-registered abandonment condition is met. The rationale states verbatim: 'if the next backtest still shows a negative per-trade expectancy with a favourable reward:risk and a ~150-300 trade sample, that is evidence about the mechanism itself and the strategy should be abandoned rather than re-tuned.' The backtest shows exactly that: favourable designed reward:risk, a 499-trade sample, and negative expectancy (-0.089%). - The code is CORRECT and faithfully implements the iteration-3 fixes (capture_frac from entry_z/exit_z; target_pct = capture_frac * latched deviation; stop_pct = min(stop_rr*target_pct, stop_loss_pct), stop_rr clamped <=0.9; take-profit at target; polarity/trend gate/latching/sizing intact). NO L17 code-defect signature (win 0.467, |Sharpe| 2.69 < 5, PF 0.63). Noted so the developer does not chase a phantom coding bug — the geometry fix worked; the mechanism has no edge.

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