← Terug naar artikelen
July 12, 2026
5 min leestijd

DCC-GARCH: Dynamische correlaties voor pairs en portefeuillerisico

#volatility
#GARCH
#DCC
#correlation
#portfolio
#pairs-trading
#crypto

Vraag de meeste crypto-desks naar de correlatie tussen BTC en ETH en je krijgt een enkel getal — 0,8, misschien 0,75 — berekend over een venster waarvan niemand zich herinnert het gekozen te hebben. Dat getal is een leugen, of op zijn minst een gevaarlijke versimpeling. Steekproefcorrelatie is een gemiddelde over een periode waarin de werkelijke afhankelijkheidsstructuur voortdurend in beweging was. In rustige markten drijven BTC en ETH ver genoeg uit elkaar om een marktneutraal paar aantrekkelijk te laten lijken. In een liquidatiecascade koppelen ze aan elkaar en aan al het andere, en de diversificatie waarvoor je betaalde verdampt op precies het moment dat je haar nodig hebt.

Dit is geen subtiel effect. Neem eender welke drawdown uit 2022 — de LUNA-ineenstorting in mei, de 3AC-ontrafeling in juni, de FTX-implosie in november — en je ziet de gemiddelde paarsgewijze correlatie over de top-20 tokens binnen enkele dagen oplopen van de range 0,4-0,6 richting 0,9+. Correlatie is geen constante die af en toe slecht wordt geschat; het is een tijdreeks met haar eigen dynamiek, haar eigen clustering en haar eigen regimes. Haar als een scalair behandelen is het multivariate equivalent van uitgaan van constante volatiliteit — een fout die we in Deel 1 van deze serie al voor een enkel activum hebben ontkracht.

Dit artikel is Deel 3 van een vierdelige volatiliteitsserie. Deel 1 bouwde univariate GARCH(1,1) met de arch-bibliotheek en liet zien hoe volatiliteit clustert en terugkeert naar het gemiddelde. Deel 2 voegde asymmetrie (GJR-GARCH, EGARCH) en Student-t-innovaties toe om het leverage-effect en de dikke staarten te vangen. Hier gaan we multivariaat: we modelleren de volledige conditionele covariantiematrix HtH_t terwijl deze evolueert, met behulp van Engle's Dynamic Conditional Correlation (DCC) model. Dat geeft ons twee dingen die een scalaire correlatie nooit kan — een dynamische hedgeratio voor pairs trading, en een eerlijke, tijdsvariërende portefeuillevariantie voor risicogebaseerde allocatie. Deel 4 sluit de serie af met een op volatiliteit gerichte backtest die de univariate en multivariate voorspellingen samenbindt tot een positiegroottebepaling.

We gaan ervan uit dat je Deel 1 en 2 hebt gelezen, dus we leiden univariate GARCH niet opnieuw af. Als je het gezamenlijke staartgedrag wilt — de kans dat twee activa samen hun 1%-kwantiel doorbreken — dan is dat een copula-vraag, en die behandelen we in Copula-modellen voor gezamenlijk risico. DCC en copula's zijn complementair: de copula geeft je een statische-maar-flexibele staartafhankelijkheidsstructuur, terwijl DCC je een hanteerbare tijdreeks van de volledige correlatiematrix geeft. Dit artikel gaat over die laatste.

Waarom statische correlatie faalt in crypto

Voor de machinerie, wees precies over wat er faalt. Een enkele steekproefcorrelatie ρ^\hat{\rho} over een venster [tw,t][t-w, t] schat

ρ^ij=s(ri,srˉi)(rj,srˉj)s(ri,srˉi)2s(rj,srˉj)2\hat{\rho}_{ij} = \frac{\sum_{s} (r_{i,s} - \bar{r}_i)(r_{j,s} - \bar{r}_j)}{\sqrt{\sum_s (r_{i,s}-\bar{r}_i)^2}\sqrt{\sum_s (r_{j,s}-\bar{r}_j)^2}}

Dit draagt drie impliciete aannames, allemaal onwaar voor crypto:

  1. Stationariteit van afhankelijkheid. Het venster heeft één ware ρ\rho. In werkelijkheid heeft afhankelijkheid regimes — een rustig-marktregime rond 0,5 en een stressregime rond 0,95 — en ρ^\hat{\rho} mengt ze tot een betekenisloos midden.
  2. Constante marginale volatiliteit. Pearson-correlatie is een genormaliseerde covariantie. Als σi,t\sigma_{i,t} en σj,t\sigma_{j,t} zelf bewegen (dat doen ze — dat is de hele premisse van Deel 1 en 2), dan produceert zelfs een constante covariantie een tijdsvariërende correlatie, en vice versa. Je kunt de twee niet scheiden zonder een volatiliteitsmodel eronder.
  3. Symmetrie over marktrichting. Correlatie stijgt in drawdowns meer dan in rally's. Dit is de multivariate neef van het leverage-effect. Een voortschrijdend venster kan dit niet uitdrukken zonder zo kort te worden dat het pure ruis is.

De voortschrijdend-vensteroplossing — herbereken ρ^\hat{\rho} over de laatste 30 of 60 dagen — ruilt het ene probleem voor het andere. Korte vensters zijn responsief maar rumoerig en lopen achter op de werkelijke breuk; lange vensters zijn stabiel maar verouderd. Erger nog, een voortschrijdende correlatiematrix over dd activa blijft niet gegarandeerd positief semidefiniet zodra je begint met krimpen of oplappen, wat elke stroomafwaartse optimizer breekt. We willen een model dat (a) wordt aangedreven door een deugdelijk volatiliteitsproces per activum, (b) per constructie bij elke stap een geldige correlatiematrix produceert, en (c) parameters heeft die we via maximum likelihood kunnen schatten in plaats van door een vensterlengte uit de hoge hoed te toveren. Dat model is DCC-GARCH.

Het multivariate probleem: de conditionele covariantiematrix

