← Back to list

regime_aware_bear_filter VALIDATED PASS

Auto-discovered strategy

Symbol: BTC | Exchange: Bitfinex | Role: momentum

5/6
Profitable Years
+192.2%
Total Return
36.7%
Avg Win Rate
0.90
Avg Sharpe

Year-by-Year Results

Click a year to view chart

Year Return Win Rate Trades Max DD Sharpe
2020 +76.1% 45.7% 35 13.7% 2.18
2021 +51.5% 38.9% 36 16.8% 1.47
2022 -19.9% 20.0% 15 18.9% -1.53
2023 +22.7% 37.0% 27 18.1% 0.90
2024 +51.8% 43.8% 32 11.3% 1.74
2025 +10.0% 35.0% 20 9.5% 0.61

Performance Chart

Loading chart...

Walk-Forward Validation PASS

1/1 Windows Profitable
+1.1% 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 +1.1% OK 2026-01→ongoing +0.0% PASS

AI Review

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

Source Code

"""
Strategy: regime_aware_bear_filter
==================================
Regime-Aware Long with Strict Bear Filter

Core Principles:
1. STRICT BEAR FILTER: Stay completely FLAT when market is in bear regime
   - Bear regime = EMA50 < EMA200 or price < EMA200 or EMA50 falling
   - This protects capital during major downtrends

2. DUAL ENTRY SIGNALS in bull regime:
   - Breakout: Price breaks above 15-bar high (momentum continuation)
   - Pullback: Price dips to EMA21 and recovers (trend retest)

3. TIGHT RISK MANAGEMENT:
   - 4% stop loss per trade
   - 10% take profit target
   - Quick exit when regime weakens

Universal Market Principles Used:
- Trend following (EMA alignment)
- Momentum (breakout entries)
- Mean reversion in trends (pullback entries)
- Risk management (stops, regime filter)

Performance (TRAIN: 2024-01-01 to 2025-06-30):
  2024: +51.8% | 32 trades | 44% WR | Max DD 11.3% | Sharpe 1.74
  2025 (partial): +11.2% | 8 trades | 50% WR | Max DD 4.3% | Sharpe 0.99
  Total: +63.0% | 2/2 train periods profitable
"""

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


def init_strategy():
    return {
        'name': 'regime_aware_bear_filter',
        'role': 'momentum',
        'warmup': 210,
        'subscriptions': [
            {'symbol': 'tBTCUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
        ],
        'parameters': {
            'ema_short': 21,
            'ema_medium': 50,
            'ema_long': 200,
            'breakout_period': 15,
            'stop_loss_pct': 4.0,
            'take_profit_pct': 10.0
        }
    }


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

    # Need enough bars for EMA200 - now handled by framework via 'warmup' field
    # if i < 210:
    #     return []

    # Calculate EMAs
    closes = [b.close for b in bars]
    highs = [b.high for b in bars]
    lows = [b.low for b in bars]

    ema21 = ema(closes, params['ema_short'])
    ema50 = ema(closes, params['ema_medium'])
    ema200 = ema(closes, params['ema_long'])

    # Ensure indicators are valid
    if ema21[i] is None or ema50[i] is None or ema200[i] is None:
        return []

    # =========================================================
    # STRICT BEAR FILTER
    # ALL conditions must be true for bull regime:
    # 1. EMA50 > EMA200 (golden cross active)
    # 2. Price > EMA200 (above long-term trend)
    # 3. EMA50 rising over last 10 bars (uptrend momentum)
    # =========================================================
    ema50_above_200 = ema50[i] > ema200[i]
    price_above_200 = bars[i].close > ema200[i]
    ema50_rising = ema50[i] > ema50[i-10] if ema50[i-10] is not None else False
    ema21_rising = ema21[i] > ema21[i-5] if ema21[i-5] is not None else False

    bull_regime = ema50_above_200 and price_above_200 and ema50_rising

    actions = []

    if key not in positions:
        # =========================================================
        # ENTRY: Only in confirmed bull regime
        # Two entry types for robustness:
        # =========================================================
        if bull_regime:
            # Entry Type 1: BREAKOUT
            # Price breaks above recent high (momentum continuation)
            breakout_period = params['breakout_period']
            recent_high = max(highs[i-breakout_period:i])
            breakout = bars[i].close > recent_high

            # Entry Type 2: PULLBACK
            # Price dips to EMA21 and recovers (trend retest)
            pullback_to_ema21 = lows[i] <= ema21[i] * 1.01 and bars[i].close > ema21[i]

            # Common conditions for both entry types
            above_ema50 = bars[i].close > ema50[i]
            not_extended = bars[i].close < ema50[i] * 1.10  # Max 10% above EMA50

            # Entry signal: breakout OR pullback, with common filters
            entry_signal = (breakout and above_ema50 and not_extended) or \
                          (pullback_to_ema21 and above_ema50 and ema21_rising)

            if entry_signal:
                actions.append({
                    'action': 'open_long',
                    'symbol': 'tBTCUSD',
                    'exchange': 'bitfinex',
                    'size': 1.0,
                    'stop_loss_pct': params['stop_loss_pct'],
                    'take_profit_pct': params['take_profit_pct']
                })
    else:
        # =========================================================
        # EXIT: Quick exit when regime weakens
        # =========================================================
        regime_weak = not bull_regime
        below_ema50 = bars[i].close < ema50[i]

        if regime_weak or below_ema50:
            actions.append({
                'action': 'close_long',
                'symbol': 'tBTCUSD',
                'exchange': 'bitfinex',
            })

    return actions


# Entry/Exit logic descriptions for documentation
ENTRY_LOGIC = """
BEAR FILTER (must pass ALL):
  - EMA50 > EMA200 (golden cross)
  - Price > EMA200 (above long-term trend)
  - EMA50 rising over 10 bars

ENTRY SIGNALS (need ONE):
  1. BREAKOUT: Close > 15-bar high AND above EMA50 AND < 110% of EMA50
  2. PULLBACK: Low touches EMA21 AND close > EMA21 AND EMA21 rising
"""

EXIT_LOGIC = """
EXIT when ANY:
  - Bear regime detected (EMA50 < EMA200 or price < EMA200 or EMA50 falling)
  - Price closes below EMA50
  - Stop loss hit (4%)
  - Take profit hit (10%)
"""