← Voltar aos artigos
July 12, 2026
5 min read

DCC-GARCH: Correlações Dinâmicas para Pares e Risco de Portfólio

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

Pergunte para a maioria das mesas de operação cripto qual é a correlação entre BTC e ETH e você receberá um número único — 0,8, talvez 0,75 — calculado sobre alguma janela que ninguém se lembra de ter escolhido. Esse número é uma mentira, ou pelo menos uma simplificação perigosa. A correlação amostral é uma média sobre um período durante o qual a verdadeira estrutura de dependência estava em movimento constante. Em mercados calmos, BTC e ETH se distanciam o suficiente para fazer um par market-neutral parecer atraente. Em uma cascata de liquidações, eles se travam um ao outro e a tudo mais, e a diversificação pela qual você pagou evapora exatamente no momento em que você mais precisa dela.

Esse não é um efeito sutil. Pegue qualquer drawdown de 2022 — o colapso da LUNA em maio, o desmonte da 3AC em junho, a implosão da FTX em novembro — e você verá a correlação média entre pares nos 20 principais tokens marchar da faixa de 0,4-0,6 em direção a 0,9+ em questão de dias. Correlação não é uma constante que ocasionalmente é mal estimada; é uma série temporal com dinâmica própria, clustering próprio e regimes próprios. Tratá-la como um escalar é o equivalente multivariado de assumir volatilidade constante — um erro que já passamos a Parte 1 desta série desmontando para um único ativo.

Este artigo é a Parte 3 de uma série de quatro partes sobre volatilidade. A Parte 1 construiu o GARCH(1,1) univariado com a biblioteca arch e mostrou como a volatilidade se agrupa em clusters e reverte à média. A Parte 2 adicionou assimetria (GJR-GARCH, EGARCH) e inovações Student-t para capturar o efeito alavancagem e as caudas pesadas. Aqui vamos para o multivariado: modelamos toda a matriz de covariância condicional HtH_t conforme ela evolui, usando o modelo de Correlação Condicional Dinâmica (DCC) de Engle. Isso nos dá duas coisas que uma correlação escalar nunca pode — uma razão de hedge dinâmica para pairs trading, e uma variância de portfólio honesta e variável no tempo para alocação baseada em risco. A Parte 4 encerra a série com um backtest de targeting de volatilidade que amarra as previsões univariadas e multivariadas em uma regra de dimensionamento de posição.

Assumimos que você leu as Partes 1 e 2, então não vamos re-derivar o GARCH univariado. Se você quer o comportamento de cauda conjunta — a probabilidade de dois ativos romperem seu quantil de 1% juntos — isso é uma questão de cópulas, e cobrimos isso em Modelos de Cópula para Risco Conjunto. DCC e cópulas são complementares: a cópula dá a você uma estrutura de dependência de cauda estática-mas-flexível, enquanto o DCC dá a você uma série temporal tratável de toda a matriz de correlação. Este artigo trata do segundo caso.

Por Que a Correlação Estática Falha em Cripto

Antes da maquinaria, seja preciso sobre o que falha. Uma única correlação amostral ρ^\hat{\rho} sobre uma janela [tw,t][t-w, t] estima

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

Isso carrega três suposições implícitas, todas falsas para cripto:

  1. Estacionariedade da dependência. A janela tem um único ρ\rho verdadeiro. Na realidade a dependência tem regimes — um regime de mercado tranquilo próximo de 0,5 e um regime de estresse próximo de 0,95 — e ρ^\hat{\rho} os mistura em uma média sem sentido.
  2. Volatilidade marginal constante. A correlação de Pearson é uma covariância normalizada. Se σi,t\sigma_{i,t} e σj,t\sigma_{j,t} estão eles próprios em movimento (estão — essa é toda a premissa das Partes 1 e 2), então mesmo uma covariância constante produz uma correlação variável no tempo, e vice-versa. Você não consegue separar os dois sem um modelo de volatilidade por baixo.
  3. Simetria entre as direções de mercado. A correlação sobe mais em drawdowns do que em rallies. Este é o primo multivariado do efeito alavancagem. Uma janela móvel não consegue expressar isso sem se tornar tão curta que vira puro ruído.

O ajuste de janela móvel — recalcular ρ^\hat{\rho} nos últimos 30 ou 60 dias — troca um problema por outro. Janelas curtas são responsivas mas ruidosas e ficam atrasadas em relação à quebra real; janelas longas são estáveis mas obsoletas. Pior, uma matriz de correlação móvel sobre dd ativos não tem garantia de permanecer semidefinida positiva assim que você começa a fazer shrinkage ou remendos, o que quebra todo otimizador downstream. Queremos um modelo que (a) seja guiado por um processo de volatilidade adequado por ativo, (b) produza uma matriz de correlação válida em cada passo por construção, e (c) tenha parâmetros que possamos estimar por máxima verossimilhança em vez de escolher o comprimento de uma janela de forma arbitrária. Esse modelo é o DCC-GARCH.

