Buy after 3 consecutive candles with rising lows, all staying above EMA20, then breakout
Symbol: ETH | Exchange: Binance
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +92.1% | 50.0% | 24 | 15.3% | 1.41 |
| 2021 | +5.9% | 45.8% | 24 | 37.6% | 0.10 |
| 2022 | +8.3% | 43.8% | 16 | 10.4% | 0.38 |
| 2023 | +9.7% | 35.7% | 14 | 10.9% | 0.46 |
| 2024 | +12.8% | 34.8% | 23 | 13.9% | 0.52 |
| 2025 | +14.1% | 33.3% | 18 | 12.5% | 0.47 |
See strategy file
See strategy file
"""
Strategy: higher_lows_ema20_support
===================================
Buy after 3 consecutive candles with rising lows, all staying above EMA20, then breakout
Performance: 6/6 years profitable | Total: +145.4%
2020: +92.3% | 50% WR | 24 trades
2021: +4.8% | 46% WR | 24 trades
2022: +8.4% | 44% WR | 16 trades
2023: +14.3% | 43% WR | 14 trades
2024: +13.7% | 36% WR | 22 trades
2025: +12.0% | 35% WR | 17 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")
from lib import ema
def init_strategy():
return {
'name': 'higher_lows_ema20_support',
'subscriptions': [
{'symbol': 'ETHUSDT', 'exchange': 'binance', 'timeframe': '4h'},
],
'parameters': {}
}
def process_time_step(ctx):
key = ('ETHUSDT', 'binance')
bars = ctx['bars'].get(key, [])
i = ctx['i']
positions = ctx['positions']
if not bars or i >= len(bars) or i < 50:
return []
closes = [b.close for b in bars]
ema20 = ema(closes, 20)
ema50 = ema(closes, 50)
if ema20[i] is None or ema50[i] is None:
return []
actions = []
has_position = key in positions
if not has_position:
# Entry: 3 consecutive higher lows above EMA20, breakout on 4th bar
if bars[i].close <= ema50[i]:
return []
c1, c2, c3 = bars[i-3], bars[i-2], bars[i-1]
current = bars[i]
# Check for higher lows (accumulation)
higher_lows = c2.low > c1.low and c3.low > c2.low
if not higher_lows:
return []
# All 3 setup candles must have lows ABOVE EMA20
if ema20[i-3] is None or ema20[i-2] is None or ema20[i-1] is None:
return []
above_ema20 = (c1.low > ema20[i-3] and
c2.low > ema20[i-2] and
c3.low > ema20[i-1])
if not above_ema20:
return []
# Current candle must break above previous 3 highs (breakout)
highest = max(c1.high, c2.high, c3.high)
breakout = current.close > highest
# Current should be bullish
bullish = current.close > current.open
if breakout and bullish:
actions.append({
'action': 'open_long',
'symbol': 'ETHUSDT',
'exchange': 'binance',
'size': 1.0,
})
else:
# Exit: close below EMA20
if bars[i].close < ema20[i]:
actions.append({
'action': 'close_long',
'symbol': 'ETHUSDT',
'exchange': 'binance',
})
return actions