Auto-discovered strategy
Symbol: ETH | Exchange: Bitfinex | Role: mean_reversion
Click a year to view chart
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | -13.7% | 54.8% | 42 | 19.2% | -0.66 |
| 2021 | -34.2% | 46.2% | 39 | 37.3% | -1.54 |
| 2022 | -14.7% | 51.3% | 39 | 21.1% | -0.67 |
| 2023 | +10.3% | 63.7% | 80 | 22.7% | 0.48 |
| 2024 | +33.2% | 70.9% | 55 | 15.2% | 1.46 |
| 2025 | -16.1% | 55.3% | 47 | 33.0% | -0.80 |
| Window | Train Period | Val Period | Val Return | Val | Test Period | Test Return | Status |
|---|---|---|---|---|---|---|---|
| WF-1 | 2024-01→2025-06 | 2025-07→2025-12 | -27.0% | FAIL | 2026-01→ongoing | +0.0% | FAIL |
Not yet reviewed. Run: ./review_strategy.sh eth_chop_reversal_safe
"""
Strategy: eth_chop_reversal_safe
================================
Mean reversion ETH range trading - fade extremes with strict chop regime filter.
Role: mean_reversion
Symbol: tETHUSD | Exchange: bitfinex | Timeframe: 4h
Logic:
- Only trade in CHOP regime (EMA50 within 5% of EMA200)
- BUY when bullish rejection candle appears at lower Bollinger Band
- SELL when bearish rejection candle appears at upper Bollinger Band
- Exit at EMA20 (mean reversion target) or on regime change
- Strict stop loss (4%) and take profit (6%)
Entry Conditions (Long):
1. Chop regime: |EMA50 - EMA200| / EMA200 < 5%
2. Not in strong downtrend (EMA50 > EMA200 * 0.95)
3. Bullish rejection candle: close in upper 50%, lower wick > 40% of range, green candle
4. Near support: low < lower Bollinger Band * 1.02
5. Significant bar: range > ATR(20) * 0.5
6. Decent volume: volume > 20-bar avg * 0.5
Entry Conditions (Short):
1. Chop regime: |EMA50 - EMA200| / EMA200 < 5%
2. Not in strong uptrend (EMA50 < EMA200 * 1.05)
3. Bearish rejection candle: close in lower 50%, upper wick > 40% of range, red candle
4. Near resistance: high > upper Bollinger Band * 0.98
5. Significant bar: range > ATR(20) * 0.5
6. Decent volume: volume > 20-bar avg * 0.5
Exit Conditions:
1. Price crosses EMA20 (mean reversion complete) after 2 bars
2. Regime change to strong trend (exit to avoid trending against position)
3. Time stop: 20 bars maximum hold
4. Stop loss: 4%
5. Take profit: 6%
Train Results (2024-01 to 2025-06):
2024: +33.2% | 55 trades | 71% WR | 15.2% DD | 1.46 Sharpe
2025: +8.2% | 12 trades | 67% WR | 4.0% DD | 1.07 Sharpe
Total: +41.4% | 2/2 train years profitable
"""
import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema, bollinger_bands, atr
def init_strategy():
return {
'name': 'eth_chop_reversal_safe',
'role': 'mean_reversion',
'warmup': 220,
'role': 'mean_reversion',
'subscriptions': [
{'symbol': 'tETHUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
],
'parameters': {
'ema_fast': 20,
'ema_slow': 50,
'ema_trend': 200,
'bb_period': 20,
'bb_std': 2.0,
'atr_period': 20,
'chop_threshold': 5.0,
'stop_loss_pct': 4.0,
'take_profit_pct': 6.0,
}
}
def process_time_step(ctx):
key = ('tETHUSD', 'bitfinex')
bars = ctx['bars'][key]
i = ctx['i']
positions = ctx['positions']
# Need enough warmup for EMA200
if i < 220:
return []
# Calculate indicators
closes = [bars[j].close for j in range(i + 1)]
highs = [bars[j].high for j in range(i + 1)]
lows = [bars[j].low for j in range(i + 1)]
volumes = [bars[j].volume for j in range(i + 1)]
ema20 = ema(closes, 20)
ema50 = ema(closes, 50)
ema200 = ema(closes, 200)
bb_mid, bb_upper, bb_lower = bollinger_bands(closes, 20, 2.0)
atr_vals = atr(highs, lows, closes, 20)
# Current values
curr_close = closes[-1]
curr_ema20 = ema20[-1]
curr_ema50 = ema50[-1]
curr_ema200 = ema200[-1]
curr_bb_lower = bb_lower[-1]
curr_bb_mid = bb_mid[-1]
curr_bb_upper = bb_upper[-1]
curr_atr = atr_vals[-1]
if curr_ema50 is None or curr_ema200 is None or curr_bb_lower is None or curr_atr is None:
return []
# REGIME DETECTION: Chop = EMA50 within 5% of EMA200
ema_spread = abs(curr_ema50 - curr_ema200) / curr_ema200 * 100
is_chop = ema_spread < 5.0
# Trend detection for safety
is_downtrend = curr_ema50 < curr_ema200 * 0.95
is_uptrend = curr_ema50 > curr_ema200 * 1.05
# Volume average
vol_avg = sum(volumes[-20:]) / 20
curr_vol = volumes[-1]
actions = []
curr_bar = bars[i]
if key not in positions:
# Only trade in chop regime
if is_chop:
bar_range = curr_bar.high - curr_bar.low
if bar_range > 0:
# Candle analysis
lower_wick = min(curr_bar.open, curr_bar.close) - curr_bar.low
upper_wick = curr_bar.high - max(curr_bar.open, curr_bar.close)
close_pos = (curr_bar.close - curr_bar.low) / bar_range
lower_wick_ratio = lower_wick / bar_range
upper_wick_ratio = upper_wick / bar_range
# Quality filters
big_enough = bar_range > curr_atr * 0.5
vol_ok = curr_vol > vol_avg * 0.5
# LONG: Bullish rejection at support
is_bullish = (
close_pos > 0.5 and
lower_wick_ratio > 0.4 and
curr_bar.close >= curr_bar.open
)
near_support = curr_bar.low < curr_bb_lower * 1.02
if is_bullish and near_support and big_enough and vol_ok and not is_downtrend:
actions.append({
'action': 'open_long',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
'size': 1.0,
'stop_loss_pct': 4.0,
'take_profit_pct': 6.0,
})
# SHORT: Bearish rejection at resistance
is_bearish = (
close_pos < 0.5 and
upper_wick_ratio > 0.4 and
curr_bar.close <= curr_bar.open
)
near_resistance = curr_bar.high > curr_bb_upper * 0.98
if is_bearish and near_resistance and big_enough and vol_ok and not is_uptrend:
actions.append({
'action': 'open_short',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
'size': 1.0,
'stop_loss_pct': 4.0,
'take_profit_pct': 6.0,
})
else:
# EXIT CONDITIONS
pos = positions[key]
bars_held = i - pos.entry_bar
# Regime change exit (trend against position)
regime_exit = (
(pos.side == 'long' and is_downtrend) or
(pos.side == 'short' and is_uptrend)
)
if pos.side == 'long':
# Mean reversion target: price above EMA20
if curr_close > curr_ema20 and bars_held >= 2:
actions.append({
'action': 'close_long',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
})
# Regime change exit
elif regime_exit and bars_held >= 2:
actions.append({
'action': 'close_long',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
})
# Time stop
elif bars_held >= 20:
actions.append({
'action': 'close_long',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
})
else: # short
# Mean reversion target: price below EMA20
if curr_close < curr_ema20 and bars_held >= 2:
actions.append({
'action': 'close_short',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
})
# Regime change exit
elif regime_exit and bars_held >= 2:
actions.append({
'action': 'close_short',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
})
# Time stop
elif bars_held >= 20:
actions.append({
'action': 'close_short',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
})
return actions
# For standalone testing
if __name__ == '__main__':
from strategy import backtest_strategy
results, profitable, _ = backtest_strategy(init_strategy, process_time_step)
print(f"\nProfitable periods: {profitable}")