O Problema Multivariado: A Matriz de Covariância Condicional

Seja rtRdr_t \in \mathbb{R}^d o vetor de retornos para dd ativos no tempo tt, com média condicional μt\mu_t (frequentemente apenas uma constante ou um pequeno termo AR) e resíduo ϵt=rtμt\epsilon_t = r_t - \mu_t. Assumimos

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

onde HtH_t é a matriz de covariância condicional d×dd \times d dado o conjunto de informação Ft1\mathcal{F}_{t-1}, e D\mathcal{D} é alguma distribuição condicional (Gaussiana ou, melhor para cripto, Student-t multivariada). Tudo em modelagem de volatilidade multivariada é uma resposta diferente para uma única pergunta: como parametrizar a dinâmica de HtH_t para que ela permaneça simétrica e definida positiva a cada passo sem uma explosão de parâmetros?

Duas respostas clássicas mostram por que o problema é difícil.

VECH

O modelo VECH (Bollerslev, Engle, Wooldridge 1988) escreve a semi-vetorização de HtH_t como uma função linear dos resíduos quadrados passados e das covariâncias passadas:

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

onde vech()\mathrm{vech}(\cdot) empilha o triângulo inferior de uma matriz simétrica em um vetor de comprimento d(d+1)/2d(d+1)/2. Isso é maximamente geral — cada variância e covariância depende de cada variância e covariância passada — e maximamente inútil além de d=3d=3. Para dd ativos, AA e BB são cada um d(d+1)2×d(d+1)2\frac{d(d+1)}{2} \times \frac{d(d+1)}{2}. Em d=5d=5 isso é duas matrizes 15×1515\times 15, aproximadamente 450 parâmetros, além de restrições de definição positiva dolorosas até de expressar. A superfície de verossimilhança é um pântano.

BEKK

O modelo BEKK (Engle & Kroner 1995) garante a definição positiva por construção usando uma forma quadrática:

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

com CC triangular superior. Como cada termo é uma forma quadrática, Ht0H_t \succ 0 automaticamente desde que CC0C'C \succ 0. O BEKK é mais parcimonioso que o VECH mas ainda escala como O(d2)O(d^2) parâmetros — as matrizes AA e BB são cada uma d×dd \times d. Para d=10d=10 você está estimando algo na ordem de 200+ parâmetros conjuntamente por MLE, em dados diários ruidosos de cripto, sem garantia de que o otimizador converge para algo significativo. Na prática, o BEKK completo fica confinado a d4d \le 4, e mesmo assim as pessoas usam as restrições "diagonal" ou "escalar" que descartam a maior parte da dinâmica cruzada.

Essa é a maldição da dimensionalidade para o GARCH multivariado: o número de parâmetros cresce quadraticamente, mas a quantidade de informação nos dados não. Você fica sem graus de liberdade muito antes de ficar sem ativos com os quais se importa. Qualquer book cripto com 10-30 tokens está completamente fora de alcance para VECH ou BEKK.

A saída, devida a Engle, é parar de tentar modelar HtH_t diretamente e, em vez disso, fatorá-la em peças que já sabemos como estimar de forma barata.

O DCC de Engle (2002): A Decomposição em Dois Passos

O modelo de Correlação Condicional Constante (CCC) de Bollerslev (1990) foi a primeira fatoração parcimoniosa. Ele escreve

Ht=DtRDtH_t = D_t\, R\, D_t

onde Dt=diag(σ1,t,,σd,t)D_t = \mathrm{diag}(\sigma_{1,t}, \ldots, \sigma_{d,t}) é a matriz diagonal dos desvios-padrão condicionais — um GARCH univariado por ativo — e RR é uma matriz de correlação constante. Isso é uma enorme simplificação: você ajusta dd modelos GARCH univariados independentes, depois estima uma única matriz de correlação amostral dos resíduos padronizados. A definição positiva é automática desde que RR seja uma matriz de correlação válida e todos os σi,t>0\sigma_{i,t} > 0.

O problema do CCC está bem ali no nome — a correlação é constante, exatamente a suposição que abrimos este artigo rejeitando. A Correlação Condicional Dinâmica de Engle (2002) mantém a bela fatoração do CCC mas deixa a matriz de correlação respirar:

Ht=DtRtDtH_t = D_t\, R_t\, D_t

Agora RtR_t é variável no tempo. O genial é que as volatilidades e as correlações são estimadas em dois passos separados, então nunca enfrentamos a otimização conjunta completa de O(d2)O(d^2).

Passo 1: GARCH univariado por ativo

Para cada ativo ii, ajuste um modelo GARCH univariado exatamente como nas Partes 1 e 2 — GARCH(1,1), GJR-GARCH ou EGARCH com inovações Student-t, o que se ajustar melhor para aquela série. Isso dá as variâncias condicionais σi,t2\sigma_{i,t}^2 e, portanto, Dt=diag(σ1,t,,σd,t)D_t = \mathrm{diag}(\sigma_{1,t}, \ldots, \sigma_{d,t}).

