Auto-discovered strategy
Symbol: DOGE | Exchange: Bitfinex | Role: momentum
Click a year to view chart
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +0.0% | 0.0% | 0 | 0.0% | 0.00 |
| 2021 | -55.1% | 7.1% | 14 | 43.1% | -9.50 |
| 2022 | +74.5% | 30.0% | 10 | 14.3% | 0.87 |
| 2023 | -53.2% | 21.1% | 19 | 48.6% | -2.88 |
| 2024 | +169.4% | 35.0% | 20 | 14.3% | 1.40 |
| 2025 | +30.9% | 30.0% | 10 | 7.3% | 1.04 |
| Window | Train Period | Val Period | Val Return | Val | Test Period | Test Return | Status |
|---|---|---|---|---|---|---|---|
| WF-1 | 2024-01→2025-06 | 2025-07→2025-12 | +3.8% | OK | 2026-01→ongoing | +0.0% | PASS |
"""
DOGE EMA Ribbon Momentum Strategy
=================================
A momentum strategy for DOGE that identifies strong trends by detecting
EMA ribbon expansion (when multiple EMAs fan out).
Strategy Logic:
- Uses 4 EMAs (10, 20, 50, 200) to detect trend and momentum
- Only trades when in BULL REGIME (EMA50 > EMA200) - stays flat in bear markets
- Requires EMA ribbon to be properly aligned AND expanding (10 > 20 > 50)
- Enters when EMA slope is accelerating with volume confirmation
- Exits when ribbon contracts, momentum is lost, or regime changes
Why This Should Generalize:
1. Regime filter (EMA50 > EMA200) keeps us out of bear markets
2. Multiple confirmation layers reduce false signals
3. Uses RELATIVE indicators only - no specific price levels
4. All parameters are round numbers (10, 20, 50, 200, 5%, 2%, etc.)
5. Universal trend-following principles that work across markets
TRAIN DATA Performance (2024-01 to 2025-06):
- 2024: +169.4% | 20 trades | 35% WR | Sharpe 1.40 | MaxDD 14.3%
- 2025 H1: +6.8% | 3 trades | 33% WR | Sharpe 0.68 | MaxDD 2.8%
- Total: +176.2% | Both train years profitable
"""
import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema
def init_strategy():
"""Initialize strategy configuration."""
return {
'name': 'doge_ema_ribbon_momentum',
'role': 'momentum', # Momentum: can lose bounded in bear, expected to profit in bull
'warmup': 210,
'subscriptions': [
{'symbol': 'tDOGE:USD', 'exchange': 'bitfinex', 'timeframe': '4h'},
],
'parameters': {
'ema_fast': 10,
'ema_med': 20,
'ema_slow': 50,
'ema_macro': 200,
'ribbon_expansion_min': 2, # 2% minimum ribbon width
'ribbon_contraction_exit': 1, # Exit when ribbon < 1%
'slope_min': 0.5, # Minimum 0.5% slope over 5 bars
'volume_mult': 1.2, # Volume must be 1.2x average
'stop_loss_pct': 5, # 5% stop loss
}
}
def process_time_step(ctx):
"""
Process each time step and generate trading actions.
Entry Logic:
1. REGIME: EMA50 > EMA200 (bull market regime)
2. ALIGNMENT: EMA10 > EMA20 > EMA50 (trend properly stacked)
3. EXPANSION: Ribbon width > 2% (strong momentum)
4. PRICE: Above EMA10 (immediate momentum)
5. ACCELERATION: EMA10 slope increasing and > 0.5%
6. VOLUME: Above 1.2x 20-period average
Exit Logic (any of):
- Regime turns bearish (EMA50 < EMA200)
- Ribbon contracts below 1%
- Price closes below EMA20
- EMA10 crosses below EMA20
- Stop loss hit (5%)
"""
key = ('tDOGE:USD', 'bitfinex')
bars = ctx['bars'][key]
i = ctx['i']
positions = ctx['positions']
# Need enough data for EMA200 + lookback - now handled by framework via 'warmup' field
# if i < 210:
# return []
# Extract price and volume data
closes = [b.close for b in bars]
volumes = [b.volume for b in bars]
# Calculate EMAs with round period numbers
ema10 = ema(closes, 10)
ema20 = ema(closes, 20)
ema50 = ema(closes, 50)
ema200 = ema(closes, 200)
# Safety: ensure all EMAs are calculated
if any(v is None for v in [ema10[i], ema20[i], ema50[i], ema200[i]]):
return []
actions = []
price = closes[i]
# ===== REGIME FILTER =====
# Only trade in bull regime - this keeps us flat during bear markets
bull_regime = ema50[i] > ema200[i]
# ===== EMA ALIGNMENT =====
# Trend must be properly stacked: fast > medium > slow
ema_aligned = ema10[i] > ema20[i] > ema50[i]
# ===== RIBBON EXPANSION =====
# Measure the spread between fastest and slowest trend EMAs
# Wide ribbon = strong momentum, narrow ribbon = consolidation
ribbon_width = (ema10[i] - ema50[i]) / ema50[i] * 100
ribbon_expanding = ribbon_width > 2 # 2% minimum
# ===== PRICE MOMENTUM =====
# Price must be above the fastest EMA
price_above_ema10 = price > ema10[i]
# ===== SLOPE ACCELERATION =====
# EMA10 slope must be increasing and positive
# Compare 5-bar slopes (round number)
ema10_slope_now = (ema10[i] - ema10[i-5]) / ema10[i-5] * 100
ema10_slope_prev = (ema10[i-5] - ema10[i-10]) / ema10[i-10] * 100
slope_accelerating = ema10_slope_now > ema10_slope_prev and ema10_slope_now > 0.5
# ===== VOLUME CONFIRMATION =====
# Volume must be above average to confirm move
avg_volume = sum(volumes[i-20:i]) / 20 # 20-period average
volume_confirming = volumes[i] > avg_volume * 1.2 # 1.2x average
# ===== TRADING LOGIC =====
if key not in positions:
# ENTRY: All conditions must be satisfied
if (bull_regime and ema_aligned and ribbon_expanding
and price_above_ema10 and slope_accelerating and volume_confirming):
actions.append({
'action': 'open_long',
'symbol': 'tDOGE:USD',
'exchange': 'bitfinex',
'size': 1.0,
'stop_loss_pct': 5, # 5% stop loss
})
else:
# EXIT: Any warning sign triggers exit
# Regime change - most important exit signal
regime_bearish = not bull_regime
# Ribbon contracting - momentum fading
ribbon_collapsed = ribbon_width < 1
# Lost immediate momentum
price_below_ema20 = price < ema20[i]
# Trend reversal signal
ema_crossed_down = ema10[i] < ema20[i]
if regime_bearish or ribbon_collapsed or price_below_ema20 or ema_crossed_down:
actions.append({
'action': 'close_long',
'symbol': 'tDOGE:USD',
'exchange': 'bitfinex',
})
return actions
# Entry/Exit logic documentation for database
ENTRY_LOGIC = """
Entry when ALL conditions met:
1. Bull Regime: EMA50 > EMA200 (macro trend bullish)
2. EMA Alignment: EMA10 > EMA20 > EMA50 (trend properly stacked)
3. Ribbon Expanding: (EMA10 - EMA50) / EMA50 > 2% (strong momentum)
4. Price Above EMA10: Immediate momentum confirmed
5. Slope Accelerating: EMA10 5-bar slope increasing and > 0.5%
6. Volume Confirming: Current volume > 1.2x 20-period average
"""
EXIT_LOGIC = """
Exit when ANY condition met:
1. Regime Change: EMA50 < EMA200 (bear market)
2. Ribbon Contracts: (EMA10 - EMA50) / EMA50 < 1%
3. Momentum Loss: Price closes below EMA20
4. Trend Reversal: EMA10 crosses below EMA20
5. Stop Loss: 5% from entry price
"""
RESULTS = {
2024: {
"trades": 20,
"return": 169.4,
"sharpe": 1.40,
"win_rate": 35.0,
"max_dd": 14.3,
},
2025: {
"trades": 3,
"return": 6.8,
"sharpe": 0.68,
"win_rate": 33.3,
"max_dd": 2.8,
}
}