Strategies
The strategy stack
| name | universe | timeframe | entry | exit | status |
|---|---|---|---|---|---|
mean_reversion_v1 | BTC/ETH/SOL/AVAX/DOGE | 15-min | EMA-9 crosses below EMA-21 + RSI(14) < 35 | RSI > 65 OR hold > 4h OR stop hit | ๐ซ negative edge on all windows โ 270d: 100 trades, 0.73:1 W:L, +$1.45 |
mean_reversion_v2 | BTC/ETH only | 15-min | EMA-9/21 cross-down + RSI<32 + not in downtrend | 12h 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_v1 | BTC/ETH/SOL | 15-min | fast_ema > slow_ema * 1.0005 + close > 16-bar high | 2.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_v1 | BTC/ETH/SOL | 15-min | momentum_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_v2 | BTC/ETH/SOL | 15-min | regime_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_v2 | BTC/ETH | 15-min | mr_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.