Dos modelos ajustados extraímos os resíduos padronizados:

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

Por construção, cada zi,tz_{i,t} tem (aproximadamente) variância condicional unitária. Empilhe-os em um vetor zt=(z1,t,,zd,t)z_t = (z_{1,t}, \ldots, z_{d,t})'. Esses resíduos padronizados são a matéria-prima para o passo de correlação — eles tiveram suas dinâmicas de volatilidade individuais removidas, então qualquer co-movimento remanescente é dependência pura, não um artefato de volatilidade. (Essa é a mesma lógica estilo PIT que o artigo de cópulas usa antes de ajustar as margens; aqui paramos na padronização em vez de ir até o fim para uniformes.)

Passo 2: A recursão de correlação DCC

Modelamos um processo auxiliar QtQ_t, uma matriz simétrica definida positiva d×dd \times d, com uma recursão estilo GARCH guiada pelos produtos externos dos resíduos padronizados:

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

onde:

  • Qˉ=1Tt=1Tztzt\bar{Q} = \frac{1}{T}\sum_{t=1}^{T} z_t z_t' é a matriz de correlação incondicional dos resíduos padronizados (isso é targeting de correlação — mais sobre isso abaixo),
  • a0a \ge 0 governa o quanto o choque de hoje zt1zt1z_{t-1}z_{t-1}' puxa a correlação,
  • b0b \ge 0 governa a persistência — quanto do Qt1Q_{t-1} de ontem carrega adiante,
  • e a restrição de reversão à média é a+b<1a + b < 1 (com a,b>0a, b > 0), diretamente análoga a α+β<1\alpha + \beta < 1 no GARCH univariado.

Note que a estrutura é idêntica a uma recursão GARCH(1,1) escalar, mas em matrizes: uma âncora de longo prazo Qˉ\bar{Q}, um termo de choque e um termo de persistência. Como é uma combinação convexa de matrizes semidefinidas positivas (Qˉ\bar{Q}, o produto externo de rank 1, e o Qt1Q_{t-1} anterior), QtQ_t permanece definida positiva desde que Qˉ0\bar{Q} \succ 0 e os pesos sejam não negativos. É isso que nos compra matrizes de covariância válidas garantidas de graça.

QtQ_t é quase uma matriz de correlação mas não exatamente — sua diagonal não é exatamente 1. Então normalizamos:

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 a elemento, a correlação condicional entre os ativos ii e jj é

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

Este RtR_t é uma matriz de correlação adequada — diagonal unitária, elementos fora da diagonal em [1,1][-1,1], definida positiva — a cada passo de tempo, por construção. Remontando a covariância condicional 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}

Essa última forma elemento a elemento é a que você usará constantemente: a covariância condicional de dois ativos é sua correlação dinâmica multiplicada por cada uma de suas volatilidades dinâmicas. Cada ingrediente do lado direito é variável no tempo e vem de um modelo que você pode estimar.

O modelo inteiro tem apenas dois parâmetros de correlação, aa e bb, independentemente de d=2d = 2 ou d=50d = 50. O lado da volatilidade escala linearmente (um GARCH univariado por ativo, cada um com ~4-5 parâmetros, todos ajustados independentemente e embaraçosamente paralelos). É por isso que o DCC escala onde BEKK e VECH não conseguem: a maldição da dimensionalidade fica confinada a Qˉ\bar{Q}, que é targeted (inserida como uma estimativa amostral) em vez de otimizada.

A restrição escalar e seu custo

Os escalares a,ba, b significam que todo par de ativos compartilha a mesma dinâmica de correlação — a mesma velocidade de ajuste e a mesma persistência. A correlação BTC-ETH e a correlação DOGE-SHIB se movem no mesmo ritmo mesmo que suas economias sejam diferentes. Esse é o preço da tratabilidade, e geralmente é um preço aceitável. Generalizações (DCC Generalizado com matrizes A,BA, B; o DCC assimétrico de Cappiello-Engle-Sheppard) relaxam isso ao custo de parâmetros e estabilidade de estimação. Mencionamos o aDCC abaixo.

A Quase-Log-Verossimilhança do DCC

Para estimar aa e bb precisamos da verossimilhança. O resultado chave de Engle é que a log-verossimilhança Gaussiana se separa em uma parte de volatilidade e uma parte de correlação, o que justifica o estimador em dois passos. Assumindo ϵtFt1N(0,Ht)\epsilon_t \mid \mathcal{F}_{t-1} \sim \mathcal{N}(0, H_t), a contribuição da log-verossimilhança no tempo 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)

Substitua Ht=DtRtDtH_t = D_t R_t D_t. Então 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)

Agora divida somando e subtraindo ztztz_t'z_t:

