Auto-discovered strategy
Symbol: BTC | Exchange: Bitfinex | Role: momentum
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 |
| 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 |
Not yet reviewed. Run: ./review_strategy.sh regime_aware_bear_filter
"""
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%)
"""