← Torna agli articoli
July 12, 2026
5 min di lettura

DCC-GARCH: correlazioni dinamiche per coppie e rischio di portafoglio

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

Chiedi alla maggior parte dei desk cripto la correlazione tra BTC ed ETH e ti daranno un solo numero — 0.8, forse 0.75 — calcolato su una finestra che nessuno ricorda di aver scelto. Quel numero e una bugia, o quantomeno una semplificazione pericolosa. La correlazione campionaria e una media su un periodo durante il quale la vera struttura di dipendenza si muoveva di continuo. Nei mercati calmi BTC ed ETH si allontanano abbastanza da rendere attraente una coppia market-neutral. In una cascata di liquidazioni si agganciano l'uno all'altro e a tutto il resto, e la diversificazione che hai pagato evapora esattamente nel momento in cui ne hai bisogno.

Non e un effetto sottile. Prendi un qualsiasi drawdown del 2022 — il collasso di LUNA a maggio, lo smontaggio di 3AC a giugno, l'implosione di FTX a novembre — e vedrai la correlazione media a coppie sui primi 20 token marciare dall'intervallo 0.4-0.6 verso 0.9+ nel giro di pochi giorni. La correlazione non e una costante che ogni tanto viene stimata male; e una serie storica con le proprie dinamiche, il proprio clustering e i propri regimi. Trattarla come uno scalare e l'equivalente multivariato dell'assumere volatilita costante — un errore che abbiamo gia dedicato la Parte 1 di questa serie a smontare per un singolo asset.

Questo articolo e la Parte 3 di una serie sulla volatilita in quattro parti. La Parte 1 ha costruito il GARCH(1,1) univariato con la libreria arch e ha mostrato come la volatilita si aggreghi in cluster e torni verso la media. La Parte 2 ha aggiunto l'asimmetria (GJR-GARCH, EGARCH) e innovazioni Student-t per catturare il leverage effect e le code spesse. Qui passiamo al multivariato: modelliamo l'intera matrice di covarianza condizionale HtH_t mentre evolve, usando il modello Dynamic Conditional Correlation (DCC) di Engle. Questo ci da due cose che una correlazione scalare non potra mai dare — un hedge ratio dinamico per il pairs trading e una varianza di portafoglio onesta e variabile nel tempo per l'allocazione basata sul rischio. La Parte 4 chiude la serie con un backtest a volatilita obiettivo che lega le previsioni univariate e multivariate in una regola di dimensionamento delle posizioni.

Diamo per scontato che tu abbia letto le Parti 1 e 2, quindi non rideriveremo il GARCH univariato. Se vuoi il comportamento congiunto sulle code — la probabilita che due asset sforino insieme il loro quantile all'1% — quella e una questione di copule, e la trattiamo in Modelli di copula per il rischio congiunto. DCC e copule sono complementari: la copula ti da una struttura di dipendenza di coda statica ma flessibile, mentre il DCC ti da una serie storica trattabile dell'intera matrice di correlazione. Questo articolo riguarda quest'ultima.

Perche la correlazione statica si rompe nel cripto

Prima della macchina, sii preciso su cosa fallisce. Una singola correlazione campionaria ρ^\hat{\rho} su una finestra [tw,t][t-w, t] stima

ρ^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}}

