GARCH Assimétrico e de Caudas Pesadas: EGARCH, GJR e Student-t
Na Parte 1 desta série construímos o GARCH(1,1) do zero: a intuição do agrupamento de volatilidade (volatility clustering), a recursão da variância condicional, a estimação por máxima verossimilhança, a previsão e os diagnósticos de resíduos padrão com a biblioteca arch. Se ainda não leu, comece por lá — este texto assume que você já sabe ajustar e interpretar um GARCH(1,1) simples e não vai rederivar o básico.
O GARCH(1,1) simples é uma boa linha de base e uma má resposta final. Ele tem dois defeitos estruturais que são baratos de ignorar num backtest e caros de ignorar com capital real. Primeiro, ele é simétrico: o modelo reage a um dia de exatamente como reage a um dia de , porque o choque entra na recursão da variância apenas através do seu quadrado, . Elevar ao quadrado descarta o sinal. Segundo, ele assume inovações gaussianas: mesmo depois de o GARCH absorver o agrupamento de volatilidade, os resíduos padronizados de BTC e ETH são visivelmente caududos (fat-tailed), e uma verossimilhança gaussiana sistematicamente subprecifica a cauda. Um VaR de 99% de um GARCH(1,1)-Normal será violado muito mais do que 1% das vezes.
Este texto corrige os dois defeitos. Adicionamos assimetria com GJR-GARCH e EGARCH, e caudas pesadas com inovações Student- e skew- de Hansen. Depois fazemos aquilo que de fato paga as contas: transformar a distribuição condicional ajustada numa previsão de Value-at-Risk e Expected Shortfall de um passo à frente, e fazer o backtest dessa previsão de forma honesta com os testes de Kupiec e Christoffersen. Um modelo de volatilidade que você nunca testa em termos de risco é decoração.
O Efeito Alavancagem, e Por Que Cripto É Mais Confuso
Em ações, a assimetria tem nome e história. O efeito alavancagem (leverage effect) (Black, 1976): quando o preço de uma ação cai, sua razão dívida/capital próprio sobe, o capital próprio torna-se mecanicamente mais arriscado, e a volatilidade aumenta. Más notícias elevam a volatilidade futura mais do que boas notícias de magnitude equivalente. Empiricamente, este é um dos fatos estilizados mais robustos da literatura de volatilidade em ações.
Cripto não tem capital próprio nem alavancagem de balanço no sentido corporativo, mas uma assimetria semelhante ao efeito alavancagem ainda aparece na maior parte do tempo — impulsionada por desalavancagem forçada em vez de contabilidade. Quando o BTC cai fortemente, empréstimos sobrecolateralizados são liquidados, posições compradas em futuros perpétuos são fechadas à força, o funding se inverte, e a cascata alimenta a volatilidade. Assim, o mecanismo difere, mas o sinal frequentemente concorda com o das ações: movimentos de queda disparam mais volatilidade.
A ressalva importante: cripto é mais confuso, e você deve tratar a assimetria como uma questão empírica, não como uma lei. Movimentos de alta violentos — short squeezes, um rally alimentado por alavancagem, um gap de aprovação de ETF — também podem disparar a volatilidade realizada. Dependendo do ativo e da janela amostral, a assimetria estimada pode ser forte, fraca, ou ocasionalmente ter o sinal "errado". A disciplina que este texto exige: ajuste o modelo assimétrico, veja se o parâmetro de assimetria é estatisticamente significativo e na direção esperada, e só mantenha o parâmetro extra se ele justificar seu lugar. Não presuma que a história das ações se transfere; teste-a.
Testando a Assimetria Antes de Modelá-la
O argumento acima diz "trate a assimetria como empírica" — então, antes de ajustar um modelo assimétrico, execute um teste formal barato para saber se a assimetria sequer está presente. Os testes de sign-bias de Engle-Ng (1993) fazem exatamente isso. Ajuste primeiro um GARCH(1,1) simétrico, pegue seus resíduos padronizados ao quadrado , e faça a regressão deles sobre indicadores do sinal e do tamanho do choque anterior:
onde e . A lógica: se o modelo simétrico já capturou tudo, o sinal e o tamanho do choque de ontem não devem prever o resíduo ao quadrado de hoje, logo . Os testes individuais são o sign-bias (), o negative-size-bias () e o positive-size-bias (); um teste conjunto sobre os três é o omnibus. Um ou significativo indica que choques negativos são sistematicamente mal precificados pelo modelo simétrico — seu indicativo de que GJR ou EGARCH vão ajudar.
import statsmodels.api as sm
def sign_bias_test(symmetric_res):
"""Engle-Ng sign-bias tests on a fitted symmetric GARCH result."""
z = symmetric_res.std_resid.dropna()
z2 = (z ** 2).values[1:]
eps_lag = z.values[:-1] # standardized shock proxy
neg = (eps_lag < 0).astype(float)
X = np.column_stack([
np.ones_like(eps_lag), # intercept
neg, # sign bias
neg * eps_lag, # negative size bias
(1 - neg) * eps_lag, # positive size bias
])
ols = sm.OLS(z2, X).fit()
names = ["const", "sign_bias", "neg_size_bias", "pos_size_bias"]
for nm, coef, t, p in zip(names, ols.params, ols.tvalues, ols.pvalues):
print(f"{nm:16s} coef={coef:+.4f} t={t:+.2f} p={p:.3f}")
print(f"Joint F p-value: {ols.f_pvalue:.4f}")
return ols
sign_bias_test(models["GARCH-N"])
Se o teste conjunto for insignificante, você tem licença empírica para permanecer simétrico e economizar dois parâmetros. Se for significativo — o resultado comum para BTC/ETH —, prossiga para GJR/EGARCH com a consciência tranquila, sabendo que está modelando uma característica real e não perseguindo ruído. Esta é a disciplina empírica que a introdução exigiu: não presuma a história de alavancagem das ações, teste-a.
GJR-GARCH: Assimetria via um Termo de Limiar
O modelo de Glosten-Jagannathan-Runkle (1993) — por vezes chamado TGARCH ou threshold GARCH — é a menor edição possível ao GARCH(1,1) que permite que boas e más notícias tenham efeitos diferentes. Relembre a recursão simétrica de variância condicional da Parte 1:
O GJR adiciona um termo de limiar: uma dose extra de variância que se ativa apenas após um choque negativo.
onde é o indicador
Leia a recursão por casos. Após um choque positivo (), o indicador é zero e o impacto do choque ao quadrado sobre a variância do próximo período é apenas . Após um choque negativo, o indicador é um e o impacto é . O parâmetro é toda a história da assimetria num único número:
- : choques negativos elevam a volatilidade mais do que choques positivos de magnitude igual. Este é o efeito alavancagem, e é o que se espera encontrar em BTC/ETH na maior parte do tempo.
- : o modelo colapsa de volta ao GARCH(1,1) simétrico. Um teste de razão de verossimilhança ou teste sobre é, portanto, um teste direto de se a assimetria existe.
- : choques positivos elevam mais a volatilidade — o regime ocasional de rally cripto. Raro, mas não descarte a priori.
Positividade e Estacionariedade
Como ainda é construída de forma aditiva, precisamos que cada termo permaneça não negativo. As condições de positividade suficientes são
Note que o próprio pode ser negativo desde que , de modo que o impacto pós-má-notícia nunca fica negativo.
Para a estacionariedade em covariância, assuma que as inovações são padronizadas com uma distribuição simétrica em torno de zero, de modo que e o indicador contribui com em média. A condição de estacionariedade torna-se
A variância incondicional (de longo prazo) é então
Este é o análogo GJR do resultado da Parte 1 , com o termo extra contabilizando a contribuição média da meia-vida da alavancagem. Se sua distribuição de inovações for assimétrica (skew- de Hansen, abaixo), o é substituído pela probabilidade real de , mas é a referência padrão usada para a persistência reportada.
EGARCH: Modelando o log-Variância, Sem Restrições de Positividade
O GJR mantém você dentro de uma camisa de força de positividade da variância: toda combinação de parâmetros precisa ser verificada contra restrições de desigualdade, o que é irritante durante a otimização e pior ainda durante a reestimação em janela móvel, quando uma janela ocasionalmente entra numa região inviável. O Exponential GARCH de Nelson (1991) contorna isso completamente ao modelar o logaritmo da variância condicional. Como pode ser qualquer número real, é automaticamente positivo independentemente dos parâmetros. Nenhuma restrição a impor.
Escreva a recursão em termos da inovação padronizada :
Dois termos carregam o choque, e separá-los é a ideia central:
- O termo de magnitude responde ao tamanho do choque, sem o sinal. Subtrair o centra de modo que um choque de magnitude média não contribua com nada. Para uma normal padrão, ; para uma Student- padronizada o valor absoluto esperado é menor e depende de , mas o
archcuida disso internamente. - O termo de sinal é a assimetria. É linear na inovação com sinal, de modo que um negativo empurra na direção oposta a um positivo.
A convenção de sinal importa e costuma confundir. Nesta parametrização, o efeito alavancagem (más notícias elevam a volatilidade) corresponde a : um choque negativo então torna , aumentando o log-variância. Este é o sinal oposto ao do GJR. Sempre consulte a documentação do próprio modelo quanto à convenção em vez de presumir; o arch reporta o EGARCH com seu próprio sinal, e verificamos isso contra uma curva de impacto de notícias mais abaixo, em vez de confiar na memória.
Como tudo é aditivo em logaritmos, a persistência de um EGARCH(1,1) é governada pelo único coeficiente autorregressivo sobre ; a estacionariedade exige apenas . Essa é uma condição muito mais limpa do que a desigualdade do GJR, e é uma vantagem prática real quando você reajusta em janelas móveis.
Uma sutileza que vale a pena declarar: a resposta do EGARCH a choques é exponencial na inovação (você exponencia no final), enquanto o GJR é quadrático. O EGARCH, portanto, reage mais violentamente a choques grandes — uma característica útil em cripto, onde os eventos de cauda são os que importam, mas também uma razão pela qual o EGARCH pode ocasionalmente produzir previsões de variância implausivelmente grandes após um dia atípico. Nenhum é universalmente melhor; a escolha se faz pelo ajuste fora da amostra e por backtests de risco, que é o propósito de toda esta série.
A Curva de Impacto de Notícias
A forma mais limpa de ver a diferença entre GARCH simétrico, GJR e EGARCH é a curva de impacto de notícias (news impact curve) (Engle e Ng, 1993): mantenha fixo em seu nível de longo prazo e plote a variância condicional do próximo período em função do último choque . Ela responde a: "dado um choque deste tamanho e sinal, quanto o modelo eleva a volatilidade de amanhã?"
- O GARCH simétrico produz uma parábola simétrica centrada em zero. Um choque de e um de caem na mesma altura. Este é precisamente o defeito que estamos corrigindo.
- O GJR produz uma parábola com uma quebra em zero — mais íngreme à esquerda (choques negativos) do que à direita quando . As duas metades têm curvatura e , respectivamente.
- O EGARCH produz um V assimétrico e exponencial: os dois braços têm inclinações diferentes por causa do termo , e o conjunto se curva para cima mais rápido do que uma parábola por causa da exponenciação final.
Plotamos os três a partir dos parâmetros ajustados mais adiante, na seção de implementação — é o diagnóstico mais útil para comunicar o que a assimetria compra.
Caudas Pesadas: Inovações Student-t e Skew-t
A assimetria corrige a resposta do modelo ao sinal dos choques. Ela nada faz sobre a distribuição dos choques em si. O GARCH simples assume , e essa suposição é quase sempre errada para cripto. Mesmo depois de o GARCH remover o agrupamento de volatilidade, os resíduos padronizados mantêm curtose excessiva — são caududos. Uma verossimilhança gaussiana, ajustando-se aos ombros da distribuição, subestima a frequência com que um dia padronizado de , ou sigmas realmente ocorre.
A consequência para o risco é direta. Um VaR gaussiano de 99% usa o quantil , então prevê . Se a verdadeira distribuição padronizada for Student- com, digamos, graus de liberdade, o verdadeiro quantil de 1% está próximo de — o VaR gaussiano é otimista em cerca de nesse nível de confiança. Você o violará muito mais do que 1% das vezes e será sistematicamente surpreendido por dias "impossíveis". Isto não é uma peculiaridade de cripto; Bollerslev (1987) introduziu o -GARCH precisamente porque os resíduos de ações e câmbio mostravam as mesmas caudas pesadas. Cripto é apenas uma versão mais extrema do mesmo problema.
Student-t Padronizada
A densidade Student- tem um parâmetro de graus de liberdade que controla a espessura da cauda: pequeno significa caudas pesadas, e conforme a converge para a gaussiana. O detalhe é que a distribuição bruta tem variância , então precisamos padronizá-la para variância unitária antes de usá-la como inovação — caso contrário, o "" na recursão GARCH não seria de fato o desvio padrão condicional.
A inovação Student- padronizada com variância unitária tem densidade
Note o dentro — essa é a padronização, reescalando de modo que . A contribuição de log-verossimilhança de uma observação, dada a variância condicional GARCH e , é
O termo é o Jacobiano da transformação de para — o mesmo termo que você viu na verossimilhança GARCH gaussiana da Parte 1. Só a forma muda. Maximizar conjuntamente sobre os parâmetros GARCH e é exatamente o que o arch faz quando você passa dist='t'.
O estimado é ele próprio informativo. Para retornos diários de BTC/ETH, tipicamente você chega à faixa — caudas pesadas, mas com variância finita (o que exige ) e geralmente curtose finita (o que exige ). Se seu ajustado cair abaixo de 4, esteja ciente de que a curtose amostral é tecnicamente infinita no modelo e alguns estimadores ficam instáveis; é um sinal para examinar de perto outliers e a qualidade dos dados.
Skew-t de Hansen
A Student- é caudada mas ainda simétrica — as caudas esquerda e direita são igualmente pesadas. Os resíduos de retorno de cripto costumam ser também assimétricos: a cauda esquerda (crashes) é mais pesada que a direita. A skew- de Hansen (1994) generaliza a padronizada com um parâmetro de assimetria ao lado de :
onde as constantes , , e são escolhidas de modo que tenha média zero e variância unitária para todo válido. A distribuição se divide em , usando um escalonamento diferente em cada parte para dobrar mais massa para uma cauda.
Interpretação: dá uma distribuição assimétrica à esquerda (queda mais pesada), que é o resultado usual para cripto e o que se esperaria emparelhar com um efeito alavancagem. recupera a Student- simétrica, então um teste de diz se o termo de assimetria está comprando algo. No arch isso é dist='skewt', que estima tanto quanto . O ganho é um VaR cujo quantil da cauda esquerda é honestamente mais pesado que o da cauda direita — exatamente o que se quer quando as perdas que você está tentando sobreviver são assimétricas. Isso se conecta diretamente com a assimetria entre perda e lucro em resultados de posições: um drawdown de precisa de mais do que para se recuperar, então modelar mal a cauda esquerda é mais custoso do que modelar mal a direita.
Implementação em Python
Agora ajustamos tudo isso com a biblioteca arch. A configuração espelha a Parte 1: buscar retornos diários, escalar por 100 para condicionamento numérico (os otimizadores GARCH se comportam mal quando os retornos são ), e ajustar com uma média constante. Se você quiser intraday ou um modelo de média diferente, a maquinaria é idêntica.
Configuração e Dados
import numpy as np
import pandas as pd
from arch import arch_model
from arch.univariate import GARCH, EGARCH, ConstantMean, StudentsT, SkewStudent
from scipy import stats
def fetch_returns(symbol="BTC-USD", start="2019-01-01", end="2025-12-31"):
"""Daily log returns, in percent (scaled x100 for the optimizer)."""
import yfinance as yf
px = yf.download(symbol, start=start, end=end)["Close"].dropna()
ret = 100.0 * np.log(px / px.shift(1)).dropna()
ret.name = symbol
return ret
r = fetch_returns("BTC-USD")
print(f"{len(r)} daily observations, "
f"annualized vol ~ {r.std() * np.sqrt(365):.0f}%")
Cripto negocia 24/7, então anualizamos com 365, não 252 — uma fonte pequena mas recorrente de confusão quando você compara um Sharpe ou vol de cripto com os números de uma mesa de ações.
Ajustando Quatro Modelos
O padrão no arch: vol='Garch' com p=1, q=1 é GARCH simétrico; adicionar o=1 ativa o termo de limiar GJR; vol='EGARCH' muda para o modelo de log-variância. A distribuição de inovações é definida com dist: 'normal', 't', 'skewt'.
def fit(returns, vol="Garch", p=1, o=0, q=1, dist="normal"):
am = arch_model(returns, mean="Constant",
vol=vol, p=p, o=o, q=q, dist=dist)
res = am.fit(disp="off")
return res
models = {
"GARCH-N": fit(r, vol="Garch", o=0, dist="normal"), # Part 1 baseline
"GJR-t": fit(r, vol="Garch", o=1, dist="t"), # asymmetry + fat tails
"EGARCH-t": fit(r, vol="EGARCH", o=1, dist="t"), # log-variance asymmetry
"GJR-skewt": fit(r, vol="Garch", o=1, dist="skewt"), # + skew
}
for name, res in models.items():
print(f"\n===== {name} =====")
print(res.summary().tables[1]) # parameter table
Para vol='EGARCH', o argumento o controla o termo assimétrico () e p/q controlam os termos de magnitude e defasagem; o=1, p=1, q=1 é o EGARCH(1,1) padrão. Um detalhe: os nomes de parâmetros do EGARCH no arch são as mesmas letras, mas a convenção de sinal no termo de assimetria é a de Nelson, de modo que uma estimativa negativa é o efeito alavancagem. Verificamos isso a partir da curva de impacto de notícias em vez de confiar na memória.
Interpretando o Ajuste GJR
Uma tabela de parâmetros GJR- se parece aproximadamente com isto (valores ilustrativos, não um experimento reportado — reajuste com seus próprios dados):
coef std err t P>|t|
omega 0.0480 0.017 2.82 0.005
alpha[1] 0.0620 0.018 3.44 0.001
gamma[1] 0.0910 0.028 3.25 0.001
beta[1] 0.8850 0.021 42.1 0.000
nu 4.30 0.55 7.82 0.000
Como interpretar:
gamma[1] = 0.091com uma estatística acima de 3 é um efeito alavancagem estatisticamente significativo. Após um choque negativo, o impacto do choque ao quadrado é ; após um choque positivo é apenas . Más notícias movem a volatilidade deste modelo cerca de mais do que boas notícias de tamanho igual.nu = 4.3confirma caudas pesadas — longe da gaussiana (), e baixo o suficiente para que o quarto momento seja mal finito. Um VaR gaussiano nesta série seria mal otimista.- A persistência é — muito alta, como de costume para cripto diário: choques decaem lentamente e a volatilidade é fortemente agrupada.
A linha mais importante a verificar é a linha do . Se seu valor- for grande, o termo assimétrico não está justificando seu lugar nesse ativo e nessa janela, e você deve preferir o modelo simétrico mais simples. Esta é disciplina de seleção de modelo, não decoração — mais sobre isso abaixo.
Comparando Modelos por Critérios de Informação
A log-verossimilhança sempre melhora quando você adiciona parâmetros, então você não pode selecionar apenas com base na log-verossimilhança. Use AIC/BIC, que penalizam o número de parâmetros (o BIC mais agressivamente):
def compare(models: dict) -> pd.DataFrame:
rows = []
for name, res in models.items():
rows.append({
"model": name,
"n_params": len(res.params),
"loglik": res.loglikelihood,
"AIC": res.aic,
"BIC": res.bic,
})
df = pd.DataFrame(rows).set_index("model")
return df.sort_values("BIC")
print(compare(models))
Regras práticas de interpretação: uma melhoria de BIC de mais de ~6 sobre a linha de base é forte evidência de que a estrutura extra é real; uma diferença de 1–2 é ruído. Se GJR-t supera GARCH-N em 30+ pontos de BIC mas GJR-skewt supera GJR-t em apenas 1, mantenha a e descarte a assimetria — o parâmetro de assimetria não está se pagando com esses dados. Não leia AIC/BIC como substituto de validação fora da amostra; eles recompensam o ajuste dentro da amostra ajustado pela complexidade, o que é necessário mas não suficiente. O teste real é o backtest de VaR e, em última instância, a avaliação walk-forward.
Plotando a Curva de Impacto de Notícias
Este é o gráfico que compensa — ele torna a assimetria visível e verifica a convenção de sinal do EGARCH.
import matplotlib.pyplot as plt
def news_impact_curve(res, shock_grid):
"""
Next-period conditional variance as a function of the last shock,
holding sigma_{t-1} at the model's unconditional level.
Works for symmetric GARCH, GJR (o=1), and EGARCH.
"""
p = res.params
vol_name = res.model.volatility.__class__.__name__
sigma2_bar = np.mean(res.conditional_volatility ** 2)
omega = p["omega"]
alpha = p.get("alpha[1]", 0.0)
gamma = p.get("gamma[1]", 0.0)
beta = p.get("beta[1]", 0.0)
if vol_name == "EGARCH":
sig_prev = np.sqrt(sigma2_bar)
z = shock_grid / sig_prev
E_abs = np.sqrt(2 / np.pi) # approx; arch uses the fitted dist's E|z|
log_s2 = (omega + beta * np.log(sigma2_bar)
+ alpha * (np.abs(z) - E_abs) + gamma * z)
return np.exp(log_s2)
else:
ind = (shock_grid < 0).astype(float)
return omega + (alpha + gamma * ind) * shock_grid**2 + beta * sigma2_bar
shocks = np.linspace(-8, 8, 401) # daily % shocks
plt.figure(figsize=(8, 5))
for name in ["GARCH-N", "GJR-t", "EGARCH-t"]:
nic = news_impact_curve(models[name], shocks)
plt.plot(shocks, nic, label=name, lw=2)
plt.axvline(0, color="gray", lw=0.8, ls="--")
plt.xlabel("Last shock $\\varepsilon_{t-1}$ (daily %)")
plt.ylabel("Next-period conditional variance $\\sigma_t^2$")
plt.title("News impact curve: symmetric vs GJR vs EGARCH (BTC)")
plt.legend()
plt.tight_layout()
Ao rodar isto, a curva simétrica GARCH-N é uma parábola limpa centrada em zero — um choque de e um de dão variância idêntica. GJR-t é uma parábola com uma quebra na origem, mais alta no braço esquerdo. EGARCH-t é o V exponencial, e se seu braço esquerdo fica acima do direito você confirmou o efeito alavancagem e a convenção de sinal num único olhar. Se o braço esquerdo do EGARCH ficar abaixo do direito, ou foi estimado positivo (um regime de alta volatilidade) ou você tem o sinal invertido — o gráfico diz qual sem qualquer suposição.
Uma Comparação Lado a Lado dos Quatro Modelos
Antes de passarmos para risco, ajuda colocar os quatro modelos lado a lado. Cada linha é uma decisão de design, e as colunas mostram o que essa decisão custa e compra.
| Propriedade | GARCH-N | GJR-t | EGARCH-t | GJR-skewt |
|---|---|---|---|---|
| Assimetria (sinal do choque) | nenhuma | limiar | com sinal | limiar |
| Forma da cauda da inovação | Gaussiana | Student- | Student- | skew- |
| Assimetria na inovação | não | não | não | sim () |
| Restrições de positividade | sim | sim () | nenhuma (forma log) | sim |
| Condição de estacionariedade | ||||
| Parâmetros extras vs. linha de base | 0 | |||
| Veredito típico em cripto | falha no backtest de VaR | forte, robusto | forte, robusto | marginal sobre GJR-t |
O padrão a internalizar: o salto da coluna 1 para a coluna 2 — adicionar assimetria e caudas pesadas de uma vez — é onde vive quase toda a melhoria na calibração de risco. Os refinamentos subsequentes (a forma funcional do EGARCH, o termo de assimetria) são reais, mas de segunda ordem, e em muitas séries de cripto estão dentro do ruído. Gaste seu orçamento de modelagem no primeiro salto e seja cético quanto ao resto.
Aplicação de Risco: VaR e Expected Shortfall
Ajustar um modelo de volatilidade mais sofisticado só vale a pena se melhora uma decisão. A decisão mais limpa de melhorar é a previsão de risco de cauda de um passo à frente: quão ruim pode ser amanhã? Produzimos um Value-at-Risk e uma Expected Shortfall (também conhecida como CVaR, que o pipeline de portfólio HRP/CVaR usa como objetivo) de um dia à frente diretamente da previsão GARCH-/skew- ajustada.
Da Distribuição Condicional ao VaR
A maquinaria GARCH fornece uma previsão de um passo à frente para a média condicional e o desvio padrão condicional . O retorno é modelado como com extraído da distribuição padronizada ajustada (Gaussiana, , ou skew-). Assim, o quantil- do retorno é apenas uma transformação afim do quantil- da distribuição padronizada:
onde é o quantil (inverso da CDF) da inovação padronizada e o sinal negativo à frente segue a convenção de que o VaR é um número de perda positivo. Para um VaR de 99%, e você insere . Todo o benefício da /skew- aparece aqui: é mais negativo do que o gaussiano , então o VaR é honestamente maior.
Expected Shortfall
O VaR diz o limiar; nada diz sobre quão ruim é a violação quando ela ocorre. A Expected Shortfall — a perda média condicional a exceder o VaR — diz, e é coerente (subaditiva), motivo pelo qual é a medida de risco por trás da otimização CVaR e pelo qual o Basileia migrou para ela. Para um modelo de locação-escala,
O termo de expectativa condicional na cauda tem formas fechadas para as distribuições padrão. Para a Gaussiana, com ,
onde é a densidade normal padrão. Para a Student- padronizada com graus de liberdade e (na escala padronizada), a expectativa de cauda é
onde é a densidade padronizada. A Expected Shortfall da excede a gaussiana por mais do que o VaR excede, porque a cauda da não é apenas mais distante — é mais pesada, então a perda média além do limiar é desproporcionalmente grande. Essa lacuna extra é o número que um modelo gaussiano esconde de você.
Calculando VaR e ES a partir de um Modelo arch Ajustado
As distribuições do arch expõem um método ppf (quantil), então podemos obter o quantil padronizado diretamente e evitar rederivar qualquer coisa. Para a ES integramos numericamente, o que é robusto e funciona uniformemente entre normal/t/skewt.
from scipy import integrate
def var_es_forecast(res, alpha=0.99):
"""
One-step-ahead VaR and ES at level alpha, on the same (x100) scale
as the returns fed to the model. Divide by 100 for fractional units.
"""
fc = res.forecast(horizon=1, reindex=False)
mu = fc.mean.iloc[-1, 0]
sigma = np.sqrt(fc.variance.iloc[-1, 0])
dist = res.model.distribution # StudentsT / SkewStudent / Normal
dp = [res.params[k] for k in res.params.index
if k in ("nu", "eta", "lambda", "lam")]
z_q = dist.ppf(1 - alpha, dp) if dp else dist.ppf(1 - alpha)
z_q = float(np.atleast_1d(z_q)[0])
def pdf(z):
arr = np.atleast_1d(z).astype(float)
lp = dist.loglikelihood(dp, arr, np.ones_like(arr), individual=True) \
if dp else dist.loglikelihood([], arr, np.ones_like(arr),
individual=True)
return np.exp(lp)
num, _ = integrate.quad(lambda z: z * pdf(z), -30, z_q, limit=200)
es_z = num / (1 - alpha) # E[z | z <= z_q]
var = -(mu + sigma * z_q)
es = -(mu + sigma * es_z)
return {"mu": mu, "sigma": sigma, "z_q": z_q,
"VaR": var, "ES": es}
for name in ["GARCH-N", "GJR-t", "GJR-skewt"]:
out = var_es_forecast(models[name], alpha=0.99)
print(f"{name:11s} sigma={out['sigma']:.2f}% "
f"z_q={out['z_q']:+.2f} "
f"VaR99={out['VaR']:.2f}% ES99={out['ES']:.2f}%")
A coluna z_q é toda a história num único número. O modelo gaussiano usa ; a com usa algo próximo de ; a skew- empurra o quantil esquerdo ainda mais para fora enquanto puxa o direito para dentro. Mesmo , VaR materialmente maior. Se você tem rodado VaR gaussiano em cripto, esta é a lacuna que você tem absorvido silenciosamente.
Um Passo vs. Múltiplos Passos: Uma Ressalva
Tudo acima é uma previsão de um dia à frente, e é aí que o VaR GARCH é mais limpo. Duas coisas complicam horizontes mais longos e você deve conhecê-las antes de extrapolar.
Primeiro, as previsões de variância revertem à média. A variância condicional passos à frente de um GARCH estacionário converge para o nível incondicional conforme cresce, e a variância cumulativa de dias é a soma das previsões por passo — ela não é a menos que a volatilidade esteja em sua média de longo prazo. O escalonamento ingênuo "raiz-quadrada-do-tempo" ignora essa reversão à média e está errado precisamente após um choque, quando você mais precisa do número. Use a trajetória de variância multi-passo do próprio modelo.
Segundo, a distribuição de um retorno multi-dias não tem a mesma forma da inovação de um dia. Somar vários choques diários distribuídos como (através da recursão GARCH não linear) não dá uma distribuição no horizonte de dias; não há forma fechada limpa. Para o VaR multi-dias, o caminho honesto é a simulação: extraia trajetórias de inovação da distribuição padronizada ajustada, passe-as pela recursão GARCH para obter trajetórias de retorno simuladas, agregue em retornos de dias, e leia o quantil empírico. Isso também trata naturalmente o caso skew-, onde não existe absolutamente nenhum quantil analítico multi-horizonte. As fórmulas analíticas de um passo neste texto são exatas; trate qualquer atalho multi-passo como uma aproximação a validar.
Backtest de VaR: Kupiec e Christoffersen
Uma previsão de VaR é uma afirmação probabilística: "a perda excederá este limiar em apenas dos dias." Você a testa contando as violações (dias em que a perda realizada excedeu o VaR previsto) ao longo de uma avaliação walk-forward e verificando duas coisas. Primeiro, a taxa de violação está correta? Segundo, as violações são independentes, ou se agrupam (o que significa que o modelo falha exatamente quando importa, durante picos de volatilidade)?
Seja a sequência de violação, o número de violações ao longo de dias, e a taxa observada. Taxa alvo .
O teste de cobertura incondicional de Kupiec (1995) verifica via uma razão de verossimilhança:
O teste de independência de Christoffersen (1998) verifica que uma violação hoje não é prevista por uma violação ontem. Seja a contagem de transições do estado para o estado na sequência de violação, , , e . Então
Os dois se combinam no teste de cobertura condicional , que verifica simultaneamente taxa correta e independência. Um modelo pode passar em Kupiec (número correto de violações) mas falhar em Christoffersen (todas se agruparam numa única semana de crash) — esse é o modo de falha que você mais quer capturar, porque violações agrupadas são as que explodem uma conta.
from scipy.stats import chi2
def var_backtest(losses, var, p):
"""
losses, var: 1D arrays, same length; loss>0 is a loss, var>0 threshold.
p = 1 - alpha (target violation rate, e.g. 0.01 for 99% VaR).
Returns Kupiec, Christoffersen-independence, and conditional-coverage LR.
"""
losses = np.asarray(losses)
var = np.asarray(var)
I = (losses > var).astype(int) # violation indicators
T = len(I)
N = int(I.sum())
pi_hat = N / T
eps = 1e-12
ll_null = N * np.log(p + eps) + (T - N) * np.log(1 - p + eps)
ll_alt = N * np.log(pi_hat + eps) + (T - N) * np.log(1 - pi_hat + eps)
LR_uc = -2 * (ll_null - ll_alt)
p_uc = 1 - chi2.cdf(LR_uc, df=1)
n00 = np.sum((I[:-1] == 0) & (I[1:] == 0))
n01 = np.sum((I[:-1] == 0) & (I[1:] == 1))
n10 = np.sum((I[:-1] == 1) & (I[1:] == 0))
n11 = np.sum((I[:-1] == 1) & (I[1:] == 1))
pi01 = n01 / (n00 + n01) if (n00 + n01) else 0.0
pi11 = n11 / (n10 + n11) if (n10 + n11) else 0.0
pi = (n01 + n11) / (n00 + n01 + n10 + n11)
def _ll(pi01, pi11, pi_pooled, use_pooled):
if use_pooled:
a = (n00 + n10) * np.log(1 - pi_pooled + eps)
b = (n01 + n11) * np.log(pi_pooled + eps)
return a + b
return (n00 * np.log(1 - pi01 + eps) + n01 * np.log(pi01 + eps)
+ n10 * np.log(1 - pi11 + eps) + n11 * np.log(pi11 + eps))
LR_ind = -2 * (_ll(pi01, pi11, pi, True) - _ll(pi01, pi11, pi, False))
p_ind = 1 - chi2.cdf(LR_ind, df=1)
LR_cc = LR_uc + LR_ind
p_cc = 1 - chi2.cdf(LR_cc, df=2)
return {
"T": T, "violations": N,
"obs_rate": pi_hat, "target_rate": p,
"LR_uc": LR_uc, "p_uc": p_uc,
"LR_ind": LR_ind, "p_ind": p_ind,
"LR_cc": LR_cc, "p_cc": p_cc,
}
Para gerar as entradas losses/var de forma honesta, você reajusta (ou pelo menos reprevê) numa janela expansiva ou móvel e registra o VaR de um passo à frente para cada dia fora da amostra, depois compara com a perda realizada naquele dia. Nunca faça backtest de VaR dentro da amostra — um modelo ajustado no mesmo crash que está sendo pedido a prever parecerá muito melhor do que realmente é. Esta é a mesma disciplina da paridade backtest-ao vivo: a avaliação deve usar apenas informação disponível no momento da decisão.
def walk_forward_var(returns, alpha=0.99, start=750, refit_every=25,
vol="Garch", o=1, dist="t"):
"""
Expanding-window one-step VaR. Refit every `refit_every` days
(refitting daily is correct but slow; every ~25 days is a common
compromise -- validate the shortcut on your data).
"""
losses, vars_ = [], []
res = None
for t in range(start, len(returns)):
if res is None or (t - start) % refit_every == 0:
am = arch_model(returns.iloc[:t], mean="Constant",
vol=vol, p=1, o=o, q=1, dist=dist)
res = am.fit(disp="off")
fc = res.forecast(horizon=1, reindex=False)
mu = fc.mean.iloc[-1, 0]
sig = np.sqrt(fc.variance.iloc[-1, 0])
dp = [res.params[k] for k in res.params.index
if k in ("nu", "eta", "lambda", "lam")]
z_q = float(np.atleast_1d(
res.model.distribution.ppf(1 - alpha, dp) if dp
else res.model.distribution.ppf(1 - alpha))[0])
var_t = -(mu + sig * z_q)
vars_.append(var_t)
losses.append(-returns.iloc[t]) # realized loss for that day
return np.array(losses), np.array(vars_)
losses, vars_ = walk_forward_var(r, alpha=0.99, dist="t")
print(var_backtest(losses, vars_, p=0.01))
A leitura: um VaR de 99% bem calibrado mostra uma taxa observada próxima de 1%, um Kupiec não significativo (p_uc grande), e um Christoffersen não significativo (p_ind grande) — sem agrupamento. Na prática, o resultado honesto em cripto é que o GARCH-Normal falha em Kupiec (violações demais, p_uc minúsculo) enquanto GJR- ou EGARCH- passa ou chega perto. Esse contraste é todo o argumento deste texto transformado em teste de hipótese. Se mesmo o modelo mostra violações agrupadas (p_ind pequeno), sua dinâmica de volatilidade ainda está mal especificada — frequentemente um sinal de que você precisa de memória mais longa (componente/FIGARCH) ou de uma camada de regime, o que se conecta à detecção de regime com HMMs.
Classificando Modelos por Perda de Cauda, Não Apenas Aprovado/Reprovado
Kupiec e Christoffersen dão um veredito binário — o modelo é ou não é rejeitado. Isso é necessário, mas grosseiro: dois modelos podem ambos "passar" enquanto um é significativamente mais preciso. Para classificar previsões de VaR concorrentes, pontue-as com uma função de perda estritamente consistente para o quantil, a perda pinball (de quantil):
onde é o quantil VaR (com sinal) e o retorno realizado. Em média ao longo dos dias fora da amostra, uma perda pinball média menor significa um quantil melhor calibrado e mais preciso; como a perda é consistente para o quantil-, minimizá-la não recompensa um modelo por ser preguiçosamente largo. Para comparar dois modelos formalmente, alimente as diferenças de perda diária deles a um teste de Diebold-Mariano.
def pinball_loss(returns, var, alpha=0.99):
tau = 1 - alpha
q = -np.asarray(var) # VaR is a positive loss; quantile is negative
r = np.asarray(returns)
hit = (r < q).astype(float)
return np.mean((tau - hit) * (r - q))
Para a Expected Shortfall especificamente, note que a ES não é elicitável sozinha (não há função de perda cujo minimizador seja apenas a ES), o que é uma ressalva teórica genuína: você avalia a ES conjuntamente com o VaR usando as regras de pontuação de Fissler-Ziegel, ou recorre à prática mais simples de verificar se a magnitude média da violação corresponde à ES prevista pelo modelo. Uma verificação de ES crua mas útil: entre os dias de violação de VaR, compare a perda média realizada com a ES média prevista nesses dias — devem estar próximas.
O enquadramento regulatório é a abordagem semáforo de Basileia: ao longo de 250 dias de negociação, 0-4 violações de um VaR de 99% é "verde" (aceitável), 5-9 é "amarelo" (escrutínio), 10+ é "vermelho" (o modelo é rejeitado e os multiplicadores de capital sobem). É uma prima mais grosseira do Kupiec, mas é a linguagem que os comitês de risco de fato falam, e vale a pena reportá-la junto com as estatísticas LR.
Considerações Práticas
Quando os Parâmetros Extras Não Compensam
O padrão honesto é o ceticismo diante da complexidade. Todo parâmetro que você adiciona é um botão que o otimizador pode sobreajustar, e o GARCH assimétrico de caudas pesadas tem vários. Orientação concreta:
- Amostras ilíquidas ou curtas. Com algumas centenas de observações diárias, o erro padrão de e será grande, e você vai "detectar" assimetrias que são ruído amostral. Numa altcoin nova ou pouco líquida, um GARCH- simétrico é frequentemente o modelo mais complexo que os dados conseguem sustentar. Ajustar skew- EGARCH a 200 dias é enganar a si mesmo.
- O termo de assimetria frequentemente não cobre seu custo. Na prática, mover de Normal para é uma melhoria grande e confiável (caudas pesadas são reais e fortes). Mover de para skew- é frequentemente marginal — um ganho de BIC de 1 ou 2, às vezes negativo. Adicione assimetria apenas quando os dados claramente a exigem.
- EGARCH vs. GJR costuma ser um empate em dados diários. Ambos codificam a mesma história qualitativa com formas funcionais diferentes. Escolha pelo backtest de VaR fora da amostra, não por qual tem a log-verossimilhança mais bonita dentro da amostra.
- Frequência mais alta muda a resposta. Em barras horárias ou de minuto, a sazonalidade intradiária e a microestrutura dominam, e um GARCH de estilo diário simples está mal especificado independentemente da assimetria. Problema diferente, ferramental diferente.
Esta é a mesma lição de avaliação honesta sem edge robusto: um modelo mais complexo que não sobrevive a teste fora da amostra é pior do que o modelo simples que substituiu, porque carrega a ilusão de precisão. Reporte o resultado negativo — "a assimetria não ajudou no ETH" — como um achado real, e use a otimização walk-forward como árbitro, não o AIC dentro da amostra.
Estas São as Marginais Sobre as Quais Todo o Resto É Construído
Os modelos aqui não são um ponto final; são o bloco de construção univariado para a maquinaria de risco conjunto. O texto sobre modelos de cópula para risco conjunto em cripto usa exatamente EGARCH/GJR- como as marginais GARCH-EVT antes de ajustar uma vine copula — você ajusta um GARCH assimétrico de caudas pesadas por ativo, extrai resíduos padronizados, e só então modela a dependência entre ativos. Se sua marginal for um GARCH gaussiano simétrico, a cópula herda seus erros de cauda não importa quão bom seja o modelo de dependência. Marginais ruins, VaR conjunto ruim.
Para o problema de volatilidade multivariada — correlações variando no tempo em vez de variâncias por ativo — veja Parte 3, DCC-GARCH, que sobrepõe um modelo de correlação dinâmica a estes ajustes univariados. E para transformar uma previsão de volatilidade em dimensionamento de posição e um backtest de trading, a Parte 4 sobre volatility targeting usa as previsões destes exatos modelos para escalar a exposição inversamente ao risco previsto.
Uma Alternativa Livre de Distribuição
Tudo na seção de risco repousa sobre uma suposição paramétrica: que os resíduos padronizados seguem uma ou skew-. Essa suposição é testável e geralmente razoável, mas pode falhar. Se você preferir não se comprometer com nenhuma forma de cauda, a predição conforme oferece intervalos de predição livres de distribuição com garantias de cobertura em amostra finita — uma filosofia genuinamente diferente que não faz nenhuma afirmação sobre a distribuição das inovações. As duas abordagens são complementares: o GARCH- paramétrico dá uma densidade condicional completa (e, portanto, a ES, que os intervalos conformes não fornecem diretamente), enquanto o conforme dá cobertura que se mantém mesmo quando sua densidade está errada. Em produção, usar ambos como verificação cruzada é seguro barato.
Higiene Numérica e de Fluxo de Trabalho
- Escale os retornos por 100. Os otimizadores GARCH convergem muito mais confiavelmente em retornos percentuais do que em retornos fracionários brutos. Lembre-se de desescalonar VaR/ES se reportar em unidades fracionárias.
- Observe a persistência. Se estimar acima de ~0.999, o modelo está quase integrado (estilo IGARCH); as previsões revertem à média extremamente devagar e as previsões de variância de longo horizonte se tornam pouco confiáveis. Não necessariamente errado, mas sinalize.
- Falhas de convergência em janelas móveis. A forma logarítmica do EGARCH evita restrições de positividade, mas ainda pode falhar em convergir numa janela patológica. Envolva
fit()num try/except e volte aos parâmetros da janela anterior em vez de derrubar um backtest ao vivo. - Modelo de média. Usamos uma média constante ao longo de todo o texto. Para a maior parte do cripto diário, a média condicional está próxima de zero e é dominada pela volatilidade; não gaste complexidade de modelo tentando prevê-la a menos que tenha uma razão real.
Resumo
- O GARCH(1,1) simples tem dois defeitos estruturais: é simétrico (reage a e de forma idêntica porque os choques entram como ) e assume inovações gaussianas (subprecificando as caudas pesadas de cripto). Ambos custam dinheiro real através de VaR otimista.
- O GJR-GARCH adiciona um termo de limiar . Um significativo é o efeito alavancagem: más notícias elevam mais a volatilidade. A positividade exige ; a persistência é .
- O EGARCH modela , então não há restrições de positividade e a estacionariedade é apenas . A assimetria entra através de um termo com sinal (a alavancagem é nesta convenção) separado de um termo de magnitude .
- A curva de impacto de notícias — variância do próximo período vs. o último choque — torna a assimetria visível e verifica a convenção de sinal do EGARCH num único olhar.
- As inovações Student- (
dist='t') corrigem as caudas via um grau de liberdade (tipicamente 3–6 para cripto); a skew- de Hansen (dist='skewt') adiciona uma assimetria para uma cauda esquerda mais pesada. Mover de Normal para é um ganho grande e confiável; de para skew- é frequentemente marginal. - VaR e ES decorrem da distribuição condicional ajustada: , com o quantil caudado tornando o risco honestamente maior do que o gaussiano. A ES (coerente, CVaR) captura a perda média além do VaR.
- Faça backtest com Kupiec e Christoffersen. Kupiec verifica a taxa de violação; Christoffersen verifica se as violações não estão agrupadas. Um modelo pode passar em um e falhar no outro — violações agrupadas são o modo de falha perigoso. Faça o backtest estritamente fora da amostra.
- Disciplina acima de complexidade. Adicione assimetria/skew apenas quando sobrevive ao BIC e a um backtest de VaR fora da amostra. Em séries curtas ou ilíquidas, o modelo mais simples geralmente vence.
References:
- Nelson, D. B. (1991). Conditional heteroskedasticity in asset returns: A new approach. Econometrica, 59(2), 347-370. DOI
- Glosten, L. R., Jagannathan, R., & Runkle, D. E. (1993). On the relation between the expected value and the volatility of the nominal excess return on stocks. Journal of Finance, 48(5), 1779-1801. DOI
- Bollerslev, T. (1987). A conditionally heteroskedastic time series model for speculative prices and rates of return. Review of Economics and Statistics, 69(3), 542-547. DOI
- Hansen, B. E. (1994). Autoregressive conditional density estimation. International Economic Review, 35(3), 705-730. DOI
- Engle, R. F., & Ng, V. K. (1993). Measuring and testing the impact of news on volatility. Journal of Finance, 48(5), 1749-1778. DOI
- Christoffersen, P. F. (1998). Evaluating interval forecasts. International Economic Review, 39(4), 841-862. DOI
- Kupiec, P. H. (1995). Techniques for verifying the accuracy of risk measurement models. Journal of Derivatives, 3(2), 73-84. DOI
- Black, F. (1976). Studies of stock price volatility changes. Proceedings of the American Statistical Association, Business and Economic Statistics Section, 177-181.
- McNeil, A. J., Frey, R., & Embrechts, P. (2015). Quantitative Risk Management: Concepts, Techniques and Tools (2nd ed.). Princeton University Press.
- Sheppard, K. (2023). arch: Autoregressive conditional heteroskedasticity models in Python. GitHub.
MarketMaker.cc Team
Quantitative Research & Strategy