← Back to list

volume_thrust_breakout_sol

Volume Thrust Breakout - SOLUSDT A momentum breakout strategy that combines: 1. Volume surge (2.2x+ average)

Symbol: SOL | Exchange: Binance

5/6
Profitable Years
+181.0%
Total Return
46.2%
Avg Win Rate
0.94
Avg Sharpe

Year-by-Year Results

Year Return Win Rate Trades Max DD Sharpe
2020 +0.0% 33.3% 9 18.5% 0.00
2021 +49.3% 47.1% 34 41.0% 1.20
2022 +12.6% 40.0% 15 19.8% 0.52
2023 +59.0% 50.0% 40 29.2% 1.46
2024 +20.7% 50.0% 16 9.8% 1.03
2025 +39.5% 57.1% 21 14.3% 1.43

Entry Logic

See strategy file

Exit Logic

See strategy file

Source Code

"""
Strategy: volume_thrust_breakout_sol
====================================
Volume Thrust Breakout - SOLUSDT

A momentum breakout strategy that combines:
1. Volume surge (2.2x+ average)
2. Breakout above 20-bar high
3. Price above EMA-50 (trend filter)
4. Bullish bar confirmation

Entry:
- Volume ratio > 2.2x (20-bar average)
- Price breaks above 20-bar high
- Price above EMA-50 (uptrend)
- Bullish candle (close > open)

Exit:
- Max hold: 12 bars (2 days on 4h timeframe)
- Momentum loss: price drops below EMA-50
- Take profit: 10%
- Stop loss: 5%

Performance: 5/6 years profitable | Total: +88.3%
2020: -29.3% | 11% WR | 9 trades
2021: +13.1% | 40% WR | 30 trades
2022: +6.1% | 56% WR | 16 trades
2023: +31.4% | 43% WR | 37 trades
2024: +28.1% | 47% WR | 17 trades
2025: +39.1% | 55% WR | 20 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")
from lib import ema


def init_strategy():
    return {
        'name': 'volume_thrust_breakout_sol',
        'subscriptions': [
            {'symbol': 'SOLUSDT', 'exchange': 'binance', 'timeframe': '4h'},
        ],
        'parameters': {
            'take_profit_pct': 10.0,
            'stop_loss_pct': 5.0,
            'hold_bars': 12,
        }
    }


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]
    highs = [b.high for b in bars]
    opens = [b.open for b in bars]
    volumes = [b.volume for b in bars]

    # Calculate EMA-50
    ema50 = ema(closes, 50)

    if ema50[i] is None:
        return []

    # Calculate 20-bar volume moving average
    volume_ma = sum(volumes[i-20:i]) / 20 if i >= 20 else 0

    # 20-bar high (excluding current bar)
    high_20 = max(highs[i-20:i]) if i >= 20 else 0

    actions = []
    has_position = key in positions

    if not has_position:
        # Entry: volume thrust breakout
        if volume_ma == 0:
            return []

        vol_ratio = volumes[i] / volume_ma

        # Volume surge (2.2x+ average)
        if vol_ratio <= 2.2:
            return []

        # Breakout above 20-bar high
        if closes[i] <= high_20:
            return []

        # Price above EMA-50 (uptrend)
        if closes[i] <= ema50[i]:
            return []

        # Bullish bar
        if closes[i] <= opens[i]:
            return []

        actions.append({
            'action': 'open_long',
            'symbol': 'SOLUSDT',
            'exchange': 'binance',
            'size': 1.0,
            'take_profit_pct': 10.0,
            'stop_loss_pct': 5.0,
        })
    else:
        # Exit conditions
        pos = positions[key]
        bars_held = i - pos.entry_bar

        # Max holding period: 12 bars
        if bars_held >= 12:
            actions.append({
                'action': 'close_long',
                'symbol': 'SOLUSDT',
                'exchange': 'binance',
            })
        # Momentum loss: price below EMA-50 (after holding for at least 2 bars)
        elif bars_held >= 2 and closes[i] < ema50[i]:
            actions.append({
                'action': 'close_long',
                'symbol': 'SOLUSDT',
                'exchange': 'binance',
            })

    return actions