Questo porta con se tre assunzioni implicite, tutte false per il cripto:

  1. Stazionarieta della dipendenza. La finestra ha un solo vero ρ\rho. In realta la dipendenza ha regimi — un regime di mercato calmo vicino a 0.5 e un regime di stress vicino a 0.95 — e ρ^\hat{\rho} li fonde in una via di mezzo priva di significato.
  2. Volatilita marginale costante. La correlazione di Pearson e una covarianza normalizzata. Se σi,t\sigma_{i,t} e σj,t\sigma_{j,t} sono a loro volta in movimento (lo sono — e l'intera premessa delle Parti 1 e 2), allora anche una covarianza costante produce una correlazione variabile nel tempo, e viceversa. Non puoi separare le due cose senza un modello di volatilita sottostante.
  3. Simmetria rispetto alla direzione del mercato. La correlazione sale nei drawdown piu di quanto salga nei rally. Questo e il cugino multivariato del leverage effect. Una finestra mobile non puo esprimerlo senza diventare cosi corta da essere puro rumore.

La correzione a finestra mobile — ricalcolare ρ^\hat{\rho} sugli ultimi 30 o 60 giorni — scambia un problema con un altro. Le finestre corte sono reattive ma rumorose e sono in ritardo rispetto alla rottura effettiva; le finestre lunghe sono stabili ma stantie. Peggio, una matrice di correlazione mobile su dd asset non e garantita rimanere semidefinita positiva una volta che inizi a ridurla o rattopparla, il che rompe ogni ottimizzatore a valle. Vogliamo un modello che (a) sia guidato da un vero processo di volatilita per asset, (b) produca per costruzione una matrice di correlazione valida a ogni passo e (c) abbia parametri che possiamo stimare per massima verosimiglianza anziche scegliendo una lunghezza di finestra a caso. Quel modello e il DCC-GARCH.

Il problema multivariato: la matrice di covarianza condizionale

Sia rtRdr_t \in \mathbb{R}^d il vettore dei rendimenti per dd asset al tempo tt, con media condizionale μt\mu_t (spesso solo una costante o un piccolo termine AR) e residuo ϵt=rtμt\epsilon_t = r_t - \mu_t. Assumiamo

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

dove HtH_t e la matrice di covarianza condizionale d×dd \times d dato l'insieme informativo Ft1\mathcal{F}_{t-1}, e D\mathcal{D} e una qualche distribuzione condizionale (gaussiana o, meglio per il cripto, Student-t multivariata). Tutto nella modellazione della volatilita multivariata e una diversa risposta a una sola domanda: come parametrizzi le dinamiche di HtH_t affinche resti simmetrica definita positiva a ogni passo senza un'esplosione di parametri?

Due risposte classiche mostrano perche il problema e difficile.

VECH

Il modello VECH (Bollerslev, Engle, Wooldridge 1988) scrive la mezza-vettorizzazione di HtH_t come funzione lineare dei residui quadrati passati e delle covarianze passate:

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

dove vech()\mathrm{vech}(\cdot) impila il triangolo inferiore di una matrice simmetrica in un vettore di lunghezza d(d+1)/2d(d+1)/2. Questo e massimamente generale — ogni varianza e covarianza dipende da ogni varianza e covarianza passata — e massimamente inutile oltre d=3d=3. Per dd asset, AA e BB sono ciascuna d(d+1)2×d(d+1)2\frac{d(d+1)}{2} \times \frac{d(d+1)}{2}. A d=5d=5 sono due matrici 15×1515\times 15, all'incirca 450 parametri, piu vincoli di definitezza positiva che sono penosi persino da esprimere. La superficie di verosimiglianza e una palude.

BEKK

Il modello BEKK (Engle & Kroner 1995) garantisce la definitezza positiva per costruzione usando una forma quadratica:

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

con CC triangolare superiore. Poiche ogni termine e una forma quadratica, Ht0H_t \succ 0 automaticamente finche CC0C'C \succ 0. BEKK e piu parsimonioso di VECH ma scala comunque come O(d2)O(d^2) parametri — le matrici AA e BB sono d×dd \times d ciascuna. Per d=10d=10 stai stimando dell'ordine di 200+ parametri congiuntamente per MLE, su dati cripto giornalieri rumorosi, senza alcuna garanzia che l'ottimizzatore converga a qualcosa di significativo. In pratica il BEKK pieno e confinato a d4d \le 4, e anche allora si usano le restrizioni "diagonale" o "scalare" che buttano via gran parte delle dinamiche incrociate.

Questa e la maledizione della dimensionalita per il GARCH multivariato: il numero di parametri cresce quadraticamente, ma la quantita di informazione nei dati no. Esaurisci i gradi di liberta molto prima di esaurire gli asset che ti interessano. Qualsiasi paniere cripto con 10-30 token e completamente fuori portata per VECH o BEKK.

La via d'uscita, dovuta a Engle, e smettere di provare a modellare HtH_t direttamente e invece fattorizzarlo in pezzi che sappiamo gia stimare a buon mercato.

Il DCC di Engle (2002): la decomposizione in due passi

Il modello Constant Conditional Correlation (CCC) di Bollerslev (1990) fu la prima fattorizzazione parsimoniosa. Scrive

Ht=DtRDtH_t = D_t\, R\, D_t

dove Dt=diag(σ1,t,,σd,t)D_t = \mathrm{diag}(\sigma_{1,t}, \ldots, \sigma_{d,t}) e la matrice diagonale delle deviazioni standard condizionali — un GARCH univariato per asset — e RR e una matrice di correlazione costante. Questa e un'enorme semplificazione: adatti dd modelli GARCH univariati indipendenti, poi stimi una singola matrice di correlazione campionaria dei residui standardizzati. La definitezza positiva e automatica finche RR e una matrice di correlazione valida e tutti i σi,t>0\sigma_{i,t} > 0.

Il problema del CCC e proprio nel nome — la correlazione e costante, che e esattamente l'assunzione con cui abbiamo aperto questo articolo per rifiutarla. La Dynamic Conditional Correlation di Engle (2002) mantiene la bellissima fattorizzazione del CCC ma lascia respirare la matrice di correlazione:

Ht=DtRtDtH_t = D_t\, R_t\, D_t

Ora RtR_t e variabile nel tempo. Il colpo di genio e che le volatilita e le correlazioni sono stimate in due passi separati, cosicche non affrontiamo mai l'ottimizzazione congiunta O(d2)O(d^2) completa.

Passo 1: GARCH univariato per asset

Per ogni asset ii, adatta un modello GARCH univariato esattamente come nelle Parti 1 e 2 — GARCH(1,1), GJR-GARCH o EGARCH con innovazioni Student-t, quello che si adatta meglio a quella serie. Questo fornisce le varianze condizionali σi,t2\sigma_{i,t}^2 e quindi Dt=diag(σ1,t,,σd,t)D_t = \mathrm{diag}(\sigma_{1,t}, \ldots, \sigma_{d,t}).

Dai modelli adattati estraiamo i residui standardizzati:

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

Per costruzione ogni zi,tz_{i,t} ha (approssimativamente) varianza condizionale unitaria. Impilali in un vettore zt=(z1,t,,zd,t)z_t = (z_{1,t}, \ldots, z_{d,t})'. Questi residui standardizzati sono la materia prima per il passo di correlazione — le loro singole dinamiche di volatilita sono state rimosse, quindi qualunque co-movimento resti e pura dipendenza, non un artefatto di volatilita. (Questa e la stessa logica in stile PIT che l'articolo sulle copule usa prima di adattare le marginali; qui ci fermiamo alla standardizzazione anziche arrivare fino alle uniformi.)

