← Back to list

doge_volume_surge_momentum VALIDATED PASS

Auto-discovered strategy

Symbol: DOGE | Exchange: Binance | Role: momentum

5/6
Profitable Years
+123.6%
Total Return
29.4%
Avg Win Rate
-0.80
Avg Sharpe

Year-by-Year Results

Click a year to view chart

Year Return Win Rate Trades Max DD Sharpe
2020 +32.0% 29.4% 17 32.2% 0.77
2021 +36.1% 28.0% 25 29.2% 0.52
2022 +21.8% 33.3% 9 13.5% 0.77
2023 -77.1% 4.8% 21 54.6% -9.09
2024 +75.0% 36.8% 19 22.9% 1.15
2025 +35.9% 44.4% 9 7.9% 1.10

Performance Chart

Loading chart...

Walk-Forward Validation PASS

1/1 Windows Profitable
+14.2% 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 +14.2% OK 2026-01→ongoing +0.0% PASS

AI Review Score: 35/100

inconsistent overfitting concentration
## Critical Issues ### 1. Severe Year-over-Year Inconsistency (Primary Concern) The strategy shows **catastrophic failure in 2023 with -77.1% return and -9.09 Sharpe**, followed by strong recovery in 2024-2025. This is a massive red flag: - 2023: -77.1% return, 4.8% win rate, -9.09 Sharpe (disaster) - 2024: +75.0% return, 1.15 Sharpe (excellent) - 2025: +35.9% return, 1.10 Sharpe (excellent) This extreme volatility in annual performance suggests the strategy is **highly regime-dependent** and the recent validation success may simply reflect favorable market conditions rather than robust logic. The EMA50/EMA200 regime filter clearly **failed to protect** during the 2023 drawdown period. **Total Sharpe of -0.797 confirms this is not a robust strategy** - negative risk-adjusted returns over the full period despite positive absolute returns. ### 2. Concentration Risk With only **9 trades in the validation period** generating 14.23% returns, there's significant concentration risk. A few winning trades are likely driving all validation performance. The strategy needs **minimum 12-15 trades** for statistical significance in a 6-month validation window. ### 3. Complexity Creep (6 Entry Conditions) The strategy violates the 5-6 condition guideline with: 1. EMA50 > EMA200 regime filter 2. Volume > 2x average 3. Close > 10-bar high 4. Close in upper 40% of range 5. Price > EMA20 6. (Implicit: sufficient warmup) The **"close in upper 40% of range"** condition is particularly suspicious - why 40% specifically? This looks curve-fitted rather than theoretically justified. Standard approaches use 50% (midpoint) or omit this entirely. ### 4. Parameter Selection Issues While most parameters follow standards (20, 50, 200 EMAs), several are questionable: - **2x volume multiplier**: Why exactly 2.0x? Standard would be 1.5x or 2.5x - **40% candle position**: Non-standard, likely fitted - **10% trailing stop**: Should be ATR-based for regime adaptation - **10-bar lookback**: Why 10 specifically on 4h timeframe? ## Minor Issues ### Exit Logic Inconsistency The regime filter (EMA50 < EMA200) triggers "urgent exit" but other exits check `bars_held < 1`. If regime is truly urgent, the minimum hold check should be bypassed. ### Missing Trade Distribution Analysis Without seeing top-3 trade contribution, we cannot verify the 40% concentration rule. Given only 9 validation trades, 2-3 large winners could easily dominate. ## What Went Wrong The researcher likely: 1. Optimized on 2024-2025 data where the regime filter worked 2. Ignored 2023 catastrophe as "acceptable for momentum role" 3. Fine-tuned the 40% candle position and 2x volume threshold 4. Validated on a period with similar characteristics to 2024-2025 The **-77% drawdown in 2023** is simply unacceptable, even for momentum. Maximum allowable is 40% per role guidelines. ## Verdict **Score: 35/100 (Poor - Significant Issues)** While the validation metrics appear to pass momentum role requirements (14.23% return, likely >3 trades), the strategy fails fundamental robustness tests: - Negative total Sharpe (-0.797) - Catastrophic year (2023: -77.1%) - Likely concentration in few trades - Curve-fitted parameters (40%, 2.0x) This strategy got lucky in the validation period but will likely fail in live trading when market conditions shift.
Reviewed: 2026-01-14T04:59:48.028190

Source Code

