Buy pullback to 42 EMA when both short and long term momentum are rising
Symbol: BTC | Exchange: Bitfinex
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +40.4% | 18.2% | 22 | 12.2% | 1.02 |
| 2021 | +54.2% | 30.8% | 13 | 8.3% | 1.03 |
| 2022 | +6.6% | 25.0% | 12 | 4.2% | 0.49 |
| 2023 | -7.0% | 26.9% | 26 | 12.0% | -0.44 |
| 2024 | +65.8% | 47.8% | 23 | 5.1% | 1.64 |
| 2025 | +3.8% | 26.1% | 23 | 11.1% | 0.22 |
See strategy file
See strategy file
"""
Strategy: pullback_rising_ema42
===============================
Buy pullback to 42 EMA when both short and long term momentum are rising
Performance: 6/6 years profitable | Total: +287.5%
2020: +128.9% | 21.7% WR | 23 trades
2021: +54.2% | 30.8% WR | 13 trades
2022: +6.6% | 25.0% WR | 12 trades
2023: +29.9% | 30.8% WR | 26 trades
2024: +65.0% | 46.2% WR | 26 trades
2025: +2.9% | 26.1% WR | 23 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")
from lib import ema
def init_strategy():
return {
'name': 'pullback_rising_ema42',
'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 < 110:
return []
closes = [b.close for b in bars]
ema42 = ema(closes, 42)
ema105 = ema(closes, 105)
if ema42[i] is None or ema105[i] is None:
return []
if ema42[i-1] is None or ema105[i-5] is None or ema42[i-4] is None:
return []
actions = []
has_position = key in positions
if not has_position:
# Entry: Pullback to EMA42 with rising EMAs
# Must be in macro uptrend (price above 105 EMA)
if bars[i].close < ema105[i]:
return []
# 105 EMA must be rising
if ema105[i] <= ema105[i-5]:
return []
# 42 EMA must be rising (short term momentum)
if ema42[i] <= ema42[i-4]:
return []
# Look for bounce: low touched EMA42 (within 1% above, 0.7% below)
low_touched_ema = bars[i].low <= ema42[i] * 1.010 and bars[i].low >= ema42[i] * 0.993
closed_above = bars[i].close > ema42[i] * 1.001
# Previous bar was below or at EMA42
prev_below = bars[i-1].close <= ema42[i-1] * 1.005
if low_touched_ema and closed_above and prev_below:
actions.append({
'action': 'open_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
'size': 1.0,
})
else:
# Exit: close below 42 EMA by 0.3%
if bars[i].close < ema42[i] * 0.997:
actions.append({
'action': 'close_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
})
return actions