Passo 2: la ricorsione di correlazione DCC

Modelliamo un processo ausiliario QtQ_t, una matrice simmetrica definita positiva d×dd \times d, con una ricorsione simile a un GARCH guidata dai prodotti esterni dei residui standardizzati:

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

dove:

  • Qˉ=1Tt=1Tztzt\bar{Q} = \frac{1}{T}\sum_{t=1}^{T} z_t z_t' e la matrice di correlazione incondizionale dei residui standardizzati (questo e il correlation targeting — piu avanti se ne parla),
  • a0a \ge 0 governa quanto fortemente lo shock odierno zt1zt1z_{t-1}z_{t-1}' tira la correlazione,
  • b0b \ge 0 governa la persistenza — quanto del Qt1Q_{t-1} di ieri viene trasportato in avanti,
  • e il vincolo di ritorno verso la media e a+b<1a + b < 1 (con a,b>0a, b > 0), direttamente analogo a α+β<1\alpha + \beta < 1 nel GARCH univariato.

Nota che la struttura e identica a una ricorsione GARCH(1,1) scalare, ma su matrici: un'ancora di lungo periodo Qˉ\bar{Q}, un termine di shock e un termine di persistenza. Poiche e una combinazione convessa di matrici semidefinite positive (Qˉ\bar{Q}, il prodotto esterno di rango 1 e il precedente Qt1Q_{t-1}), QtQ_t resta definita positiva finche Qˉ0\bar{Q} \succ 0 e i pesi sono non negativi. E questo che ci procura matrici di covarianza valide garantite gratis.

QtQ_t e quasi una matrice di correlazione ma non del tutto — la sua diagonale non e esattamente 1. Quindi la normalizziamo:

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}

Elemento per elemento, la correlazione condizionale tra gli asset ii e jj e

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

Questa RtR_t e una matrice di correlazione a tutti gli effetti — diagonale unitaria, fuori diagonale in [1,1][-1,1], definita positiva — a ogni singolo passo temporale, per costruzione. Riassembla la covarianza condizionale completa:

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}

Quest'ultima forma elemento per elemento e quella che userai di continuo: la covarianza condizionale di due asset e la loro correlazione dinamica moltiplicata per ciascuna delle loro volatilita dinamiche. Ogni ingrediente sul lato destro e variabile nel tempo e proviene da un modello che puoi stimare.

L'intero modello ha solo due parametri di correlazione, aa e bb, indipendentemente dal fatto che d=2d = 2 o d=50d = 50. Il lato della volatilita scala linearmente (un GARCH univariato per asset, ciascuno con ~4-5 parametri, tutti adattati indipendentemente e imbarazzantemente in parallelo). E per questo che il DCC scala dove BEKK e VECH non possono: la maledizione della dimensionalita e confinata a Qˉ\bar{Q}, che e targettizzato (inserito come stima campionaria) anziche ottimizzato.

La restrizione scalare e il suo costo

Gli scalari a,ba, b significano che ogni coppia di asset condivide le stesse dinamiche di correlazione — la stessa velocita di aggiustamento e la stessa persistenza. La correlazione BTC-ETH e la correlazione DOGE-SHIB si muovono allo stesso ritmo anche se la loro economia differisce. Questo e il prezzo della trattabilita, ed e di solito un prezzo accettabile. Le generalizzazioni (Generalized DCC con matrici A,BA, B; il DCC asimmetrico di Cappiello-Engle-Sheppard) lo rilassano al costo di parametri e stabilita di stima. Menzioniamo l'aDCC piu avanti.

La quasi-log-verosimiglianza DCC

Per stimare aa e bb ci serve la verosimiglianza. Il risultato chiave di Engle e che la log-verosimiglianza gaussiana si separa in una parte di volatilita e una parte di correlazione, il che e cio che giustifica lo stimatore in due passi. Assumendo ϵtFt1N(0,Ht)\epsilon_t \mid \mathcal{F}_{t-1} \sim \mathcal{N}(0, H_t), il contributo alla log-verosimiglianza al tempo tt e

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)

Sostituisci Ht=DtRtDtH_t = D_t R_t D_t. Allora Ht=Dt2Rt|H_t| = |D_t|^2 |R_t| e Ht1=Dt1Rt1Dt1H_t^{-1} = D_t^{-1} R_t^{-1} D_t^{-1}, e usando 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)

Ora suddividilo aggiungendo e sottraendo ztztz_t'z_t:

t=12(dlog(2π)+2logDt+ϵtDt2ϵt)parte di volatilita   tV  12(logRt+ztRt1ztztzt)parte di correlazione   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{parte di volatilita }\;\ell_t^{V}} \;\underbrace{-\frac{1}{2}\left( \log|R_t| + z_t' R_t^{-1} z_t - z_t' z_t \right)}_{\text{parte di correlazione }\;\ell_t^{C}}

