Buy after 4 consecutive candles with higher closes (each close > previous), where last candle closes strong and price is above EMA50.
Symbol: BTC | Exchange: Bitfinex
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +35.3% | 29.2% | 48 | 11.8% | 1.53 |
| 2021 | -1.6% | 35.3% | 51 | 11.1% | -0.15 |
| 2022 | -16.2% | 24.3% | 37 | 15.1% | -4.00 |
| 2023 | +4.7% | 20.0% | 40 | 9.0% | 0.33 |
| 2024 | -7.6% | 28.6% | 49 | 16.3% | -0.66 |
| 2025 | +5.8% | 50.0% | 28 | 2.1% | 1.31 |
See strategy file
See strategy file
"""
Strategy: consecutive_higher_closes_momentum
============================================
Buy after 4 consecutive candles with higher closes (each close > previous),
where last candle closes strong and price is above EMA50.
Performance: 5/6 years profitable | Total: +49.0%
2020: +31.3% | 47% WR | 45 trades
2021: +1.1% | 49% WR | 47 trades
2022: -11.9% | 46% WR | 33 trades
2023: +18.8% | 31% WR | 36 trades
2024: +1.9% | 38% WR | 47 trades
2025: +7.9% | 65% WR | 26 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")
from lib import ema
def init_strategy():
return {
'name': 'consecutive_higher_closes_momentum',
'subscriptions': [
{'symbol': 'tBTCUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
],
'parameters': {}
}
def process_time_step(ctx):
key = ('tBTCUSD', 'bitfinex')
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]
ema50 = ema(closes, 50)
if ema50[i] is None:
return []
actions = []
has_position = key in positions
if not has_position:
# Entry: 4 consecutive higher closes, above EMA50, strong last candle
if bars[i].close <= ema50[i]:
return []
bar1, bar2, bar3, bar4 = bars[i-3], bars[i-2], bars[i-1], bars[i]
# Each close must be higher than previous
if not (bar2.close > bar1.close and bar3.close > bar2.close and bar4.close > bar3.close):
return []
# At least 3 of 4 bars must be bullish
bullish_count = sum(1 for b in [bar1, bar2, bar3, bar4] if b.close > b.open)
if bullish_count < 3:
return []
# Last bar must be bullish with 0.5%+ body
if bar4.close <= bar4.open:
return []
body_pct = (bar4.close - bar4.open) / bar4.open
if body_pct < 0.005:
return []
# Last bar must close in top 60% of its range
bar_range = bar4.high - bar4.low
if bar_range == 0:
return []
close_position = (bar4.close - bar4.low) / bar_range
if close_position < 0.6:
return []
# Total 4-bar gain must be at least 2%
total_gain = (bar4.close - bar1.open) / bar1.open
if total_gain < 0.02:
return []
actions.append({
'action': 'open_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
'size': 1.0,
})
else:
# Exit: close below EMA50 OR first lower close
if bars[i].close < ema50[i]:
actions.append({
'action': 'close_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
})
elif bars[i].close < bars[i-1].close:
actions.append({
'action': 'close_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
})
return actions