Auto-discovered strategy
Symbol: BTC | Exchange: Binance | Role: momentum
Click a year to view chart
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +103.7% | 57.9% | 19 | 17.4% | 2.73 |
| 2021 | -0.2% | 25.0% | 16 | 16.7% | -0.01 |
| 2022 | -0.7% | 25.0% | 4 | 5.0% | -0.08 |
| 2023 | +10.4% | 33.3% | 15 | 10.1% | 0.45 |
| 2024 | +31.5% | 37.5% | 16 | 23.4% | 1.01 |
| 2025 | +9.1% | 36.4% | 11 | 7.6% | 0.81 |
| 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% | FAIL | 2026-01→ongoing | +0.0% | FAIL |
Not yet reviewed. Run: ./review_strategy.sh swing_support_trend_bounce
"""
Swing Support Trend Bounce Strategy
====================================
A support/resistance bounce strategy for BTCUSDT that:
1. Only trades in strong uptrends (full EMA cascade: EMA20 > EMA50 > EMA200)
2. Identifies swing low support levels from recent 20 bars
3. Enters on bounce from support with volume confirmation and breakout
4. Uses tight stops and regime-based exits
This strategy should stay FLAT during bear markets due to the
strict EMA cascade requirement - if EMAs are not aligned, no trades.
Entry conditions:
- EMA20 > EMA50 > EMA200 (full uptrend)
- EMA50 rising over 5 bars
- Price above EMA50
- Price tested swing low support (within 5%) in last 5 bars
- Price bounced above support
- Breakout above 10-bar high
- Bullish candle with >50% body ratio
- Volume >1.2x 20-bar average
Exit conditions:
- Close below EMA50 (support broken)
- EMA20 crosses below EMA50 (trend weakening)
- Stop loss: 5%
- Take profit: 15%
Training Performance (2024-2025H1):
- 2024: +31.5% | 16 trades | 38% WR | Sharpe 1.01 | MaxDD 23.4%
- 2025H1: +8.1% | 5 trades | 40% WR | Sharpe 0.87 | MaxDD 5.0%
- Total: +39.6%
"""
import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema
def init_strategy():
return {
'name': 'swing_support_trend_bounce',
'role': 'momentum', # Momentum: allows bounded loss in bear market
'warmup': 200,
'subscriptions': [
{'symbol': 'BTCUSDT', 'exchange': 'binance', 'timeframe': '4h'},
],
'parameters': {}
}
def process_time_step(ctx):
"""
Swing Support Trend Bounce
A support/resistance bounce strategy that:
1. Only trades in strong uptrends (full EMA cascade)
2. Identifies swing low support levels
3. Enters on bounce from support with volume confirmation
4. Uses tight stops and regime-based exits
This strategy should stay flat during bear markets due to the
strict EMA cascade requirement.
"""
key = ('BTCUSDT', 'binance')
bars = ctx['bars'][key]
i = ctx['i']
positions = ctx['positions']
# Data
closes = [b.close for b in bars[:i+1]]
lows = [b.low for b in bars[:i+1]]
highs = [b.high for b in bars[:i+1]]
opens = [b.open for b in bars[:i+1]]
volumes = [b.volume for b in bars[:i+1]]
# EMAs (using round numbers)
ema20 = ema(closes, 20)
ema50 = ema(closes, 50)
ema200 = ema(closes, 200)
actions = []
if key not in positions:
# === ENTRY CONDITIONS ===
# 1. All EMAs must be defined
if any(e[i] is None for e in [ema20, ema50, ema200]):
return []
# 2. STRONG REGIME: EMA cascade (20 > 50 > 200)
# This keeps us flat in bear markets
if not (ema20[i] > ema50[i] > ema200[i]):
return []
# 3. EMA50 must be rising (momentum)
if i >= 5 and ema50[i-5] is not None:
if ema50[i] <= ema50[i-5]:
return []
# 4. Price above EMA50 (structure intact)
if closes[i] < ema50[i]:
return []
# 5. Define support from 20-bar swing low
swing_low = min(lows[max(0, i-20):i])
# 6. Price tested support zone (within 5%) in last 5 bars
support_zone_top = swing_low * 1.05
tested_support = False
for j in range(i-5, i+1):
if lows[j] <= support_zone_top:
tested_support = True
break
if not tested_support:
return []
# 7. Now above support (bounced)
if closes[i] < swing_low * 1.02:
return []
# 8. Breakout above 10-bar high (momentum resuming)
recent_high = max(highs[max(0, i-10):i])
if closes[i] <= recent_high:
return []
# 9. Bullish candle with strong body (>50%)
is_bullish = closes[i] > opens[i]
bar_range = highs[i] - lows[i]
body_ratio = (closes[i] - opens[i]) / bar_range if bar_range > 0 else 0
if not (is_bullish and body_ratio > 0.5):
return []
# 10. Volume above average (1.2x)
avg_vol = sum(volumes[i-20:i]) / 20
if volumes[i] < avg_vol * 1.2:
return []
# Enter with stops
actions.append({
'action': 'open_long',
'symbol': 'BTCUSDT',
'exchange': 'binance',
'size': 1.0,
'stop_loss_pct': 5.0, # 5% stop
'take_profit_pct': 15.0, # 3:1 R/R
})
else:
# === EXIT CONDITIONS ===
# Exit if close below EMA50 (support broken)
if closes[i] < ema50[i]:
actions.append({
'action': 'close_long',
'symbol': 'BTCUSDT',
'exchange': 'binance',
})
# Exit on EMA cascade breakdown
elif ema20[i] < ema50[i]:
actions.append({
'action': 'close_long',
'symbol': 'BTCUSDT',
'exchange': 'binance',
})
return actions