La parte di volatilita tV\ell_t^V dipende solo dai parametri del GARCH univariato (tramite DtD_t) — massimizzarla equivale esattamente ad adattare dd modelli GARCH univariati indipendenti, cosa che abbiamo fatto nel Passo 1. La parte di correlazione tC\ell_t^C dipende da aa e bb (tramite RtR_t), dati i residui standardizzati del Passo 1. Quindi nel Passo 2 massimizziamo solo

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)

(il termine ztztz_t'z_t non dipende da a,ba, b, quindi lo scartiamo). Questa e un'ottimizzazione a due parametri indipendentemente da quanti asset — questo e tutto il punto. Si chiama quasi-verosimiglianza perche lo stimatore in due passi e consistente ma non pienamente efficiente; gli errori standard richiedono una correzione (Engle & Sheppard 2001), ma per la generazione di segnali cio che conta sono le stime puntuali.

Per il cripto, le innovazioni gaussiane sottostimano il rischio di coda. Sostituire la verosimiglianza Student-t multivariata e una modifica plug-in a t\ell_t (sostituisci il kernel gaussiano con la densita tt multivariata e aggiungi un parametro di gradi di liberta ν\nu). Manteniamo la quasi-verosimiglianza gaussiana nello stimatore qui sotto per chiarezza e segnaliamo dove entra ν\nu — la standardizzazione delle Parti 1-2 ha gia usato innovazioni t sulle marginali, il che cattura gran parte del beneficio di coda.

Implementazione in Python

Un fatto brutale ma importante: la libreria arch non fa GARCH multivariato o DCC. arch e un eccellente motore univariato (ci appoggiamo a esso proprio per quello), ma non c'e alcun dcc_model al suo interno. Le tue opzioni pratiche sono:

  1. Costruisci il tuo DCC sopra arch — adatta i modelli univariati con arch, estrai i residui standardizzati, implementa la ricorsione QQ e la quasi-verosimiglianza di correlazione in NumPy/SciPy, e ottimizza i due scalari. E cio che facciamo qui sotto. Sono circa 60 righe e completamente trasparenti.
  2. Il pacchetto mgarch di PyPI — un'implementazione DCC-GARCH leggera in puro Python. Comodo per un adattamento veloce, meno flessibile se vuoi marginali GJR o innovazioni t collegate con precisione.
  3. rmgarch di R (Alexios Galanos) — l'implementazione di riferimento. dccspec / dccfit supportano DCC, aDCC, GARCH-copula, Student-t ed errori standard corretti. Se stai facendo ricerca seria sulla volatilita multivariata, rmgarch (chiamato da Python via rpy2 se proprio devi) e il gold standard.

Costruiamo l'opzione 1 perche rende esplicita ogni parte mobile e riutilizza le competenze univariate delle Parti 1-2.

Passo 1: adattare le marginali GARCH univariate con 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())

Un rapido controllo di sanita sui residui standardizzati e importante. Se una colonna ha una deviazione standard lontana da 1, o una pesante autocorrelazione residua nel suo quadrato (Ljung-Box su zi,t2z_{i,t}^2), la marginale univariata e mal specificata e il passo DCC ereditera quell'errore. Sistema prima la marginale — a questo serviva la Parte 2.

Passo 2: la ricorsione DCC e la quasi-log-verosimiglianza

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)

Eseguendo questo su un paniere BTC/ETH/SOL/BNB su qualche anno di dati giornalieri si produce un output della forma seguente (i numeri sotto sono illustrativi, non provenienti da uno specifico esperimento datato — eseguilo sui tuoi dati):

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

Come leggerlo:

  • a=0.029a = 0.029 e piccolo — la matrice di correlazione non sobbalza allo shock di un singolo giorno. Ogni giorno spinge RtR_t verso il prodotto esterno zt1zt1z_{t-1}z_{t-1}' solo di ~3%.
  • b=0.940b = 0.940 e grande — le correlazioni sono altamente persistenti. Una volta che il paniere si accoppia in un evento di stress, resta accoppiato per un po', decadendo lentamente verso Qˉ\bar{Q}. Questo rispecchia l'esperienza vissuta dei drawdown cripto: le correlazioni non tornano indietro di scatto nel momento in cui il prezzo si stabilizza.
  • a+b=0.969<1a + b = 0.969 < 1 conferma il ritorno verso la media. Il processo di correlazione ha un livello di lungo periodo stazionario (Qˉ\bar{Q}) a cui ritorna, con un'emivita di circa log(0.5)/log(a+b)22\log(0.5)/\log(a+b) \approx 22 giorni. Se mai stimi a+ba + b essenzialmente pari a 1, il processo di correlazione e integrato — non ha alcuna ancora di lungo periodo, di solito un sintomo di una rottura strutturale all'interno del tuo campione che il modello sta assorbendo come persistenza infinita.

La persistenza quasi unitaria e il minuscolo caricamento dello shock sono l'impronta digitale canonica del DCC attraverso le classi di asset, e il cripto non fa eccezione. E anche il motivo per cui una correlazione mobile a 30 giorni e un sostituto cosi scadente: una finestra mobile assume implicitamente aa e bb che non corrispondono affatto a questa struttura di decadimento.

