← Back to list

higher_high_lower_low_momentum

Buy when 3 consecutive 8-bar periods show higher highs AND higher lows with momentum confirmation (close in top 30% of range) Symbol: BTC (tBTCUSD) | Exchange: Bitfinex

Symbol: BTC | Exchange: Bitfinex

5/6
Profitable Years
+129.5%
Total Return
43.8%
Avg Win Rate
0.63
Avg Sharpe

Year-by-Year Results

Year Return Win Rate Trades Max DD Sharpe
2020 +38.6% 42.3% 26 16.6% 1.08
2021 -10.9% 34.6% 26 28.9% -0.32
2022 +0.9% 41.7% 12 11.4% 0.06
2023 +75.8% 50.0% 16 6.3% 1.85
2024 +23.1% 44.4% 27 19.4% 0.90
2025 +2.0% 50.0% 16 7.5% 0.19

Entry Logic

See strategy file

Exit Logic

See strategy file

Source Code

"""
Strategy: higher_high_lower_low_momentum
========================================
Buy when 3 consecutive 8-bar periods show higher highs AND higher lows
with momentum confirmation (close in top 30% of range)

Symbol: BTC (tBTCUSD) | Exchange: Bitfinex
Performance: 5/6 years profitable | Total: +129.5%
2020: +38.6% | 42% WR | 26 trades
2021: -10.9% | 35% WR | 26 trades
2022: +0.9% | 42% WR | 12 trades
2023: +75.8% | 50% WR | 16 trades
2024: +23.1% | 44% WR | 27 trades
2025: +2.0% | 50% WR | 16 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")


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


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

    lookback = 8
    periods = 3

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

    actions = []
    has_position = key in positions

    if not has_position:
        # Entry: 3 consecutive 8-bar periods with HH and HL
        # Calculate highs and lows for each period
        highs = []
        lows = []
        for j in range(periods):
            start = i - (j+1) * lookback
            end = i - j * lookback
            period_high = max(b.high for b in bars[start:end])
            period_low = min(b.low for b in bars[start:end])
            highs.append(period_high)
            lows.append(period_low)

        # Must have higher highs AND higher lows
        higher_highs = all(highs[j-1] > highs[j] for j in range(1, len(highs)))
        higher_lows = all(lows[j-1] > lows[j] for j in range(1, len(lows)))

        if not (higher_highs and higher_lows):
            return []

        # Momentum filter: close in upper portion of range
        recent_high = max(b.high for b in bars[i-lookback:i])
        recent_low = min(b.low for b in bars[i-lookback:i])
        range_size = recent_high - recent_low

        if range_size > 0:
            position_in_range = (bars[i].close - recent_low) / range_size
            if position_in_range > 0.7:
                actions.append({
                    'action': 'open_long',
                    'symbol': 'tBTCUSD',
                    'exchange': 'bitfinex',
                    'size': 1.0,
                })
    else:
        # Exit: price breaks below recent 8-bar low
        recent_low = min(b.low for b in bars[i-lookback:i])
        if bars[i].close < recent_low:
            actions.append({
                'action': 'close_long',
                'symbol': 'tBTCUSD',
                'exchange': 'bitfinex',
            })

    return actions