Strategies

The strategy stack

nameuniversetimeframeentryexitstatus
mean_reversion_v1BTC/ETH/SOL/AVAX/DOGE15-minEMA-9 crosses below EMA-21 + RSI(14) < 35RSI > 65 OR hold > 4h OR stop hit๐Ÿšซ negative edge on all windows โ€” 270d: 100 trades, 0.73:1 W:L, +$1.45
mean_reversion_v2BTC/ETH only15-minEMA-9/21 cross-down + RSI<32 + not in downtrend12h max OR stop>4% OR profit-lock>+1.8%๐Ÿšซ 270d: 20 trades, 0.86:1 W:L, +$0.22 โ€” wider stops help a bit, not enough
momentum_v1BTC/ETH/SOL15-minfast_ema > slow_ema * 1.0005 + close > 16-bar high2.5 ATR stop, 24h max, trend-break exit๐Ÿšซ 270d: 66 trades, 0.72:1 W:L, -$3.41 โ€” win rate 58% but stops kill winners
regime_mom_v1BTC/ETH/SOL15-minmomentum_v1 entry + regime must be trending_up (ADX โ‰ฅ 20 + EMA slope > 0)2.5 ATR stop, 24h max, trend-break exitโœ… 270d: 29 trades, 1.88:1 W:L, +$60.30, sharpe +0.535
regime_mom_v2BTC/ETH/SOL15-minregime_mom_v1 entry + volume > 1.2 ร— 20-bar SMA (the load-bearing fix)2.5 ATR stop, 24h max, trend-break exitโœ…โœ… 365d: 13 trades, 1.85:1 W:L, +$33.99, sharpe +0.898 โ€” FIRST to pass strict 0.5 Sharpe gate on 365d
regime_mr_v2BTC/ETH15-minmr_v2 entry + regime must be ranging (ADX โ‰ค 12)same as mr_v2๐Ÿšซ 90d: 2 trades, +$0.16 โ€” too few trades for stat-sig

Why regime matters: classical retail crypto strategies fail in isolation because they’re applied to wrong regimes. Mean-reversion bleeds in trending markets (stops fire before bounces play out); momentum bleeds in ranging markets (trend-break exits fire on noise). The regime filter cuts out the regime-inappropriate trades and stabilizes the backtest across multiple windows. regime_mom_v1 90d โ†’ 270d โ†’ 365d all positive (54 trades, 1.19:1 W:L on 365d) is the load-bearing structural-edge number.

Why two strategies? Single-strategy bots die when regimes rotate. BTC trades in clear regimes (trending / ranging / volatile) that change every 3-7 weeks. The bot needs to know which regime it’s in and call the appropriate strategy.

mean_reversion_v1 โ€” dead on arrival

The v1 strategy shipped on day 1 and immediately failed its 30-day backtest:

  • 9 trades over 30 days on real BTC/ETH/SOL/AVAX/DOGE bar data
  • 55.6% win rate (sounds OK; isn’t โ€” see below)
  • $-1.94 net P&L
  • 0.27:1 win:loss ratio (every win made $0.20, every loss cost $0.73)
  • sharpe-lite: -0.24

The problem is structural: the 2.5% hard stop is tighter than the average upside capture in a trending regime, so the bot cuts winners short and lets losers run. This is the textbook mean-reversion death-by-tight-stops. The strategy doesn’t have edge โ€” its wins are smaller than its losses.

Live-fire status: blocked. The harness tests/test_strategy_backtest.py is the gatekeeper; v1 never produced a positive verdict and so v1 doesn’t get a Trader.place() call into the live paper account.

momentum_v1 โ€” spec only

Still drafting. The intent: breakout in the direction of the trend with a tight trailing stop. Trade WITH momentum, not against it.

entry:  price makes a new N-bar high AND ADX > 25 (trending) AND above 200-EMA
stop:   1.5 ATR trailing
exit:   stop hit OR new N-bar low (trailing stop trails below)
universe: BTC, ETH (most liquid pairs only)

This is the strategy v1 was not. Backtest pending.

regime_classifier โ€” the controller

A single strategy is not enough. The regime classifier decides which strategy to call per pair per bar:

trending_up   โ†’ momentum_v1
ranging       โ†’ mean_reversion_v1 (with relaxed stops, since stops are the v1 killer)
trending_down โ†’ momentum_v1 (shorting, but Alpaca retail crypto is long-only โ€” handled below)
high_vol      โ†’ pause new entries, sit in cash

Alpaca retail crypto constraint: long-only. So in trending_down the bot can either (a) sit in cash (raising cash%), or (b) short a stablecoin pair, or (c) buy inverse contracts. Strategy must respect venue constraints.