Alcune note implementative che risparmiano tempo reale di debug:

  • Inizializzazione. Partire da [0.03, 0.94] riflette la stima cripto tipica: aa piccolo (le correlazioni reagiscono agli shock ma non violentemente), bb grande (le correlazioni sono persistenti). Se il tuo ottimizzatore vaga verso a+b1a+b \to 1 il processo di correlazione e integrato — di solito un segno di una rottura strutturale nel campione (un cambio di regime che il modello si sforza di adattare come persistenza).
  • Convenzione temporale. All'interno del ciclo valutiamo RtR_t rispetto a ztz_t e poi aggiorniamo QQ con ztztz_t z_t' per il passo successivo. Questo mantiene RtR_t funzione dell'informazione fino a t1t-1 soltanto — nessun look-ahead. Sbagliare questo off-by-one e il bug DCC piu comune in assoluto, e gonfia silenziosamente l'adattamento in-sample.
  • Correlation targeting. Inseriamo Qˉ\bar{Q} come correlazione campionaria anziche stimarla. E cio che rende l'ottimizzazione bidimensionale. Il costo e che Qˉ\bar{Q} usa l'intero campione, quindi in un walk-forward rigoroso devi ristimarla solo sulla finestra di addestramento (vedi sotto).

Passo 3: ricostruire i percorsi di correlazione e covarianza

Una volta fissati a,ba, b, esegui la ricorsione ancora una volta, questa volta memorizzando l'intero percorso di RtR_t (e HtH_t) cosicche le strategie a valle possano usarlo.

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

La serie rho_btc_eth e il frutto dell'intero esercizio: invece di un solo numero, ora hai una correlazione giornaliera che puoi tracciare, sogliare o alimentare in una strategia. Su dati cripto reali la vedrai tipicamente variare da circa 0.5 nei tratti tranquilli a oltre 0.9 durante lo stress — esattamente l'ampiezza che una singola correlazione campionaria media via.

Previsione a un passo in avanti

Per il trading dal vivo ti serve Ht+1H_{t+1} del periodo successivo a partire dall'informazione disponibile adesso. Il lato della volatilita viene dalla previsione a un passo di ciascun modello arch; il lato della correlazione e un altro giro della ricorsione:

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)

Ricorda che tutto e in unita scalate (×100) perche abbiamo adattato arch su series * 100. Dividi le volatilita per 100 (e le covarianze per 1002=10,000100^2 = 10{,}000) per tornare alle unita di rendimento grezzo prima di alimentare una strategia. Tenere dritta la scalatura e tedioso ma una frequente fonte di bug silenziosi.

Applicazione 1: un hedge ratio dinamico per il pairs trading

La classica coppia market-neutral — lunga su un asset, corta su una quantita pesata per il beta di un altro — vive o muore in base all'hedge ratio β\beta. Stimalo con OLS statico su una finestra di addestramento ed erediterai esattamente il problema della correlazione stantia di cui parla tutto questo articolo: la copertura che neutralizzava l'esposizione al mercato lo scorso trimestre e sbagliata questo trimestre.

Il DCC ti da l'hedge ratio come serie storica. La copertura a minima varianza dell'esposizione a ETH usando BTC e il coefficiente di regressione condizionale

β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}}

Ogni termine sulla destra e un output del DCC. L'hedge ratio si muove per due ragioni distinte, e il DCC le separa in modo pulito: la correlazione ρt\rho_t cambia (gli asset si accoppiano o si disaccoppiano) e il rapporto di volatilita σETH,t/σBTC,t\sigma_{\text{ETH},t}/\sigma_{\text{BTC},t} cambia (un asset diventa relativamente piu volatile). Un beta da OLS mobile impasta entrambi gli effetti insieme con un ritardo; il DCC li attribuisce.

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

Alimenta spread in qualunque motore di pairs tu usi. La copertura dinamica non crea di per se un vantaggio — rende lo spread che negozi genuinamente market-neutral nel tempo, cosicche il tuo segnale di ritorno verso la media non e contaminato da un'esposizione direzionale alla deriva. Se costruisci strategie di pairs, questo si inserisce direttamente nei framework di Arbitraggio statistico e pairs trading nel cripto e nell'approccio a distanza per le coppie, sostituendo il loro hedge ratio fisso. La serie di correlazione stessa e anche un input piu pulito per un segnale di coppia basato sulla correlazione rispetto a qualsiasi finestra mobile — ottieni un ρt\rho_t lisciato e coerente col modello anziche una stima a finestra rumorosa.

Due avvertenze specifiche sull'uso di βt\beta_t dal vivo. Primo, ritardalo — negozia su βt1\beta_{t-1}, mai sul βt\beta_t contemporaneo, o stai sbirciando. Secondo, un hedge ratio che sbanda ogni giorno genera turnover e commissioni; nel mercato 24/7 del cripto con costi di funding sulla gamba corta, una copertura iper-reattiva puo dissanguare piu di quanto corregga la deriva. Liscia βt\beta_t (una EWMA, o ribilancia la copertura solo quando si muove oltre una banda) e dimensiona il tutto con criterio — il dimensionamento delle posizioni su un segnale rumoroso e una disciplina a se, trattata in Dimensionamento con il criterio di Kelly.

