← Back to list

eth_basis_pair

ETH Spot/Perp Basis Pair Trading A delta-neutral pair trading strategy that trades the basis (premium/discount) between ETH spot and ETH perpetual futures.

Symbol: ETH | Exchange: Bitfinex

6/6
Profitable Years
+340.0%
Total Return
52.6%
Avg Win Rate
0.53
Avg Sharpe

Year-by-Year Results

Year Return Win Rate Trades Max DD Sharpe
2020 +159.8% 55.5% 308 43.0% 1.31
2021 +126.1% 52.5% 322 52.2% 1.05
2022 +41.9% 56.9% 204 28.2% 0.58
2023 +1.8% 50.0% 50 21.9% 0.06
2024 +3.8% 50.5% 222 22.4% 0.07
2025 +6.5% 50.0% 204 29.4% 0.11

Entry Logic

See strategy file

Exit Logic

See strategy file

Source Code

"""
Strategy: eth_basis_pair
========================
ETH Spot/Perp Basis Pair Trading

A delta-neutral pair trading strategy that trades the basis (premium/discount)
between ETH spot and ETH perpetual futures.

Entry Conditions:
- When perp trades at premium (>0.15%): long spot, short perp
- When perp trades at discount (<-0.15%): short spot, long perp

Exit Conditions:
- Basis normalizes (<0.05%)
- Time exit after 18 bars (3 days on 4h)

Performance: 6/6 years profitable | Total: +340.0%
2020: +159.8% | 56% WR | 308 trades
2021: +126.1% | 52% WR | 322 trades
2022: +41.9% | 57% WR | 204 trades
2023: +1.8% | 50% WR | 50 trades
2024: +3.8% | 50% WR | 222 trades
2025: +6.5% | 50% WR | 204 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")


def init_strategy():
    return {
        'name': 'eth_basis_pair',
        'subscriptions': [
            {'symbol': 'tETHUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
            {'symbol': 'tETHF0:USTF0', 'exchange': 'bitfinex', 'timeframe': '4h'},
        ],
        'parameters': {
            'basis_threshold': 0.15,
            'hold_bars': 18,
        }
    }


def process_time_step(ctx):
    spot_key = ('tETHUSD', 'bitfinex')
    perp_key = ('tETHF0:USTF0', 'bitfinex')

    spot_bars = ctx['bars'].get(spot_key, [])
    perp_bars = ctx['bars'].get(perp_key, [])
    i = ctx['i']
    positions = ctx['positions']
    params = ctx['parameters']

    if not spot_bars or not perp_bars or i < 50:
        return []

    # Calculate basis (perp premium/discount vs spot)
    spot_price = spot_bars[i].close
    perp_price = perp_bars[i].close
    basis_pct = (perp_price - spot_price) / spot_price * 100

    actions = []
    has_spot = spot_key in positions
    has_perp = perp_key in positions

    if not has_spot and not has_perp:
        # Entry: significant basis
        if basis_pct > params['basis_threshold']:
            # Perp at premium - long spot, short perp (collect premium)
            actions.append({
                'action': 'open_long',
                'symbol': 'tETHUSD',
                'exchange': 'bitfinex',
                'size': 1.0,
            })
            actions.append({
                'action': 'open_short',
                'symbol': 'tETHF0:USTF0',
                'exchange': 'bitfinex',
                'size': 1.0,
            })
        elif basis_pct < -params['basis_threshold']:
            # Perp at discount - short spot, long perp
            actions.append({
                'action': 'open_short',
                'symbol': 'tETHUSD',
                'exchange': 'bitfinex',
                'size': 1.0,
            })
            actions.append({
                'action': 'open_long',
                'symbol': 'tETHF0:USTF0',
                'exchange': 'bitfinex',
                'size': 1.0,
            })

    elif has_spot and has_perp:
        # Exit: basis normalized or time exit
        spot_pos = positions[spot_key]
        bars_held = i - spot_pos.entry_bar

        should_exit = bars_held >= params['hold_bars'] or abs(basis_pct) < 0.05

        if should_exit:
            spot_pos = positions[spot_key]
            perp_pos = positions[perp_key]

            if spot_pos.side == 'long':
                actions.append({
                    'action': 'close_long',
                    'symbol': 'tETHUSD',
                    'exchange': 'bitfinex',
                })
            else:
                actions.append({
                    'action': 'close_short',
                    'symbol': 'tETHUSD',
                    'exchange': 'bitfinex',
                })

            if perp_pos.side == 'long':
                actions.append({
                    'action': 'close_long',
                    'symbol': 'tETHF0:USTF0',
                    'exchange': 'bitfinex',
                })
            else:
                actions.append({
                    'action': 'close_short',
                    'symbol': 'tETHF0:USTF0',
                    'exchange': 'bitfinex',
                })

    return actions