t=12(dlog(2π)+2logDt+ϵtDt2ϵt)parte de volatilidade   tV  12(logRt+ztRt1ztztzt)parte de correlac¸a˜  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 de volatilidade }\;\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 de correlação }\;\ell_t^{C}}

A parte de volatilidade tV\ell_t^V depende apenas dos parâmetros GARCH univariados (através de DtD_t) — maximizá-la é exatamente ajustar dd modelos GARCH univariados independentes, o que fizemos no Passo 1. A parte de correlação tC\ell_t^C depende de aa e bb (através de RtR_t), dados os resíduos padronizados do Passo 1. Então no Passo 2 maximizamos apenas

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)

(o termo ztztz_t'z_t não depende de a,ba, b, então o descartamos). Essa é uma otimização de dois parâmetros independentemente de quantos ativos existam — esse é todo o ponto. É chamada de quase-verossimilhança porque o estimador em dois passos é consistente mas não totalmente eficiente; os erros padrão precisam de uma correção (Engle & Sheppard 2001), mas para geração de sinal as estimativas pontuais são o que importa.

Para cripto, as inovações Gaussianas subestimam o risco de cauda. Trocar para a verossimilhança Student-t multivariada é uma mudança direta em t\ell_t (substitua o kernel Gaussiano pela densidade tt multivariada e adicione um parâmetro de graus de liberdade ν\nu). Mantemos a quase-verossimilhança Gaussiana no estimador abaixo por clareza e observamos onde ν\nu entra — a padronização das Partes 1-2 já usou inovações t nas margens, o que captura a maior parte do benefício de cauda.

Implementação em Python

Um fato contundente mas importante: a biblioteca arch não faz GARCH multivariado ou DCC. arch é um excelente motor univariado (nos apoiamos nela exatamente para isso), mas não há dcc_model nela. Suas opções práticas são:

  1. Construir seu próprio DCC em cima do arch — ajustar modelos univariados com arch, extrair resíduos padronizados, implementar a recursão de QQ e a quase-verossimilhança de correlação em NumPy/SciPy, e otimizar os dois escalares. É o que fazemos abaixo. São cerca de 60 linhas e completamente transparente.
  2. O pacote PyPI mgarch — uma implementação leve em Python puro de DCC-GARCH. Conveniente para um ajuste rápido, menos flexível se você quiser margens GJR ou inovações t com precisão.
  3. O rmgarch do R (Alexios Galanos) — a implementação de referência. dccspec / dccfit suportam DCC, aDCC, GARCH-copula, Student-t e erros padrão adequados. Se você está fazendo pesquisa séria de volatilidade multivariada, o rmgarch (chamado do Python via rpy2 se necessário) é o padrão ouro.

Construímos a opção 1 porque torna cada parte móvel explícita e reutiliza as habilidades univariadas das Partes 1-2.

Passo 1: Ajustar margens GARCH univariadas com 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())

Uma verificação rápida de sanidade nos resíduos padronizados importa. Se qualquer coluna tiver um desvio padrão muito distante de 1, ou autocorrelação remanescente pesada em seu quadrado (Ljung-Box em zi,t2z_{i,t}^2), a margem univariada está mal especificada e o passo DCC herdará esse erro. Corrija a margem primeiro — era para isso que servia a Parte 2.

Passo 2: A recursão DCC e a quase-log-verossimilhança

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)

Rodar isso em um book BTC/ETH/SOL/BNB ao longo de alguns anos de dados diários produz saída na seguinte forma (os números abaixo são ilustrativos, não de um experimento datado específico — rode nos seus próprios dados):

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

Como interpretar:

  • a=0,029a = 0,029 é pequeno — a matriz de correlação não dispara com o choque de um único dia. Cada dia empurra RtR_t em direção ao produto externo zt1zt1z_{t-1}z_{t-1}' em apenas ~3%.
  • b=0,940b = 0,940 é grande — as correlações são altamente persistentes. Uma vez que o book se acopla em um evento de estresse, ele permanece acoplado por um tempo, decaindo de volta em direção a Qˉ\bar{Q} lentamente. Isso corresponde à experiência vivida dos drawdowns em cripto: as correlações não voltam ao normal no momento em que o preço se estabiliza.
  • a+b=0,969<1a + b = 0,969 < 1 confirma a reversão à média. O processo de correlação tem um nível de longo prazo estacionário (Qˉ\bar{Q}) ao qual retorna, com uma meia-vida de aproximadamente log(0.5)/log(a+b)22\log(0.5)/\log(a+b) \approx 22 dias. Se você alguma vez estimar a+ba + b essencialmente igual a 1, o processo de correlação está integrado — não tem âncora de longo prazo, geralmente um sintoma de uma quebra estrutural dentro da sua amostra que o modelo está absorvendo como persistência infinita.

A persistência quase unitária e o pequeno carregamento de choque são a assinatura canônica do DCC em diversas classes de ativos, e cripto não é exceção. É também por isso que uma correlação móvel de 30 dias é um substituto tão pobre: uma janela móvel implicitamente assume aa e bb que não correspondem em nada a essa estrutura de decaimento.

