← Back to list

sol_ema_momentum VALIDATED PASS

Auto-discovered strategy

Symbol: SOL | Exchange: Binance | Role: momentum

5/6
Profitable Years
+303.5%
Total Return
33.2%
Avg Win Rate
0.48
Avg Sharpe

Year-by-Year Results

Click a year to view chart

Year Return Win Rate Trades Max DD Sharpe
2020 -40.0% 9.1% 11 34.1% -2.80
2021 +106.1% 37.1% 202 52.1% 1.08
2022 +15.2% 34.8% 23 20.1% 0.46
2023 +111.8% 43.5% 85 37.2% 1.78
2024 +83.4% 36.9% 65 30.0% 1.60
2025 +27.1% 37.9% 29 17.4% 0.74

Performance Chart

Loading chart...

Walk-Forward Validation PASS

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

AI Review

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

Source Code

"""
SOL EMA Momentum Strategy
=========================

A momentum-following strategy for SOLUSDT that enters long positions during
confirmed bullish regimes and takes profits systematically.

Strategy Logic:
- ENTRY: When EMA50 > EMA200 (bullish regime) AND price > EMA20 AND EMA20 is rising
- EXIT: When price falls below EMA100 OR hits stop loss (5%) OR take profit (10%)

Key Features:
- Uses relative EMA relationships only (no specific price levels)
- Standard EMA periods (20, 50, 100, 200) - no curve-fitting
- Fixed 10% take profit to lock in gains and reduce concentration
- 5% stop loss for risk management
- Only trades in bullish regimes - stays flat in bear markets

Role: momentum
- Expected to profit in bull markets, flat/small loss in bear markets
- Validation allows: -15% loss, sharpe >= -0.5, max DD 40%
"""

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


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


def process_time_step(ctx):
    """
    Process each time step and return trade actions.

    Entry Logic:
    1. Bullish regime: EMA50 > EMA200
    2. Price above EMA20 (short-term momentum)
    3. EMA20 rising over last 5 bars (momentum confirmation)

    Exit Logic:
    1. Price falls below EMA100 (trend weakening)
    2. Stop loss at 5% (risk management)
    3. Take profit at 10% (lock in gains)
    """
    key = ('SOLUSDT', 'binance')
    bars = ctx['bars'][key]
    i = ctx['i']
    positions = ctx['positions']

    actions = []

    # Extract close prices for indicator calculation
    closes = [b.close for b in bars[:i+1]]

    # Calculate EMAs
    ema20 = ema(closes, 20)
    ema50 = ema(closes, 50)
    ema100 = ema(closes, 100)
    ema200 = ema(closes, 200)

    price = closes[-1]

    # Need valid indicator values
    if ema50[-1] is None or ema200[-1] is None or ema20[-1] is None or ema100[-1] is None:
        return []
    if len(ema20) < 5 or ema20[-5] is None:
        return []

    # Entry conditions
    bullish_regime = ema50[-1] > ema200[-1]
    price_above_ema20 = price > ema20[-1]
    ema20_rising = ema20[-1] > ema20[-5]

    # Exit condition
    price_below_ema100 = price < ema100[-1]

    if key not in positions:
        # Enter long when all conditions met
        if bullish_regime and price_above_ema20 and ema20_rising:
            actions.append({
                'action': 'open_long',
                'symbol': 'SOLUSDT',
                'exchange': 'binance',
                'size': 1.0,
                'stop_loss_pct': 5.0,
                'take_profit_pct': 10.0,
            })
    else:
        # Exit when price falls below EMA100
        if price_below_ema100:
            actions.append({
                'action': 'close_long',
                'symbol': 'SOLUSDT',
                'exchange': 'binance',
            })

    return actions


if __name__ == '__main__':
    from strategy import backtest_strategy
    results, profitable, _ = backtest_strategy(init_strategy, process_time_step)