Laat rtRdr_t \in \mathbb{R}^d de vector van rendementen zijn voor dd activa op tijdstip tt, met conditioneel gemiddelde μt\mu_t (vaak gewoon een constante of een kleine AR-term) en residu ϵt=rtμt\epsilon_t = r_t - \mu_t. We nemen aan

ϵtFt1D(0,Ht)\epsilon_t \mid \mathcal{F}_{t-1} \sim \mathcal{D}(0, H_t)

waarbij HtH_t de d×dd \times d conditionele covariantiematrix is gegeven de informatieset Ft1\mathcal{F}_{t-1}, en D\mathcal{D} een conditionele verdeling is (Gaussisch of, beter voor crypto, multivariaat Student-t). Alles in multivariate volatiliteitsmodellering is een ander antwoord op één vraag: hoe parametriseer je de dynamiek van HtH_t zodat deze bij elke stap symmetrisch positief definiet blijft zonder een explosie van parameters?

Twee klassieke antwoorden laten zien waarom het probleem lastig is.

VECH

Het VECH-model (Bollerslev, Engle, Wooldridge 1988) schrijft de half-vectorisatie van HtH_t als een lineaire functie van voorbije gekwadrateerde residuen en voorbije covarianties:

vech(Ht)=c+Avech(ϵt1ϵt1)+Bvech(Ht1)\mathrm{vech}(H_t) = c + A\,\mathrm{vech}(\epsilon_{t-1}\epsilon_{t-1}') + B\,\mathrm{vech}(H_{t-1})

waarbij vech()\mathrm{vech}(\cdot) de onderste driehoek van een symmetrische matrix stapelt in een vector van lengte d(d+1)/2d(d+1)/2. Dit is maximaal algemeen — elke variantie en covariantie hangt af van elke voorbije variantie en covariantie — en maximaal nutteloos voorbij d=3d=3. Voor dd activa zijn AA en BB elk d(d+1)2×d(d+1)2\frac{d(d+1)}{2} \times \frac{d(d+1)}{2}. Bij d=5d=5 zijn dat twee 15×1515\times 15 matrices, ruwweg 450 parameters, plus positief-definietheidsbeperkingen die pijnlijk zijn om zelfs maar uit te drukken. Het likelihood-oppervlak is een moeras.

BEKK

Het BEKK-model (Engle & Kroner 1995) garandeert positieve definietheid per constructie met behulp van een kwadratische vorm:

Ht=CC+Aϵt1ϵt1A+BHt1BH_t = C'C + A'\,\epsilon_{t-1}\epsilon_{t-1}'\,A + B'\,H_{t-1}\,B

met CC bovendriehoekig. Omdat elke term een kwadratische vorm is, geldt Ht0H_t \succ 0 automatisch zolang CC0C'C \succ 0. BEKK is spaarzamer dan VECH maar schaalt nog steeds als O(d2)O(d^2) parameters — de AA- en BB-matrices zijn elk d×dd \times d. Voor d=10d=10 schat je in de orde van 200+ parameters gezamenlijk via MLE, op rumoerige dagelijkse cryptodata, zonder garantie dat de optimizer naar iets zinvols convergeert. In de praktijk blijft volledig BEKK beperkt tot d4d \le 4, en zelfs dan gebruiken mensen de "diagonale" of "scalaire" beperkingen die het merendeel van de kruisdynamiek weggooien.

Dit is de vloek van de dimensionaliteit voor multivariate GARCH: het aantal parameters groeit kwadratisch, maar de hoeveelheid informatie in de data niet. Je bent je vrijheidsgraden kwijt lang voordat je zonder activa zit waar je om geeft. Elk cryptoboek met 10-30 tokens is volledig buiten bereik voor VECH of BEKK.

De uitweg, te danken aan Engle, is om te stoppen met proberen HtH_t direct te modelleren en het in plaats daarvan te factoriseren in stukken die we al goedkoop weten te schatten.

Engle's DCC (2002): de tweestapsdecompositie

Bollerslev's Constant Conditional Correlation (CCC) model (1990) was de eerste spaarzame factorisatie. Het schrijft

Ht=DtRDtH_t = D_t\, R\, D_t

waarbij Dt=diag(σ1,t,,σd,t)D_t = \mathrm{diag}(\sigma_{1,t}, \ldots, \sigma_{d,t}) de diagonaalmatrix van conditionele standaarddeviaties is — één univariate GARCH per activum — en RR een constante correlatiematrix is. Dit is een enorme versimpeling: je fit dd onafhankelijke univariate GARCH-modellen en schat vervolgens een enkele steekproefcorrelatiematrix van de gestandaardiseerde residuen. Positieve definietheid is automatisch zolang RR een geldige correlatiematrix is en alle σi,t>0\sigma_{i,t} > 0.

Het probleem van CCC zit precies in de naam — de correlatie is constant, wat exact de aanname is waarmee we dit artikel openden om haar te verwerpen. Engle's Dynamic Conditional Correlation (2002) behoudt CCC's prachtige factorisatie maar laat de correlatiematrix ademen:

Ht=DtRtDtH_t = D_t\, R_t\, D_t

Nu is RtR_t tijdsvariërend. De genialiteit is dat de volatiliteiten en de correlaties in twee afzonderlijke stappen worden geschat, zodat we nooit met de volledige O(d2)O(d^2) gezamenlijke optimalisatie worden geconfronteerd.

Stap 1: Univariate GARCH per activum

Fit voor elk activum ii een univariate GARCH-model precies zoals in Deel 1 en 2 — GARCH(1,1), GJR-GARCH of EGARCH met Student-t-innovaties, wat het beste bij die reeks paste. Dit geeft conditionele varianties σi,t2\sigma_{i,t}^2 en dus Dt=diag(σ1,t,,σd,t)D_t = \mathrm{diag}(\sigma_{1,t}, \ldots, \sigma_{d,t}).

Uit de gefitte modellen halen we de gestandaardiseerde residuen:

zi,t=ϵi,tσi,tz_{i,t} = \frac{\epsilon_{i,t}}{\sigma_{i,t}}

Per constructie heeft elke zi,tz_{i,t} (bij benadering) eenheidsconditionele variantie. Stapel ze in een vector zt=(z1,t,,zd,t)z_t = (z_{1,t}, \ldots, z_{d,t})'. Deze gestandaardiseerde residuen zijn het ruwe materiaal voor de correlatiestap — hun individuele volatiliteitsdynamiek is eruit gestript, dus wat er aan comovement overblijft is pure afhankelijkheid, geen volatiliteitsartefact. (Dit is dezelfde PIT-achtige logica die het copula-artikel gebruikt voordat de marges worden gefit; hier stoppen we bij standaardisatie in plaats van helemaal door te gaan naar uniformen.)

Stap 2: De DCC-correlatierecursie

We modelleren een hulpproces QtQ_t, een d×dd \times d symmetrische positief-definiete matrix, met een GARCH-achtige recursie aangedreven door de uitproducten van gestandaardiseerde residuen:

Qt=(1ab)Qˉ+azt1zt1+bQt1Q_t = (1 - a - b)\,\bar{Q} + a\, z_{t-1} z_{t-1}' + b\, Q_{t-1}

waarbij:

  • Qˉ=1Tt=1Tztzt\bar{Q} = \frac{1}{T}\sum_{t=1}^{T} z_t z_t' de onconditionele correlatiematrix van de gestandaardiseerde residuen is (dit is correlation targeting — meer hierover hieronder),
  • a0a \ge 0 bepaalt hoe sterk de schok van vandaag zt1zt1z_{t-1}z_{t-1}' de correlatie trekt,
  • b0b \ge 0 bepaalt persistentie — hoeveel van de Qt1Q_{t-1} van gisteren wordt meegedragen,
  • en de mean-reversion-beperking is a+b<1a + b < 1 (met a,b>0a, b > 0), direct analoog aan α+β<1\alpha + \beta < 1 in univariate GARCH.

Merk op dat de structuur identiek is aan een scalaire GARCH(1,1)-recursie, maar op matrices: een langetermijnanker Qˉ\bar{Q}, een schokterm en een persistentieterm. Omdat het een convexe combinatie is van positief-semidefiniete matrices (Qˉ\bar{Q}, het rang-1 uitproduct en het vorige Qt1Q_{t-1}), blijft QtQ_t positief definiet zolang Qˉ0\bar{Q} \succ 0 en de gewichten niet-negatief zijn. Dit is wat ons gratis gegarandeerd geldige covariantiematrices oplevert.

QtQ_t is bijna een correlatiematrix maar niet helemaal — zijn diagonaal is niet exact 1. Dus normaliseren we het:

Rt=(diag(Qt))1/2Qt(diag(Qt))1/2R_t = \left(\mathrm{diag}(Q_t)\right)^{-1/2}\, Q_t\, \left(\mathrm{diag}(Q_t)\right)^{-1/2}

Elementsgewijs is de conditionele correlatie tussen activa ii en jj

ρij,t=qij,tqii,tqjj,t\rho_{ij,t} = \frac{q_{ij,t}}{\sqrt{q_{ii,t}\, q_{jj,t}}}

Deze RtR_t is een deugdelijke correlatiematrix — eenheidsdiagonaal, off-diagonalen in [1,1][-1,1], positief definiet — bij elke afzonderlijke tijdstap, per constructie. Stel de volledige conditionele covariantie weer samen:

Ht=DtRtDt,hij,t=ρij,tσi,tσj,tH_t = D_t\, R_t\, D_t, \qquad h_{ij,t} = \rho_{ij,t}\,\sigma_{i,t}\,\sigma_{j,t}

Die laatste elementsgewijze vorm is degene die je voortdurend zult gebruiken: de conditionele covariantie van twee activa is hun dynamische correlatie maal elk van hun dynamische volatiliteiten. Elk ingrediënt aan de rechterkant is tijdsvariërend en komt uit een model dat je kunt schatten.

Het hele model heeft slechts twee correlatieparameters, aa en bb, ongeacht of d=2d = 2 of d=50d = 50. De volatiliteitszijde schaalt lineair (één univariate GARCH per activum, elk met ~4-5 parameters, allemaal onafhankelijk gefit en gênant parallel). Dit is waarom DCC schaalt waar BEKK en VECH dat niet kunnen: de dimensionaliteitsvloek is beperkt tot Qˉ\bar{Q}, die getarget wordt (ingeplugd als een steekproefschatting) in plaats van geoptimaliseerd.

De scalaire beperking en haar kosten

De scalairen a,ba, b betekenen dat elk paar activa dezelfde correlatiedynamiek deelt — dezelfde aanpassingssnelheid en dezelfde persistentie. De BTC-ETH-correlatie en de DOGE-SHIB-correlatie bewegen op hetzelfde ritme, ook al verschilt hun economie. Dit is de prijs van hanteerbaarheid, en het is meestal een aanvaardbare prijs. Generalisaties (Generalized DCC met matrix A,BA, B; de Cappiello-Engle-Sheppard asymmetrische DCC) versoepelen dit ten koste van parameters en schattingsstabiliteit. We noemen aDCC hieronder.

De DCC quasi-log-likelihood

Om aa en bb te schatten hebben we de likelihood nodig. Engle's belangrijkste resultaat is dat de Gaussische log-likelihood scheidt in een volatiliteitsdeel en een correlatiedeel, en dat is wat de tweestapsschatter rechtvaardigt. Uitgaande van ϵtFt1N(0,Ht)\epsilon_t \mid \mathcal{F}_{t-1} \sim \mathcal{N}(0, H_t) is de log-likelihood-bijdrage op tijdstip tt

t=12(dlog(2π)+logHt+ϵtHt1ϵt)\ell_t = -\frac{1}{2}\left( d\log(2\pi) + \log|H_t| + \epsilon_t' H_t^{-1} \epsilon_t \right)

Substitueer Ht=DtRtDtH_t = D_t R_t D_t. Dan geldt Ht=Dt2Rt|H_t| = |D_t|^2 |R_t| en Ht1=Dt1Rt1Dt1H_t^{-1} = D_t^{-1} R_t^{-1} D_t^{-1}, en met zt=Dt1ϵtz_t = D_t^{-1}\epsilon_t:

t=12(dlog(2π)+2logDt+logRt+ztRt1zt)\ell_t = -\frac{1}{2}\left( d\log(2\pi) + 2\log|D_t| + \log|R_t| + z_t' R_t^{-1} z_t \right)

Splits het nu op door ztztz_t'z_t toe te voegen en af te trekken:

t=12(dlog(2π)+2logDt+ϵtDt2ϵt)volatiliteitsdeel   tV  12(logRt+ztRt1ztztzt)correlatiedeel   tC\ell_t = \underbrace{-\frac{1}{2}\left( d\log(2\pi) + 2\log|D_t| + \epsilon_t' D_t^{-2}\epsilon_t \right)}_{\text{volatiliteitsdeel }\;\ell_t^{V}} \;\underbrace{-\frac{1}{2}\left( \log|R_t| + z_t' R_t^{-1} z_t - z_t' z_t \right)}_{\text{correlatiedeel }\;\ell_t^{C}}

Het volatiliteitsdeel tV\ell_t^V hangt alleen af van de univariate GARCH-parameters (via DtD_t) — het maximaliseren ervan is exact het fitten van dd onafhankelijke univariate GARCH-modellen, wat we in Stap 1 deden. Het correlatiedeel tC\ell_t^C hangt af van aa en bb (via RtR_t), gegeven de gestandaardiseerde residuen uit Stap 1. Dus in Stap 2 maximaliseren we alleen

LC(a,b)=12t=1T(logRt+ztRt1zt)\mathcal{L}^C(a, b) = -\frac{1}{2}\sum_{t=1}^{T}\left( \log|R_t| + z_t' R_t^{-1} z_t \right)

(de term ztztz_t'z_t hangt niet af van a,ba, b, dus die laten we vallen). Dit is een tweeparameter-optimalisatie ongeacht hoeveel activa — dat is het hele punt. Het wordt een quasi-likelihood genoemd omdat de tweestapsschatter consistent maar niet volledig efficiënt is; de standaardfouten hebben een correctie nodig (Engle & Sheppard 2001), maar voor signaalgeneratie zijn de puntschattingen wat telt.

Voor crypto onderschatten Gaussische innovaties het staartrisico. Het inwisselen van de multivariate Student-t-likelihood is een drop-in wijziging aan t\ell_t (vervang de Gaussische kernel door de multivariaat-tt-dichtheid en voeg een vrijheidsgradenparameter ν\nu toe). We houden de Gaussische quasi-likelihood in de schatter hieronder voor de duidelijkheid en geven aan waar ν\nu binnenkomt — de standaardisatie uit Deel 1-2 gebruikte al t-innovaties op de marges, wat het merendeel van het staartvoordeel vangt.

Python-implementatie

Een botte maar belangrijke feit: de arch-bibliotheek doet geen multivariate GARCH of DCC. arch is een superieure univariate engine (we leunen er precies daarvoor op), maar er zit geen dcc_model in. Je praktische opties zijn:

  1. Bouw je eigen DCC bovenop arch — fit univariate modellen met arch, extraheer gestandaardiseerde residuen, implementeer de QQ-recursie en de correlatie-quasi-likelihood in NumPy/SciPy, en optimaliseer de twee scalairen. Dit is wat we hieronder doen. Het is ongeveer 60 regels en volledig transparant.
  2. Het mgarch PyPI-pakket — een lichtgewicht pure-Python DCC-GARCH-implementatie. Handig voor een snelle fit, minder flexibel als je GJR-marges of t-innovaties precies bedraad wilt hebben.
  3. R's rmgarch (Alexios Galanos) — de referentie-implementatie. dccspec / dccfit ondersteunen DCC, aDCC, GARCH-copula, Student-t en deugdelijke standaardfouten. Als je serieus multivariaat volatiliteitsonderzoek doet, is rmgarch (indien nodig aangeroepen vanuit Python via rpy2) de gouden standaard.

We bouwen optie 1 omdat die elk bewegend onderdeel expliciet maakt en de univariate vaardigheden uit Deel 1-2 hergebruikt.

Stap 1: Fit univariate GARCH-marges met 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())

Een snelle sanity check op de gestandaardiseerde residuen is van belang. Als een kolom een standaarddeviatie ver van 1 heeft, of zware resterende autocorrelatie in zijn kwadraat (Ljung-Box op zi,t2z_{i,t}^2), dan is de univariate marge verkeerd gespecificeerd en zal de DCC-stap die fout overerven. Fix eerst de marge — daar was Deel 2 voor.

Stap 2: De DCC-recursie en 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)

Dit uitvoeren op een BTC/ETH/SOL/BNB-boek over een paar jaar dagelijkse data produceert output in de volgende vorm (onderstaande getallen zijn illustratief, niet uit een specifiek gedateerd experiment — draai het op je eigen data):

DCC estimates: a = 0.0287, b = 0.9401, a+b = 0.9688
log-likelihood: -3812.44

Hoe je het leest:

  • a=0.029a = 0.029 is klein — de correlatiematrix schokt niet op de schok van een enkele dag. Elke dag duwt RtR_t slechts ~3% richting het uitproduct zt1zt1z_{t-1}z_{t-1}'.
  • b=0.940b = 0.940 is groot — correlaties zijn zeer persistent. Zodra het boek in een stressgebeurtenis aan elkaar koppelt, blijft het een tijdje gekoppeld en keert langzaam terug richting Qˉ\bar{Q}. Dit komt overeen met de doorleefde ervaring van cryptodrawdowns: correlaties springen niet terug op het moment dat de prijs stabiliseert.
  • a+b=0.969<1a + b = 0.969 < 1 bevestigt mean reversion. Het correlatieproces heeft een stationair langetermijnniveau (Qˉ\bar{Q}) waar het naar terugkeert, met een halfwaardetijd van ruwweg log(0.5)/log(a+b)22\log(0.5)/\log(a+b) \approx 22 dagen. Als je ooit a+ba + b in wezen gelijk aan 1 schat, is het correlatieproces geïntegreerd — het heeft geen langetermijnanker, meestal een symptoom van een structurele breuk binnen je steekproef die het model absorbeert als oneindige persistentie.

De bijna-eenheidspersistentie en de kleine schokbelasting is de canonieke DCC-vingerafdruk over activaklassen heen, en crypto is geen uitzondering. Het is ook waarom een 30-daagse voortschrijdende correlatie zo'n slechte vervanging is: een voortschrijdend venster gaat impliciet uit van een aa en bb die helemaal niet overeenkomen met deze vervalstructuur.

Een paar implementatienotities die echte debugtijd besparen:

  • Initialisatie. Beginnen bij [0.03, 0.94] weerspiegelt de typische cryptoschatting: kleine aa (correlaties reageren op schokken maar niet heftig), grote bb (correlaties zijn persistent). Als je optimizer afdwaalt naar a+b1a+b \to 1 is het correlatieproces geïntegreerd — meestal een teken van een structurele breuk in de steekproef (een regimeverandering die het model met moeite als persistentie probeert te fitten).
  • Timingconventie. Binnen de lus scoren we RtR_t tegen ztz_t en werken daarna QQ bij met ztztz_t z_t' voor de volgende stap. Dit houdt RtR_t een functie van informatie tot en met t1t-1 alleen — geen look-ahead. Deze off-by-one verkeerd krijgen is de allergrootste veelvoorkomende DCC-bug, en het inflateert de in-sample fit stilletjes.
  • Correlation targeting. We pluggen Qˉ\bar{Q} in als de steekproefcorrelatie in plaats van het te schatten. Dit is wat de optimalisatie tweedimensionaal maakt. De kost is dat Qˉ\bar{Q} de volledige steekproef gebruikt, dus in een strikte walk-forward moet je het opnieuw schatten op alleen het trainingsvenster (zie hieronder).

Stap 3: Reconstrueer de correlatie- en covariantiepaden

Zodra a,ba, b vastliggen, draai de recursie nog een keer, dit keer met opslag van het volledige RtR_t- (en HtH_t-) pad zodat stroomafwaartse strategieën het kunnen gebruiken.

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))

De rho_btc_eth-reeks is de opbrengst van de hele oefening: in plaats van één getal heb je nu een dagelijkse correlatie die je kunt plotten, drempelen of in een strategie voeren. Op echte cryptodata zul je haar doorgaans zien variëren van ruwweg 0,5 in rustige stukken tot boven 0,9 tijdens stress — precies de spreiding die een enkele steekproefcorrelatie wegmiddelt.

One-step-ahead-voorspelling

Voor live trading heb je de volgende-periode Ht+1H_{t+1} nodig uit informatie die nu beschikbaar is. De volatiliteitszijde komt uit de one-step-voorspelling van elk arch-model; de correlatiezijde is nog één draai van de recursie:

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)

Onthoud dat alles in geschaalde (×100) eenheden is omdat we arch fitten op series * 100. Deel volatiliteiten door 100 (en covarianties door 1002=10,000100^2 = 10{,}000) om terug te keren naar ruwe-rendementseenheden voordat je een strategie voedt. De schaling recht houden is vervelend maar een frequente bron van stille bugs.

Toepassing 1: Een dynamische hedgeratio voor pairs trading

Het klassieke marktneutrale paar — long het ene activum, short een beta-gewogen hoeveelheid van een ander — leeft of sterft op de hedgeratio β\beta. Schat het via statische OLS over een trainingsvenster en je erft precies het verouderde-correlatieprobleem waar dit hele artikel over gaat: de hedge die vorig kwartaal de marktblootstelling neutraliseerde, is dit kwartaal verkeerd.

DCC geeft je de hedgeratio als een tijdreeks. De minimum-variantie-hedge van ETH-blootstelling met behulp van BTC is de conditionele regressiecoëfficiënt

βt=Covt(rETH,rBTC)Vart(rBTC)=hETH,BTC,tσBTC,t2=ρETH,BTC,tσETH,tσBTC,t\beta_t = \frac{\mathrm{Cov}_t(r_{\text{ETH}}, r_{\text{BTC}})}{\mathrm{Var}_t(r_{\text{BTC}})} = \frac{h_{\text{ETH,BTC},t}}{\sigma_{\text{BTC},t}^2} = \rho_{\text{ETH,BTC},t}\,\frac{\sigma_{\text{ETH},t}}{\sigma_{\text{BTC},t}}

Elke term aan de rechterkant is een DCC-output. De hedgeratio beweegt om twee verschillende redenen, en DCC scheidt ze netjes: de correlatie ρt\rho_t verandert (de activa koppelen of ontkoppelen), en de volatiliteitsverhouding σETH,t/σBTC,t\sigma_{\text{ETH},t}/\sigma_{\text{BTC},t} verandert (het ene activum wordt relatief volatieler). Een voortschrijdende-OLS-beta smeert beide effecten samen met een vertraging; DCC attribueert ze.

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()

Voed spread in welke pairs-engine je ook draait. De dynamische hedge creëert op zichzelf geen edge — het maakt de spread die je verhandelt door de tijd heen echt marktneutraal, zodat je mean-reversion-signaal niet wordt vervuild door driftende directionele blootstelling. Als je pairs-strategieën bouwt, past dit direct in de raamwerken in Statistical Arbitrage & Pairs Trading in Crypto en de distance approach to pairs, waarbij hun vaste hedgeratio wordt vervangen. De correlatiereeks zelf is ook een schonere input voor een op correlatie gebaseerd paarsignaal dan welk voortschrijdend venster ook — je krijgt een gladgestreken, modelconsistente ρt\rho_t in plaats van een rumoerige vensterschatting.

Twee waarschuwingen die specifiek zijn voor het live gebruiken van βt\beta_t. Ten eerste, vertraag het — verhandel op βt1\beta_{t-1}, nooit op de gelijktijdige βt\beta_t, anders gluur je vooruit. Ten tweede, een hedgeratio die elke dag heen en weer zwiept genereert omzet en kosten; in crypto's 24/7-markt met funding costs op het short-been kan een overreactieve hedge meer bloeden dan de drift die het corrigeert. Strijk βt\beta_t glad (een EWMA, of herbalanceer de hedge alleen wanneer deze voorbij een band beweegt) en dimensioneer het geheel verstandig — positiegroottebepaling op basis van een rumoerig signaal is een eigen discipline, behandeld in Kelly-criterium-sizing.

Toepassing 2: Tijdsvariërende portefeuillevariantie

Voor een portefeuille met gewichtsvector ww is de conditionele variantie

σp,t2=wHtw=ijwiwjρij,tσi,tσj,t\sigma_{p,t}^2 = w'\, H_t\, w = \sum_{i}\sum_{j} w_i w_j\, \rho_{ij,t}\,\sigma_{i,t}\,\sigma_{j,t}

Met een statische covariantiematrix — de Markowitz-standaard — is dit getal een constante die je eenmaal berekende en waarvan je doet alsof deze nog steeds waar is. Dat is niet zo. Portefeuillerisico ademt met de markt, en het ademt het hardst precies wanneer correlaties omhoogschieten, want in een drawdown stijgen zowel de σi,t\sigma_{i,t}-termen als de ρij,t\rho_{ij,t}-termen samen en vermenigvuldigen ze. Een portefeuille die er in rustige markten uitzag als 40% geannualiseerde vol kan in een stressweek op 80%+ draaien, en een statische covariantiematrix zal je vertellen dat er niets veranderd is.

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())

Deze tijdsvariërende σp,t\sigma_{p,t} is de eerlijke input die risicogebaseerde allocatie nodig heeft. Mean-variance-optimalisatie (Markowitz voor crypto) met een statische steekproefcovariantie optimaliseert tegen een verzinsel; het voeden met HtH_t (of zijn korte-horizonvoorspelling) maakt de efficiënte grens zelf tijdsvariërend en dwingt de optimizer om risico af te bouwen in stijgende-correlatieregimes in plaats van erna. Risk-parity- en hiërarchische benaderingen — de HRP + CVaR-pijplijn — zijn nog gevoeliger voor de covariantie-input, omdat de hele allocatie een functie is van de risicomatrix. En als je allocators onderling vergelijkt, zoals in portefeuille-optimalisatiealgoritmen vergeleken, is of ze statische of dynamische covariantie verbruiken vaak een grotere aanjager van het gerealiseerde risico dan de keuze van algoritme.

De directe toepassing is volatility targeting van de hele portefeuille: kies een doel-geannualiseerde vol σ\sigma^{*}, en schaal bruto blootstelling met σ/σp,t\sigma^{*} / \sigma_{p,t} elke periode zodat het gerealiseerde risico ongeveer constant blijft in plaats van op te blazen in crises. Dat sluit de lus met Deel 4, dat precies deze regel bouwt en backtest.

Toepassing 3: Correlatie als regimesignaal

Voorbij hedging en sizing draagt de correlatiematrix een macrosignaal. De enkele nuttigste scalair die je kunt extraheren is de gemiddelde paarsgewijze correlatie:

ρˉt=2d(d1)i<jρij,t\bar{\rho}_t = \frac{2}{d(d-1)}\sum_{i < j} \rho_{ij,t}

Wanneer ρˉt\bar{\rho}_t over het boek stijgt, betreedt de markt een risk-off-regime — idiosyncratische verhalen doen er niet meer toe en alles verhandelt als één macrobeta. Dit is de kwantitatieve vingerafdruk van "correlaties gaan naar 1 in een crisis." Het neigt drawdowns voor te lopen of ermee samen te vallen, wat het een bruikbare regime-indicator maakt in plaats van een achterlopende postmortem.

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)