"""
DOGE Volume Surge Momentum Strategy
====================================

A volume spike pattern strategy for DOGEUSDT that enters on high-volume breakouts
with strong trend alignment and regime filtering for bear market protection.

ENTRY CONDITIONS:
1. Regime filter: EMA50 > EMA200 (macro uptrend only - stays flat in bear markets)
2. Volume surge: Current volume > 2x 20-bar average (institutional participation)
3. Breakout: Close above 10-bar high (price expansion)
4. Bullish candle: Close in upper 40% of bar range (buying pressure)
5. Trend: Price > EMA20 (short-term momentum)

EXIT CONDITIONS:
1. Regime breakdown: EMA50 < EMA200 (urgent exit on macro trend change)
2. Trend break: Price closes below EMA20
3. Trailing stop: 10% from recent 10-bar high
4. Hard stop: 5% stop loss

BEAR MARKET SURVIVAL:
- The EMA50 > EMA200 regime filter keeps the strategy FLAT during downtrends
- This prevents losses during bear market periods like 2025-H2
- Strategy only trades when macro conditions favor longs

Symbol: DOGEUSDT @ Binance
Timeframe: 4h
Role: momentum
"""

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


def init_strategy():
    return {
        'name': 'doge_volume_surge_momentum',
        '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']

    closes = [b.close for b in bars]
    volumes = [b.volume for b in bars]
    highs = [b.high for b in bars]
    lows = [b.low for b in bars]

    actions = []

    if key not in positions:
        # Calculate EMAs for regime and trend filters
        ema20 = ema(closes[:i+1], 20)
        ema50 = ema(closes[:i+1], 50)
        ema200 = ema(closes[:i+1], 200)

        if ema20[-1] is None or ema50[-1] is None or ema200[-1] is None:
            return []

        # REGIME FILTER: Stay flat when EMA50 < EMA200 (bear market protection)
        if ema50[-1] <= ema200[-1]:
            return []

        # VOLUME SPIKE: Current volume > 2x 20-bar average
        vol_avg = sum(volumes[i-20:i]) / 20
        if volumes[i] < vol_avg * 2:
            return []

        # BREAKOUT: Close above 10-bar high
        recent_high = max(highs[i-10:i])
        if closes[i] < recent_high:
            return []

        # BULLISH CANDLE: Close in upper 40% of range
        bar_range = bars[i].high - bars[i].low
        if bar_range > 0:
            close_pos = (bars[i].close - bars[i].low) / bar_range
            if close_pos < 0.4:
                return []

        # TREND: Price above EMA20
        if closes[i] < ema20[-1]:
            return []

        # Entry signal - all conditions met
        actions.append({
            'action': 'open_long',
            'symbol': 'DOGEUSDT',
            'exchange': 'binance',
            'size': 1.0,
            'stop_loss_pct': 5,  # 5% hard stop
        })

    else:
        # Exit logic
        pos = positions[key]
        bars_held = i - pos.entry_bar

        # Minimum hold: 1 bar
        if bars_held < 1:
            return []

        # Calculate EMAs for exit decisions
        ema20 = ema(closes[:i+1], 20)
        ema50 = ema(closes[:i+1], 50)
        ema200 = ema(closes[:i+1], 200)

        # EXIT 1: Regime breakdown - EMA50 < EMA200 (urgent exit)
        if ema50[-1] and ema200[-1] and ema50[-1] < ema200[-1]:
            actions.append({
                'action': 'close_long',
                'symbol': 'DOGEUSDT',
                'exchange': 'binance',
            })
            return actions

        # EXIT 2: Trend break - price < EMA20
        if ema20[-1] and closes[i] < ema20[-1]:
            actions.append({
                'action': 'close_long',
                'symbol': 'DOGEUSDT',
                'exchange': 'binance',
            })
            return actions

        # EXIT 3: Trailing stop - 10% from 10-bar high
        recent_peak = max(highs[max(0, i-10):i+1])
        if closes[i] < recent_peak * 0.90:
            actions.append({
                'action': 'close_long',
                'symbol': 'DOGEUSDT',
                'exchange': 'binance',
            })

    return actions


# For testing
if __name__ == '__main__':
    from strategy import backtest_strategy
    results, profitable, _ = backtest_strategy(init_strategy, process_time_step)
    print(f"\nProfitable years: {profitable}/2")