DCC-GARCH: Korelasi Dinamis untuk Pairs dan Risiko Portofolio
Tanyakan pada sebagian besar meja perdagangan kripto tentang korelasi antara BTC dan ETH, dan Anda akan mendapatkan satu angka tunggal — 0,8, mungkin 0,75 — yang dihitung atas suatu jendela yang tak seorang pun ingat pernah memilihnya. Angka itu adalah sebuah kebohongan, atau setidaknya penyederhanaan yang berbahaya. Korelasi sampel adalah rata-rata sepanjang suatu periode di mana struktur ketergantungan yang sebenarnya bergerak terus-menerus. Di pasar yang tenang, BTC dan ETH melenceng cukup jauh sehingga membuat pair yang market-neutral tampak menarik. Dalam sebuah kaskade likuidasi, keduanya saling terkunci satu sama lain dan dengan segala hal lainnya, dan diversifikasi yang telah Anda bayar menguap tepat pada saat Anda membutuhkannya.
Ini bukan efek yang halus. Tarik drawdown mana pun dari tahun 2022 — keruntuhan LUNA pada Mei, unwinding 3AC pada Juni, keruntuhan FTX pada November — dan Anda akan melihat rata-rata korelasi berpasangan di antara 20 token teratas beranjak dari kisaran 0,4-0,6 menuju 0,9+ dalam hitungan hari. Korelasi bukanlah konstanta yang sesekali diestimasi dengan buruk; ia adalah sebuah deret waktu dengan dinamikanya sendiri, clustering-nya sendiri, dan rezim-rezimnya sendiri. Memperlakukannya sebagai skalar adalah padanan multivariat dari mengasumsikan volatilitas yang konstan — sebuah kesalahan yang sudah kita bongkar untuk satu aset tunggal di Bagian 1 dari seri ini.
Artikel ini adalah Bagian 3 dari seri volatilitas empat bagian. Bagian 1 membangun GARCH(1,1) univariat dengan library arch dan menunjukkan bagaimana volatilitas mengelompok dan kembali ke rata-rata (mean-revert). Bagian 2 menambahkan asimetri (GJR-GARCH, EGARCH) dan inovasi Student-t untuk menangkap efek leverage dan fat tails. Di sini kita beralih ke multivariat: kita memodelkan seluruh matriks kovariansi kondisional saat ia berevolusi, menggunakan model Dynamic Conditional Correlation (DCC) dari Engle. Itu memberi kita dua hal yang tidak pernah bisa diberikan oleh korelasi skalar — sebuah hedge ratio dinamis untuk pairs trading, dan variansi portofolio yang jujur serta berubah seiring waktu untuk alokasi berbasis risiko. Bagian 4 menutup seri ini dengan sebuah backtest yang menargetkan volatilitas (volatility-targeted) yang mengikat prakiraan univariat dan multivariat ke dalam sebuah aturan penentuan ukuran posisi.
Kami mengasumsikan Anda telah membaca Bagian 1 dan 2, sehingga kami tidak akan menurunkan ulang GARCH univariat. Jika Anda menginginkan perilaku tail bersama — probabilitas bahwa dua aset menembus kuantil 1% mereka secara bersamaan — itu adalah pertanyaan copula, dan kami membahasnya di Copula Models for Joint Risk. DCC dan copula bersifat saling melengkapi: copula memberi Anda struktur ketergantungan ekor (tail-dependence) yang statis namun fleksibel, sementara DCC memberi Anda sebuah deret waktu yang tractable dari keseluruhan matriks korelasi. Artikel ini membahas yang terakhir.
Mengapa Korelasi Statis Gagal di Kripto
Sebelum masuk ke mekanismenya, mari kita tepat mengenai apa yang gagal. Sebuah korelasi sampel tunggal atas jendela mengestimasi
Ini membawa tiga asumsi implisit, semuanya keliru untuk kripto:
- Stasioneritas ketergantungan. Jendela tersebut memiliki satu yang sebenarnya. Pada kenyataannya ketergantungan memiliki rezim — sebuah rezim pasar tenang di sekitar 0,5 dan sebuah rezim stres di sekitar 0,95 — dan mencampur keduanya menjadi sebuah nilai tengah yang tak bermakna.
- Volatilitas marginal yang konstan. Korelasi Pearson adalah kovariansi yang dinormalisasi. Jika dan sendiri bergerak (dan memang demikian — itulah keseluruhan premis dari Bagian 1 dan 2), maka bahkan sebuah kovariansi yang konstan pun menghasilkan sebuah korelasi yang berubah seiring waktu, dan sebaliknya. Anda tidak dapat memisahkan keduanya tanpa sebuah model volatilitas yang mendasarinya.
- Simetri lintas arah pasar. Korelasi naik dalam drawdown lebih besar ketimbang dalam rally. Ini adalah sepupu multivariat dari efek leverage. Sebuah jendela bergulir (rolling window) tidak dapat mengekspresikannya tanpa menjadi begitu pendek sehingga menjadi murni derau (noise).
Perbaikan berupa jendela bergulir — menghitung ulang atas 30 atau 60 hari terakhir — menukar satu masalah dengan masalah lain. Jendela pendek responsif tetapi berisik dan tertinggal dari titik patah yang sesungguhnya; jendela panjang stabil tetapi usang. Lebih buruk lagi, sebuah matriks korelasi bergulir atas aset tidak dijamin tetap positive semi-definite begitu Anda mulai menyusutkan atau menambalnya, dan itu merusak setiap optimizer hilir (downstream). Kita menginginkan sebuah model yang (a) digerakkan oleh sebuah proses volatilitas yang tepat per aset, (b) menghasilkan sebuah matriks korelasi yang valid pada setiap langkah secara konstruksi, dan (c) memiliki parameter yang dapat kita estimasi melalui maximum likelihood alih-alih dengan memilih panjang jendela secara sembarangan. Model itu adalah DCC-GARCH.
Masalah Multivariat: Matriks Kovariansi Kondisional
Misalkan adalah vektor imbal hasil untuk aset pada waktu , dengan rata-rata kondisional (sering kali hanya sebuah konstanta atau suku AR kecil) dan residual . Kita asumsikan
di mana adalah matriks kovariansi kondisional berukuran dengan diberikan himpunan informasi , dan adalah suatu distribusi kondisional (Gaussian atau, lebih baik untuk kripto, Student-t multivariat). Segala hal dalam pemodelan volatilitas multivariat adalah jawaban yang berbeda atas satu pertanyaan: bagaimana Anda memarametrisasi dinamika agar ia tetap symmetric positive definite pada setiap langkah tanpa ledakan jumlah parameter?
Dua jawaban klasik menunjukkan mengapa masalah ini sulit.
VECH
Model VECH (Bollerslev, Engle, Wooldridge 1988) menuliskan half-vectorization dari sebagai fungsi linier dari residual kuadrat masa lalu dan kovariansi masa lalu:
di mana menumpuk segitiga bawah dari sebuah matriks simetris menjadi sebuah vektor berpanjang . Ini bersifat maksimal umum — setiap variansi dan kovariansi bergantung pada setiap variansi dan kovariansi masa lalu — dan maksimal tak berguna melewati . Untuk aset, dan masing-masing berukuran . Pada itu berarti dua matriks , kira-kira 450 parameter, ditambah kendala positive-definiteness yang menyakitkan bahkan untuk sekadar diekspresikan. Permukaan likelihood-nya adalah sebuah rawa.
BEKK
Model BEKK (Engle & Kroner 1995) menjamin positive definiteness secara konstruksi menggunakan sebuah bentuk kuadratik:
dengan berbentuk segitiga atas (upper triangular). Karena setiap suku merupakan bentuk kuadratik, secara otomatis selama . BEKK lebih hemat parameter ketimbang VECH tetapi tetap berskala sebagai parameter — matriks dan masing-masing berukuran . Untuk Anda mengestimasi dalam orde 200+ parameter secara bersamaan melalui MLE, atas data kripto harian yang berisik, tanpa jaminan bahwa optimizer akan konvergen ke sesuatu yang bermakna. Dalam praktik BEKK penuh terbatas pada , dan bahkan pada saat itu orang menggunakan pembatasan "diagonal" atau "skalar" yang membuang sebagian besar dinamika lintas-aset.
Inilah kutukan dimensionalitas untuk GARCH multivariat: jumlah parameter tumbuh secara kuadratik, tetapi jumlah informasi dalam data tidak. Anda kehabisan derajat kebebasan jauh sebelum Anda kehabisan aset yang Anda pedulikan. Setiap book kripto dengan 10-30 token sepenuhnya di luar jangkauan VECH atau BEKK.
Jalan keluarnya, berkat Engle, adalah berhenti mencoba memodelkan secara langsung dan alih-alih memfaktorkannya menjadi bagian-bagian yang sudah kita ketahui cara mengestimasinya secara murah.
DCC dari Engle (2002): Dekomposisi Dua Langkah
Model Constant Conditional Correlation (CCC) dari Bollerslev (1990) adalah faktorisasi hemat parameter yang pertama. Ia menuliskan
di mana adalah matriks diagonal dari deviasi standar kondisional — satu GARCH univariat per aset — dan adalah sebuah matriks korelasi konstan. Ini merupakan penyederhanaan besar: Anda mencocokkan (fit) model GARCH univariat yang independen, lalu mengestimasi sebuah matriks korelasi sampel tunggal dari residual yang telah distandarisasi. Positive definiteness terjamin secara otomatis selama adalah matriks korelasi yang valid dan semua .
Masalah CCC ada tepat di namanya — korelasinya konstan, yang persis merupakan asumsi yang kita tolak di pembuka artikel ini. Dynamic Conditional Correlation dari Engle (2002) mempertahankan faktorisasi indah CCC tetapi membiarkan matriks korelasi bernapas:
Kini berubah seiring waktu. Kejeniusannya adalah bahwa volatilitas dan korelasi diestimasi dalam dua langkah terpisah, sehingga kita tidak pernah menghadapi optimasi bersama yang penuh.
Langkah 1: GARCH univariat per aset
Untuk setiap aset , cocokkan sebuah model GARCH univariat persis seperti di Bagian 1 dan 2 — GARCH(1,1), GJR-GARCH, atau EGARCH dengan inovasi Student-t, apa pun yang paling cocok untuk deret tersebut. Ini memberikan variansi kondisional dan karenanya .
Dari model-model yang telah dicocokkan kita mengekstrak residual yang distandarisasi:
Secara konstruksi setiap memiliki (secara aproksimasi) variansi kondisional satuan. Tumpuk mereka menjadi sebuah vektor . Residual yang distandarisasi ini adalah bahan mentah untuk langkah korelasi — dinamika volatilitas individualnya telah dilucuti, sehingga pergerakan bersama apa pun yang tersisa adalah ketergantungan murni, bukan artefak volatilitas. (Ini adalah logika gaya PIT yang sama yang digunakan artikel copula sebelum mencocokkan margin; di sini kita berhenti pada standarisasi alih-alih melangkah sampai ke uniform.)
Langkah 2: Rekursi korelasi DCC
Kita memodelkan sebuah proses bantu , sebuah matriks yang simetris positive-definite, dengan rekursi ala GARCH yang digerakkan oleh outer product dari residual yang distandarisasi:
di mana:
- adalah matriks korelasi tak-bersyarat (unconditional) dari residual yang distandarisasi (inilah correlation targeting — lebih lanjut mengenai ini di bawah),
- mengatur seberapa kuat guncangan hari ini menarik korelasi,
- mengatur persistensi — seberapa banyak kemarin yang terbawa ke depan,
- dan kendala mean-reversion adalah (dengan ), analog langsung dengan pada GARCH univariat.
Perhatikan bahwa strukturnya identik dengan rekursi GARCH(1,1) skalar, tetapi pada matriks: sebuah jangkar jangka panjang , sebuah suku guncangan, dan sebuah suku persistensi. Karena ia merupakan kombinasi konveks dari matriks-matriks positive-semi-definite (, outer product berperingkat 1, dan sebelumnya), tetap positive definite selama dan bobot-bobotnya non-negatif. Inilah yang memberi kita matriks kovariansi yang valid secara terjamin secara gratis.
hampir menjadi sebuah matriks korelasi tetapi tidak sepenuhnya — diagonalnya tidak persis 1. Maka kita menormalisasinya:
Secara elemen demi elemen, korelasi kondisional antara aset dan adalah
ini adalah matriks korelasi yang tepat — diagonal satuan, elemen luar-diagonal dalam , positive definite — pada setiap langkah waktu, secara konstruksi. Susun kembali matriks kovariansi kondisional penuh:
Bentuk elemen demi elemen yang terakhir itulah yang akan terus-menerus Anda gunakan: kovariansi kondisional dua aset adalah korelasi dinamis mereka dikalikan dengan masing-masing volatilitas dinamis mereka. Setiap bahan di ruas kanan berubah seiring waktu dan berasal dari sebuah model yang dapat Anda estimasi.
Keseluruhan model hanya memiliki dua parameter korelasi, dan , terlepas dari apakah atau . Sisi volatilitas berskala secara linier (satu GARCH univariat per aset, masing-masing dengan ~4-5 parameter, semuanya dicocokkan secara independen dan sangat paralel). Inilah sebabnya DCC berskala di tempat BEKK dan VECH tidak bisa: kutukan dimensionalitas terbatas pada , yang di-target (dimasukkan sebagai estimasi sampel) alih-alih dioptimasi.
Pembatasan skalar dan biayanya
Skalar berarti setiap pasang aset berbagi dinamika korelasi yang sama — kecepatan penyesuaian yang sama dan persistensi yang sama. Korelasi BTC-ETH dan korelasi DOGE-SHIB bergerak pada irama yang sama meskipun ekonomi keduanya berbeda. Inilah harga dari tractability, dan biasanya ini adalah harga yang dapat diterima. Generalisasi (Generalized DCC dengan matriks ; DCC asimetris Cappiello-Engle-Sheppard) melonggarkannya dengan mengorbankan parameter dan stabilitas estimasi. Kami menyebut aDCC di bawah.
Quasi-Log-Likelihood DCC
Untuk mengestimasi dan kita membutuhkan likelihood. Hasil kunci dari Engle adalah bahwa log-likelihood Gaussian terpisah menjadi sebuah bagian volatilitas dan sebuah bagian korelasi, yang merupakan pembenaran bagi estimator dua langkah. Dengan mengasumsikan , kontribusi log-likelihood pada waktu adalah
Substitusikan . Maka dan , dan dengan menggunakan :
Sekarang pisahkan dengan menambah dan mengurangi :
Bagian volatilitas hanya bergantung pada parameter GARCH univariat (melalui ) — memaksimalkannya persis sama dengan mencocokkan model GARCH univariat yang independen, yang telah kita lakukan di Langkah 1. Bagian korelasi bergantung pada dan (melalui ), dengan diberikan residual yang distandarisasi dari Langkah 1. Jadi di Langkah 2 kita hanya memaksimalkan
(suku tidak bergantung pada , sehingga kita membuangnya). Ini adalah optimasi dua parameter tak peduli berapa banyak aset — itulah inti keseluruhannya. Ia disebut quasi-likelihood karena estimator dua langkah bersifat konsisten tetapi tidak sepenuhnya efisien; galat baku (standard error) memerlukan koreksi (Engle & Sheppard 2001), tetapi untuk pembangkitan sinyal yang penting adalah estimasi titiknya.
Untuk kripto, inovasi Gaussian meremehkan risiko ekor. Menukarnya dengan likelihood Student-t multivariat merupakan perubahan langsung (drop-in) pada (ganti kernel Gaussian dengan densitas -multivariat dan tambahkan sebuah parameter derajat kebebasan ). Kami mempertahankan quasi-likelihood Gaussian dalam estimator di bawah demi kejelasan dan menandai di mana masuk — standarisasi dari Bagian 1-2 sudah menggunakan inovasi-t pada margin, yang menangkap sebagian besar manfaat ekor.
Implementasi Python
Sebuah fakta yang tumpul tetapi penting: library arch tidak melakukan GARCH multivariat atau DCC. arch adalah mesin univariat yang unggul (kita bersandar padanya persis untuk itu), tetapi tidak ada dcc_model di dalamnya. Opsi praktis Anda adalah:
- Buat DCC sendiri di atas
arch— cocokkan model univariat denganarch, ekstrak residual yang distandarisasi, implementasikan rekursi dan quasi-likelihood korelasi dalam NumPy/SciPy, dan optimasi kedua skalar. Inilah yang kita lakukan di bawah. Panjangnya sekitar 60 baris dan sepenuhnya transparan. - Paket
mgarchdi PyPI — sebuah implementasi DCC-GARCH pure-Python yang ringan. Praktis untuk pencocokan cepat, kurang fleksibel jika Anda menginginkan margin GJR atau inovasi-t yang tersambung secara presisi. rmgarchdari R (Alexios Galanos) — implementasi rujukan.dccspec/dccfitmendukung DCC, aDCC, GARCH-copula, Student-t, dan galat baku yang tepat. Jika Anda melakukan riset volatilitas multivariat yang serius,rmgarch(dipanggil dari Python viarpy2jika terpaksa) adalah standar emas.
Kita membangun opsi 1 karena ia membuat setiap bagian yang bergerak menjadi eksplisit dan menggunakan kembali keterampilan univariat dari Bagian 1-2.
Langkah 1: Cocokkan margin GARCH univariat dengan arch
import numpy as np
import pandas as pd
from arch import arch_model
from scipy.optimize import minimize
def fetch_returns(symbols, start="2022-01-01", end="2025-12-31"):
"""
Daily log returns for a list of crypto symbols.
Replace with your data source (ccxt for 24/7 exchange data,
yfinance for a quick sketch).
"""
import yfinance as yf
px = yf.download([f"{s}-USD" for s in symbols],
start=start, end=end)["Close"]
px.columns = symbols
rets = np.log(px / px.shift(1)).dropna()
return rets
symbols = ["BTC", "ETH", "SOL", "BNB"]
returns = fetch_returns(symbols)
def fit_univariate(series, dist="t"):
"""
Fit GJR-GARCH(1,1) with Student-t innovations (Part 2 model).
Returns the fitted result and the *scaled* series it was fit on.
We scale returns by 100 for the optimizer's numerical health,
exactly as in Parts 1 and 2.
"""
scaled = series * 100.0
model = arch_model(scaled, mean="Constant",
vol="GARCH", p=1, o=1, q=1, dist=dist)
res = model.fit(disp="off")
return res
fits = {s: fit_univariate(returns[s]) for s in symbols}
Z = pd.DataFrame({s: fits[s].std_resid for s in symbols}).dropna()
Sigma = pd.DataFrame({s: fits[s].conditional_volatility
for s in symbols}).loc[Z.index]
print(Z.describe())
Sebuah pemeriksaan kewarasan cepat pada residual yang distandarisasi itu penting. Jika ada kolom yang memiliki deviasi standar jauh dari 1, atau autokorelasi tersisa yang berat pada kuadratnya (Ljung-Box pada ), berarti margin univariatnya salah spesifikasi (misspecified) dan langkah DCC akan mewarisi galat tersebut. Perbaiki dulu marginnya — itulah gunanya Bagian 2.
Langkah 2: Rekursi DCC dan quasi-log-likelihood
def dcc_negloglik(params, Z):
"""
Negative DCC quasi-log-likelihood (Gaussian) in (a, b).
Z : (T, d) array of standardized residuals from Step 1.
Implements:
Q_t = (1-a-b) Qbar + a z_{t-1} z_{t-1}' + b Q_{t-1}
R_t = diag(Q_t)^{-1/2} Q_t diag(Q_t)^{-1/2}
LL = -1/2 sum_t ( log|R_t| + z_t' R_t^{-1} z_t )
with correlation targeting: Qbar = sample corr of Z.
"""
a, b = params
if a <= 0 or b <= 0 or a + b >= 1.0:
return 1e10
Z = np.asarray(Z)
T, d = Z.shape
Qbar = np.cov(Z, rowvar=False, bias=True) # unconditional (targeted)
dinv = np.diag(1.0 / np.sqrt(np.diag(Qbar)))
Qbar = dinv @ Qbar @ dinv
Q = Qbar.copy() # initialize Q_1 at the target
ll = 0.0
for t in range(T):
q_diag = np.sqrt(np.diag(Q))
R = Q / np.outer(q_diag, q_diag)
sign, logdet = np.linalg.slogdet(R)
if sign <= 0:
return 1e10
z = Z[t]
Rinv_z = np.linalg.solve(R, z)
ll += -0.5 * (logdet + z @ Rinv_z)
Q = (1 - a - b) * Qbar + a * np.outer(z, z) + b * Q
return -ll
def fit_dcc(Z):
"""Estimate (a, b) by maximizing the DCC quasi-log-likelihood."""
res = minimize(
dcc_negloglik, x0=[0.03, 0.94], args=(np.asarray(Z),),
method="L-BFGS-B",
bounds=[(1e-6, 0.5), (1e-6, 0.999)],
)
a, b = res.x
print(f"DCC estimates: a = {a:.4f}, b = {b:.4f}, a+b = {a+b:.4f}")
print(f"log-likelihood: {-res.fun:.2f}")
return a, b
a_hat, b_hat = fit_dcc(Z)
Menjalankan ini pada sebuah book BTC/ETH/SOL/BNB atas beberapa tahun data harian menghasilkan keluaran dalam bentuk berikut (angka-angka di bawah bersifat ilustratif, bukan berasal dari eksperimen bertanggal tertentu — jalankan pada data Anda sendiri):
DCC estimates: a = 0.0287, b = 0.9401, a+b = 0.9688
log-likelihood: -3812.44
Cara membacanya:
- kecil — matriks korelasi tidak melonjak karena guncangan satu hari. Setiap hari hanya menyentuh ke arah outer product sekitar ~3%.
- besar — korelasi sangat persisten. Begitu book saling berpaut (couple up) dalam sebuah peristiwa stres, ia tetap berpaut untuk beberapa waktu, meluruh kembali menuju secara perlahan. Ini cocok dengan pengalaman nyata drawdown kripto: korelasi tidak langsung pulih (snap back) saat harga stabil.
- mengonfirmasi mean reversion. Proses korelasi memiliki sebuah tingkat jangka panjang stasioner () yang menjadi tujuan pulangnya, dengan half-life kira-kira hari. Jika Anda pernah mengestimasi pada dasarnya sama dengan 1, proses korelasinya terintegrasi (integrated) — ia tidak memiliki jangkar jangka panjang, biasanya merupakan gejala dari sebuah structural break di dalam sampel Anda yang diserap model sebagai persistensi tak hingga.
Persistensi mendekati satuan dan pembebanan guncangan yang mungil adalah sidik jari (fingerprint) kanonik DCC di seluruh kelas aset, dan kripto tidak terkecuali. Inilah pula mengapa korelasi bergulir 30 hari merupakan pengganti yang begitu buruk: sebuah jendela bergulir secara implisit mengasumsikan dan yang sama sekali tidak cocok dengan struktur peluruhan ini.
Beberapa catatan implementasi yang menghemat banyak waktu debugging nyata:
- Inisialisasi. Memulai pada
[0.03, 0.94]mencerminkan estimasi kripto yang tipikal: kecil (korelasi bereaksi terhadap guncangan tetapi tidak dengan keras), besar (korelasi persisten). Jika optimizer Anda mengembara ke maka proses korelasinya terintegrasi — biasanya sebuah tanda structural break dalam sampel (sebuah perubahan rezim yang berusaha keras dicocokkan model sebagai persistensi). - Konvensi waktu (timing). Di dalam loop kita menilai (score) terhadap dan lalu memperbarui dengan untuk langkah berikutnya. Ini menjaga sebagai fungsi dari informasi hingga saja — tanpa look-ahead. Salah menangani off-by-one ini adalah bug DCC yang paling umum, dan ia secara diam-diam menggelembungkan kecocokan in-sample.
- Correlation targeting. Kita memasukkan sebagai korelasi sampel alih-alih mengestimasinya. Inilah yang membuat optimasinya menjadi dua dimensi. Biayanya adalah menggunakan seluruh sampel, sehingga dalam walk-forward yang ketat Anda harus mengestimasinya ulang hanya pada jendela pelatihan (lihat di bawah).
Langkah 3: Rekonstruksi jalur korelasi dan kovariansi
Begitu tetap, jalankan rekursi sekali lagi, kali ini menyimpan seluruh jalur (dan ) sehingga strategi hilir dapat menggunakannya.
def dcc_filter(Z, Sigma, a, b):
"""
Run the DCC recursion with fixed (a,b) and return the full paths:
R_path : (T, d, d) conditional correlation matrices
H_path : (T, d, d) conditional covariance matrices (scaled units)
Sigma : (T, d) conditional volatilities aligned with Z.
"""
Z = np.asarray(Z); Sig = np.asarray(Sigma)
T, d = Z.shape
Qbar = np.cov(Z, rowvar=False, bias=True)
dinv = np.diag(1.0 / np.sqrt(np.diag(Qbar)))
Qbar = dinv @ Qbar @ dinv
Q = Qbar.copy()
R_path = np.empty((T, d, d))
H_path = np.empty((T, d, d))
for t in range(T):
q_diag = np.sqrt(np.diag(Q))
R = Q / np.outer(q_diag, q_diag)
R_path[t] = R
Dt = np.diag(Sig[t]) # D_t = diag(sigma_i,t)
H_path[t] = Dt @ R @ Dt # H_t = D_t R_t D_t
z = Z[t]
Q = (1 - a - b) * Qbar + a * np.outer(z, z) + b * Q
return R_path, H_path
R_path, H_path = dcc_filter(Z, Sigma, a_hat, b_hat)
i, j = symbols.index("BTC"), symbols.index("ETH")
rho_btc_eth = pd.Series(R_path[:, i, j], index=Z.index, name="rho_BTC_ETH")
print(rho_btc_eth.describe())
print("min/max correlation:", rho_btc_eth.min().round(3),
rho_btc_eth.max().round(3))
Deret rho_btc_eth adalah hasil (payoff) dari keseluruhan latihan ini: alih-alih satu angka, Anda kini memiliki sebuah korelasi harian yang dapat Anda plot, ambil ambang batasnya (threshold), atau umpankan ke sebuah strategi. Pada data kripto nyata Anda biasanya akan melihatnya berkisar dari kira-kira 0,5 pada masa-masa tenang hingga di atas 0,9 selama stres — persis rentang yang dirata-ratakan hilang oleh sebuah korelasi sampel tunggal.
Prakiraan satu langkah ke depan
Untuk perdagangan langsung (live) Anda membutuhkan periode berikutnya dari informasi yang tersedia sekarang. Sisi volatilitas berasal dari prakiraan satu langkah tiap model arch; sisi korelasi adalah satu putaran rekursi lagi:
def dcc_forecast_next(Z, a, b, fits, symbols):
"""One-step-ahead H_{t+1} using info through the last observation."""
Z = np.asarray(Z); T, d = Z.shape
Qbar = np.cov(Z, rowvar=False, bias=True)
dinv = np.diag(1.0 / np.sqrt(np.diag(Qbar)))
Qbar = dinv @ Qbar @ dinv
Q = Qbar.copy()
for t in range(T):
z = Z[t]
Q = (1 - a - b) * Qbar + a * np.outer(z, z) + b * Q
q_diag = np.sqrt(np.diag(Q))
R_next = Q / np.outer(q_diag, q_diag)
sig_next = np.array([
np.sqrt(fits[s].forecast(horizon=1, reindex=False)
.variance.iloc[-1, 0])
for s in symbols
])
Dt = np.diag(sig_next)
H_next = Dt @ R_next @ Dt
return R_next, H_next, sig_next
R_next, H_next, sig_next = dcc_forecast_next(Z, a_hat, b_hat, fits, symbols)
Ingat bahwa segalanya berada dalam satuan yang diskalakan (×100) karena kita mencocokkan arch pada series * 100. Bagi volatilitas dengan 100 (dan kovariansi dengan ) untuk kembali ke satuan imbal hasil mentah sebelum mengumpankan ke sebuah strategi. Menjaga penskalaan tetap benar itu membosankan tetapi merupakan sumber bug diam-diam yang sering.
Aplikasi 1: Sebuah Hedge Ratio Dinamis untuk Pairs Trading
Pair market-neutral klasik — long satu aset, short sejumlah aset lain yang dibobot beta — hidup atau mati bergantung pada hedge ratio . Estimasikan ia dengan OLS statis atas sebuah jendela pelatihan dan Anda mewarisi persis masalah korelasi usang yang menjadi bahasan keseluruhan artikel ini: hedge yang menetralkan paparan pasar kuartal lalu keliru pada kuartal ini.
DCC memberi Anda hedge ratio sebagai sebuah deret waktu. Hedge variansi-minimum dari paparan ETH menggunakan BTC adalah koefisien regresi kondisional
Setiap suku di ruas kanan adalah keluaran DCC. Hedge ratio bergerak karena dua alasan yang berbeda, dan DCC memisahkannya dengan bersih: korelasi berubah (aset saling berpaut atau melepas), dan rasio volatilitas berubah (satu aset menjadi relatif lebih volatil). Beta rolling-OLS mengaburkan kedua efek itu bersamaan dengan lag; DCC mengatribusikannya.
def dynamic_hedge_ratio(R_path, Sigma, base="BTC", target="ETH",
symbols=symbols, index=Z.index):
"""
beta_t to hedge `target` exposure with `base`:
beta_t = rho_t * sigma_target,t / sigma_base,t
(Scaling cancels in the ratio, so scaled units are fine here.)
"""
i = symbols.index(target)
j = symbols.index(base)
rho = R_path[:, i, j]
sig = np.asarray(Sigma)
beta = rho * sig[:, i] / sig[:, j]
return pd.Series(beta, index=index, name=f"beta_{target}_{base}")
beta_t = dynamic_hedge_ratio(R_path, Sigma)
print(beta_t.describe())
spread = (returns["ETH"] - beta_t.shift(1) * returns["BTC"]).dropna()
Umpankan spread ke mesin pairs apa pun yang Anda jalankan. Hedge dinamis dengan sendirinya tidak menciptakan sebuah edge — ia membuat spread yang Anda perdagangkan benar-benar market-neutral sepanjang waktu, sehingga sinyal mean-reversion Anda tidak terkontaminasi oleh paparan direksional yang menyimpang (drifting). Jika Anda membangun strategi pairs, ini langsung terpasang ke dalam kerangka kerja di Statistical Arbitrage & Pairs Trading in Crypto dan pendekatan jarak untuk pairs, menggantikan hedge ratio tetap mereka. Deret korelasi itu sendiri juga merupakan masukan yang lebih bersih untuk sebuah sinyal pair berbasis korelasi ketimbang jendela bergulir apa pun — Anda memperoleh yang mulus dan konsisten-model alih-alih sebuah estimasi berjendela yang berisik.
Dua peringatan yang spesifik untuk menggunakan secara langsung. Pertama, beri lag padanya — perdagangkan berdasarkan , jangan pernah sekontemporer, atau Anda mengintip (peeking). Kedua, sebuah hedge ratio yang berputar liar setiap hari menghasilkan turnover dan biaya; di pasar kripto 24/7 dengan biaya funding pada kaki short, sebuah hedge yang terlalu reaktif dapat menguras lebih banyak ketimbang penyimpangan yang dikoreksinya. Haluskan (sebuah EWMA, atau seimbangkan ulang hedge hanya ketika ia bergerak melewati sebuah band) dan tentukan ukuran keseluruhannya secara wajar — penentuan ukuran posisi dari sebuah sinyal yang berisik adalah disiplin tersendiri, dibahas di penentuan ukuran dengan kriteria Kelly.
Aplikasi 2: Variansi Portofolio yang Berubah Seiring Waktu
Untuk sebuah portofolio dengan vektor bobot , variansi kondisionalnya adalah
Dengan matriks kovariansi statis — default Markowitz — angka ini adalah sebuah konstanta yang Anda hitung sekali dan Anda anggap masih benar. Padahal tidak. Risiko portofolio bernapas bersama pasar, dan ia bernapas paling keras persis ketika korelasi melonjak, karena dalam sebuah drawdown baik suku maupun suku naik bersamaan dan saling mengalikan. Sebuah portofolio yang tampak seperti vol tahunan 40% di pasar yang tenang bisa berjalan pada 80%+ dalam sepekan penuh stres, dan sebuah matriks kovariansi statis akan memberitahu Anda bahwa tidak ada yang berubah.
def portfolio_vol_path(H_path, weights, index=Z.index, unscale=1e4):
"""
Conditional portfolio volatility sigma_{p,t} = sqrt(w' H_t w).
H_path is in scaled (x100) units, so covariances carry a 100^2
factor: divide by unscale=1e4 to return to raw-return variance.
"""
w = np.asarray(weights)
var_t = np.einsum("i,tij,j->t", w, H_path, w) / unscale
return pd.Series(np.sqrt(var_t), index=index, name="port_vol")
w = np.array([0.4, 0.3, 0.2, 0.1]) # BTC, ETH, SOL, BNB
pv = portfolio_vol_path(H_path, w)
pv_annual = pv * np.sqrt(365)
print(pv_annual.describe())
yang berubah seiring waktu ini adalah masukan jujur yang dibutuhkan oleh alokasi berbasis risiko. Optimasi mean-variance (Markowitz untuk kripto) dengan kovariansi sampel yang statis berarti mengoptimasi terhadap sebuah fiksi; mengumpankannya (atau prakiraannya berhorizon pendek) membuat efficient frontier itu sendiri berubah seiring waktu dan memaksa optimizer untuk menurunkan risiko (de-risk) memasuki rezim-rezim korelasi yang naik alih-alih sesudahnya. Pendekatan risk-parity dan hierarkis — pipeline HRP + CVaR — bahkan lebih sensitif terhadap masukan kovariansi, karena keseluruhan alokasinya adalah sebuah fungsi dari matriks risiko. Dan jika Anda membandingkan para allocator secara langsung, seperti di perbandingan algoritma optimasi portofolio, apakah mereka mengonsumsi kovariansi statis atau dinamis sering kali merupakan pendorong risiko terealisasi yang lebih besar ketimbang pilihan algoritmanya.
Aplikasi langsungnya adalah volatility targeting untuk keseluruhan portofolio: pilih sebuah vol tahunan target , dan skalakan paparan bruto (gross) dengan setiap periode sehingga risiko terealisasi tetap kira-kira konstan alih-alih menggelembung dalam krisis. Itu menutup lingkaran dengan Bagian 4, yang membangun dan melakukan backtest persis atas aturan ini.
Aplikasi 3: Korelasi sebagai Sinyal Rezim
Di luar hedging dan penentuan ukuran, matriks korelasi membawa sebuah sinyal makro. Skalar tunggal paling berguna yang dapat Anda ekstrak adalah korelasi berpasangan rata-rata:
Ketika naik di seluruh book, pasar sedang memasuki sebuah rezim risk-off — kisah-kisah idiosinkratik berhenti berarti dan segalanya diperdagangkan sebagai satu beta makro. Ini adalah sidik jari kuantitatif dari "korelasi menuju 1 dalam krisis." Ia cenderung mendahului atau berbarengan dengan drawdown, yang menjadikannya sebuah indikator rezim yang dapat dipakai alih-alih sebuah postmortem yang tertinggal.
def avg_pairwise_corr(R_path, index=Z.index):
T, d, _ = R_path.shape
iu = np.triu_indices(d, k=1) # upper-triangle off-diagonals
avg = R_path[:, iu[0], iu[1]].mean(axis=1)
return pd.Series(avg, index=index, name="avg_corr")
avg_corr = avg_pairwise_corr(R_path)
roll_q = avg_corr.rolling(365, min_periods=90).quantile(0.80)
risk_off = (avg_corr > roll_q)
Anda dapat menggunakan risk_off sebagai sebuah throttle mandiri (potong paparan bruto, lebarkan stop, hentikan strategi mean-reversion yang tergilas ketika segalanya bergerak seiring tren bersama) atau sebagai sebuah fitur dalam sebuah model rezim yang lebih formal. Ia berpadu secara alami dengan pendekatan hidden-Markov di deteksi rezim dengan HMM: korelasi DCC rata-rata adalah salah satu variabel observasi yang lebih informatif yang dapat Anda serahkan ke sebuah HMM, karena ia bersifat forward-looking mengenai stres sistemik dengan cara yang tidak dimiliki imbal hasil masa lalu. Peringatan jujurnya: korelasi yang naik memberitahu Anda bahwa diversifikasi sedang gagal, bukan ke arah mana pasar akan bergerak. Ia adalah sebuah sinyal risiko, bukan sinyal alfa, dan seharusnya ditentukan ukurannya demikian — lihat asimetri kerugian dan keuntungan untuk memahami mengapa memperlakukan sebuah rezim risiko sebagai taruhan direksional berakhir buruk.
Pertimbangan Praktis
Stabilitas estimasi dan jumlah aset
DCC berskala jauh lebih baik ketimbang BEKK, tetapi "berskala" tidaklah sama dengan "gratis." Matriks correlation-targeting adalah sebuah korelasi sampel , dan matriks korelasi sampel menjadi ill-conditioned saat mendekati jumlah observasi. Dengan 4 aset dan 1000 hari Anda baik-baik saja. Dengan 60 aset dan 400 hari, nyaris singular, invers-nya dalam likelihood meledak, dan dapat mengembara menjadi non-PD akibat derau numerik. Mitigasi, kira-kira dalam urutan seberapa sering Anda akan membutuhkannya:
- Susutkan (shrink) menuju sebuah target terstruktur (Ledoit-Wolf, atau menuju identitas / sebuah matriks korelasi konstan) sebelum menjalankan rekursi. Ini adalah perbaikan bertuas paling tinggi untuk book besar.
- Kelompokkan aset ke dalam segelintir sektor (majors, L1, DeFi, memes), modelkan di dalam dan lintas pada tingkat sektor, atau jalankan DCC pada faktor komponen utama (principal-component) alih-alih aset mentah.
- Utamakan lebih banyak data ketimbang lebih banyak aset. DCC memiliki selera tak terpuaskan akan sejarah yang panjang, bersih, dan sekontemporer — yang persis merupakan hal yang tidak dimiliki token-token muda.
Secara realistis, batasi DCC langsung hingga paling banyak beberapa lusin aset. Untuk semesta yang besar, DCC pada imbal hasil faktor ditambah residual idiosinkratik adalah workaround standarnya.
Correlation targeting adalah jalan pintas dengan biaya
Menargetkan membuat estimasi menjadi tractable tetapi memanggang korelasi tak-bersyarat seluruh-sampel ke dalam setiap . Dalam sebuah backtest yang ketat ini merupakan sebuah kebocoran look-ahead: matriks korelasi hari- Anda "mengetahui" korelasi rata-rata seluruh sampel, termasuk masa depan. Untuk evaluasi yang jujur Anda harus mengestimasi ulang hanya pada jendela pelatihan dan menahannya tetap di luar-sampel, atau menggulirkannya ke depan. Ini adalah disiplin yang sama yang ditegakkan oleh keseluruhan kerangka kerja walk-forward optimization, dan ia mudah dilanggar secara tak sengaja dengan sebuah np.cov(Z) yang praktis atas seluruh array — seperti yang dilakukan kode pengajaran kita di atas. Perbaiki dulu sebelum Anda memercayai satu angka P&L pun.
Irama pencocokan ulang (refit) dan disiplin look-ahead
Anda tidak perlu mengoptimasi ulang setiap hari — keduanya parameter yang stabil. Sebuah irama produksi yang masuk akal:
- Estimasi ulang dan parameter GARCH univariat secara mingguan atau bulanan.
- Jalankan filter (perbarui , ) setiap periode dengan parameter yang dibekukan untuk memperoleh dan yang segar. Filtering itu murah; fitting tidak.
- Selalu prakirakan, jangan pernah menghaluskan (smooth). Gunakan yang dibangun dari informasi hingga untuk berdagang pada . Struktur dua-lintasan (fit pada sebuah jendela, lalu filter ke depan) itulah yang menjaga Anda tetap jujur.
Kesenjangan antara backtest DCC dan performa langsung hampir selalu merupakan sebuah kebocoran look-ahead — seluruh-sampel, sekontemporer, atau pencocokan ulang pada data yang mencakup perdagangan yang sedang Anda evaluasi. Disiplin mencocokkan backtest dengan kondisi langsung adalah topik tersendiri di paritas backtest-langsung, dan DCC adalah sebuah model yang menghukum kecerobohan di sini lebih dari kebanyakan model lain. Jika, setelah evaluasi walk-forward yang bersih, korelasi dinamis tidak menambahkan apa pun di atas sebuah estimasi bergulir sederhana untuk strategi Anda, itu adalah sebuah hasil negatif yang nyata dan layak dipublikasikan — pola pikir di hasil negatif yang jujur berlaku secara langsung.
DCC Asimetris (aDCC)
Sama seperti efek leverage univariat (Bagian 2) berarti kabar buruk menaikkan volatilitas lebih besar ketimbang kabar baik, korelasi naik lebih besar setelah guncangan negatif bersama ketimbang setelah guncangan positif bersama. Cappiello, Engle & Sheppard (2006) menangkap ini dengan DCC asimetris, menambahkan sebuah suku yang digerakkan oleh outer product dari residual yang distandarisasi bagian-negatif :
di mana dan mengukur tendangan korelasi ekstra dari pergerakan turun (downside) bersama. Untuk kripto, di mana korelasi-kehancuran (crash-correlation) adalah risiko dominan, suku asimetri biasanya signifikan dan sepadan dengan satu parameter tambahan itu. rmgarch mencocokkan aDCC di luar kotak (model="aDCC"); menambahkan suku ke estimator NumPy kita adalah sebuah latihan yang lugas.
Perbandingan: DCC Melawan Alternatif-Alternatifnya
Di mana posisi DCC di antara cara-cara Anda mungkin memperoleh sebuah matriks kovariansi untuk sebuah book kripto? Ringkasan jujurnya:
| Pendekatan | Parameter | Berskala hingga | berubah seiring waktu? | PD terjamin? | Ketergantungan ekor? |
|---|---|---|---|---|---|
| Kovariansi sampel / bergulir | 0 (panjang jendela) | berapa pun | secara kasar (lag, berisik) | tidak (perlu ditambal) | tidak |
| EWMA (RiskMetrics) | 1 () | berapa pun | ya (peluruhan tunggal) | ya | tidak |
| CCC-GARCH | margin + | lusinan | tidak ( konstan) | ya | tidak |
| DCC-GARCH | margin + 2 | lusinan | ya | ya | tidak |
| aDCC-GARCH | margin + 3 | lusinan | ya, asimetris | ya | parsial |
| BEKK | ya (kaya) | ya | tidak | ||
| VECH | ya (paling kaya) | menyakitkan | tidak | ||
| GARCH-copula | margin + copula | lusinan (vines) | copula statis | ya | ya |
Beberapa pembacaan atas tabel ini:
- EWMA adalah baseline murah yang seharusnya dikalahkan setiap orang sebelum mengklaim DCC membantu. Ia adalah kasus khusus satu-parameter dalam semangatnya — sebuah peluruhan eksponensial tunggal yang diterapkan langsung pada kovariansi — dan untuk banyak book ia mengejutkan sulit untuk diperbaiki di luar-sampel. Jika DCC tidak mengalahkan EWMA dalam walk-forward yang bersih, gunakan EWMA.
- CCC vs DCC adalah inti keseluruhan artikel ini: faktorisasi yang sama, tetapi CCC membekukan dan DCC membiarkannya bergerak. Kedua parameter tambahan () adalah keseluruhan perbedaannya, dan dalam kripto keduanya sepadan dengan bayarannya.
- BEKK/VECH membeli dinamika yang lebih kaya — setiap kovariansi dapat merespons setiap guncangan masa lalu — tetapi biaya parameternya membatasinya pada book yang mungil. Untuk apa pun melewati 4 aset keduanya bukan opsi nyata.
- GARCH-copula adalah satu-satunya baris dengan "ya" di bawah ketergantungan ekor. Itulah kembali sifat saling melengkapinya: DCC memodelkan pusat dinamis dari distribusi bersama, copula memodelkan ekor statisnya. Jika pertanyaan risiko Anda adalah "apa yang terjadi ketika segalanya hancur sekaligus," raihlah pipeline copula; jika ia adalah "berapa hedge ratio / variansi portofolio saya sekarang," raihlah DCC.
Default praktis untuk sebuah meja kripto sistematis: DCC (atau aDCC) untuk hedge ratio dan kovariansi dinamis di badan, sebuah overlay copula untuk risiko-ekor dan CVaR, dan EWMA sebagai baseline pemeriksa-kewarasan yang menjaga Anda tetap jujur mengenai apakah mesin tambahan itu membayar dirinya sendiri.
Batasan
- Dinamika skalar. Satu dan satu untuk semua pasangan adalah pembatasan yang kuat. BTC-ETH dan dua altcoin yang tak dikenal berbagi kecepatan penyesuaian yang sama. Generalized DCC melonggarkan ini tetapi memperkenalkan kembali ledakan parameter yang justru dirancang untuk dihindari oleh DCC.
- Kehilangan efisiensi dua-langkah. Estimator quasi-likelihood bersifat konsisten tetapi tidak sepenuhnya efisien, dan galat baku yang naif keliru. Gunakan koreksi Engle-Sheppard jika Anda peduli mengenai inferensi; untuk pembangkitan sinyal, estimasi titik sudah cukup.
- Ekor Gaussian secara default. Quasi-likelihood Gaussian polos meremehkan risiko ekor bersama. Inovasi Student-t membantu; untuk ketergantungan ekor yang sesungguhnya (probabilitas pergerakan ekstrem yang simultan), DCC adalah alat yang keliru dan sebuah model copula adalah yang benar. DCC memberi Anda badan dinamis dari korelasi; copula memberi Anda ekor statis. Meja yang serius menggunakan keduanya.
- Korelasi bukanlah kausasi, dan bukan arah. yang naik memperingatkan bahwa diversifikasi sedang gagal; ia tidak mengatakan apa pun mengenai arah pasar. Jangan membebani sebuah sinyal risiko dengan ekspektasi direksional.
- Kelaparan data. Segala hal di atas mengasumsikan sejarah yang panjang, bersih, dan tersinkronisasi. Token kripto yang paling baru dan paling menarik melanggar ketiganya.
Ringkasan
- Korelasi statis adalah kebohongan di kripto. Korelasi mengelompok, persisten, dan melonjak ke arah 1 dalam drawdown — persis ketika diversifikasi seharusnya membantu. Sebuah korelasi sampel tunggal merata-ratakan sebuah proses yang berpindah rezim menjadi sebuah nilai tengah yang tak bermakna.
- GARCH multivariat penuh (VECH, BEKK) tidak berskala. Jumlah parameter tumbuh sebagai ; keduanya dalam praktik terbatas pada segelintir aset.
- DCC (Engle 2002) memfaktorkan masalah: , dengan dari pencocokan GARCH univariat independen (gunakan kembali Bagian 1-2) dan dari sebuah rekursi dua-parameter. Ia berskala hingga lusinan aset karena hanya yang dioptimasi.
- Rekursi , dinormalisasi menjadi , menghasilkan sebuah matriks korelasi positive-definite yang valid pada setiap langkah, dengan , .
archtidak melakukan DCC. Cocokkan margin denganarch, lalu implementasikan estimator NumPy/SciPy ~60 baris di sini, atau gunakanmgarch(Python) ataurmgarch(R, rujukan).- Tiga hasil konkret: sebuah hedge ratio dinamis untuk pairs trading; sebuah variansi portofolio yang jujur dan berubah seiring waktu untuk alokasi berbasis risiko; dan korelasi berpasangan rata-rata sebagai sebuah sinyal rezim risk-off.
- Disiplin adalah segalanya. Correlation targeting membocorkan rata-rata seluruh-sampel, jadi estimasi ulang hanya pada data pelatihan; beri lag pada setiap hedge ratio; filter ke depan, jangan pernah menghaluskan. Evaluasi walk-forward tidak dapat ditawar.
- aDCC menambahkan sebuah suku asimetri downside dan biasanya sepadan di kripto, di mana korelasi-kehancuran mendominasi.
- Bagian 4 menggunakan prakiraan-prakiraan ini untuk membangun dan melakukan backtest atas sebuah strategi yang menargetkan volatilitas.
Referensi:
- Engle, R. (2002). Dynamic Conditional Correlation: A Simple Class of Multivariate Generalized Autoregressive Conditional Heteroskedasticity Models. Journal of Business & Economic Statistics, 20(3), 339-350. DOI
- Engle, R. & Sheppard, K. (2001). Theoretical and Empirical Properties of Dynamic Conditional Correlation Multivariate GARCH. NBER Working Paper 8554. DOI
- Bollerslev, T. (1990). Modelling the Coherence in Short-Run Nominal Exchange Rates: A Multivariate Generalized ARCH Model. Review of Economics and Statistics, 72(3), 498-505. DOI
- Cappiello, L., Engle, R., & Sheppard, K. (2006). Asymmetric Dynamics in the Correlations of Global Equity and Bond Returns. Journal of Financial Econometrics, 4(4), 537-572. DOI
- Engle, R. & Kroner, K. (1995). Multivariate Simultaneous Generalized ARCH. Econometric Theory, 11(1), 122-150. DOI
- Bollerslev, T., Engle, R., & Wooldridge, J. (1988). A Capital Asset Pricing Model with Time-Varying Covariances. Journal of Political Economy, 96(1), 116-131. DOI
- Galanos, A. (2022). rmgarch: Multivariate GARCH Models. R package. CRAN.
MarketMaker.cc Team
Riset & Strategi Kuantitatif