Je kunt risk_off gebruiken als een op zichzelf staande throttle (verminder bruto blootstelling, verbreed stops, sta mean-reversion-strategieën stil die worden overreden wanneer alles samen trendt) of als een kenmerk in een formeler regimemodel. Het past van nature bij de hidden-Markov-benadering in regimedetectie met HMM's: gemiddelde DCC-correlatie is een van de meer informatieve observatievariabelen die je een HMM kunt aanreiken, omdat het vooruitkijkend is over systemische stress op een manier waarop achterlopende rendementen dat niet zijn. De eerlijke kanttekening: stijgende correlatie vertelt je dat diversificatie faalt, niet welke kant de markt op gaat. Het is een risicosignaal, geen alfasignaal, en moet als zodanig gedimensioneerd worden — zie de asymmetrie van verliezen en winsten voor waarom het behandelen van een risicoregime als een directionele weddenschap slecht afloopt.

Praktische overwegingen

Schattingsstabiliteit en aantal activa

DCC schaalt veel beter dan BEKK, maar "schaalt" is niet "gratis." De correlation-targeting-matrix Qˉ\bar{Q} is een d×dd \times d steekproefcorrelatie, en steekproefcorrelatiematrices worden slecht geconditioneerd naarmate dd het aantal observaties nadert. Met 4 activa en 1000 dagen zit je goed. Met 60 activa en 400 dagen is Qˉ\bar{Q} bijna singulier, explodeert zijn inverse in de likelihood, en kan RtR_t door numerieke ruis niet-PD afdwalen. Mitigaties, ruwweg in volgorde van hoe vaak je ze nodig hebt:

  • Krimp Qˉ\bar{Q} richting een gestructureerd doel (Ledoit-Wolf, of richting de identiteit / een constante-correlatiematrix) voordat je de recursie draait. Dit is de enkele fix met de meeste hefboomwerking voor grote boeken.
  • Groepeer activa in een handvol sectoren (majors, L1's, DeFi, memes), modelleer binnen en over op sectorniveau, of draai DCC op principale-componentfactoren in plaats van ruwe activa.
  • Verkies meer data boven meer activa. DCC heeft een onverzadigbare honger naar een lange, schone, gelijktijdige historie — precies wat jonge tokens niet hebben.

Realistisch gezien, houd directe DCC tot hooguit een paar dozijn activa. Voor een groot universum is DCC op factorrendementen plus idiosyncratische residuen de standaardomweg.

Correlation targeting is een shortcut met een kost

Het targeten van Qˉ\bar{Q} maakt de schatting hanteerbaar maar bakt de volledige-steekproef onconditionele correlatie in elke RtR_t. In een strikte backtest is dit een look-ahead-lek: je dag-tt-correlatiematrix "kent" de gemiddelde correlatie van de hele steekproef, inclusief de toekomst. Voor eerlijke evaluatie moet je Qˉ\bar{Q} opnieuw schatten op alleen het trainingsvenster en het out-of-sample vasthouden, of het naar voren rollen. Dit is dezelfde discipline die het hele walk-forward-optimalisatie-raamwerk afdwingt, en het is makkelijk om per ongeluk te overtreden met een handige np.cov(Z) over de volledige array — zoals onze onderwijscode hierboven doet. Fix het voordat je ook maar één P&L-getal vertrouwt.

Refit-cadans en look-ahead-discipline

Je hoeft a,ba, b niet elke dag opnieuw te optimaliseren — het zijn stabiele parameters. Een verstandige productiecadans:

  • Herschat a,ba, b en de univariate GARCH-parameters wekelijks of maandelijks.
  • Draai de filter (update QtQ_t, σi,t\sigma_{i,t}) elke periode met de bevroren parameters om verse RtR_t en HtH_t te krijgen. Filteren is goedkoop; fitten niet.
  • Voorspel altijd, strijk nooit glad. Gebruik RtR_t gebouwd uit informatie tot en met t1t-1 om op tt te verhandelen. De twee-pass-structuur (fit op een venster, filter dan vooruit) is wat je eerlijk houdt.

De kloof tussen een DCC-backtest en live prestaties is bijna altijd een look-ahead-lek — volledige-steekproef Qˉ\bar{Q}, gelijktijdige βt\beta_t, of herfitten op data die de trade bevat die je evalueert. De discipline van het matchen van backtest aan live condities is een eigen onderwerp in backtest-live-pariteit, en DCC is een model dat slordigheid hier meer bestraft dan de meeste. Als, na schone walk-forward-evaluatie, de dynamische correlatie niets toevoegt boven een simpele voortschrijdende schatting voor jouw strategie, dan is dat een echt en publiceerbaar negatief resultaat — de mindset in eerlijke negatieve resultaten is direct van toepassing.

Asymmetrische DCC (aDCC)

Net zoals het univariate leverage-effect (Deel 2) betekent dat slecht nieuws de volatiliteit meer verhoogt dan goed nieuws, stijgen correlaties meer na gezamenlijke negatieve schokken dan na gezamenlijke positieve. Cappiello, Engle & Sheppard (2006) vangen dit met asymmetrische DCC, waarbij een term wordt toegevoegd die wordt aangedreven door het uitproduct van de negatieve-deel gestandaardiseerde residuen zt=min(zt,0)z_t^- = \min(z_t, 0):

Qt=(QˉaQˉbQˉgNˉ)+azt1zt1+gzt1zt1+bQt1Q_t = (\bar{Q} - a\bar{Q} - b\bar{Q} - g\bar{N}) + a\, z_{t-1} z_{t-1}' + g\, z_{t-1}^- z_{t-1}^{-\prime} + b\, Q_{t-1}

waarbij Nˉ=1Ttztzt\bar{N} = \frac{1}{T}\sum_t z_t^- z_t^{-\prime} en g0g \ge 0 de extra correlatiekick meet van gezamenlijke neerwaartse bewegingen. Voor crypto, waar crash-correlatie het dominante risico is, is de asymmetrieterm meestal significant en de ene extra parameter waard. rmgarch fit aDCC out of the box (model="aDCC"); het toevoegen van de ztz_t^--term aan onze NumPy-schatter is een rechttoe rechtaan oefening.

Vergelijking: DCC tegen de alternatieven

Waar staat DCC te midden van de manieren waarop je een covariantiematrix voor een cryptoboek zou kunnen krijgen? De eerlijke samenvatting:

Benadering Params Schaalt naar Tijdsvariërende ρ\rho? PD gegarandeerd? Staartafhankelijkheid?
Steekproef- / voortschrijdende covariantie 0 (vensterlengte) elke dd grof (vertraagd, rumoerig) nee (behoeft oplappen) nee
EWMA (RiskMetrics) 1 (λ\lambda) elke dd ja (enkel verval) ja nee
CCC-GARCH dd marges + Qˉ\bar{Q} dozijnen nee (constante RR) ja nee
DCC-GARCH dd marges + 2 dozijnen ja ja nee
aDCC-GARCH dd marges + 3 dozijnen ja, asymmetrisch ja gedeeltelijk
BEKK O(d2)O(d^2) 4\le 4 ja (rijk) ja nee
VECH O(d4)O(d^4) 3\le 3 ja (rijkst) pijnlijk nee
GARCH-copula dd marges + copula dozijnen (vines) statische copula ja ja

Een paar lezingen van deze tabel:

  • EWMA is de goedkope baseline die iedereen zou moeten verslaan voordat men beweert dat DCC helpt. Het is naar de geest een eenparameter-speciaalgeval — een enkel exponentieel verval direct toegepast op de covariantie — en voor veel boeken is het verbluffend moeilijk om er out-of-sample op te verbeteren. Als DCC EWMA niet verslaat in schone walk-forward, gebruik dan EWMA.
  • CCC vs DCC is het hele punt van dit artikel: dezelfde factorisatie, maar CCC bevriest RR en DCC laat het bewegen. De twee extra parameters (a,ba, b) zijn het hele verschil, en in crypto verdienen ze hun bestaan.
  • BEKK/VECH kopen rijkere dynamiek — elke covariantie kan reageren op elke voorbije schok — maar de parameterkost beperkt ze tot piepkleine boeken. Voor alles voorbij 4 activa zijn ze geen echte optie.
  • GARCH-copula is de enige rij met een "ja" onder staartafhankelijkheid. Dat is de complementariteit weer: DCC modelleert het dynamische centrum van de gezamenlijke verdeling, copula's modelleren zijn statische staarten. Als je risicovraag "wat gebeurt er wanneer alles tegelijk breekt" is, grijp dan naar de copula-pijplijn; als het "wat is mijn hedgeratio / portefeuillevariantie nu" is, grijp dan naar DCC.

De praktische standaard voor een systematische crypto-desk: DCC (of aDCC) voor hedgeratio's en dynamische covariantie in het lichaam, een copula-overlay voor staartrisico en CVaR, en EWMA als de sanity-check-baseline die je eerlijk houdt over de vraag of de extra machinerie zichzelf terugverdient.

Beperkingen

  • Scalaire dynamiek. Eén aa en één bb voor alle paren is een sterke beperking. BTC-ETH en twee obscure alts delen dezelfde aanpassingssnelheid. Generalized DCC versoepelt dit maar herintroduceert de parameterexplosie die DCC was ontworpen om te vermijden.
  • Tweestaps-efficiëntieverlies. De quasi-likelihood-schatter is consistent maar niet volledig efficiënt, en naïeve standaardfouten zijn verkeerd. Gebruik de Engle-Sheppard-correctie als je om inferentie geeft; voor signaalgeneratie volstaan de puntschattingen.
  • Gaussische staarten standaard. De gewone Gaussische quasi-likelihood onderschat het gezamenlijke staartrisico. Student-t-innovaties helpen; voor echte staartafhankelijkheid (de kans op simultane extreme bewegingen) is DCC het verkeerde gereedschap en is een copula-model het juiste. DCC geeft je het dynamische lichaam van de correlatie; copula's geven je de statische staart. Serieuze desks gebruiken beide.
  • Correlatie is geen causaliteit, en geen richting. Stijgende ρˉt\bar{\rho}_t waarschuwt dat diversificatie faalt; het zegt niets over marktrichting. Overlaad een risicosignaal niet met directionele verwachtingen.
  • Datahonger. Alles hierboven gaat uit van lange, schone, gesynchroniseerde histories. Crypto's nieuwste en meest interessante tokens overtreden alle drie.

Samenvatting

  • Statische correlatie is een leugen in crypto. Correlaties clusteren, persisteren en schieten in drawdowns richting 1 — precies wanneer diversificatie zou moeten helpen. Een enkele steekproef ρ^\hat{\rho} middelt een regime-wisselend proces tot een betekenisloos midden.
  • Volledige multivariate GARCH (VECH, BEKK) schaalt niet. Het parameteraantal groeit als O(d2)O(d^2); beide zijn in de praktijk beperkt tot een handvol activa.
  • DCC (Engle 2002) factoriseert het probleem: Ht=DtRtDtH_t = D_t R_t D_t, met DtD_t uit onafhankelijke univariate GARCH-fits (hergebruik Deel 1-2) en RtR_t uit een tweeparameter-recursie. Het schaalt naar dozijnen activa omdat alleen a,ba, b worden geoptimaliseerd.
  • De recursie Qt=(1ab)Qˉ+azt1zt1+bQt1Q_t = (1-a-b)\bar{Q} + a\,z_{t-1}z_{t-1}' + b\,Q_{t-1}, genormaliseerd naar RtR_t, produceert bij elke stap een geldige positief-definiete correlatiematrix, met a,b>0a,b>0, a+b<1a+b<1.
  • arch doet geen DCC. Fit marges met arch, implementeer dan de ~60-regel NumPy/SciPy-schatter hier, of gebruik mgarch (Python) of rmgarch (R, de referentie).
  • Drie concrete opbrengsten: een dynamische hedgeratio βt=ρtσETH,t/σBTC,t\beta_t = \rho_t\,\sigma_{\text{ETH},t}/\sigma_{\text{BTC},t} voor pairs trading; een eerlijke tijdsvariërende portefeuillevariantie wHtww'H_t w voor risicogebaseerde allocatie; en gemiddelde paarsgewijze correlatie als een risk-off-regimesignaal.
  • Discipline is alles. Correlation targeting lekt het volledige-steekproefgemiddelde, dus herschat Qˉ\bar{Q} op alleen trainingsdata; vertraag elke hedgeratio; filter vooruit, strijk nooit glad. Walk-forward-evaluatie is niet onderhandelbaar.
  • aDCC voegt een neerwaartse-asymmetrieterm toe en is meestal de moeite waard in crypto, waar crash-correlatie domineert.
  • Deel 4 gebruikt deze voorspellingen om een op volatiliteit gerichte strategie te bouwen en te backtesten.

Referenties:

  • 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.
Disclaimer: De informatie in dit artikel is uitsluitend bedoeld voor educatieve en informatieve doeleinden en vormt geen financieel, beleggings- of handelsadvies. Het handelen in cryptovaluta brengt een aanzienlijk risico op verlies met zich mee.

MarketMaker.cc Team

Kwantitatief onderzoek en strategie

Bespreek op Telegram
Newsletter

Blijf de markt voor

Abonneer je op onze nieuwsbrief voor exclusieve AI-handelsinzichten, marktanalyses en platformupdates.

We respecteren je privacy. Je kunt je op elk moment afmelden.