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
| 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 |
See strategy file
See strategy file
"""
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