← Back to list

doge_ema50_pullback_v2 VALIDATED FAIL

Auto-discovered strategy

Symbol: DOGE | Exchange: Binance | Role: momentum

4/6
Profitable Years
+604.8%
Total Return
25.9%
Avg Win Rate
0.30
Avg Sharpe

Year-by-Year Results

Click a year to view chart

Year Return Win Rate Trades Max DD Sharpe
2020 +39.1% 26.1% 23 23.2% 0.94
2021 +332.1% 31.2% 16 21.9% 0.96
2022 -22.1% 20.0% 10 20.5% -2.03
2023 -1.4% 30.4% 23 15.4% -0.05
2024 +237.4% 26.1% 23 24.9% 1.40
2025 +19.7% 21.4% 14 18.4% 0.56

Performance Chart

Loading chart...

Walk-Forward Validation FAIL

0/1 Windows Profitable
-16.9% OOS Return
0.00 Median Sharpe
0.000 Score
Window Train Period Val Period Val Return Val Test Period Test Return Status
WF-1 2024-01→2025-06 2025-07→2025-12 -16.9% FAIL 2026-01→ongoing +0.0% FAIL

AI Review

Not yet reviewed. Run: ./review_strategy.sh doge_ema50_pullback_v2

Source Code

"""
DOGE EMA50 Pullback Strategy
=============================

Buy pullbacks to EMA50 in confirmed uptrends on DOGE/USDT.

Entry Conditions:
1. Macro uptrend: EMA50 > EMA200
2. Mid-term momentum: EMA100 rising (5-bar slope positive)
3. Pullback zone: Low within 3% of EMA50
4. Bounce confirmed: Close above EMA50
5. Not overextended: Close < EMA50 * 1.10
6. Volume confirmation: Above 80% of 20-bar average

Exit Conditions:
1. Close below EMA50 by 1%
2. EMA100 starts falling (early trend weakness warning)
3. Trend reversal: EMA50 < EMA200

Risk Management:
- 5% stop loss per trade
- Only trades during confirmed uptrends

Train Performance (2024-01 to 2025-06):
- 2024: +237.4% | 23 trades | 26% WR | Sharpe 1.40 | MaxDD 24.9%
- 2025H1: +13.2% | 6 trades | 33% WR | Sharpe 0.61 | MaxDD 5.6%
- Total: +250.6% | Profit Factor: 4.59
"""

import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema, sma, atr


def init_strategy():
    return {
        'name': 'doge_ema50_pullback_v2',
        'role': 'momentum',
        'warmup': 200,
        'subscriptions': [
            {'symbol': 'DOGEUSDT', 'exchange': 'binance', 'timeframe': '4h'},
        ],
        'parameters': {}
    }


def process_time_step(ctx):
    key = ('DOGEUSDT', 'binance')
    bars = ctx['bars'][key]
    i = ctx['i']
    positions = ctx['positions']

    # Initialize indicators once
    if 'indicators' not in ctx['state']:
        closes = [b.close for b in bars]
        lows = [b.low for b in bars]
        highs = [b.high for b in bars]
        volumes = [b.volume for b in bars]

        ctx['state']['indicators'] = {
            'ema50': ema(closes, 50),
            'ema100': ema(closes, 100),
            'ema200': ema(closes, 200),
            'atr': atr(highs, lows, closes, 20),
            'vol_sma': sma(volumes, 20),
        }

    ind = ctx['state']['indicators']

    # Safety checks
    if ind['ema50'][i] is None or ind['ema100'][i] is None or ind['ema200'][i] is None:
        return []
    if ind['atr'][i] is None or ind['vol_sma'][i] is None:
        return []

    actions = []

    if key not in positions:
        # === ENTRY CONDITIONS ===

        # 1. MACRO REGIME: EMA50 > EMA200 (uptrend)
        macro_uptrend = ind['ema50'][i] > ind['ema200'][i]
        if not macro_uptrend:
            return []

        # 2. MID REGIME: EMA100 rising (5-bar slope positive)
        if i >= 5 and ind['ema100'][i-5] is not None:
            ema100_rising = ind['ema100'][i] > ind['ema100'][i-5]
        else:
            ema100_rising = False
        if not ema100_rising:
            return []

        # 3. PULLBACK: Low within 3% of EMA50
        ema50 = ind['ema50'][i]
        low = bars[i].low
        pullback_zone = low <= ema50 * 1.03 and low >= ema50 * 0.97

        # 4. BOUNCE: Close above EMA50
        close_above = bars[i].close > ema50

        # 5. NOT OVER-EXTENDED: Close within 10% of EMA50
        not_extended = bars[i].close < ema50 * 1.10

        # 6. VOLUME: Above 80% average
        volume_ok = bars[i].volume > ind['vol_sma'][i] * 0.8

        if pullback_zone and close_above and not_extended and volume_ok:
            actions.append({
                'action': 'open_long',
                'symbol': 'DOGEUSDT',
                'exchange': 'binance',
                'size': 1.0,
                'stop_loss_pct': 5.0,
            })
    else:
        # === EXIT CONDITIONS ===

        # Exit if close below EMA50 by 1%
        if bars[i].close < ind['ema50'][i] * 0.99:
            actions.append({
                'action': 'close_long',
                'symbol': 'DOGEUSDT',
                'exchange': 'binance',
            })
        # Exit if EMA100 starts falling (early warning)
        elif i >= 5 and ind['ema100'][i-5] is not None and ind['ema100'][i] <= ind['ema100'][i-5]:
            actions.append({
                'action': 'close_long',
                'symbol': 'DOGEUSDT',
                'exchange': 'binance',
            })
        # Exit if trend reverses
        elif ind['ema50'][i] < ind['ema200'][i]:
            actions.append({
                'action': 'close_long',
                'symbol': 'DOGEUSDT',
                'exchange': 'binance',
            })

    return actions


# For direct testing
if __name__ == '__main__':
    from strategy import backtest_strategy
    print("Testing DOGE EMA50 Pullback V2")
    print("="*50)
    results, profitable, _ = backtest_strategy(init_strategy, process_time_step)