Arbitraj Statistik dan Dagangan Pasangan dalam Pasaran Kripto: Dari Kointegrasi hingga Penapis Kalman
Pada tahun 1987, sekumpulan ahli fizik di Morgan Stanley memperoleh $50 juta dalam masa setahun dengan memperdagangkan pasangan saham menggunakan algoritma yang tidak dapat dijelaskan sepenuhnya oleh mana-mana daripada mereka kepada pengurusan bank. Pengurusan tidak membantah. Pada tahun 2026, anda boleh melancarkan idea yang sama di bursa kripto — dengan niaga hadapan kekal, pasaran 24/7, dan kecairan yang akan dicemburui oleh Nunzio Tartaglia. Namun ada kelemahannya: apa yang berkesan dengan saham Ford dan GM pada era pra-internet memerlukan adaptasi serius untuk dunia di mana BTC boleh jatuh 20% dalam semalam dan kadar pendanaan boleh berbalik dalam satu blok sahaja.
Artikel ini adalah kupasan lengkap tentang arbitraj statistik dan dagangan pasangan untuk pasaran kripto. Dari teori matematik (kointegrasi, proses Ornstein-Uhlenbeck, penapis Kalman) hingga kod Python berfungsi yang boleh anda jalankan pada data sebenar. Gaya penulisan berorientasikan kejuruteraan: kami menerangkan formula, menunjukkan kod, dan tidak menyembunyikan perangkap.
1. Sejarah Ringkas: Dari Jesuit hingga Quants
Arbitraj statistik dalam bentuk moden lahir di meja dagangan Morgan Stanley pada pertengahan 1980-an. Nunzio Tartaglia — seorang bekas paderi Jesuit dengan PhD dalam fizik — mengumpulkan pasukan ahli matematik, ahli fizik, dan saintis komputer. Objektif: cari corak dalam harga saham yang tidak dapat dilihat oleh pedagang tradisional.
Ideanya sangat mudah. Jika saham Coca-Cola dan Pepsi secara historis bergerak bersama (yang masuk akal — mereka menjual air manis yang sama dalam botol berwarna berbeza), maka divergens dalam harga mereka adalah anomali sementara. Beli yang ketinggalan, jual yang terdepan, tunggu konvergens, kunci keuntungan. Strategi berkecuali pasaran: arah pasaran tidak menjadi perhatian kami.
Pasukan Tartaglia termasuk orang-orang yang kemudiannya akan mengubah seluruh Wall Street:
- David Shaw — kemudiannya mendirikan D.E. Shaw & Co., salah satu dana lindung nilai kuantitatif terbesar
- Peter Muller — mendirikan PDT Partners, kumpulan stat arb legenda dalam Morgan Stanley
- Robert Frey — kemudiannya menyertai Renaissance Technologies di bawah Jim Simons
Kumpulan ini beroperasi sebagai makmal penyelidikan dalam bank pelaburan. Automasi adalah canggih: kluster VAX menjana isyarat, dan pelaksanaan melalui terminal. Pada tahun terbaik (1987-1988), strategi ini memperoleh puluhan juta. Kemudian datang dua tahun berturut-turut kerugian, dan pada tahun 1989 Morgan Stanley menutup meja dagangan itu.
Tetapi idea itu sudah tersebar. Alumni kumpulan itu menyebarkan konsep dagangan pasangan ke seluruh Wall Street. Gatev, Goetzmann, dan Rouwenhorst menerbitkan kertas akademik klasik pada tahun 2006 — "Pairs Trading: Performance of a Relative-Value Arbitrage Rule" — menunjukkan bahawa strategi dagangan pasangan yang mudah secara konsisten memberikan pulangan tahunan ~11% dari tahun 1962 hingga 2002 pada ekuiti AS. Ia merupakan jawapan yang meyakinkan kepada hipotesis pasaran cekap: pasaran secara keseluruhan mungkin cekap, tetapi pasangan aset tertentu secara sistematik menyimpang dari keseimbangan.
Hari ini, arbitraj statistik adalah industri dengan beratus-ratus bilion dolar dalam AUM, dan pasaran kripto menawarkan tanah yang sangat subur: kecairan berfragmen, struktur mikro yang belum matang, dagangan sepanjang masa, dan niaga hadapan kekal dengan kadar pendanaan — instrumen yang tidak wujud dalam pasaran tradisional.
2. Asas Matematik: Korelasi Adalah Perangkap
Mengapa Korelasi Tidak Berkesan
Mari mulakan dengan kesilapan yang dilakukan oleh hampir setiap quant pemula: "BTC dan ETH berkorelasi dengan pekali 0.85, jadi kita boleh memperdagangkan pasangan itu." Tidak. Anda tidak boleh. Boleh — tetapi anda akan rugi wang.
Korelasi mengukur hubungan linear antara pulangan dua aset. Dua aset boleh berkorelasi sempurna, namun harga mereka menyimpang selama-lamanya. Contoh klasik: dua jalan rawak dengan kenaikan berkorelasi — ia menyimpang tanpa had walaupun korelasi tinggi. Anda akan membuka kedudukan mengharapkan "konvergens" yang tidak akan pernah datang.

