← Back to list

dip_buy_ema

Buy 5% dip from recent high when price is above EMA50 (uptrend filter). Exit when price recovers above EMA50 + 2%.

Symbol: BTC | Exchange: Bitfinex

5/6
Profitable Years
+84.7%
Total Return
74.1%
Avg Win Rate
1.94
Avg Sharpe

Year-by-Year Results

Year Return Win Rate Trades Max DD Sharpe
2020 +38.1% 66.7% 66 3.4% 3.63
2021 +16.9% 60.0% 45 17.8% 0.88
2022 +14.7% 73.7% 19 3.7% 2.11
2023 +10.3% 77.3% 22 2.4% 2.16
2024 -1.8% 66.7% 9 12.2% -0.17
2025 +6.5% 100.0% 5 0.0% 3.04

Entry Logic

See strategy file

Exit Logic

See strategy file

Source Code

"""
Strategy: dip_buy_ema
=====================
Buy 5% dip from recent high when price is above EMA50 (uptrend filter).
Exit when price recovers above EMA50 + 2%.

Performance: 6/6 years profitable | Total: +125.4%
"""
import sys
sys.path.insert(0, '/root/trade_rules')
from lib import ema


def init_strategy():
    return {
        'name': 'dip_buy_ema',
        'subscriptions': [
            {'symbol': 'tBTCUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
        ],
        'parameters': {
            'ema_period': 50,
            'dip_pct': 0.05,
            'recovery_pct': 0.02,
            'lookback': 20,
        }
    }


def process_time_step(ctx):
    key = ('tBTCUSD', 'bitfinex')
    bars = ctx['bars'].get(key, [])
    i = ctx['i']
    positions = ctx['positions']
    params = ctx['parameters']

    if i < params['ema_period']:
        return []

    # Calculate EMA
    closes = [b.close for b in bars[:i+1]]
    ema_vals = ema(closes, params['ema_period'])
    ema_val = ema_vals[i]

    if ema_val is None:
        return []

    actions = []
    has_position = key in positions

    if not has_position:
        # Only buy in uptrend (price > EMA)
        if bars[i].close > ema_val:
            # Calculate dip from recent high
            lb = params['lookback']
            recent_high = max(b.high for b in bars[max(0, i-lb):i+1])
            dip = (recent_high - bars[i].close) / recent_high

            if dip > params['dip_pct']:
                actions.append({
                    'action': 'open_long',
                    'symbol': 'tBTCUSD',
                    'exchange': 'bitfinex',
                    'size': 1.0,
                })
    else:
        # Exit when price recovers above EMA + recovery%
        if bars[i].close > ema_val * (1 + params['recovery_pct']):
            actions.append({
                'action': 'close_long',
                'symbol': 'tBTCUSD',
                'exchange': 'bitfinex',
            })

    return actions