Auto-discovered strategy
Symbol: ETH | Exchange: Bitfinex | Role: momentum
Click a year to view chart
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +15.8% | 44.0% | 25 | 14.4% | 0.57 |
| 2021 | +9.4% | 47.1% | 17 | 8.7% | 0.42 |
| 2022 | -24.8% | 14.3% | 7 | 22.6% | -4.19 |
| 2023 | -13.7% | 38.1% | 21 | 19.2% | -0.82 |
| 2024 | +19.0% | 56.2% | 16 | 12.1% | 1.04 |
| 2025 | +32.4% | 58.3% | 12 | 5.8% | 2.11 |
| Window | Train Period | Val Period | Val Return | Val | Test Period | Test Return | Status |
|---|---|---|---|---|---|---|---|
| WF-1 | 2024-01→2025-06 | 2025-07→2025-12 | +9.6% | OK | 2026-01→ongoing | +0.0% | PASS |
Not yet reviewed. Run: ./review_strategy.sh eth_ema_stack_momentum
"""
ETH EMA Stack Momentum Strategy
===============================
A momentum strategy for tETHUSD that enters when price shows strong
trend confirmation across multiple EMA timeframes with rising slopes.
CONCEPT:
When all EMAs (20, 50, 200) are in a "stacked" bullish configuration
AND all are rising, this indicates strong institutional conviction.
We enter when price shows momentum (consecutive higher closes) within
a healthy distance zone from the trend (1.5-8% above EMA50).
This differs from other EMA strategies by focusing on:
1. SLOPE AGREEMENT: All 3 major EMAs must be rising (not just aligned)
2. DISTANCE ZONE: Price must be in a "goldilocks" zone from EMA50
3. MOMENTUM CONFIRMATION: Consecutive higher closes required
ENTRY CONDITIONS:
1. Full EMA cascade: Price > EMA20 > EMA50 > EMA200
2. All EMAs rising:
- EMA20 higher than 5 bars ago
- EMA50 higher than 10 bars ago
- EMA200 higher than 20 bars ago
3. Price momentum: 2 consecutive higher closes
4. Distance zone: 1.5-8% above EMA50 (not too close, not extended)
5. Bullish bar: Close > Open, close in upper 50% of range
6. Bar quality: Range > 0.5x ATR(20)
7. Volume: Above 20-bar average
EXIT CONDITIONS:
1. Price closes below EMA50 (trend weakening)
2. EMA20 crosses below EMA50 (bearish cross)
3. Time exit: 15 bars maximum hold
4. Stop loss: 5%
5. Take profit: 8%
TRAIN RESULTS (2024-01 to 2025-06):
2024: +19.0% | 16 trades | 56% WR | 8.8% max DD
2025H1: +2.5% | 6 trades | 33% WR | 5.8% max DD
Total: +21.5%
ROBUSTNESS FEATURES:
- Uses only relative indicators (EMAs, ATR, volume ratios)
- Round parameters: 5, 10, 15, 20, 50, 200
- All EMAs must be rising - strong trend confirmation
- Distance zone prevents chasing extended moves
- Momentum confirmation reduces false signals
Symbol: tETHUSD
Exchange: bitfinex
Timeframe: 4h
Role: momentum
"""
import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema, sma, atr
def init_strategy():
"""Initialize the EMA Stack Momentum strategy."""
return {
'name': 'eth_ema_stack_momentum',
'role': 'momentum',
'warmup': 200, # EMA200 needs 200 bars
'subscriptions': [
{'symbol': 'tETHUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
],
'parameters': {}
}
def process_time_step(ctx):
"""
Process each time step and return trading actions.
Entry Logic:
- Full EMA cascade alignment (Price > EMA20 > EMA50 > EMA200)
- All EMAs rising (slope check)
- Price momentum (consecutive higher closes)
- Distance zone (1.5-8% above EMA50)
- Bullish bar confirmation
- Volume above average
Exit Logic:
- Close below EMA50
- EMA20 < EMA50 crossover
- Time exit (15 bars)
- Stop loss 5%, Take profit 8%
"""
key = ('tETHUSD', 'bitfinex')
bars = ctx['bars'].get(key, [])
i = ctx['i']
positions = ctx['positions']
if not bars or i >= len(bars):
return []
closes = [b.close for b in bars]
highs = [b.high for b in bars]
lows = [b.low for b in bars]
volumes = [b.volume for b in bars]
# Calculate indicators
ema20 = ema(closes, 20)
ema50 = ema(closes, 50)
ema200 = ema(closes, 200)
vol_ma = sma(volumes, 20)
atr_vals = atr(highs, lows, closes, 20)
# Ensure all indicators are valid
if any(x[i] is None for x in [ema20, ema50, ema200, vol_ma, atr_vals]):
return []
if i < 20:
return []
actions = []
has_position = key in positions
if not has_position:
# ==================== ENTRY CONDITIONS ====================
# 1. FULL EMA CASCADE: Price > EMA20 > EMA50 > EMA200
if not (closes[i] > ema20[i] > ema50[i] > ema200[i]):
return []
# 2. ALL EMAs RISING (slope confirmation)
ema20_rising = ema20[i] > ema20[i-5] if ema20[i-5] else False
ema50_rising = ema50[i] > ema50[i-10] if ema50[i-10] else False
ema200_rising = ema200[i] > ema200[i-20] if ema200[i-20] else False
if not (ema20_rising and ema50_rising and ema200_rising):
return []
# 3. MOMENTUM: 2 consecutive higher closes
if closes[i] <= closes[i-1] or closes[i-1] <= closes[i-2]:
return []
# 4. DISTANCE ZONE: 1.5-8% above EMA50
dist_ema50 = (closes[i] - ema50[i]) / ema50[i] * 100
if dist_ema50 < 1.5 or dist_ema50 > 8.0:
return []
# 5. BULLISH BAR: Close > Open and in upper 50% of range
if bars[i].close <= bars[i].open:
return []
bar_range = highs[i] - lows[i]
if bar_range > 0:
close_pos = (closes[i] - lows[i]) / bar_range
if close_pos < 0.5:
return []
# 6. BAR QUALITY: Range > 0.5x ATR
if bar_range < atr_vals[i] * 0.5:
return []
# 7. VOLUME: Above 20-bar average
if volumes[i] < vol_ma[i]:
return []
# All conditions met - ENTER LONG
actions.append({
'action': 'open_long',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
'size': 1.0,
'stop_loss_pct': 5.0, # 5% stop loss
'take_profit_pct': 8.0, # 8% take profit
})
else:
# ==================== EXIT CONDITIONS ====================
pos = positions[key]
bars_held = i - pos.entry_bar
# 1. Close below EMA50 (trend weakening)
below_ema50 = closes[i] < ema50[i]
# 2. EMA20 crosses below EMA50 (bearish cross)
ema_breakdown = ema20[i] < ema50[i]
# 3. Time exit: 15 bars maximum hold
time_exit = bars_held >= 15
if below_ema50 or ema_breakdown or time_exit:
actions.append({
'action': 'close_long',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
})
return actions
# Allow direct execution for testing
if __name__ == "__main__":
from strategy import backtest_strategy
print("Testing ETH EMA Stack Momentum Strategy...")
results, profitable, _ = backtest_strategy(init_strategy, process_time_step, verbose=True)