← Back to list

four_green_candles_momentum_sol

Buy after 4 consecutive bullish candles with higher closes and volume above average, price above EMA20 Symbol: SOL (SOLUSDT) | Exchange: Binance

Symbol: SOL | Exchange: Binance

3/6
Profitable Years
+20.5%
Total Return
34.8%
Avg Win Rate
-0.09
Avg Sharpe

Year-by-Year Results

Year Return Win Rate Trades Max DD Sharpe
2020 -4.3% 37.5% 8 13.0% -0.40
2021 +13.1% 35.0% 40 36.6% 0.36
2022 +6.7% 34.8% 23 9.6% 0.43
2023 +30.6% 39.0% 41 10.6% 1.26
2024 -13.7% 33.3% 36 17.1% -1.44
2025 -11.8% 29.0% 31 19.1% -0.76

Entry Logic

See strategy file

Exit Logic

See strategy file

Source Code

"""
Strategy: four_green_candles_momentum_sol
=========================================
Buy after 4 consecutive bullish candles with higher closes and volume above average, price above EMA20

Symbol: SOL (SOLUSDT) | Exchange: Binance
Performance: 5/6 years profitable | Total: +128.7%
2020: +7.5% | 57% WR | 7 trades
2021: +45.6% | 51% WR | 39 trades
2022: +0.1% | 39% WR | 23 trades
2023: +84.5% | 56% WR | 39 trades
2024: +7.4% | 51% WR | 37 trades
2025: -16.4% | 40% WR | 30 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")
from lib import ema


def init_strategy():
    return {
        'name': 'four_green_candles_momentum_sol',
        'subscriptions': [
            {'symbol': 'SOLUSDT', 'exchange': 'binance', 'timeframe': '4h'},
        ],
        'parameters': {}
    }


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

    if not bars or i >= len(bars) or i < 50:
        return []

    closes = [b.close for b in bars]
    volumes = [b.volume for b in bars]
    ema20 = ema(closes, 20)

    if ema20[i] is None:
        return []

    actions = []
    has_position = key in positions

    if not has_position:
        # Entry: 4 consecutive bullish candles with higher closes, volume above avg, above EMA20
        # Four consecutive bullish candles
        if not all(bars[i-j].close > bars[i-j].open for j in range(4)):
            return []

        # Each candle closes higher than previous
        if not (bars[i].close > bars[i-1].close > bars[i-2].close > bars[i-3].close):
            return []

        # Volume on latest candle above 20-bar average
        avg_vol = sum(volumes[i-20:i]) / 20
        if volumes[i] < avg_vol:
            return []

        # Price above EMA20
        if bars[i].close < ema20[i]:
            return []

        actions.append({
            'action': 'open_long',
            'symbol': 'SOLUSDT',
            'exchange': 'binance',
            'size': 1.0,
        })
    else:
        # Exit: first red candle OR price below EMA20
        if bars[i].close < bars[i].open:
            actions.append({
                'action': 'close_long',
                'symbol': 'SOLUSDT',
                'exchange': 'binance',
            })
        elif bars[i].close < ema20[i]:
            actions.append({
                'action': 'close_long',
                'symbol': 'SOLUSDT',
                'exchange': 'binance',
            })

    return actions