Auto-discovered strategy
Symbol: BTC | Exchange: Bitfinex | Role: momentum
Click a year to view chart
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +25.2% | 36.7% | 30 | 15.0% | 0.74 |
| 2021 | +34.3% | 53.3% | 15 | 5.0% | 1.57 |
| 2022 | +8.4% | 66.7% | 3 | 1.9% | 0.94 |
| 2023 | +5.5% | 28.6% | 21 | 13.9% | 0.23 |
| 2024 | +30.1% | 41.7% | 24 | 17.7% | 1.19 |
| 2025 | +8.3% | 30.0% | 10 | 3.4% | 0.89 |
| Window | Train Period | Val Period | Val Return | Val | Test Period | Test Return | Status |
|---|---|---|---|---|---|---|---|
| WF-1 | 2024-01→2025-06 | 2025-07→2025-12 | -2.8% | FAIL | 2026-01→ongoing | +0.0% | FAIL |
Not yet reviewed. Run: ./review_strategy.sh volume_surge_momentum_breakout
#!/usr/bin/env python3
"""
Volume Surge Momentum Breakout Strategy
========================================
CONCEPT: Captures momentum continuation moves when volume surges on a new high
within an established uptrend. Uses strict regime filtering to stay flat in
bear markets.
ENTRY CONDITIONS (all must be true):
1. Bull regime: EMA50 > EMA200 (macro uptrend)
2. EMA alignment: EMA20 > EMA50 (strong momentum)
3. Price above EMA20 (trend confirmation)
4. Volume surge: >= 2x 20-bar average
5. New 10-bar high (breakout)
6. Bullish candle (close > open)
EXIT CONDITIONS:
1. Close below EMA20 (momentum loss) OR
2. Regime turns bearish (EMA50 < EMA200)
RISK MANAGEMENT:
- 5% stop loss
- 15% take profit
- No trades in bear markets (regime filter)
ROLE: momentum - Expected to profit in bull, acceptable bounded loss in bear
"""
import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema, sma
def init_strategy():
return {
'name': 'volume_surge_momentum_breakout',
'role': 'momentum',
'warmup': 200,
'role': 'momentum', # Trend following, may lose bounded in bear
'subscriptions': [
{'symbol': 'tBTCUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
],
'parameters': {
'ema_fast': 20,
'ema_mid': 50,
'ema_slow': 200,
'volume_mult': 2.0,
'breakout_period': 10,
'stop_loss_pct': 5,
'take_profit_pct': 15,
}
}
def process_time_step(ctx):
key = ('tBTCUSD', 'bitfinex')
bars = ctx['bars'][key]
i = ctx['i']
positions = ctx['positions']
state = ctx['state']
# Warmup period for EMA200
if i < 200:
return []
# Pre-compute indicators (cached in state)
if 'ema20' not in state:
closes = [b.close for b in bars]
highs = [b.high for b in bars]
volumes = [b.volume for b in bars]
state['ema20'] = ema(closes, 20)
state['ema50'] = ema(closes, 50)
state['ema200'] = ema(closes, 200)
state['vol_sma'] = sma(volumes, 20)
state['highs'] = highs
ema20 = state['ema20']
ema50 = state['ema50']
ema200 = state['ema200']
vol_sma = state['vol_sma']
highs = state['highs']
actions = []
# Safety: check for None values
if ema50[i] is None or ema200[i] is None or vol_sma[i] is None or ema20[i] is None:
return []
# REGIME FILTER: Bull market only
in_bull_regime = ema50[i] > ema200[i]
if key not in positions:
# === ENTRY LOGIC ===
# Hard filter: No trades in bear market
if not in_bull_regime:
return []
# 1. EMA alignment: strong momentum (EMA20 > EMA50)
ema_aligned = ema20[i] > ema50[i]
# 2. Price above EMA20: confirming trend
above_ema20 = bars[i].close > ema20[i]
# 3. Volume surge: >= 2x average
vol_ratio = bars[i].volume / vol_sma[i] if vol_sma[i] > 0 else 0
volume_surge = vol_ratio >= 2.0
# 4. New 10-bar high: breakout confirmation
high_10 = max(highs[i-10:i])
new_high = bars[i].close > high_10
# 5. Bullish candle: close > open
bullish_candle = bars[i].close > bars[i].open
# All conditions must be met
if ema_aligned and above_ema20 and volume_surge and new_high and bullish_candle:
actions.append({
'action': 'open_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
'size': 1.0,
'stop_loss_pct': 5,
'take_profit_pct': 15,
})
else:
# === EXIT LOGIC ===
# 1. Momentum loss: close below EMA20
below_ema20 = bars[i].close < ema20[i]
# 2. Regime turns bearish
regime_broken = not in_bull_regime
if below_ema20 or regime_broken:
actions.append({
'action': 'close_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
})
return actions
if __name__ == "__main__":
from strategy import backtest_strategy
print("\n" + "="*60)
print("VOLUME SURGE MOMENTUM BREAKOUT - BACKTEST")
print("="*60)
results, profitable, _ = backtest_strategy(init_strategy, process_time_step)
print("\n" + "="*60)
if profitable >= 2:
print(f"SUCCESS: {profitable}/2 train periods profitable")
print("Strategy ready for validation on unseen 2025-H2 data")
else:
print(f"NEEDS WORK: Only {profitable}/2 profitable")