← Back to list

eth_regime_breakout_v5 VALIDATED FAIL

Auto-discovered strategy

Symbol: ETH | Exchange: Bitfinex | Role: momentum

4/6
Profitable Years
+124.2%
Total Return
38.0%
Avg Win Rate
0.55
Avg Sharpe

Year-by-Year Results

Click a year to view chart

Year Return Win Rate Trades Max DD Sharpe
2020 +81.9% 52.2% 23 11.1% 2.11
2021 -1.8% 33.3% 21 27.2% -0.06
2022 +1.2% 20.0% 15 12.3% 0.05
2023 -9.7% 36.4% 22 15.0% -0.56
2024 +26.4% 52.6% 19 13.4% 1.03
2025 +26.2% 33.3% 21 22.1% 0.73

Performance Chart

Loading chart...

Walk-Forward Validation FAIL

0/1 Windows Profitable
-13.8% 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 -13.8% FAIL 2026-01→ongoing +0.0% FAIL

AI Review

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

Source Code

"""
Strategy: eth_regime_breakout_v5
================================
ETH trend following strategy with regime filter.

CONCEPT:
- Uses EMA cascade (50 > 100 > 200) as regime filter
- Only trades in direction of the macro trend
- Enters on 20-bar breakouts with volume confirmation
- Trades both long (bull regime) and short (bear regime)

REGIME FILTER (Critical for bear market survival):
- Bull: EMA50 > EMA100 > EMA200 (only longs)
- Bear: EMA50 < EMA100 < EMA200 (only shorts)
- Neutral: Stay flat

ENTRY CONDITIONS:
Long (Bull regime):
- Price above EMA50
- EMA50 rising over 10 bars
- Breakout above 20-bar high
- Volume > 1.3x 20-bar average
- ROC(10) > 1% (momentum confirmation)
- Not extended (< 10% from EMA50)
- Strong close (close in upper 55% of candle range)

Short (Bear regime):
- Price below EMA50
- EMA50 falling over 10 bars
- Breakdown below 20-bar low
- Volume > 1.3x 20-bar average
- ROC(10) < -1%
- Not extended
- Weak close (close in lower 45% of candle range)

EXIT CONDITIONS:
- Close crosses EMA50 (trend weakening)
- Regime breaks (EMA50 crosses EMA100)
- Take profit at 15%
- Max hold 25 bars
- Momentum reversal (ROC(10) crosses +/-4%)

RISK MANAGEMENT:
- 5% stop loss per trade
- Max drawdown target: <20%

TRAIN PERFORMANCE (2024-2025H1):
- 2024: +26.4%, Sharpe 1.03, MaxDD 13.4%, 19 trades, 53% WR
- 2025: +31.9%, Sharpe 1.17, MaxDD 11.4%, 9 trades, 33% WR
- Total: +58.3%
"""

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


def init_strategy():
    return {
        'name': 'eth_regime_breakout_v5',
        'role': 'momentum',
        'warmup': 50,
        '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']

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

    closes = [b.close for b in bars]
    highs = [b.high for b in bars]
    lows = [b.low for b in bars]
    volumes = [b.volume for b in bars]

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

    # Volume
    vol_ma = sma(volumes, 20)

    if any(x[i] is None for x in [ema20, ema50, ema100, ema200, vol_ma]):
        return []

    actions = []
    has_position = key in positions

    # Regime detection
    bull = ema50[i] > ema100[i] and ema100[i] > ema200[i]
    bear = ema50[i] < ema100[i] and ema100[i] < ema200[i]

    if not has_position:
        # ========== LONG (Bull Regime Only) ==========
        if bull:
            above_ema50 = bars[i].close > ema50[i]
            ema50_rising = ema50[i] > ema50[i-10]

            # Breakout with volume
            high_20 = max(highs[i-20:i])
            breakout = bars[i].close > high_20
            vol_surge = volumes[i] > vol_ma[i] * 1.3

            # Momentum
            roc_10 = (closes[i] - closes[i-10]) / closes[i-10] * 100
            mom_ok = roc_10 > 1

            # Not extended
            ext = (bars[i].close - ema50[i]) / ema50[i] * 100
            safe = ext < 10

            # Strong close
            candle_range = bars[i].high - bars[i].low + 0.0001
            strength = (bars[i].close - bars[i].low) / candle_range
            strong = strength > 0.55

            if above_ema50 and ema50_rising and breakout and vol_surge and mom_ok and safe and strong:
                actions.append({
                    'action': 'open_long',
                    'symbol': 'tETHUSD',
                    'exchange': 'bitfinex',
                    'size': 1.0,
                    'stop_loss_pct': 5.0,
                })

        # ========== SHORT (Bear Regime Only) ==========
        elif bear:
            below_ema50 = bars[i].close < ema50[i]
            ema50_falling = ema50[i] < ema50[i-10]

            # Breakdown with volume
            low_20 = min(lows[i-20:i])
            breakdown = bars[i].close < low_20
            vol_surge = volumes[i] > vol_ma[i] * 1.3

            # Momentum
            roc_10 = (closes[i] - closes[i-10]) / closes[i-10] * 100
            mom_ok = roc_10 < -1

            # Not extended
            ext = (ema50[i] - bars[i].close) / ema50[i] * 100
            safe = ext < 10

            # Weak close
            candle_range = bars[i].high - bars[i].low + 0.0001
            weakness = (bars[i].close - bars[i].low) / candle_range
            weak = weakness < 0.45

            if below_ema50 and ema50_falling and breakdown and vol_surge and mom_ok and safe and weak:
                actions.append({
                    'action': 'open_short',
                    'symbol': 'tETHUSD',
                    'exchange': 'bitfinex',
                    'size': 1.0,
                    'stop_loss_pct': 5.0,
                })
    else:
        pos = positions[key]
        bars_held = i - pos.entry_bar
        entry_price = pos.entry_price

        if pos.side == 'long':
            below_ema50 = bars[i].close < ema50[i]
            regime_break = ema50[i] < ema100[i]
            gain = (bars[i].close - entry_price) / entry_price * 100
            tp = gain > 15
            time_out = bars_held > 25
            roc_10 = (closes[i] - closes[i-10]) / closes[i-10] * 100
            mom_dead = roc_10 < -4

            if below_ema50 or regime_break or tp or time_out or mom_dead:
                actions.append({
                    'action': 'close_long',
                    'symbol': 'tETHUSD',
                    'exchange': 'bitfinex',
                })
        else:
            above_ema50 = bars[i].close > ema50[i]
            regime_flip = ema50[i] > ema100[i]
            gain = (entry_price - bars[i].close) / entry_price * 100
            tp = gain > 15
            time_out = bars_held > 25
            roc_10 = (closes[i] - closes[i-10]) / closes[i-10] * 100
            mom_up = roc_10 > 4

            if above_ema50 or regime_flip or tp or time_out or mom_up:
                actions.append({
                    'action': 'close_short',
                    'symbol': 'tETHUSD',
                    'exchange': 'bitfinex',
                })

    return actions


# For standalone testing
if __name__ == '__main__':
    from strategy import backtest_strategy

    print("Backtesting eth_regime_breakout_v5...")
    results, profitable, _ = backtest_strategy(init_strategy, process_time_step)
    print(f"\nProfitable years: {profitable}/2")