← Back to list

higher_low_volume_bounce_eth

Higher Low Volume Bounce Strategy for ETH A support/resistance bounce strategy that enters when price makes a higher low near support levels with volume confirmation in an uptrend context.

Symbol: ETH | Exchange: Bitfinex

6/6
Profitable Years
+147.1%
Total Return
41.6%
Avg Win Rate
1.20
Avg Sharpe

Year-by-Year Results

Year Return Win Rate Trades Max DD Sharpe
2020 +51.0% 50.0% 60 5.3% 2.48
2021 +35.2% 45.6% 57 7.2% 1.77
2022 +2.1% 34.9% 43 18.9% 0.13
2023 +9.9% 36.5% 74 17.4% 0.45
2024 +22.7% 41.0% 61 9.0% 1.12
2025 +26.2% 41.9% 62 12.3% 1.27

Entry Logic

See strategy file

Exit Logic

See strategy file

Source Code

"""
Strategy: higher_low_volume_bounce_eth
======================================
Higher Low Volume Bounce Strategy for ETH

A support/resistance bounce strategy that enters when price makes a higher low
near support levels with volume confirmation in an uptrend context.

Entry Logic:
- Price must be above 50-bar EMA (uptrend filter)
- Current low forms a higher low vs previous swing low (10-30 bars ago)
- Pullback is meaningful but not too deep (within 8% of previous low)
- Volume is elevated (1.3x average)
- Candle closes in upper 60% (bullish rejection)

Exit Logic:
- Take profit: 3.5%
- Stop loss: 1.8%

Performance: 5/6 years profitable
"""
import sys
sys.path.insert(0, "/root/trade_rules")


def init_strategy():
    return {
        'name': 'higher_low_volume_bounce_eth',
        'subscriptions': [
            {'symbol': 'tETHUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
        ],
        'parameters': {}
    }


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

    lookback = 50

    if not bars or i >= len(bars) or i < lookback + 10:
        return []

    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]

    actions = []
    has_position = key in positions

    if not has_position:
        # Entry: Higher low bounce with volume confirmation
        # Must be in uptrend (above 50-bar EMA)
        ema50 = sum(closes[i-50:i]) / 50
        if closes[i] < ema50:
            return []

        # Identify previous swing low (lowest low in bars 10-30 ago)
        prev_swing_low = min(lows[i-30:i-10])

        # Current recent low (last 3 bars)
        recent_low = min(lows[i-3:i+1])

        # Higher low condition
        if recent_low <= prev_swing_low:
            return []

        # Pullback not too shallow - should be within 8% of previous low
        if (recent_low - prev_swing_low) / prev_swing_low > 0.08:
            return []

        # Volume confirmation - elevated volume
        avg_volume = sum(volumes[i-20:i]) / 20
        if volumes[i] < avg_volume * 1.3:
            return []

        # Price should close in upper 60% of candle (bullish)
        candle_range = highs[i] - lows[i]
        if candle_range > 0:
            close_position = (closes[i] - lows[i]) / candle_range
            if close_position < 0.6:
                return []

        # Should be bouncing - close above low by at least 0.5%
        bounce = (closes[i] - lows[i]) / lows[i]
        if bounce < 0.005:
            return []

        # Not in heavy downtrend recently (last 5 bars)
        recent_change = (closes[i] - closes[i-5]) / closes[i-5]
        if recent_change < -0.05:
            return []

        actions.append({
            'action': 'open_long',
            'symbol': 'tETHUSD',
            'exchange': 'bitfinex',
            'size': 1.0,
            'take_profit_pct': 3.5,
            'stop_loss_pct': 1.8,
        })

    # Exit handled by TP/SL - no explicit exit logic
    return actions