Applicazione 2: varianza di portafoglio variabile nel tempo

Per un portafoglio con vettore di pesi ww, la varianza condizionale e

σ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}

Con una matrice di covarianza statica — il default di Markowitz — questo numero e una costante che hai calcolato una volta e fingi sia ancora vera. Non lo e. Il rischio di portafoglio respira col mercato, e respira piu forte esattamente quando le correlazioni schizzano, perche in un drawdown sia i termini σi,t\sigma_{i,t} sia i termini ρij,t\rho_{ij,t} salgono insieme e si moltiplicano. Un portafoglio che sembrava avere il 40% di vol annualizzata nei mercati calmi puo correre all'80%+ in una settimana di stress, e una matrice di covarianza statica ti dira che nulla e cambiato.

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

Questo σp,t\sigma_{p,t} variabile nel tempo e l'input onesto di cui l'allocazione basata sul rischio ha bisogno. L'ottimizzazione media-varianza (Markowitz per il cripto) con una covarianza campionaria statica sta ottimizzando contro una finzione; alimentarla con HtH_t (o la sua previsione a breve orizzonte) rende la frontiera efficiente stessa variabile nel tempo e costringe l'ottimizzatore a ridurre il rischio entrando nei regimi di correlazione crescente anziche dopo. Gli approcci risk-parity e gerarchici — la pipeline HRP + CVaR — sono ancora piu sensibili all'input di covarianza, poiche l'intera allocazione e una funzione della matrice di rischio. E se stai confrontando allocatori uno contro l'altro, come in algoritmi di ottimizzazione di portafoglio a confronto, che consumino covarianza statica o dinamica e spesso un driver piu grande del rischio realizzato rispetto alla scelta dell'algoritmo.

L'applicazione diretta e il volatility targeting dell'intero portafoglio: scegli una vol annualizzata obiettivo σ\sigma^{*}, e scala l'esposizione lorda per σ/σp,t\sigma^{*} / \sigma_{p,t} ogni periodo cosicche il rischio realizzato resti all'incirca costante invece di gonfiarsi nelle crisi. Questo chiude il cerchio con la Parte 4, che costruisce e sottopone a backtest esattamente questa regola.

Applicazione 3: la correlazione come segnale di regime

Oltre alla copertura e al dimensionamento, la matrice di correlazione porta un segnale macro. Lo scalare piu utile in assoluto che puoi estrarre e la correlazione media a coppie:

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

Quando ρˉt\bar{\rho}_t sale attraverso il paniere, il mercato sta entrando in un regime risk-off — le storie idiosincratiche smettono di contare e tutto negozia come un unico beta macro. Questa e l'impronta quantitativa del "le correlazioni vanno a 1 in una crisi". Tende ad anticipare o coincidere con i drawdown, il che ne fa un indicatore di regime utilizzabile anziche un'autopsia in ritardo.

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)