Algumas notas de implementação que economizam tempo real de depuração:

  • Inicialização. Começar em [0.03, 0.94] reflete a estimativa típica de cripto: aa pequeno (correlações reagem a choques mas não violentamente), bb grande (correlações são persistentes). Se seu otimizador vagar para a+b1a+b \to 1, o processo de correlação está integrado — geralmente um sinal de uma quebra estrutural na amostra (uma mudança de regime que o modelo está se esforçando para ajustar como persistência).
  • Convenção de timing. Dentro do loop pontuamos RtR_t contra ztz_t e depois atualizamos QQ com ztztz_t z_t' para o próximo passo. Isso mantém RtR_t como função apenas da informação até t1t-1 — sem look-ahead. Errar esse deslocamento de um é o bug mais comum do DCC, e ele infla silenciosamente o ajuste in-sample.
  • Targeting de correlação. Inserimos Qˉ\bar{Q} como a correlação amostral em vez de estimá-la. Isso é o que torna a otimização bidimensional. O custo é que Qˉ\bar{Q} usa a amostra completa, então em um walk-forward estrito você deve reestimar isso apenas na janela de treino (veja abaixo).

Passo 3: Reconstruir os caminhos de correlação e covariância

Uma vez que a,ba, b estejam fixos, rode a recursão mais uma vez, desta vez armazenando o caminho completo de RtR_t (e HtH_t) para que estratégias downstream possam usá-lo.

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

A série rho_btc_eth é a recompensa de todo o exercício: em vez de um número, agora você tem uma correlação diária que pode plotar, limitar ou alimentar em uma estratégia. Em dados reais de cripto você tipicamente verá ela variar de aproximadamente 0,5 em períodos tranquilos até acima de 0,9 durante estresse — exatamente o espectro que uma correlação amostral única faz desaparecer na média.

Previsão um passo à frente

Para negociação ao vivo você precisa de Ht+1H_{t+1} um passo à frente a partir da informação disponível agora. O lado da volatilidade vem da previsão de um passo de cada modelo arch; o lado da correlação é mais uma volta da recursão:

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)

Lembre-se de que tudo está em unidades escaladas (×100) porque ajustamos arch em series * 100. Divida as volatilidades por 100 (e as covariâncias por 1002=10,000100^2 = 10{,}000) para voltar às unidades de retorno bruto antes de alimentar uma estratégia. Manter a escala em ordem é tedioso mas uma fonte frequente de bugs silenciosos.

Aplicação 1: Uma Razão de Hedge Dinâmica para Pairs Trading

O par market-neutral clássico — comprado em um ativo, vendido em uma quantidade beta-ponderada de outro — vive ou morre com a razão de hedge β\beta. Estime-a por OLS estático sobre uma janela de treino e você herda exatamente o problema de correlação obsoleta sobre o qual é todo este artigo: o hedge que neutralizou a exposição de mercado no trimestre passado está errado neste trimestre.

O DCC dá a você a razão de hedge como uma série temporal. O hedge de variância mínima da exposição ETH usando BTC é o coeficiente de regressão condicional

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

Cada termo do lado direito é uma saída do DCC. A razão de hedge se move por duas razões distintas, e o DCC as separa de forma limpa: a correlação ρt\rho_t muda (os ativos se acoplam ou desacoplam), e a razão de volatilidade σETH,t/σBTC,t\sigma_{\text{ETH},t}/\sigma_{\text{BTC},t} muda (um ativo fica relativamente mais volátil). Um beta de OLS móvel borra os dois efeitos juntos com um atraso; o DCC os atribui.

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

Alimente o spread no motor de pares que você roda. O hedge dinâmico não cria uma vantagem por si só — ele torna o spread negociado genuinamente market-neutral ao longo do tempo, de modo que seu sinal de reversão à média não seja contaminado por exposição direcional à deriva. Se você constrói estratégias de pares, isso se encaixa diretamente nos frameworks de Arbitragem Estatística e Pairs Trading em Cripto e a abordagem de distância para pares, substituindo sua razão de hedge fixa. A própria série de correlação também é uma entrada mais limpa para um sinal de par baseado em correlação do que qualquer janela móvel — você obtém um ρt\rho_t suavizado e consistente com o modelo em vez de uma estimativa em janela ruidosa.

Duas precauções específicas ao usar βt\beta_t ao vivo. Primeiro, atrase-o — negocie com βt1\beta_{t-1}, nunca o βt\beta_t contemporâneo, ou você estará espiando o futuro. Segundo, uma razão de hedge que oscila todo dia gera turnover e taxas; no mercado 24/7 de cripto com custos de funding na perna vendida, um hedge hiper-reativo pode sangrar mais do que a deriva que corrige. Suavize βt\beta_t (um EWMA, ou rebalanceie o hedge apenas quando ele se move além de uma banda) e dimensione tudo isso com sensatez — dimensionamento de posição a partir de um sinal ruidoso é sua própria disciplina, coberta em dimensionamento pelo critério de Kelly.

