Auto-discovered strategy
Symbol: DOGE | Exchange: Binance | Role: momentum
Click a year to view chart
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | -25.9% | 16.7% | 24 | 31.5% | -1.02 |
| 2021 | +14.9% | 42.9% | 14 | 25.1% | 0.59 |
| 2022 | +6.6% | 33.3% | 12 | 25.2% | 0.28 |
| 2023 | +46.4% | 36.4% | 33 | 17.9% | 1.31 |
| 2024 | +71.3% | 46.2% | 26 | 17.9% | 2.05 |
| 2025 | +0.7% | 26.7% | 15 | 15.0% | 0.03 |
| Window | Train Period | Val Period | Val Return | Val | Test Period | Test Return | Status |
|---|---|---|---|---|---|---|---|
| WF-1 | 2024-01→2025-06 | 2025-07→2025-12 | -15.2% | FAIL | 2026-01→ongoing | +0.0% | FAIL |
Not yet reviewed. Run: ./review_strategy.sh doge_ema50_support_bounce
"""
EMA50 Support Zone Bounce Strategy for DOGEUSDT
=================================================
A support/resistance bounce strategy that uses the EMA50 as dynamic support.
Strategy Logic:
1. REGIME FILTER: Only trade in bull markets (EMA50 > EMA100)
2. TREND FILTER: Only trade in uptrends (EMA20 > EMA50)
3. SUPPORT ZONE: Enter when price touches EMA50 zone (within 3%)
4. BOUNCE CONFIRM: Bullish candle closing above EMA50 with volume
5. EXIT: Close below EMA50 (trend break)
Key Principles (Avoiding Overfitting):
- Uses RELATIVE indicators only (EMAs, % distance)
- Round parameter values (20, 50, 100 for EMAs)
- Simple logic with few conditions
- Regime-aware: stays flat when EMA50 < EMA100
Train Performance (2024-01-01 to 2025-06-30):
2024: +71.3% | 26 trades | 46% WR
2025H1: +5.9% | 6 trades | 33% WR
Total: +77.2% | 2/2 years profitable
"""
import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema
def init_strategy():
"""Initialize the EMA50 support bounce strategy."""
return {
'name': 'doge_ema50_support_bounce',
'role': 'momentum', # Trend-following with support bounces
'warmup': 100, # EMA100 needs 100 bars
'subscriptions': [
{'symbol': 'DOGEUSDT', 'exchange': 'binance', 'timeframe': '4h'},
],
'parameters': {}
}
def process_time_step(ctx):
"""Process each time step and return trading actions."""
key = ('DOGEUSDT', 'binance')
bars = ctx['bars'][key]
i = ctx['i']
positions = ctx['positions']
# Extract price data
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]
opens = [b.open for b in bars]
# Calculate EMAs
ema20 = ema(closes, 20)
ema50 = ema(closes, 50)
ema100 = ema(closes, 100)
# Skip if indicators not ready
if ema20[i] is None or ema50[i] is None or ema100[i] is None:
return []
actions = []
if key not in positions:
# ==================
# ENTRY LOGIC
# ==================
# REGIME FILTER: Macro uptrend (EMA50 > EMA100)
if ema50[i] <= ema100[i]:
return []
# TREND FILTER: Short-term uptrend (EMA20 > EMA50)
if ema20[i] <= ema50[i]:
return []
# SUPPORT ZONE CHECK
# Price touched within 3% of EMA50 in last 2 bars
touched_zone = False
for k in range(max(0, i-2), i+1):
distance = abs(lows[k] - ema50[k]) / ema50[k]
if distance <= 0.03:
touched_zone = True
break
if not touched_zone:
return []
# BOUNCE CONFIRMATION
# 1. Close above EMA50
above_ema50 = closes[i] > ema50[i]
# 2. Bullish candle
bullish = closes[i] > opens[i]
# 3. Not overextended (within 5% of EMA50)
not_extended = closes[i] < ema50[i] * 1.05
# 4. Volume confirmation (>= 80% of 20-bar average)
avg_vol = sum(volumes[max(0, i-20):i]) / min(20, i) if i > 0 else 1
vol_ok = volumes[i] >= avg_vol * 0.8
if above_ema50 and bullish and not_extended and vol_ok:
actions.append({
'action': 'open_long',
'symbol': 'DOGEUSDT',
'exchange': 'binance',
'size': 1.0,
'stop_loss_pct': 5.0, # 5% stop loss
'take_profit_pct': 10.0, # 10% take profit (2:1 R:R)
})
else:
# ==================
# EXIT LOGIC
# ==================
# Trend break: close below EMA50 (with 1% buffer for noise)
if closes[i] < ema50[i] * 0.99:
actions.append({
'action': 'close_long',
'symbol': 'DOGEUSDT',
'exchange': 'binance',
})
return actions
# For testing/validation
if __name__ == '__main__':
from strategy import backtest_strategy
results, profitable, _ = backtest_strategy(init_strategy, process_time_step)