BTC Spot/Perp Basis Pair Trading A delta-neutral pair trading strategy that trades the basis (premium/discount) between BTC spot and BTC perpetual futures.
Symbol: BTC | Exchange: Bitfinex
| Year | Return | Win Rate | Trades | Max DD | Sharpe |
|---|---|---|---|---|---|
| 2020 | +6.9% | 50.3% | 314 | 51.7% | 0.08 |
| 2021 | +92.4% | 52.8% | 288 | 28.9% | 1.01 |
| 2022 | +3.1% | 53.3% | 60 | 25.1% | 0.09 |
| 2023 | +1.5% | 54.5% | 22 | 19.2% | 0.05 |
| 2024 | +6.9% | 50.0% | 142 | 26.8% | 0.14 |
| 2025 | +5.9% | 50.8% | 124 | 19.1% | 0.16 |
See strategy file
See strategy file
"""
Strategy: btc_basis_pair
========================
BTC Spot/Perp Basis Pair Trading
A delta-neutral pair trading strategy that trades the basis (premium/discount)
between BTC spot and BTC 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: +116.8%
2020: +6.9% | 50% WR | 314 trades
2021: +92.4% | 53% WR | 288 trades
2022: +3.1% | 53% WR | 60 trades
2023: +1.5% | 54% WR | 22 trades
2024: +6.9% | 50% WR | 142 trades
2025: +5.9% | 51% WR | 124 trades
"""
import sys
sys.path.insert(0, "/root/trade_rules")
def init_strategy():
return {
'name': 'btc_basis_pair',
'subscriptions': [
{'symbol': 'tBTCUSD', 'exchange': 'bitfinex', 'timeframe': '4h'},
{'symbol': 'tBTCF0:USTF0', 'exchange': 'bitfinex', 'timeframe': '4h'},
],
'parameters': {
'basis_threshold': 0.15,
'exit_threshold': 0.05,
'hold_bars': 18,
}
}
def process_time_step(ctx):
spot_key = ('tBTCUSD', 'bitfinex')
perp_key = ('tBTCF0: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': 'tBTCUSD',
'exchange': 'bitfinex',
'size': 1.0,
})
actions.append({
'action': 'open_short',
'symbol': 'tBTCF0: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': 'tBTCUSD',
'exchange': 'bitfinex',
'size': 1.0,
})
actions.append({
'action': 'open_long',
'symbol': 'tBTCF0: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) < params['exit_threshold']
if should_exit:
perp_pos = positions[perp_key]
if spot_pos.side == 'long':
actions.append({
'action': 'close_long',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
})
else:
actions.append({
'action': 'close_short',
'symbol': 'tBTCUSD',
'exchange': 'bitfinex',
})
if perp_pos.side == 'long':
actions.append({
'action': 'close_long',
'symbol': 'tBTCF0:USTF0',
'exchange': 'bitfinex',
})
else:
actions.append({
'action': 'close_short',
'symbol': 'tBTCF0:USTF0',
'exchange': 'bitfinex',
})
return actions
if __name__ == '__main__':
from strategy import backtest_strategy
results, profitable = backtest_strategy(init_strategy, process_time_step, verbose=True)
total = sum(r['return'] for r in results.values())
print(f"\nBTC Basis Pair: {profitable}/6 years profitable, {total:+.1f}%")