Kointegrasi: Pendekatan yang Betul
Kointegrasi adalah sifat siri harga, bukan pulangan. Dua siri tidak pegun X(t) dan Y(t) dikatakan terkointegrasi jika terdapat gabungan linear:
S(t) = Y(t) - β · X(t)
yang pegun — bermaksud ia kembali ke nilai min. Pekali β dipanggil nisbah lindung nilai, dan S(t) adalah spread.
Intuisi: BTC dan ETH boleh meroket ke bulan atau jatuh ke jurang, tetapi jika perbezaan mereka (diskalakan dengan betul) berayun di sekitar tahap tetap — itulah kointegrasi. Dan itulah tepat yang kita perlukan untuk dagangan.
Ujian Engle-Granger (1987)
Prosedur dua langkah yang Robert Engle dan Clive Granger menerima Hadiah Nobel dalam Ekonomi pada tahun 2003:
Langkah 1. Regresi OLS: Y(t) = α + β · X(t) + ε(t). Kita memperoleh nisbah lindung nilai β dan sisa ε(t).
Langkah 2. Ujian ADF (Augmented Dickey-Fuller) pada sisa ε(t). Hipotesis nol: ε(t) mempunyai akar unit (tidak pegun). Jika p-nilai < 0.05, kita menolak H₀ — siri adalah terkointegrasi.
Penting: untuk ujian kointegrasi, anda tidak boleh menggunakan nilai kritikal ADF standard. Nilai kritikal Engle-Granger diperoleh melalui simulasi Monte Carlo dan mengambil kira kebergantungan antara pemboleh ubah dalam regresi OLS. Dalam statsmodels, ini dilaksanakan dengan betul dalam fungsi coint().
Ujian Johansen
Untuk sistem dengan lebih daripada dua pemboleh ubah (cth., BTC, ETH, dan SOL serentak), ujian Johansen digunakan. Ia mencari semua hubungan kointegrasi dalam sistem dan membenarkan pembinaan portfolio berbilang aset. Ujian ini berdasarkan model VAR (regresi vektor autoregresif) dan menggunakan dua kriteria: statistik surih dan statistik nilai eigen maksimum.
Proses Ornstein-Uhlenbeck
Jika spread terkointegrasi, dinamiknya boleh dimodelkan sebagai proses Ornstein-Uhlenbeck (OU):
dS(t) = θ(μ - S(t))dt + σ dW(t)
di mana:
- θ — kelajuan pembalikan min
- μ — tahap min jangka panjang
- σ — turun naik
- W(t) — proses Wiener (gerakan Brown)
Dari parameter proses OU, separuh hayat pembalikan min dikira:
t½ = ln(2) / θ
Separuh hayat adalah metrik yang sangat penting. Jika t½ = 5 hari, spread kembali ke min dalam kira-kira 5 hari. Jika t½ = 200 hari, anda akan berada dalam kedudukan selama setengah tahun menunggu konvergens. Untuk strategi kripto, separuh hayat optimum adalah 1-30 hari. Lebih pendek — terlalu pantas, komisen memakan keuntungan. Lebih panjang — terlalu perlahan, risiko perubahan rejim struktur.
Dalam amalan, θ dianggarkan melalui regresi:
ΔS(t) = a + b · S(t-1) + ε(t)
di mana θ = -b, dan t½ = -ln(2) / b.
Penormalan Z-Skor
Untuk menjana isyarat dagangan, spread dinormalisasikan:
z(t) = (S(t) - μ̂) / σ̂
di mana μ̂ dan σ̂ adalah min bergulir dan sisihan piawai spread. Z-skor menunjukkan berapa banyak sisihan piawai spread telah menyimpang dari min. Ambang kemasukan tipikal: |z| > 2.0; ambang keluar: |z| < 0.5.
3. Memilih Pasangan dalam Pasaran Kripto
BTC-ETH: Klasik yang (Kadang-kadang) Berkesan
BTC dan ETH adalah pasangan yang paling jelas dan paling cair. Korelasi pulangan secara konsisten melebihi 0.7. Tetapi kointegrasi adalah perkara berbeza. Ia muncul dan hilang:
- Semasa pasaran mendatar 2023, BTC/ETH terkointegrasi dengan boleh dipercayai (p-nilai < 0.01)
- Semasa divergens 2024-2025 (BTC melonjak atas aliran ETF, ETH ketinggalan), kointegrasi rosak
- Menjelang awal 2026, selepas pelancaran ETH ETF dan pemulihan nisbah ETH/BTC, kointegrasi stabil semula
Kesimpulan: kointegrasi mesti dipantau secara berterusan. Parameter regresi dikira semula pada tetingkap bergulir, dan strategi dimatikan secara automatik jika p-nilai ujian ADF melebihi ambang.
Pasangan Sektor
Pasaran kripto dibahagikan dengan mudah mengikut sektor, dan pasangan dalam sektor sering menunjukkan kointegrasi yang stabil:
| Sektor | Contoh Pasangan | Ciri-ciri |
|---|---|---|
| Blockchain L1 | SOL/AVAX, NEAR/APT | Kecairan tinggi, separuh hayat 3-10 hari |
| Protokol DeFi | AAVE/COMP, UNI/SUSHI | Kecairan sederhana, separuh hayat 5-15 hari |
| Penyelesaian L2 | ARB/OP, MATIC/MANTA | Turun naik spread tinggi |
| Memekoin | DOGE/SHIB | Tidak dapat diramal tetapi menarik (tidak disyorkan) |
Pasangan terbaik untuk stat arb mempunyai tiga sifat: (1) kointegrasi stabil sepanjang tetingkap sejarah >6 bulan, (2) kecairan mencukupi — volum harian >$10J setiap aset, (3) separuh hayat yang munasabah — dari 1 hingga 30 hari.
Spot vs Niaga Hadapan Kekal (Basis)
Kategori "pasangan" berasingan adalah aset yang sama di pasaran spot dan niaga hadapan. Perbezaan antara harga niaga hadapan kekal dan harga spot (basis) adalah pegun secara takrifan: mekanisme kadar pendanaan memampaskannya kembali ke sifar. Ini menjadikan dagangan basis salah satu bentuk stat arb yang paling boleh dipercayai dalam kripto.
4. Tiga Pendekatan Dagangan
A. Dagangan Basis: Spot-Niaga Hadapan dan Pembawa Kadar Pendanaan
Bentuk stat arb yang "paling tulen" dalam kripto. Mekanismenya:
- Beli aset di spot (cth., 1 BTC)
- Buka kedudukan pendek pada niaga hadapan kekal (1 BTC)
- Jika kadar pendanaan positif (kedudukan panjang membayar pendek) — anda menerima pendanaan setiap 8 jam
Pada kadar pendanaan purata 0.01% setiap 8 jam, itu adalah ~0.03% sehari atau ~11% setahun tanpa risiko arah. Semasa pasaran lembu, kadar pendanaan boleh naik ke 0.05-0.1% setiap 8 jam — itu sudah 55-110% setahun.
Risiko: pendanaan negatif (pasaran berbalik), likuidasi kedudukan pendek semasa kenaikan harga yang tajam (penampan margin diperlukan), dan yuran bursa.
Sehingga Mac 2026, kadar pendanaan BTC purata telah stabil pada kira-kira ~0.015% per 8 jam — kira-kira 50% lebih tinggi daripada tahap 2024.
B. Arbitraj Antara Bursa
Syiling yang sama, dua bursa, harga berbeza. Sebabnya — perbezaan dalam kecairan, komposisi pedagang, dan kelajuan kemaskini buku pesanan.
Contoh: BTC di Binance: 87,175. Spread: $25 (0.029%).
Strategi: beli di Binance, jual di Bybit. Masalah: pada masa kedua-dua pesanan dilaksanakan, spread mungkin telah hilang. Penyelesaian: kekalkan baki di kedua-dua bursa dan laksanakan serentak.
Yuran tipikal:
- Binance: ~0.075% pengambil (dengan diskaun ~0.05%)
- Bybit: ~0.03% pengambil (VIP)
- Jumlah: ~0.08%
Ini bermaksud spread mesti melebihi 0.08% agar strategi menguntungkan. Pada tahun 2026, spread sedemikian berlaku:
- Pada pasangan kurang cair (altcoin) — secara kerap
- Pada pasangan utama (BTC, ETH) — hanya semasa momen turun naik tinggi
- Antara CEX dan DEX — lebih kerap, tetapi dengan risiko MEV dan gelinciran
Tanpa ko-lokasi, latensi API adalah 10-100 ms. Dengan rangkaian yang dioptimumkan — ~1 ms. Kebanyakan pedagang runcit beroperasi dalam julat 100-500 ms, yang mencukupi untuk banyak strategi arbitraj tetapi tidak mencukupi untuk bersaing dengan institusi.
C. Dagangan Pasangan dengan Leverage
Dagangan pasangan klasik pada dua aset berbeza menggunakan leverage. Ini adalah yang paling kompleks daripada tiga strategi — dan berpotensi paling menguntungkan.
Mekanisme menggunakan pasangan SOL/AVAX sebagai contoh:
- Kira nisbah lindung nilai β (cth., β = 1.3)
- Apabila z-skor > +2: pendek SOL, panjang AVAX × β
- Apabila z-skor < -2: panjang SOL, pendek AVAX × β
- Keluar: |z-skor| < 0.5 atau tamat masa (cth., 30 hari)
Dengan leverage 3x pada setiap bahagian dan purata pembalikan spread 2σ → 3σ:
- Pulangan sasaran setiap dagangan: ~3-6%
- Kekerapan purata: 2-4 dagangan sebulan setiap pasangan
- Pulangan tahunan dijangka: 30-60% (sebelum komisen dan gelinciran)
Risiko utama: korelasi boleh rosak pada masa yang paling tidak menguntungkan (biasanya semasa kejatuhan pasaran). Lebih lanjut mengenai ini dalam bahagian 8.
5. Penapis Kalman untuk Nisbah Lindung Nilai Adaptif
Mengapa Nisbah Lindung Nilai Statik Adalah Masalah
Pendekatan klasik: anggarkan β melalui OLS pada tetingkap sejarah dan tetapkan. Masalah: β berubah dari masa ke masa. Pasaran kripto sangat tidak pegun — peralihan naratif (musim DeFi → hype NFT → token AI) mengubah hubungan asas antara aset.
Menggunakan OLS bergulir (regresi bergulir) adalah separuh langkah. Anda perlu memilih panjang tetingkap: terlalu pendek — hingar; terlalu panjang — lag. Penapis Kalman menyelesaikan masalah ini dengan elegan.