Puoi usare risk_off come freno autonomo (taglia l'esposizione lorda, allarga gli stop, metti in pausa le strategie di ritorno verso la media che vengono travolte quando tutto va nella stessa direzione) o come feature in un modello di regime piu formale. Si accompagna naturalmente all'approccio hidden-Markov in rilevamento dei regimi con gli HMM: la correlazione DCC media e una delle variabili osservate piu informative che puoi passare a un HMM, perche e lungimirante riguardo allo stress sistemico in un modo in cui i rendimenti passati non lo sono. L'avvertenza onesta: una correlazione crescente ti dice che la diversificazione sta fallendo, non in quale direzione va il mercato. E un segnale di rischio, non un segnale di alpha, e va dimensionato come tale — vedi l'asimmetria tra perdite e profitti per capire perche trattare un regime di rischio come una scommessa direzionale finisce male.

Considerazioni pratiche

Stabilita di stima e numero di asset

Il DCC scala molto meglio del BEKK, ma "scala" non e "gratis". La matrice di correlation targeting Qˉ\bar{Q} e una correlazione campionaria d×dd \times d, e le matrici di correlazione campionarie diventano mal condizionate man mano che dd si avvicina al numero di osservazioni. Con 4 asset e 1000 giorni sei a posto. Con 60 asset e 400 giorni, Qˉ\bar{Q} e quasi singolare, la sua inversa nella verosimiglianza esplode, e RtR_t puo vagare fuori dalla definitezza positiva a causa del rumore numerico. Le mitigazioni, all'incirca in ordine di quanto spesso ti serviranno:

  • Riduci Qˉ\bar{Q} (shrink) verso un target strutturato (Ledoit-Wolf, o verso l'identita / una matrice a correlazione costante) prima di eseguire la ricorsione. E la singola correzione a maggior leva per i panieri grandi.
  • Raggruppa gli asset in una manciata di settori (major, L1, DeFi, meme), modella all'interno e tra i settori a livello settoriale, o esegui il DCC su fattori a componenti principali anziche su asset grezzi.
  • Preferisci piu dati a piu asset. Il DCC ha un appetito insaziabile per una storia lunga, pulita e contemporanea — che e esattamente cio che i token giovani non hanno.

Realisticamente, tieni il DCC diretto al massimo a qualche decina di asset. Per un universo ampio, il DCC sui rendimenti fattoriali piu residui idiosincratici e il workaround standard.

Il correlation targeting e una scorciatoia con un costo

Targettizzare Qˉ\bar{Q} rende la stima trattabile ma incorpora la correlazione incondizionale dell'intero campione in ogni RtR_t. In un backtest rigoroso questa e una fuga di informazione look-ahead: la tua matrice di correlazione al giorno tt "conosce" la correlazione media dell'intero campione, futuro incluso. Per una valutazione onesta devi ristimare Qˉ\bar{Q} solo sulla finestra di addestramento e tenerla fissa out-of-sample, oppure farla rollare in avanti. E la stessa disciplina che l'intero framework di ottimizzazione walk-forward impone, ed e facile violarla accidentalmente con un comodo np.cov(Z) sull'intero array — come fa il nostro codice didattico qui sopra. Sistemala prima di fidarti di un solo numero di P&L.

Cadenza di riadattamento e disciplina anti-look-ahead

Non devi riottimizzare a,ba, b ogni giorno — sono parametri stabili. Una cadenza di produzione sensata:

  • Ristima a,ba, b e i parametri GARCH univariati settimanalmente o mensilmente.
  • Esegui il filtro (aggiorna QtQ_t, σi,t\sigma_{i,t}) ogni periodo con i parametri congelati per ottenere RtR_t e HtH_t freschi. Il filtraggio e economico; l'adattamento no.
  • Prevedi sempre, non lisciare mai. Usa RtR_t costruito dall'informazione fino a t1t-1 per negoziare a tt. La struttura a due passaggi (adatta su una finestra, poi filtra in avanti) e cio che ti mantiene onesto.

Il divario tra un backtest DCC e la performance dal vivo e quasi sempre una fuga di look-ahead — Qˉ\bar{Q} sull'intero campione, βt\beta_t contemporaneo, o riadattamento su dati che includono l'operazione che stai valutando. La disciplina di far corrispondere il backtest alle condizioni dal vivo e un argomento a se in parita backtest-dal vivo, e il DCC e un modello che punisce la sciatteria qui piu della maggior parte. Se, dopo una valutazione walk-forward pulita, la correlazione dinamica non aggiunge nulla rispetto a una semplice stima mobile per la tua strategia, quello e un risultato negativo reale e pubblicabile — la mentalita in risultati negativi onesti si applica direttamente.

DCC asimmetrico (aDCC)

Proprio come il leverage effect univariato (Parte 2) significa che le cattive notizie alzano la volatilita piu di quelle buone, le correlazioni salgono di piu dopo shock congiunti negativi che dopo shock congiunti positivi. Cappiello, Engle & Sheppard (2006) catturano questo con il DCC asimmetrico, aggiungendo un termine guidato dal prodotto esterno dei residui standardizzati nella loro parte negativa 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}

dove Nˉ=1Ttztzt\bar{N} = \frac{1}{T}\sum_t z_t^- z_t^{-\prime} e g0g \ge 0 misura la spinta extra di correlazione da movimenti congiunti al ribasso. Per il cripto, dove la correlazione-da-crollo e il rischio dominante, il termine di asimmetria e di solito significativo e vale l'unico parametro in piu. rmgarch adatta l'aDCC out of the box (model="aDCC"); aggiungere il termine ztz_t^- al nostro stimatore NumPy e un esercizio semplice.

Confronto: il DCC contro le alternative

Dove si colloca il DCC tra i modi in cui potresti ottenere una matrice di covarianza per un paniere cripto? Il riassunto onesto:

Approccio Parametri Scala fino a ρ\rho variabile nel tempo? PD garantita? Dipendenza di coda?
Covarianza campionaria / mobile 0 (lunghezza finestra) qualsiasi dd grossolanamente (in ritardo, rumorosa) no (serve rattoppo) no
EWMA (RiskMetrics) 1 (λ\lambda) qualsiasi dd si (singolo decadimento) si no
CCC-GARCH dd marginali + Qˉ\bar{Q} decine no (RR costante) si no
DCC-GARCH dd marginali + 2 decine si si no
aDCC-GARCH dd marginali + 3 decine si, asimmetrica si parziale
BEKK O(d2)O(d^2) 4\le 4 si (ricca) si no
VECH O(d4)O(d^4) 3\le 3 si (la piu ricca) penosa no
GARCH-copula dd marginali + copula decine (vine) copula statica si si

Alcune letture di questa tabella:

  • EWMA e la baseline economica che tutti dovrebbero battere prima di sostenere che il DCC aiuta. E in spirito un caso speciale a un parametro — un singolo decadimento esponenziale applicato direttamente alla covarianza — e per molti panieri e sorprendentemente difficile da migliorare out-of-sample. Se il DCC non batte l'EWMA in un walk-forward pulito, usa l'EWMA.
  • CCC vs DCC e l'intero punto di questo articolo: stessa fattorizzazione, ma il CCC congela RR e il DCC lo lascia muovere. I due parametri extra (a,ba, b) sono l'intera differenza, e nel cripto si guadagnano il pane.
  • BEKK/VECH comprano dinamiche piu ricche — ogni covarianza puo rispondere a ogni shock passato — ma il costo in parametri li confina a panieri minuscoli. Per qualsiasi cosa oltre i 4 asset non sono un'opzione reale.
  • GARCH-copula e l'unica riga con un "si" sotto dipendenza di coda. E di nuovo la complementarita: il DCC modella il centro dinamico della distribuzione congiunta, le copule ne modellano le code statiche. Se la tua domanda di rischio e "cosa succede quando tutto si rompe insieme", ricorri alla pipeline con copule; se e "qual e il mio hedge ratio / la mia varianza di portafoglio adesso", ricorri al DCC.

Il default pratico per un desk cripto sistematico: DCC (o aDCC) per gli hedge ratio e la covarianza dinamica nel corpo, un overlay di copula per il rischio di coda e il CVaR, ed EWMA come baseline di controllo che ti mantiene onesto sul fatto che la macchina extra si stia ripagando.

Limitazioni

  • Dinamiche scalari. Un solo aa e un solo bb per tutte le coppie e una restrizione forte. BTC-ETH e due oscure alt condividono la stessa velocita di aggiustamento. Il Generalized DCC lo rilassa ma reintroduce l'esplosione di parametri che il DCC era progettato per evitare.
  • Perdita di efficienza del due passi. Lo stimatore quasi-verosimiglianza e consistente ma non pienamente efficiente, e gli errori standard ingenui sono sbagliati. Usa la correzione di Engle-Sheppard se ti interessa l'inferenza; per la generazione di segnali le stime puntuali bastano.
  • Code gaussiane per default. La semplice quasi-verosimiglianza gaussiana sottostima il rischio di coda congiunto. Le innovazioni Student-t aiutano; per una genuina dipendenza di coda (la probabilita di movimenti estremi simultanei), il DCC e lo strumento sbagliato e un modello di copula e quello giusto. Il DCC ti da il corpo dinamico della correlazione; le copule ti danno la coda statica. I desk seri usano entrambi.
  • La correlazione non e causalita, e non e direzione. Un ρˉt\bar{\rho}_t crescente avverte che la diversificazione sta fallendo; non dice nulla sulla direzione del mercato. Non sovraccaricare un segnale di rischio con aspettative direzionali.
  • Fame di dati. Tutto quanto sopra assume storie lunghe, pulite e sincronizzate. I token cripto piu nuovi e piu interessanti violano tutte e tre.

Riepilogo

  • La correlazione statica e una bugia nel cripto. Le correlazioni si aggregano in cluster, persistono e schizzano verso 1 nei drawdown — esattamente quando la diversificazione dovrebbe aiutare. Una singola ρ^\hat{\rho} campionaria media un processo a commutazione di regime in una via di mezzo priva di significato.
  • Il GARCH multivariato completo (VECH, BEKK) non scala. Il conteggio dei parametri cresce come O(d2)O(d^2); entrambi sono confinati in pratica a una manciata di asset.
  • Il DCC (Engle 2002) fattorizza il problema: Ht=DtRtDtH_t = D_t R_t D_t, con DtD_t da adattamenti GARCH univariati indipendenti (riutilizza le Parti 1-2) e RtR_t da una ricorsione a due parametri. Scala fino a decine di asset perche si ottimizzano solo a,ba, b.
  • La ricorsione Qt=(1ab)Qˉ+azt1zt1+bQt1Q_t = (1-a-b)\bar{Q} + a\,z_{t-1}z_{t-1}' + b\,Q_{t-1}, normalizzata a RtR_t, produce una matrice di correlazione definita positiva valida a ogni passo, con a,b>0a,b>0, a+b<1a+b<1.
  • arch non fa DCC. Adatta le marginali con arch, poi implementa lo stimatore NumPy/SciPy di ~60 righe qui presente, o usa mgarch (Python) o rmgarch (R, il riferimento).
  • Tre frutti concreti: un hedge ratio dinamico βt=ρtσETH,t/σBTC,t\beta_t = \rho_t\,\sigma_{\text{ETH},t}/\sigma_{\text{BTC},t} per il pairs trading; una varianza di portafoglio onesta e variabile nel tempo wHtww'H_t w per l'allocazione basata sul rischio; e la correlazione media a coppie come segnale di regime risk-off.
  • La disciplina e tutto. Il correlation targeting fa trapelare la media dell'intero campione, quindi ristima Qˉ\bar{Q} solo sui dati di addestramento; ritarda ogni hedge ratio; filtra in avanti, non lisciare mai. La valutazione walk-forward e imprescindibile.
  • L'aDCC aggiunge un termine di asimmetria al ribasso ed e di solito utile nel cripto, dove la correlazione-da-crollo domina.
  • La Parte 4 usa queste previsioni per costruire e sottoporre a backtest una strategia a volatilita obiettivo.

Riferimenti:

  • 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: le informazioni fornite in questo articolo hanno solo scopo didattico e informativo e non costituiscono consulenza finanziaria, di investimento o di trading. Il trading di criptovalute comporta un rischio significativo di perdita.

MarketMaker.cc Team

Ricerca Quantitativa e Strategia

Discuti su Telegram
Newsletter

Resta un Passo Avanti al Mercato

Iscriviti alla nostra newsletter per approfondimenti esclusivi sul trading con IA, analisi di mercato e aggiornamenti sulla piattaforma.

Rispettiamo la tua privacy. Annulla l'iscrizione in qualsiasi momento.