Aplicação 2: Variância de Portfólio Variável no Tempo

Para um portfólio com vetor de pesos ww, a variância condicional é

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

Com uma matriz de covariância estática — o padrão de Markowitz — esse número é uma constante que você calculou uma vez e finge que ainda é verdadeira. Não é. O risco de portfólio respira com o mercado, e ele respira mais forte exatamente quando as correlações disparam, porque em um drawdown tanto os termos σi,t\sigma_{i,t} quanto os termos ρij,t\rho_{ij,t} sobem juntos e se multiplicam. Um portfólio que parecia ter 40% de volatilidade anualizada em mercados calmos pode estar rodando 80%+ em uma semana de estresse, e uma matriz de covariância estática dirá a você que nada mudou.

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

Esse σp,t\sigma_{p,t} variável no tempo é a entrada honesta que a alocação baseada em risco precisa. A otimização média-variância (Markowitz para cripto) com uma covariância amostral estática está otimizando contra uma ficção; alimentá-la com HtH_t (ou sua previsão de curto prazo) torna a própria fronteira eficiente variável no tempo e força o otimizador a reduzir risco em regimes de correlação crescente em vez de depois deles. Abordagens de risk-parity e hierárquicas — o pipeline HRP + CVaR — são ainda mais sensíveis à entrada de covariância, já que toda a alocação é uma função da matriz de risco. E se você está comparando alocadores lado a lado, como em algoritmos de otimização de portfólio comparados, se eles consomem covariância estática ou dinâmica costuma ser um fator mais determinante do risco realizado do que a escolha do algoritmo.

A aplicação direta é o targeting de volatilidade de todo o portfólio: escolha uma volatilidade anualizada alvo σ\sigma^{*}, e escale a exposição bruta por σ/σp,t\sigma^{*} / \sigma_{p,t} a cada período para que o risco realizado permaneça aproximadamente constante em vez de disparar em crises. Isso fecha o ciclo com a Parte 4, que constrói e faz backtest exatamente dessa regra.

Aplicação 3: Correlação como Sinal de Regime

Além de hedging e dimensionamento, a matriz de correlação carrega um sinal macro. O escalar único mais útil que você pode extrair é a correlação média entre pares:

ρˉ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 sobe em todo o book, o mercado está entrando em um regime de risk-off — histórias idiossincráticas param de importar e tudo negocia como um único beta macro. Essa é a assinatura quantitativa de "as correlações vão para 1 em uma crise". Ela tende a liderar ou coincidir com drawdowns, o que a torna um indicador de regime utilizável em vez de uma autópsia atrasada.

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)

Você pode usar risk_off como um regulador autônomo (corte exposição bruta, amplie stops, suspenda estratégias de reversão à média que são atropeladas quando tudo tende junto) ou como uma feature em um modelo de regime mais formal. Ele se combina naturalmente com a abordagem de cadeia de Markov oculta em detecção de regime com HMMs: a correlação média do DCC é uma das variáveis de observação mais informativas que você pode entregar a um HMM, porque ela é prospectiva sobre estresse sistêmico de uma forma que os retornos passados não são. A ressalva honesta: correlação crescente informa que a diversificação está falhando, não para qual direção o mercado vai. É um sinal de risco, não um sinal de alfa, e deve ser dimensionado como tal — veja a assimetria entre perdas e lucros para entender por que tratar um regime de risco como uma aposta direcional termina mal.

Considerações Práticas

Estabilidade de estimação e número de ativos

O DCC escala muito melhor que o BEKK, mas "escalar" não é "grátis". A matriz de targeting de correlação Qˉ\bar{Q} é uma correlação amostral d×dd \times d, e matrizes de correlação amostral ficam mal condicionadas conforme dd se aproxima do número de observações. Com 4 ativos e 1000 dias você está bem. Com 60 ativos e 400 dias, Qˉ\bar{Q} está quase singular, sua inversa na verossimilhança explode, e RtR_t pode vagar para não-PD por ruído numérico. Mitigações, aproximadamente na ordem de quanto você vai precisar delas:

  • Aplique shrinkage em Qˉ\bar{Q} em direção a um alvo estruturado (Ledoit-Wolf, ou em direção à identidade / uma matriz de correlação constante) antes de rodar a recursão. Esse é o ajuste de maior alavancagem para books grandes.
  • Agrupe ativos em um punhado de setores (principais, L1s, DeFi, memes), modele dentro e entre no nível setorial, ou rode o DCC em fatores de componentes principais em vez de ativos brutos.
  • Prefira mais dados a mais ativos. O DCC tem um apetite insaciável por um histórico longo, limpo e contemporâneo — que é exatamente o que os tokens mais jovens não têm.

Realisticamente, mantenha o DCC direto a algumas dezenas de ativos no máximo. Para um universo grande, DCC sobre retornos de fatores mais resíduos idiossincráticos é a solução padrão.

