Auto-discovered strategy
Symbol: BTC | Exchange: Bitfinex | Role: momentum
Click a year to view chart
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +18.9% | 40.0% | 10 | 21.0% | 0.68 |
| 2021 | +0.0% | 25.0% | 12 | 15.5% | 0.00 |
| 2022 | -5.0% | 0.0% | 1 | 5.0% | 0.00 |
| 2023 | -3.6% | 28.6% | 7 | 14.4% | -0.20 |
| 2024 | +30.3% | 57.1% | 7 | 9.4% | 1.22 |
| 2025 | +10.0% | 50.0% | 2 | 5.0% | 0.71 |
| Window | Train Period | Val Period | Val Return | Val | Test Period | Test Return | Status |
|---|---|---|---|---|---|---|---|
| WF-1 | 2024-01→2025-06 | 2025-07→2025-12 | +0.0% | FAIL | 2026-01→ongoing | +0.0% | FAIL |
Not yet reviewed. Run: ./review_strategy.sh ema200_rising_cascade
"""
Strategy: ema200_rising_cascade
===============================
Ultra-conservative bull-only strategy with EMA200 rising filter.
Core Concept:
- Stay FLAT unless macro trend is VERY strong bull
- Only enter when perfect EMA cascade alignment
- Quick exits on any regime weakness
Entry Conditions (ALL must be true):
1. EMA50 > EMA200 (golden cross)
2. EMA200 rising 4%+ over 50 bars (strong bull momentum)
3. EMA50 rising 1%+ over 20 bars (momentum confirmation)
4. Price > EMA20 > EMA50 > EMA200 (perfect cascade)
5. Green candle (buying pressure)
6. Volume > 1.2x 20-bar average
7. Price within 10% of EMA50 (not overextended)
Exit Conditions (ANY triggers exit):
1. EMA50 < EMA200 (death cross)
2. EMA200 rise < 2% (bull momentum fading)
3. Price < EMA50 * 0.97 (3% below EMA50)
Risk Management:
- Stop Loss: 5%
- Take Profit: 15% (3:1 R/R)
Performance (Training Data 2024-2025H1):
- 2024: +30.3% | 7 trades | 57% WR | 9.4% DD
- 2025H1: +10.0% | 2 trades | 50% WR | 5.0% DD
- Total: +40.3% | 9.4% max drawdown
Symbol: tBTCUSD | Exchange: bitfinex | Timeframe: 4h
"""
import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema
def init_strategy():
return {
'name': 'ema200_rising_cascade',
'role': 'momentum',
'warmup': 220,
'subscriptions': [
{'symbol': 'tBTCUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
],
'parameters': {}
}
def process_time_step(ctx):
key = ('tBTCUSD', 'bitfinex')
bars = ctx['bars'][key]
i = ctx['i']
positions = ctx['positions']
# Need 220+ bars for EMA200 + lookback
if i < 220:
return []
closes = [b.close for b in bars]
volumes = [b.volume for b in bars]
# Calculate EMAs
ema20 = ema(closes, 20)
ema50 = ema(closes, 50)
ema200 = ema(closes, 200)
# Safety check for None values
if None in [ema20[i], ema50[i], ema200[i], ema200[i-50], ema50[i-20]]:
return []
# REGIME FILTERS (ultra conservative)
# 1. Golden cross: EMA50 > EMA200
golden_cross = ema50[i] > ema200[i]
# 2. EMA200 rising strongly (4%+ over 50 bars)
ema200_pct = (ema200[i] - ema200[i-50]) / ema200[i-50] * 100
ema200_strong = ema200_pct > 4.0
# 3. EMA50 also rising (momentum confirmation)
ema50_pct = (ema50[i] - ema50[i-20]) / ema50[i-20] * 100
ema50_rising = ema50_pct > 1.0
# Combined regime check
strong_bull = golden_cross and ema200_strong and ema50_rising
price = bars[i].close
actions = []
if key not in positions:
# STAY FLAT unless in perfect bull conditions
if not strong_bull:
return []
# ENTRY CONDITIONS
# Perfect EMA cascade alignment
ema_cascade = price > ema20[i] > ema50[i] > ema200[i]
# Green candle (buying pressure)
green = bars[i].close > bars[i].open
# Volume confirmation (above average)
avg_vol = sum(volumes[i-20:i]) / 20
vol_confirm = volumes[i] > avg_vol * 1.2
# Not overextended (within 10% of EMA50)
not_extended = (price - ema50[i]) / ema50[i] < 0.10
# All conditions must be met
if ema_cascade and green and vol_confirm and not_extended:
actions.append({
'action': 'open_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
'size': 1.0,
'stop_loss_pct': 5.0, # Tight stop
'take_profit_pct': 15.0, # 3:1 R/R
})
else:
# EXIT CONDITIONS (quick exit on any weakness)
cascade_break = ema50[i] < ema200[i]
ema200_weakening = ema200_pct < 2.0 # Bull momentum fading
price_weak = price < ema50[i] * 0.97 # 3% below EMA50
if cascade_break or ema200_weakening or price_weak:
actions.append({
'action': 'close_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
})
return actions
# For backwards compatibility with old rule format
def create_rule(bars):
"""Create entry/exit functions for this rule."""
closes = [b.close for b in bars]
volumes = [b.volume for b in bars]
ema20 = ema(closes, 20)
ema50 = ema(closes, 50)
ema200 = ema(closes, 200)
def entry_long(bars, i):
if i < 220:
return False
# Recalculate for current window
closes = [b.close for b in bars]
volumes = [b.volume for b in bars]
ema20 = ema(closes, 20)
ema50 = ema(closes, 50)
ema200 = ema(closes, 200)
if None in [ema20[i], ema50[i], ema200[i], ema200[i-50], ema50[i-20]]:
return False
# Regime
golden_cross = ema50[i] > ema200[i]
ema200_pct = (ema200[i] - ema200[i-50]) / ema200[i-50] * 100
ema200_strong = ema200_pct > 4.0
ema50_pct = (ema50[i] - ema50[i-20]) / ema50[i-20] * 100
ema50_rising = ema50_pct > 1.0
if not (golden_cross and ema200_strong and ema50_rising):
return False
price = bars[i].close
ema_cascade = price > ema20[i] > ema50[i] > ema200[i]
green = bars[i].close > bars[i].open
avg_vol = sum(volumes[i-20:i]) / 20
vol_confirm = volumes[i] > avg_vol * 1.2
not_extended = (price - ema50[i]) / ema50[i] < 0.10
return ema_cascade and green and vol_confirm and not_extended
def exit_long(bars, i):
if i < 220:
return False
closes = [b.close for b in bars]
ema50 = ema(closes, 50)
ema200 = ema(closes, 200)
if None in [ema50[i], ema200[i], ema200[i-50]]:
return False
ema200_pct = (ema200[i] - ema200[i-50]) / ema200[i-50] * 100
price = bars[i].close
cascade_break = ema50[i] < ema200[i]
ema200_weakening = ema200_pct < 2.0
price_weak = price < ema50[i] * 0.97
return cascade_break or ema200_weakening or price_weak
return {
'entry_long': entry_long,
'exit_long': exit_long,
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
'stop_loss_pct': 5.0,
'take_profit_pct': 15.0,
}
ENTRY_LOGIC = """
# Regime Filter (ALL required):
1. EMA50 > EMA200 (golden cross)
2. EMA200 rising 4%+ over 50 bars
3. EMA50 rising 1%+ over 20 bars
# Entry Signal (ALL required):
1. Price > EMA20 > EMA50 > EMA200 (cascade)
2. Green candle
3. Volume > 1.2x average
4. Price within 10% of EMA50
"""
EXIT_LOGIC = """
# Exit on ANY:
1. EMA50 < EMA200 (death cross)
2. EMA200 rise < 2% (momentum fading)
3. Price < EMA50 * 0.97 (3% below support)
"""