Auto-discovered rule
Symbol: ETH | Exchange: Bitfinex
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +91.1% | 47.0% | 30 | 10.0% | 1.00 |
| 2021 | +106.1% | 46.0% | 33 | 10.0% | 1.00 |
| 2022 | +8.7% | 40.0% | 15 | 10.0% | 1.00 |
| 2023 | -8.1% | 36.0% | 25 | 10.0% | 1.00 |
| 2024 | +16.0% | 50.0% | 16 | 10.0% | 1.00 |
| 2025 | +32.1% | 28.0% | 18 | 10.0% | 1.00 |
See rule file
See rule file
"""
Strategy: ema_acceleration_surge
================================
EMA Acceleration Surge Strategy
Identifies momentum acceleration opportunities by detecting when price
bounces off EMA15 with strong upward momentum in a bullish EMA structure.
Entry conditions:
- All EMAs in bullish order: EMA15 > EMA40 > EMA80
- Price above both EMA15 and EMA40
- Price touched or was near EMA15 in last 1-3 bars (pullback to support)
- Price shows acceleration (momentum now > momentum before)
- Momentum must be at least 2% over 2 bars
- EMA15 is rising
- Volume above 80% of 10-bar average
Exit:
- Price closes below EMA15
Performance: 5/6 years profitable | Total: +245.9%
2020: +91.1% | 47% WR | 30 trades
2021: +106.1% | 46% WR | 33 trades
2022: +8.7% | 40% WR | 15 trades
2023: -8.1% | 36% WR | 25 trades
2024: +16.0% | 50% WR | 16 trades
2025: +32.1% | 28% WR | 18 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")
from lib import ema
def init_strategy():
return {
'name': 'ema_acceleration_surge',
'subscriptions': [
{'symbol': 'tETHUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
],
'parameters': {}
}
def process_time_step(ctx):
key = ('tETHUSD', 'bitfinex')
bars = ctx['bars'].get(key, [])
i = ctx['i']
positions = ctx['positions']
if not bars or i >= len(bars) or i < 90:
return []
closes = [b.close for b in bars]
ema15 = ema(closes, 15)
ema40 = ema(closes, 40)
ema80 = ema(closes, 80)
if ema15[i] is None or ema40[i] is None or ema80[i] is None:
return []
actions = []
has_position = key in positions
if not has_position:
# All EMAs in bullish order
if not (ema15[i] > ema40[i] and ema40[i] > ema80[i]):
return []
# Price must be above all EMAs
if not (closes[i] > ema15[i] and closes[i] > ema40[i]):
return []
# Price was near or below EMA15 recently (1-3 bars ago)
touched_ema15 = False
for j in range(1, 4):
if i-j >= 0:
dist = abs(closes[i-j] - ema15[i-j]) / ema15[i-j]
if dist < 0.01 or closes[i-j] < ema15[i-j]:
touched_ema15 = True
break
if not touched_ema15:
return []
# Price must show acceleration (current bar stronger than previous)
momentum_now = (closes[i] - closes[i-2]) / closes[i-2]
momentum_prev = (closes[i-2] - closes[i-4]) / closes[i-4]
if momentum_now <= momentum_prev or momentum_now < 0.02:
return []
# EMA15 must be rising
ema15_rising = ema15[i] > ema15[i-3]
if not ema15_rising:
return []
# Volume check: current bar should show strength
if hasattr(bars[i], 'volume') and bars[i].volume > 0:
avg_vol = sum([bars[i-j].volume for j in range(1, 11)]) / 10
if bars[i].volume < avg_vol * 0.8:
return []
actions.append({
'action': 'open_long',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
'size': 1.0,
})
else:
# Exit when price closes below EMA15
if closes[i] < ema15[i]:
actions.append({
'action': 'close_long',
'symbol': 'tETHUSD',
'exchange': 'bitfinex',
})
return actions