O targeting de correlação é um atalho com custo

Fazer targeting de Qˉ\bar{Q} torna a estimação tratável mas embute a correlação incondicional da amostra completa em cada RtR_t. Em um backtest estrito isso é um vazamento de look-ahead: sua matriz de correlação do dia tt "conhece" a correlação média de toda a amostra, incluindo o futuro. Para uma avaliação honesta você deve reestimar Qˉ\bar{Q} apenas na janela de treino e mantê-la fixa fora da amostra, ou rolá-la para frente. Essa é a mesma disciplina que todo o framework de otimização walk-forward impõe, e é fácil de violar acidentalmente com um np.cov(Z) conveniente sobre o array completo — como o nosso código didático acima faz. Corrija isso antes de confiar em um único número de P&L.

Cadência de reajuste e disciplina contra look-ahead

Você não precisa reotimizar a,ba, b todo dia — eles são parâmetros estáveis. Uma cadência de produção sensata:

  • Reestime a,ba, b e os parâmetros GARCH univariados semanalmente ou mensalmente.
  • Rode o filtro (atualize QtQ_t, σi,t\sigma_{i,t}) a cada período com os parâmetros congelados para obter RtR_t e HtH_t atualizados. Filtrar é barato; ajustar não é.
  • Sempre preveja, nunca suavize. Use RtR_t construído a partir de informação até t1t-1 para negociar em tt. A estrutura de dois passos (ajustar em uma janela, depois filtrar para frente) é o que mantém você honesto.

A lacuna entre um backtest do DCC e a performance ao vivo é quase sempre um vazamento de look-ahead — Qˉ\bar{Q} de amostra completa, βt\beta_t contemporâneo, ou reajuste em dados que incluem a operação que você está avaliando. A disciplina de fazer o backtest corresponder às condições ao vivo é um tópico próprio em paridade backtest-ao vivo, e o DCC é um modelo que pune descuido aqui mais do que a maioria. Se, após uma avaliação walk-forward limpa, a correlação dinâmica não adicionar nada sobre uma estimativa móvel simples para sua estratégia, esse é um resultado negativo real e publicável — a mentalidade em resultados negativos honestos se aplica diretamente.

DCC Assimétrico (aDCC)

Assim como o efeito alavancagem univariado (Parte 2) significa que notícias ruins elevam a volatilidade mais do que notícias boas, as correlações sobem mais após choques negativos conjuntos do que após choques positivos conjuntos. Cappiello, Engle & Sheppard (2006) capturam isso com o DCC assimétrico, adicionando um termo guiado pelo produto externo dos resíduos padronizados de 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}

onde Nˉ=1Ttztzt\bar{N} = \frac{1}{T}\sum_t z_t^- z_t^{-\prime} e g0g \ge 0 mede o impulso extra de correlação vindo de movimentos conjuntos de baixa. Para cripto, onde a correlação de crash é o risco dominante, o termo de assimetria costuma ser significativo e vale o parâmetro extra. O rmgarch ajusta o aDCC nativamente (model="aDCC"); adicionar o termo ztz_t^- ao nosso estimador NumPy é um exercício direto.

Comparação: DCC Contra as Alternativas

Onde o DCC se encaixa entre as formas de obter uma matriz de covariância para um book cripto? O resumo honesto:

Abordagem Parâmetros Escala até ρ\rho variável no tempo? PD garantida? Dependência de cauda?
Covariância amostral / móvel 0 (comprimento da janela) qualquer dd grosseiramente (com atraso, ruidosa) não (precisa de remendo) não
EWMA (RiskMetrics) 1 (λ\lambda) qualquer dd sim (decaimento único) sim não
CCC-GARCH dd margens + Qˉ\bar{Q} dezenas não (RR constante) sim não
DCC-GARCH dd margens + 2 dezenas sim sim não
aDCC-GARCH dd margens + 3 dezenas sim, assimétrico sim parcial
BEKK O(d2)O(d^2) 4\le 4 sim (rico) sim não
VECH O(d4)O(d^4) 3\le 3 sim (mais rico) difícil não
GARCH-copula dd margens + cópula dezenas (vines) cópula estática sim sim

Algumas leituras dessa tabela:

  • EWMA é a base barata que todos deveriam superar antes de alegar que o DCC ajuda. É um caso especial de um parâmetro em espírito — um único decaimento exponencial aplicado diretamente à covariância — e para muitos books é surpreendentemente difícil de melhorar out-of-sample. Se o DCC não superar o EWMA em walk-forward limpo, use o EWMA.
  • CCC vs DCC é todo o ponto deste artigo: mesma fatoração, mas o CCC congela RR e o DCC o deixa se mover. Os dois parâmetros extras (a,ba, b) são a diferença inteira, e em cripto eles ganham seu lugar.
  • BEKK/VECH compram dinâmicas mais ricas — cada covariância pode responder a cada choque passado — mas o custo de parâmetros os confina a books minúsculos. Para qualquer coisa além de 4 ativos eles não são uma opção real.
  • GARCH-copula é a única linha com "sim" na dependência de cauda. Essa é a complementaridade de novo: o DCC modela o centro dinâmico da distribuição conjunta, as cópulas modelam suas caudas estáticas. Se sua questão de risco é "o que acontece quando tudo quebra ao mesmo tempo", recorra ao pipeline de cópulas; se é "qual é minha razão de hedge / variância de portfólio agora", recorra ao DCC.

