Розробка алгоритму парної торговлі (pairs trading)
Pairs trading — окремий випадок статистичного арбітража: ми торгуємо однією парою активів, відкриваючи одночасно довгу позицію в одному та короту в іншому. Стратегія ринково-нейтральна: прибуток не залежить від загального напрямку ринку, тільки від звуження/розширення спреду між двома активами.
Вибір пар
Не всі пари підходять для торговлі. Вимоги:
Коінтеграція — статистично значима (p-value < 0.05 за тестом Engle-Granger або Johansen). Ребалансувати та перевіряти кожні 2–4 тижні: коінтеграція може зникнути.
Економічний сенс — пара повинна мати фундаментальний зв'язок:
- BTC spot vs BTC perpetual futures
- ETH vs stETH (Lido staked ETH)
- Binance Coin (BNB) vs аналогічні біржові токени
- Конкуруючі Layer-1: SOL vs AVAX, DOT vs ATOM
- Кошик DeFi-токенів (UNI, AAVE, CRV) проти DeFi індексу
Ліквідність: обидва активи повинні мати достатній обсяг для виконання без значного slippage.
Half-life: період повернення до середнього. 3–30 днів — прийнятний діапазон. Занадто короткий — не встигнемо входити, занадто довгий — капітал заморожено надовго.
Механіка угоди
Приклад: BTC/USDT spot та BTCUSDT perpetual futures
Spread = BTC_PERP - BTC_SPOT
Basis = PERP_price - SPOT_price (зазвичай позитивна через funding)
Якщо basis аномально високий (Z-score > 2): продаємо PERP, купуємо SPOT. Чекаємо звуження. Прибуток = зміна basis.
Розміри позицій: для ринкової нейтральності вартість обох позицій повинна бути однаковою (або зважена на hedge ratio β).
def calculate_position_sizes(capital, hedge_ratio, price_x, price_y):
# Dollar-neutral
position_value = capital / 2
qty_y = position_value / price_y # продаємо Y
qty_x = qty_y * hedge_ratio # купуємо X
return qty_x, qty_y
Динамічний hedge ratio
Фіксований hedge ratio застаріває. Використовуємо rolling window OLS або Kalman Filter для безперервного оновлення.
Важливо: різке змінення hedge ratio може сигналізувати про структурний зсув у відносинах між активами. Моніторимо стабільність β.
Ризики парної торговлі
Divergence risk: спред продовжує розширюватися замість звуження. Фундаментальна причина: один з активів змінюється структурно (делістинг, hack, regulatory action). Stop-loss при Z-score = 3 або 4.
Funding risk: для perpetual позицій funding rate може з'їсти прибуток. Особливо при високому позитивному funding на PERP (ви платите як holder PERP short).
Liquidity risk: при несподіваному русі ринку закрити обидві ноги одночасно може бути складно.
Correlation breakdown: особливо актуально для крипто — у періоди market-wide рухів (BTC dump/pump) кореляції ломаються.
Розрахунок P&L та backtesting
def backtest_pairs(spread, z_scores, entry_z=2.0, exit_z=0.5, stop_z=3.5):
position = 0 # 1 = long spread, -1 = short spread
pnl = []
for i, (spread_val, z) in enumerate(zip(spread, z_scores)):
if position == 0:
if z > entry_z:
position = -1 # short spread
entry_spread = spread_val
elif z < -entry_z:
position = 1 # long spread
entry_spread = spread_val
elif position == 1:
current_pnl = spread_val - entry_spread
if z > -exit_z or z < -stop_z:
pnl.append(current_pnl)
position = 0
elif position == -1:
current_pnl = entry_spread - spread_val
if z < exit_z or z > stop_z:
pnl.append(current_pnl)
position = 0
return pnl
Моніторинг активних позицій
Кожні N хвилин перераховуємо Z-score та hedge ratio. Дашборд показує:
- Поточний Z-score та його історію
- P&L поточної позиції
- Unrealized PnL по кожній нозі
- Funding payments (для perpetual)
- Час у позиції vs очікуваний half-life
Alert при наближенні до stop-loss рівня або при різкій зміні hedge ratio (>20% від попереднього значення).
Стек: Python (statsmodels, numpy, pykalman), CCXT для виконання ордерів, PostgreSQL для історії торгів, Grafana для моніторингу. Алгоритм працює як daemon-процес з configurability параметрами через config-файл або UI.