Model Ruang Keadaan
Kami mewakili hubungan antara Y(t) dan X(t) sebagai model linear dengan pekali berubah-ubah masa:
Persamaan pemerhatian:
Y(t) = α(t) + β(t) · X(t) + ε(t), ε(t) ~ N(0, R)
Persamaan keadaan:
[α(t+1), β(t+1)]ᵀ = [α(t), β(t)]ᵀ + w(t), w(t) ~ N(0, Q)
Parameter α(t) dan β(t) dianggap sebagai keadaan tersembunyi yang melayang perlahan (jalan rawak). Penapis Kalman menganggarkan keadaan tersembunyi ini secara optimum daripada pemerhatian yang berhingar.
- R (hingar pemerhatian) — varians hingar pemerhatian. Semakin besar R, semakin perlahan penapis bertindak balas terhadap data baharu.
- Q (hingar keadaan) — matriks kovarians hingar keadaan. Semakin besar Q, semakin pantas penapis menyesuaikan diri.
Nisbah Q/R menentukan "kehalusan" penapis — analog dengan memilih panjang tetingkap dalam OLS bergulir, tetapi tanpa pemotongan data keras.
Kelebihan Berbanding OLS Bergulir
Spread yang dikira menggunakan penapis Kalman jauh lebih pegun dan lebih pembalikan min berbanding spread daripada regresi bergulir. Penapis Kalman menggunakan semua pemerhatian lalu dengan pemberat yang merosot secara eksponen, dan bukannya memotong data pada panjang tetingkap tetap. Selain itu, penapis Kalman tidak memerlukan penyetelan parameter "panjang tetingkap" — sebaliknya, ia secara automatik mengkalibrasi keseimbangan antara inersia dan keadaptifan melalui matriks Q dan R.
Pelaksanaan dengan filterpy
import numpy as np
from filterpy.kalman import KalmanFilter
def create_kalman_filter(
delta: float = 1e-4,
obs_noise: float = 1.0
) -> KalmanFilter:
"""
Creates a Kalman filter for adaptive hedge ratio estimation.
delta: state noise variance (Q = delta * I).
Larger delta → faster adaptation, more noise.
obs_noise: observation noise variance (R).
"""
kf = KalmanFilter(dim_x=2, dim_z=1)
kf.x = np.zeros((2, 1))
kf.F = np.eye(2)
kf.P = np.eye(2) * 1000
kf.Q = np.eye(2) * delta
kf.R = np.array([[obs_noise]])
return kf
def estimate_hedge_ratio(
prices_y: np.ndarray,
prices_x: np.ndarray,
delta: float = 1e-4,
obs_noise: float = 1.0
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
"""
Estimates the adaptive hedge ratio using a Kalman filter.
Returns:
alphas: array of intercepts (α)
betas: array of hedge ratios (β)
spreads: array of spreads Y - α - β*X
"""
n = len(prices_y)
kf = create_kalman_filter(delta, obs_noise)
alphas = np.zeros(n)
betas = np.zeros(n)
spreads = np.zeros(n)
for t in range(n):
kf.H = np.array([[1.0, prices_x[t]]])
kf.predict()
kf.update(np.array([[prices_y[t]]]))
alphas[t] = kf.x[0, 0]
betas[t] = kf.x[1, 0]
spreads[t] = prices_y[t] - kf.x[0, 0] - kf.x[1, 0] * prices_x[t]
return alphas, betas, spreads
Parameter delta adalah kunci. Untuk pasangan kripto dengan turun naik tinggi (memekoin, alt kecil-cap), gunakan delta = 1e-3. Untuk pasangan stabil (BTC/ETH, SOL/AVAX) — delta = 1e-5.
6. Isyarat Kemasukan dan Keluar
Ambang Z-Skor
Logik isyarat asas:
def generate_signals(
spreads: np.ndarray,
lookback: int = 60,
entry_z: float = 2.0,
exit_z: float = 0.5,
stop_z: float = 4.0
) -> np.ndarray:
"""
Generates trading signals based on spread z-score.
Returns array: +1 (long spread), -1 (short spread), 0 (flat)
"""
signals = np.zeros(len(spreads))
position = 0
for t in range(lookback, len(spreads)):
window = spreads[t - lookback:t]
mu = np.mean(window)
sigma = np.std(window)
if sigma < 1e-10:
continue
z = (spreads[t] - mu) / sigma
if position == 0:
if z > entry_z:
position = -1 # Short spread (short Y, long X)
elif z < -entry_z:
position = 1 # Long spread (long Y, short X)
else:
if position == 1 and z > -exit_z:
position = 0
elif position == -1 and z < exit_z:
position = 0
elif abs(z) > stop_z:
position = 0
signals[t] = position
return signals
Penapis Momentum
Isyarat pembalikan min tulen boleh ditingkatkan dengan penapis:
-
Penapis momentum: jangan buka kedudukan jika spread terus menyimpang. Tunggu spread berbalik sebelum masuk. Secara teknikal: z-skor telah melintasi ambang, tetapi perubahan spread semasa sudah diarahkan ke arah min.
-
Penapis turun naik: tingkatkan ambang kemasukan semasa tempoh turun naik tinggi. Apabila pasaran panik, z-skor boleh kekal melebihi 3σ selama berminggu-minggu.
-
Penapis kointegrasi: sebelum setiap dagangan, sahkan bahawa kointegrasi masih berlaku (ujian ADF bergulir). Jika p-nilai > 0.1 — hentikan dagangan.
Keluar Berasaskan Masa
Jika kedudukan telah dibuka lebih lama daripada 2× separuh hayat dan spread belum kembali — tutup secara paksa. Jika spread tidak kembali dalam masa 2× yang dijangkakan, kointegrasi berkemungkinan telah rosak, dan tidak ada yang perlu ditunggu.
7. Backtesting: Melakukannya dengan Betul
Analisis Walk-Forward
Backtest standard (latih pada semua data → uji pada semua data) tidak berguna untuk stat arb. Parameter regresi terlebih sesuai dengan data, dan hasilnya akan terlalu optimistik.
Pendekatan walk-forward:
- Bahagikan data kepada tempoh: [latih₁ → uji₁] → [latih₂ → uji₂] → ...
- Pada setiap tempoh latihan: anggarkan kointegrasi, kira nisbah lindung nilai, pilih ambang z-skor
- Pada tempoh ujian: dagangan dengan parameter tetap
- Gabungkan semua tempoh ujian untuk penilaian akhir
Konfigurasi tipikal untuk kripto: latih = 180 hari, uji = 30 hari, langkah = 30 hari.

Model Kos Transaksi
Untuk kripto, anda perlu mengambil kira:
| Komponen | Nilai Tipikal | Komen |
|---|---|---|
| Yuran pembuat | 0.02% | Pesanan had |
| Yuran pengambil | 0.05-0.075% | Pesanan pasaran |
| Gelinciran | 0.01-0.1% | Bergantung pada kecairan |
| Kadar pendanaan | ±0.01%/8j | Untuk kedudukan niaga hadapan |
| Spread (bida-tanya) | 0.01-0.05% | Pada bursa utama |
Memasuki dan keluar dari kedudukan pasangan melibatkan 4 dagangan (2 bahagian × masuk + keluar). Jumlah kos: ~0.3-0.5% setiap pusingan. Ini bermaksud keuntungan purata setiap dagangan mesti melebihi 0.5% untuk nilai jangkaan positif.
Model Gelinciran
Model linear: gelinciran = k × (saiz_pesanan / ADV), di mana ADV adalah volum harian purata. Untuk kripto, k ≈ 0.1 untuk syiling top-10 dan k ≈ 0.3-0.5 untuk altcoin.
Model yang lebih realistik adalah impak punca kuasa dua: gelinciran = k × sqrt(saiz_pesanan / ADV). Ia lebih baik mencerminkan struktur mikro pasaran sebenar.
Metrik
def calculate_metrics(returns: np.ndarray, rf: float = 0.04) -> dict:
"""
Calculates key strategy metrics.
rf: risk-free rate (annual)
"""
daily_rf = rf / 365
excess = returns - daily_rf
ann_return = np.mean(returns) * 365
ann_vol = np.std(returns) * np.sqrt(365)
sharpe = (ann_return - rf) / ann_vol if ann_vol > 0 else 0
cumulative = np.cumprod(1 + returns)
running_max = np.maximum.accumulate(cumulative)
drawdowns = (cumulative - running_max) / running_max
max_dd = np.min(drawdowns)
calmar = ann_return / abs(max_dd) if max_dd != 0 else 0
win_rate = np.mean(returns > 0) if len(returns) > 0 else 0
gains = returns[returns > 0].sum()
losses = abs(returns[returns < 0].sum())
profit_factor = gains / losses if losses > 0 else float('inf')
return {
'annual_return': f'{ann_return:.1%}',
'annual_volatility': f'{ann_vol:.1%}',
'sharpe_ratio': f'{sharpe:.2f}',
'max_drawdown': f'{max_dd:.1%}',
'calmar_ratio': f'{calmar:.2f}',
'win_rate': f'{win_rate:.1%}',
'profit_factor': f'{profit_factor:.2f}',
}
Penanda aras untuk stat arb kripto:
- Sharpe > 1.5 — strategi yang baik
- Drawdown maks < 15% — risiko yang boleh diterima
- Calmar > 2.0 — nisbah pulangan/drawdown yang cemerlang
- Faktor keuntungan > 1.5 — kelebihan yang mampan
8. Masalah Dunia Sebenar
Gelinciran dan Kecairan
Dalam backtest, anda masuk sekelika pada harga pertengahan. Dalam realiti — tidak begitu. Pada altcoin dengan volum harian 50K boleh menggerakkan harga sebanyak 0.2-0.5%. Untuk strategi pasangan, itu adalah gelinciran berganda (dua bahagian), dan boleh memakan semua keuntungan.
Penyelesaian: gunakan pesanan had (pembuat, bukan pengambil), bahagikan pesanan kepada bahagian (TWAP/VWAP), dan hadkan saiz kedudukan secara ketat berbanding ADV (maksimum 1-2% daripada volum harian).
Risiko Kadar Pendanaan
Dengan dagangan basis, anda menerima kadar pendanaan, tetapi ia boleh menjadi negatif. Dalam pasaran bearish Disember 2022, kadar pendanaan BTC adalah -0.02% setiap 8 jam — jika anda berada dalam kedudukan "panjang spot + pendek perp", anda membayar 100K kedudukan.
Perlindungan: pantau kadar pendanaan dalam masa nyata dan tutup kedudukan apabila kadar berbalik. Pendekatan yang lebih maju adalah arbitraj kadar pendanaan antara bursa (panjang di bursa dengan pendanaan rendah, pendek di bursa dengan pendanaan tinggi).
Keruntuhan Korelasi dalam Krisis
Mac 2020, Mei 2021, November 2022, Ogos 2024 — dalam setiap kejatuhan kripto, korelasi rosak. Lebih tepat lagi, korelasi menguat (semua jatuh bersama), tetapi kointegrasi rosak — spread boleh terbang ke 10σ dan tidak pernah kembali.
Ini adalah tumit Achilles dagangan pasangan. Strategi memperoleh jumlah kecil secara konsisten, kemudian kehilangan jumlah besar dalam satu hari. Profil klasik "mengutip syiling di hadapan penggelek jalan."
Perlindungan:
- Stop-loss ketat: tutup kedudukan apabila z-skor > 4σ
- Had leverage: maksimum 2-3x pada setiap bahagian
- Penapis VIX/turun naik: kurangkan saiz kedudukan apabila turun naik tersirat tinggi
- Kepelbagaian: dagangkan 10-20 pasangan serentak, jangan letakkan semua pada satu
Keperluan Modal
Untuk stat arb kripto yang serius:
- Dagangan basis: dari $50K (pada satu pasangan, satu bursa)
- Arbitraj antara bursa: dari $100K (baki di dua bursa)
- Portfolio dagangan pasangan (10 pasangan): dari $200K
- Tahap institusi: dari $1J
Dengan jumlah yang lebih kecil, komisen dan saiz kedudukan minimum menjadikan strategi tidak berdaya maju.
9. Pelaksanaan Python Hujung ke Hujung
Pengambilan Data
import ccxt
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
def fetch_ohlcv(
exchange_id: str,
symbol: str,
timeframe: str = '1h',
days: int = 365
) -> pd.DataFrame:
"""Fetch OHLCV data via ccxt."""
exchange = getattr(ccxt, exchange_id)({
'enableRateLimit': True,
})
since = int((datetime.now() - timedelta(days=days)).timestamp() * 1000)
all_candles = []
while True:
candles = exchange.fetch_ohlcv(
symbol, timeframe, since=since, limit=1000
)
if not candles:
break
all_candles.extend(candles)
since = candles[-1][0] + 1
if len(candles) < 1000:
break
df = pd.DataFrame(
all_candles,
columns=['timestamp', 'open', 'high', 'low', 'close', 'volume']
)
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('timestamp', inplace=True)
return df
sol = fetch_ohlcv('binance', 'SOL/USDT', '1h', 365)
avax = fetch_ohlcv('binance', 'AVAX/USDT', '1h', 365)
prices = pd.DataFrame({
'SOL': sol['close'],
'AVAX': avax['close']
}).dropna()
Ujian Kointegrasi
from statsmodels.tsa.stattools import coint, adfuller
from statsmodels.regression.linear_model import OLS
from statsmodels.tools import add_constant
def test_cointegration(y: np.ndarray, x: np.ndarray) -> dict:
"""
Full cointegration test with diagnostics.
"""
score, pvalue, crit_values = coint(y, x)
x_const = add_constant(x)
model = OLS(y, x_const).fit()
alpha, beta = model.params
spread = y - alpha - beta * x
adf_stat, adf_pvalue, _, _, adf_crit, _ = adfuller(spread, maxlag=20)
spread_lag = spread[:-1]
spread_diff = np.diff(spread)
spread_lag_const = add_constant(spread_lag)
hl_model = OLS(spread_diff, spread_lag_const).fit()
theta = -hl_model.params[1]
half_life = np.log(2) / theta if theta > 0 else np.inf
return {
'coint_pvalue': pvalue,
'cointegrated': pvalue < 0.05,
'hedge_ratio': beta,
'intercept': alpha,
'adf_statistic': adf_stat,
'adf_pvalue': adf_pvalue,
'half_life_hours': half_life,
'half_life_days': half_life / 24,
'spread_mean': np.mean(spread),
'spread_std': np.std(spread),
}
result = test_cointegration(
prices['SOL'].values,
prices['AVAX'].values
)
print(f"Cointegration: {result['cointegrated']} "
f"(p-value: {result['coint_pvalue']:.4f})")
print(f"Hedge ratio: {result['hedge_ratio']:.4f}")
print(f"Half-life: {result['half_life_days']:.1f} days")
Penapis Kalman + Backtester
from filterpy.kalman import KalmanFilter
class PairsBacktester:
"""
Walk-forward backtester for pairs trading
with Kalman filter.
"""
def __init__(
self,
prices_y: np.ndarray,
prices_x: np.ndarray,
kalman_delta: float = 1e-4,
obs_noise: float = 1.0,
entry_z: float = 2.0,
exit_z: float = 0.5,
stop_z: float = 4.0,
lookback: int = 60,
fee_rate: float = 0.001, # 0.1% round trip per leg
slippage_rate: float = 0.0005, # 0.05% slippage per leg
):
self.prices_y = prices_y
self.prices_x = prices_x
self.n = len(prices_y)
self.kalman_delta = kalman_delta
self.obs_noise = obs_noise
self.entry_z = entry_z
self.exit_z = exit_z
self.stop_z = stop_z
self.lookback = lookback
self.fee_rate = fee_rate
self.slippage_rate = slippage_rate
def run(self) -> pd.DataFrame:
"""Run the backtest. Returns a DataFrame with results."""
kf = KalmanFilter(dim_x=2, dim_z=1)
kf.x = np.zeros((2, 1))
kf.F = np.eye(2)
kf.P = np.eye(2) * 1000
kf.Q = np.eye(2) * self.kalman_delta
kf.R = np.array([[self.obs_noise]])
alphas = np.zeros(self.n)
betas = np.zeros(self.n)
spreads = np.zeros(self.n)
for t in range(self.n):
kf.H = np.array([[1.0, self.prices_x[t]]])
kf.predict()
kf.update(np.array([[self.prices_y[t]]]))
alphas[t] = kf.x[0, 0]
betas[t] = kf.x[1, 0]
spreads[t] = (
self.prices_y[t] - kf.x[0, 0]
- kf.x[1, 0] * self.prices_x[t]
)
positions = np.zeros(self.n)
z_scores = np.zeros(self.n)
position = 0
for t in range(self.lookback, self.n):
window = spreads[t - self.lookback:t]
mu = np.mean(window)
sigma = np.std(window)
if sigma < 1e-10:
continue
z = (spreads[t] - mu) / sigma
z_scores[t] = z
if position == 0:
if z > self.entry_z:
position = -1
elif z < -self.entry_z:
position = 1
else:
if position == 1 and z > -self.exit_z:
position = 0
elif position == -1 and z < self.exit_z:
position = 0
elif abs(z) > self.stop_z:
position = 0
positions[t] = position
spread_returns = np.diff(spreads) / np.abs(
spreads[:-1] + 1e-10
)
pnl = np.zeros(self.n)
for t in range(1, self.n):
if positions[t - 1] != 0:
raw_return = positions[t - 1] * spread_returns[t - 1]
pnl[t] = raw_return
if positions[t] != positions[t - 1]:
total_cost = 2 * (self.fee_rate + self.slippage_rate)
pnl[t] -= total_cost
return pd.DataFrame({
'price_y': self.prices_y,
'price_x': self.prices_x,
'alpha': alphas,
'beta': betas,
'spread': spreads,
'z_score': z_scores,
'position': positions,
'pnl': pnl,
'cumulative_pnl': np.cumsum(pnl),
})
bt = PairsBacktester(
prices_y=prices['SOL'].values,
prices_x=prices['AVAX'].values,
kalman_delta=1e-4,
entry_z=2.0,
exit_z=0.5,
stop_z=4.0,
lookback=60,
fee_rate=0.001,
slippage_rate=0.0005,
)
results = bt.run()
daily_pnl = results['pnl'].resample('D').sum() if hasattr(
results.index, 'freq'
) else results['pnl']
metrics = calculate_metrics(daily_pnl.values)
for k, v in metrics.items():
print(f'{k}: {v}')
Rangka Dagangan Langsung
import ccxt
import asyncio
import logging
logger = logging.getLogger(__name__)
class LivePairsTrader:
"""
Minimal skeleton for live pairs trading.
For production: add retry logic, monitoring,
alerts, balance reconciliation.
"""
def __init__(
self,
exchange_id: str,
symbol_y: str,
symbol_x: str,
api_key: str,
secret: str,
position_size_usd: float = 1000.0,
entry_z: float = 2.0,
exit_z: float = 0.5,
):
self.exchange = getattr(ccxt, exchange_id)({
'apiKey': api_key,
'secret': secret,
'enableRateLimit': True,
})
self.symbol_y = symbol_y
self.symbol_x = symbol_x
self.position_size = position_size_usd
self.entry_z = entry_z
self.exit_z = exit_z
self.position = 0 # +1, -1, 0
self.kf = create_kalman_filter(delta=1e-4)
self.spread_history = []
async def update(self):
"""One update cycle."""
ticker_y = self.exchange.fetch_ticker(self.symbol_y)
ticker_x = self.exchange.fetch_ticker(self.symbol_x)
price_y = ticker_y['last']
price_x = ticker_x['last']
self.kf.H = np.array([[1.0, price_x]])
self.kf.predict()
self.kf.update(np.array([[price_y]]))
alpha = self.kf.x[0, 0]
beta = self.kf.x[1, 0]
spread = price_y - alpha - beta * price_x
self.spread_history.append(spread)
if len(self.spread_history) < 60:
logger.info(f"Warming up: {len(self.spread_history)}/60")
return
window = np.array(self.spread_history[-60:])
z = (spread - np.mean(window)) / np.std(window)
logger.info(
f"β={beta:.4f} spread={spread:.4f} z={z:.2f} "
f"pos={self.position}"
)
new_position = self.position
if self.position == 0:
if z > self.entry_z:
new_position = -1
elif z < -self.entry_z:
new_position = 1
else:
if self.position == 1 and z > -self.exit_z:
new_position = 0
elif self.position == -1 and z < self.exit_z:
new_position = 0
if new_position != self.position:
await self._execute_trade(
new_position, price_y, price_x, beta
)
self.position = new_position
async def _execute_trade(
self, target: int, price_y: float, price_x: float,
beta: float
):
"""Execute a pairs trade."""
if target == 0:
logger.info("Closing position")
elif target == 1:
size_y = self.position_size / price_y
size_x = (self.position_size * beta) / price_x
logger.info(
f"Long spread: buy {size_y:.4f} {self.symbol_y}, "
f"sell {size_x:.4f} {self.symbol_x}"
)
elif target == -1:
size_y = self.position_size / price_y
size_x = (self.position_size * beta) / price_x
logger.info(
f"Short spread: sell {size_y:.4f} {self.symbol_y}, "
f"buy {size_x:.4f} {self.symbol_x}"
)
async def run_loop(self, interval_seconds: int = 60):
"""Main loop."""
logger.info(
f"Starting live trading: "
f"{self.symbol_y}/{self.symbol_x}"
)
while True:
try:
await self.update()
except Exception as e:
logger.error(f"Error in update: {e}")
await asyncio.sleep(interval_seconds)
Sebagai Penutup
Arbitraj statistik bukan cawan suci. Ia adalah kraf. Antara "Saya tahu apa itu kointegrasi" dan "Saya mempunyai strategi yang berfungsi secara konsisten" terdapat jurang kejuruteraan yang besar: pemprosesan data yang betul, backtesting walk-forward yang tepat, model gelinciran yang realistik, pemantauan masa nyata.
Pasaran mata wang kripto masih menawarkan lebih banyak peluang untuk stat arb berbanding pasaran tradisional — kecairan berfragmen, infrastruktur pasaran yang belum matang, dan instrumen unik seperti niaga hadapan kekal dengan kadar pendanaan mewujudkan ketidakcekapan yang telah lama diarbitrajkan ke sifar di NYSE.
Tetapi tingkap itu sedang menutup. Pemain institusi memasuki pasaran kripto, modal arbitraj semakin berkembang (mengikut anggaran, jumlah modal arbitraj di bursa kripto meningkat sebanyak 215% pada 2025), dan margin semakin berkurang. Jika anda ingin melakukan stat arb dalam kripto — sebaiknya mulakan sekarang.
Semua kod dalam artikel ini tersedia sebagai titik permulaan. Jangan jalankannya dalam persekitaran produksi tanpa ujian yang serius. Dan ingat: satu-satunya strategi yang dijamin berkesan adalah pengurusan risiko.
Karya akademik utama:
- Engle, R.F. & Granger, C.W.J. (1987). "Co-Integration and Error Correction: Representation, Estimation, and Testing". Econometrica, 55(2), 251-276.
- Gatev, E., Goetzmann, W.N. & Rouwenhorst, K.G. (2006). "Pairs Trading: Performance of a Relative-Value Arbitrage Rule". The Review of Financial Studies, 19(3), 797-827.
- Vidyamurthy, G. (2004). Pairs Trading: Quantitative Methods and Analysis. Wiley.
- Avellaneda, M. & Lee, J.H. (2010). "Statistical Arbitrage in the US Equities Market". Quantitative Finance, 10(7), 761-782.
- Frontiers (2026). "Deep learning-based pairs trading: real-time forecasting of co-integrated cryptocurrency pairs". Frontiers in Applied Mathematics and Statistics.
Pustaka berguna:
- statsmodels — kointegrasi, ADF, OLS
- filterpy — penapis Kalman
- ccxt — API bersatu untuk 100+ bursa
- arbitragelab — pustaka khusus untuk dagangan pasangan (OU, Kalman, kopula)
Pengarang
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.