O padrão prático para uma mesa cripto sistemática: DCC (ou aDCC) para razões de hedge e covariância dinâmica no corpo, uma camada de cópula para risco de cauda e CVaR, e EWMA como a linha de base de verificação de sanidade que mantém você honesto sobre se a maquinaria extra está valendo a pena.

Limitações

  • Dinâmica escalar. Um único aa e um único bb para todos os pares é uma restrição forte. BTC-ETH e dois altcoins obscuros compartilham a mesma velocidade de ajuste. O DCC Generalizado relaxa isso mas reintroduz a explosão de parâmetros que o DCC foi projetado para evitar.
  • Perda de eficiência em dois passos. O estimador de quase-verossimilhança é consistente mas não totalmente eficiente, e erros padrão ingênuos estão errados. Use a correção de Engle-Sheppard se você se importa com inferência; para geração de sinal as estimativas pontuais bastam.
  • Caudas Gaussianas por padrão. A quase-verossimilhança Gaussiana simples subestima o risco de cauda conjunto. Inovações Student-t ajudam; para dependência de cauda genuína (a probabilidade de movimentos extremos simultâneos), o DCC é a ferramenta errada e um modelo de cópula é o certo. O DCC dá a você o corpo dinâmico da correlação; cópulas dão a você a cauda estática. Mesas sérias usam ambos.
  • Correlação não é causalidade, nem direção. ρˉt\bar{\rho}_t crescente avisa que a diversificação está falhando; não diz nada sobre a direção do mercado. Não sobrecarregue um sinal de risco com expectativas direcionais.
  • Fome de dados. Tudo acima assume históricos longos, limpos e sincronizados. Os tokens mais novos e interessantes de cripto violam todos os três.

Resumo

  • A correlação estática é uma mentira em cripto. As correlações se agrupam, persistem e disparam em direção a 1 em drawdowns — exatamente quando a diversificação deveria ajudar. Um único ρ^\hat{\rho} amostral tira a média de um processo de mudança de regime em algo sem sentido.
  • O GARCH multivariado completo (VECH, BEKK) não escala. A contagem de parâmetros cresce como O(d2)O(d^2); ambos ficam confinados a um punhado de ativos na prática.
  • O DCC (Engle 2002) fatora o problema: Ht=DtRtDtH_t = D_t R_t D_t, com DtD_t vindo de ajustes GARCH univariados independentes (reutilizando as Partes 1-2) e RtR_t vindo de uma recursão de dois parâmetros. Ele escala para dezenas de ativos porque apenas a,ba, b são otimizados.
  • A recursão Qt=(1ab)Qˉ+azt1zt1+bQt1Q_t = (1-a-b)\bar{Q} + a\,z_{t-1}z_{t-1}' + b\,Q_{t-1}, normalizada para RtR_t, produz uma matriz de correlação definida positiva válida a cada passo, com a,b>0a,b>0, a+b<1a+b<1.
  • O arch não faz DCC. Ajuste as margens com arch, depois implemente o estimador NumPy/SciPy de ~60 linhas aqui, ou use mgarch (Python) ou rmgarch (R, a referência).
  • Três retornos concretos: uma razão de hedge dinâmica βt=ρtσETH,t/σBTC,t\beta_t = \rho_t\,\sigma_{\text{ETH},t}/\sigma_{\text{BTC},t} para pairs trading; uma variância de portfólio honesta e variável no tempo wHtww'H_t w para alocação baseada em risco; e a correlação média entre pares como sinal de regime risk-off.
  • A disciplina é tudo. O targeting de correlação vaza a média da amostra completa, então reestime Qˉ\bar{Q} apenas nos dados de treino; atrase toda razão de hedge; filtre para frente, nunca suavize. A avaliação walk-forward é inegociável.
  • O aDCC adiciona um termo de assimetria de baixa e geralmente vale a pena em cripto, onde a correlação de crash domina.
  • A Parte 4 usa essas previsões para construir e fazer backtest de uma estratégia com targeting de volatilidade.

Referências:

  • 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.
blog.disclaimer

MarketMaker.cc Team

Quantitative Research & Strategy

Discuss in Telegram
Newsletter

Fique à frente do mercado

Assine nossa newsletter para insights exclusivos sobre trading com IA, análises de mercado e atualizações da plataforma.

Respeitamos sua privacidade. Cancele a inscrição a qualquer momento.