← Voltar aos artigos
July 10, 2026
5 min read

GARCH(1,1): Previsão de Volatilidade em Cripto

#volatility
#GARCH
#risk
#forecasting
#crypto
#algorithmic-trading

Abra um gráfico de retornos diários do BTC e você notará algo para o qual os livros-texto sobre passeios aleatórios nunca o prepararam: a calma e o caos vêm em grupos. Um dia de queda de 6% raramente vem sozinho. Ele fica dentro de uma semana de oscilações de 4-8%, e então o mercado exala e atravessa um mês de sessões sonolentas de 1% antes da próxima tempestade. Os retornos em si parecem quase imprevisíveis — você não consegue dizer com confiança se amanhã será de alta ou de baixa — mas sua magnitude é profundamente previsível. A turbulência de hoje diz muito sobre a de amanhã.

Quase toda ferramenta de risco que um trader utiliza assume silenciosamente que isso não é verdade. O Black-Scholes precifica uma opção com um único σ\sigma constante. Um número estático de Value-at-Risk multiplica uma estimativa de volatilidade por um quantil normal. Um stop-loss fixo de 3% trata uma terça-feira morta e lateral e as horas ao redor de um anúncio do FOMC ou de um de-peg de exchange importante como se carregassem o mesmo risco. Cada uma dessas abordagens quebra exatamente da mesma forma: colapsa uma quantidade variável no tempo em uma constante, e depois se surpreende quando a constante acaba se movendo.

Este artigo é a Parte 1 de uma série de quatro partes sobre modelagem de volatilidade para cripto. Ele constrói a base: o modelo GARCH(1,1), por que ele se ajusta tão bem aos retornos de cripto, como estimá-lo honestamente por máxima verossimilhança com a biblioteca arch, e como transformar uma previsão de variância condicional em duas coisas imediatamente úteis — um tamanho de posição e uma largura de stop que respiram junto com o mercado. A Parte 2 adiciona assimetria e caudas pesadas, a Parte 3 vai para o caso multivariado, e a Parte 4 monta o backtest completo de volatility targeting. Mantemos a aplicação aqui deliberadamente simples; a estratégia honesta, validada com walk-forward, é o assunto da Parte 4.

Os Fatos Estilizados dos Retornos de Cripto

Antes de modelar qualquer coisa, vale a pena ser preciso sobre o que estamos tentando reproduzir. Os retornos financeiros empíricos — ações, câmbio e especialmente cripto — compartilham um pequeno conjunto de regularidades estatísticas robustas que foram documentadas por décadas. Costumam ser chamados de fatos estilizados, e três deles conduzem tudo o que se segue.

1. Agrupamento de volatilidade. Grandes movimentos tendem a ser seguidos por grandes movimentos (de qualquer sinal), e pequenos movimentos por pequenos movimentos. Mandelbrot notou isso nos preços do algodão em 1963. Formalmente, enquanto os retornos rtr_t são quase não correlacionados serialmente, os retornos ao quadrado rt2r_t^2 (uma proxy para a variância realizada) mostram uma autocorrelação positiva forte e de decaimento lento.

2. Caudas gordas (leptocurtose). A distribuição incondicional dos retornos tem muito mais massa nos extremos do que uma gaussiana. Onde uma distribuição normal tem curtose 3, os log-retornos diários do BTC rotineiramente ficam acima de 8-10, e os retornos de cripto de maior frequência podem ser piores. Dias de seis-sigma, que um modelo normal diz que deveriam acontecer aproximadamente uma vez a cada milhão de anos, aparecem várias vezes por década.

3. Nenhuma autocorrelação linear nos retornos, forte autocorrelação nos retornos ao quadrado. Esta é a impressão digital que separa um processo de volatilidade genuíno de uma tendência trivial. Se você regride rtr_t sobre seus próprios lags, não obtém nada explorável. Se você regride rt2r_t^2 sobre seus lags, encontra um sinal claro e persistente. Esta é precisamente a estrutura que um modelo de variância deveria capturar — e precisamente o que um modelo de σ\sigma constante descarta.

Podemos observar os três a olho nu em algumas linhas. Nada aqui requer uma fonte de dados especial; use ccxt em produção, mas para um trecho reproduzível o yfinance serve bem.

import numpy as np
import pandas as pd
import yfinance as yf
from statsmodels.graphics.tsaplots import plot_acf
from statsmodels.stats.diagnostic import acorr_ljungbox
from scipy import stats

px = yf.download("BTC-USD", start="2021-01-01", end="2025-12-31")["Close"]
ret = np.log(px / px.shift(1)).dropna()          # log returns
ret = ret.rename("btc")

print(f"Observations:     {len(ret)}")
print(f"Ann. volatility:  {ret.std() * np.sqrt(365):.2%}")
print(f"Skewness:         {stats.skew(ret):.2f}")
print(f"Excess kurtosis:  {stats.kurtosis(ret):.2f}")   # 0 == Gaussian

lb_ret  = acorr_ljungbox(ret,        lags=[10], return_df=True)
lb_ret2 = acorr_ljungbox(ret ** 2,   lags=[10], return_df=True)
print("\nLjung-Box p-value, returns   (lag 10):", float(lb_ret["lb_pvalue"].iloc[0]))
print("Ljung-Box p-value, squared   (lag 10):", float(lb_ret2["lb_pvalue"].iloc[0]))

A leitura típica (ilustrativa — sua janela será diferente): curtose em excesso bem acima de 3, um p-valor de Ljung-Box nos retornos brutos que falha em rejeitar "sem autocorrelação", e um p-valor nos retornos ao quadrado que é efetivamente zero. Esse último contraste é todo o jogo. Não há nada para negociar no sinal dos retornos no horizonte diário, mas há uma grande quantidade de estrutura em sua variância, e essa estrutura é previsível.

Uma nota sobre a natureza 24/7 de cripto. Diferente das ações, não há gap noturno nem fechamento de fim de semana, então o "dia" é uma barra limpa de 24 horas e o fator de anualização é 365\sqrt{365}, não 252\sqrt{252}. O agrupamento de volatilidade também sobrevive em escalas intradiárias, o que importa se você rodar GARCH em barras horárias — reversões de funding rate e cascatas de liquidação injetam explosões de variância agrupadas e abruptas que um modelo diário suaviza.

De ARCH a GARCH

O problema agora está claramente colocado: modelar uma variância que não é constante mas depende do passado recente. O primeiro modelo a fazer isso corretamente foi o ARCH de Engle (Autoregressive Conditional Heteroskedasticity, 1982), que lhe rendeu o prêmio Nobel em 2003.

Escreva o retorno como uma média condicional mais um choque:

rt=μt+εt,εt=σtzt,zti.i.d. (0,1)r_t = \mu_t + \varepsilon_t, \qquad \varepsilon_t = \sigma_t z_t, \qquad z_t \sim \text{i.i.d. } (0, 1)

Aqui σt2\sigma_t^2 é a variância condicional — a variância de rtr_t dado tudo o que se sabe até o momento t1t-1 — e ztz_t é uma inovação padronizada (normal padrão no caso mais simples). A palavra "condicional" faz todo o trabalho: incondicionalmente a variância pode ser constante, mas condicionada em ontem ela se move.

O ARCH(qq) de Engle torna a variância de hoje uma soma ponderada dos últimos qq choques ao quadrado:

σt2=ω+i=1qαiεti2\sigma_t^2 = \omega + \sum_{i=1}^{q} \alpha_i \, \varepsilon_{t-i}^2

com ω>0\omega > 0 e αi0\alpha_i \ge 0 para manter a variância positiva. Isso captura o agrupamento diretamente: um grande choque εt12\varepsilon_{t-1}^2 empurra σt2\sigma_t^2 para cima, o que aumenta a chance de outro grande choque, o que mantém a variância elevada. O problema é o decaimento empírico. A persistência de volatilidade em mercados reais se estende por muitos lags, então para ajustá-la um modelo ARCH precisa de um qq grande — frequentemente 8, 10 ou mais — e isso significa estimar um vetor longo e instável de αi\alpha_i que tende a sobreajustar.

O insight de Bollerslev em 1986 foi adicionar um termo que absorve toda essa persistência com um único parâmetro. A recursão do GARCH(1,1) — Generalized ARCH — é:

σt2=ω+αεt12+βσt12\sigma_t^2 = \omega + \alpha \, \varepsilon_{t-1}^2 + \beta \, \sigma_{t-1}^2

Três parâmetros, três interpretações claras:

  • ω>0\omega > 0 — a base ou piso. Uma constante que ancora o nível de longo prazo da variância. A variância nunca decai abaixo do que ω\omega sustenta.
  • α0\alpha \ge 0 — a reação às notícias. O quão violentamente a variância responde à surpresa de ontem εt12\varepsilon_{t-1}^2. Um α\alpha grande significa que a variância condicional é agitada e sensível a choques.
  • β0\beta \ge 0 — a persistência ou memória. Quanto da variância de ontem carrega para hoje. Um β\beta grande significa que a volatilidade é suave e lenta para desaparecer — a calma permanece calma, as tempestades permanecem tempestuosas.

A elegância está na recursão. Como o próprio σt12\sigma_{t-1}^2 continha um termo βσt22\beta \sigma_{t-2}^2, expandir para trás mostra que o GARCH(1,1) é um ARCH(\infty) com pesos de decaimento geométrico αβk\alpha \beta^{k} sobre choques ao quadrado passados:

σt2=ω1β+αk=0βkεt1k2\sigma_t^2 = \frac{\omega}{1-\beta} + \alpha \sum_{k=0}^{\infty} \beta^{k}\, \varepsilon_{t-1-k}^2

Então o único β\beta compra uma memória infinita e exponencialmente ponderada de choques passados. É por isso que um mero GARCH(1,1) — três parâmetros — rotineiramente supera modelos ARCH com dez, e por que ele se tornou o cavalo de batalha da modelagem de volatilidade aplicada. É, de fato, um primo próximo do estimador de variância EWMA do RiskMetrics, que é o caso especial ω=0\omega = 0, α+β=1\alpha + \beta = 1 com β\beta fixado em 0,94. O GARCH o generaliza deixando os dados escolherem α\alpha, β\beta e um nível genuíno de reversão à média.

Propriedades: Estacionariedade, Variância de Longo Prazo e Meia-Vida

A recursão do GARCH(1,1) tem algumas propriedades que vale a pena derivar, porque são elas que permitem raciocinar sobre o modelo em vez de simplesmente ajustá-lo cegamente.

Variância incondicional (de longo prazo). Assuma que o processo é estacionário em covariância de modo que a variância incondicional σˉ2=E[εt2]=E[σt2]\bar{\sigma}^2 = \mathbb{E}[\varepsilon_t^2] = \mathbb{E}[\sigma_t^2] existe e é constante ao longo do tempo. Tome a esperança de ambos os lados da recursão. Como E[εt12]=E[σt12]=σˉ2\mathbb{E}[\varepsilon_{t-1}^2] = \mathbb{E}[\sigma_{t-1}^2] = \bar{\sigma}^2:

σˉ2=ω+ασˉ2+βσˉ2        σˉ2=ω1αβ\bar{\sigma}^2 = \omega + \alpha\, \bar{\sigma}^2 + \beta\, \bar{\sigma}^2 \;\;\Longrightarrow\;\; \bar{\sigma}^2 = \frac{\omega}{1 - \alpha - \beta}

Este é o nível para o qual a volatilidade reverte à média. Ele só existe — e só é positivo — quando α+β<1\alpha + \beta < 1.

Condição de estacionariedade. Essa mesma desigualdade,

α+β<1,\alpha + \beta < 1,

é a condição de estacionariedade em covariância para o GARCH(1,1). A quantidade α+β\alpha + \beta é a persistência do processo de variância: é o coeficiente AR(1) que governa como um choque de variância decai de volta em direção a σˉ2\bar{\sigma}^2. Se α+β1\alpha + \beta \ge 1, a variância incondicional é infinita (ou indefinida) e os choques nunca desaparecem completamente.

Podemos ver a reversão à média explicitamente. Defina o desvio de variância σt2σˉ2\sigma_t^2 - \bar{\sigma}^2. Uma pequena álgebra na recursão (substituindo ω=σˉ2(1αβ)\omega = \bar{\sigma}^2(1 - \alpha - \beta)) dá, em esperança:

Et[σt+k2]σˉ2=(α+β)k(σt+12σˉ2)\mathbb{E}_t[\sigma_{t+k}^2] - \bar{\sigma}^2 = (\alpha + \beta)^{k}\,\bigl(\sigma_{t+1}^2 - \bar{\sigma}^2\bigr)

A diferença entre a variância atual e seu nível de longo prazo encolhe por um fator de (α+β)(\alpha + \beta) a cada passo. Esta é exatamente a previsão de múltiplos passos que usamos mais adiante.

Meia-vida da volatilidade. Quanto tempo leva para um choque de variância decair pela metade de volta ao normal? Defina (α+β)h=1/2(\alpha+\beta)^{h} = 1/2 e resolva:

h1/2=ln0.5ln(α+β)h_{1/2} = \frac{\ln 0.5}{\ln(\alpha + \beta)}

Para α+β=0.95\alpha + \beta = 0.95 a meia-vida é cerca de 13,5 dias; para 0.980.98 é cerca de 34 dias; para 0.990.99 é cerca de 69 dias. Este único número é frequentemente mais intuitivo do que os parâmetros brutos — ele informa, nas unidades das suas barras, o quão persistente é a volatilidade.

O problema de quase-IGARCH em cripto. Aqui está a peculiaridade específica de cripto. Quando você ajusta o GARCH(1,1) aos retornos de BTC ou ETH, quase sempre encontra α+β\alpha + \beta muito próximo de 1 — valores de 0,98, 0,99, às vezes 0,995 são rotineiros. Este é o regime quase-IGARCH (Integrated GARCH). Ele tem consequências reais:

  • A meia-vida se torna enorme (semanas a meses), então o modelo trata a volatilidade como muito persistente e pouco reversora à média.
  • A estimativa de σˉ2=ω/(1αβ)\bar{\sigma}^2 = \omega/(1-\alpha-\beta) se torna extremamente sensível: uma pequena mudança em α+β\alpha+\beta de 0,99 para 0,995 dobra a variância de longo prazo implícita. Nunca confie na estimativa pontual de volatilidade de longo prazo neste regime sem um intervalo de confiança.
  • As previsões de múltiplos passos revertem à média tão lentamente que, para horizontes práticos abaixo de algumas semanas, o GARCH se comporta quase como um passeio aleatório na variância (que é o que o EWMA assume).

Se a quase-integração é genuína ou um artefato de quebras estruturais (uma mudança permanente no nível de volatilidade sendo lida pelo modelo como um único episódio longo e persistente) é um debate real. É mais uma razão para reajustar em janelas móveis em vez de ajustar uma vez em todo o histórico, um ponto ao qual voltamos nas armadilhas. A estrutura de regime especificamente é melhor tratada por um modelo de troca explícito — veja detecção de regime com modelos ocultos de Markov, que é complementar ao GARCH em vez de um substituto.

Estimação por Máxima Verossimilhança

Os parâmetros do GARCH são estimados por máxima verossimilhança. A lógica é direta: dado θ=(μ,ω,α,β)\theta = (\mu, \omega, \alpha, \beta), a recursão produz um caminho completo de variâncias condicionais σt2(θ)\sigma_t^2(\theta), e sob uma distribuição assumida para as inovações ztz_t podemos escrever quão provável são os retornos observados. Então escolhemos θ\theta para maximizar essa verossimilhança.

Assuma inovações gaussianas ztN(0,1)z_t \sim \mathcal{N}(0,1), então rtFt1N(μ,σt2)r_t \mid \mathcal{F}_{t-1} \sim \mathcal{N}(\mu, \sigma_t^2). A densidade condicional de uma observação é

f(rtFt1)=12πσt2exp ⁣((rtμ)22σt2).f(r_t \mid \mathcal{F}_{t-1}) = \frac{1}{\sqrt{2\pi\sigma_t^2}}\exp\!\left(-\frac{(r_t - \mu)^2}{2\sigma_t^2}\right).

Como o modelo é escrito condicionalmente, a verossimilhança conjunta se fatora em um produto de densidades um-passo-à-frente, e a log-verossimilhança é uma soma simples:

(θ)=12t=1T[ln(2π)+lnσt2(θ)+(rtμ)2σt2(θ)].\ell(\theta) = -\frac{1}{2}\sum_{t=1}^{T}\left[\ln(2\pi) + \ln \sigma_t^2(\theta) + \frac{(r_t - \mu)^2}{\sigma_t^2(\theta)}\right].

Dois fatos estruturais a notar. Primeiro, σt2\sigma_t^2 aparece tanto como uma penalidade (lnσt2\ln \sigma_t^2 — o modelo é punido por afirmar alta variância) quanto no resíduo padronizado ((rtμ)2/σt2(r_t-\mu)^2/\sigma_t^2 — o modelo é punido por ser surpreendido). O ótimo equilibra os dois, o que é o que faz a variância acompanhar. Segundo, a recursão precisa de uma semente σ12\sigma_1^2; a escolha usual é a variância amostral dos retornos, e com alguns milhares de observações a semente mal importa.

Não há forma fechada para o maximizador, então otimizamos numericamente (arch usa um método quase-Newton com gradientes analíticos ou numéricos). A superfície de verossimilhança geralmente se comporta bem para o GARCH(1,1), mas duas coisas incomodam na prática: as restrições de positividade (ω,α,β0\omega,\alpha,\beta \ge 0) e o comportamento próximo à fronteira quando α+β1\alpha+\beta \to 1, onde o otimizador pode rastejar lentamente. Ambos são tratados para você por uma boa biblioteca — e você deveria usar uma. Programar manualmente um MLE de GARCH é um bom exercício de aprendizado mas uma escolha de produção ruim.

A biblioteca arch

O pacote arch de Kevin Sheppard é a ferramenta padrão em Python. O ajuste completo tem quatro linhas.

from arch import arch_model

r = ret * 100.0

model  = arch_model(r, mean="Constant", vol="Garch", p=1, q=1, dist="normal")
res    = model.fit(disp="off")
print(res.summary())

Uma palavra sobre os nomes dos argumentos, porque são uma fonte comum de confusão. No arch, p é o número de variâncias defasadas (termos β\beta, a ordem GARCH) e q é o número de resíduos ao quadrado defasados (termos α\alpha, a ordem ARCH). Então p=1, q=1 é o GARCH(1,1) que derivamos. (A notação original de Bollerslev o escreve GARCH(p,qp,q) com pp para a ordem ARCH — as duas convenções estão transpostas. Confie na documentação da própria biblioteca, não na sua memória.)

Lendo o resumo, a tabela de coeficientes se parece aproximadamente com isto (valores ilustrativos para retornos diários do BTC, não um experimento real):

                     Volatility Model
==========================================================
                 coef    std err      t      P>|t|
----------------------------------------------------------
omega          0.4821     0.201    2.40    0.016
alpha[1]       0.0912     0.021    4.34    0.000
beta[1]        0.8994     0.024   37.5     0.000
==========================================================

Como ler isso:

  • alpha[1] + beta[1] = 0,0912 + 0,8994 = 0,9906. Persistência pouco abaixo de 1 — o regime quase-IGARCH, exatamente como avisado. Meia-vida ln(0.5)/ln(0.9906)73\approx \ln(0.5)/\ln(0.9906) \approx 73 dias.
  • omega = 0,4821, então a variância de longo prazo é 0.4821/(10.9906)=51.30.4821 / (1 - 0.9906) = 51.3 em unidades de percentual ao quadrado, ou seja, uma volatilidade diária de longo prazo de 51.37.2%\sqrt{51.3} \approx 7.2\%, ou aproximadamente 7.2%×365138%7.2\%\times\sqrt{365}\approx 138\% anualizado. Esse é um número plausível para o BTC.
  • Tanto alpha quanto beta são fortemente significativos. alpha sendo pequeno em relação a beta é típico: a variância de cripto é majoritariamente persistência (memória), com uma reação modesta mas real a choques recentes.

A pegadinha da escala ×100

Esta é a forma mais comum de obter resultados sem sentido do arch, então merece sua própria subseção. O otimizador funciona melhor quando os números que ele vê são O(1)O(1) a O(100)O(100). Log-retornos diários são O(0.01)O(0.01), então seus quadrados são O(0.0001)O(0.0001) e ω\omega tem que estar em torno de 10610^{-6} — em uma faixa onde os gradientes numéricos perdem precisão e o ajuste pode falhar silenciosamente em convergir ou retornar erros-padrão sem sentido.

A correção é ajustar em retornos escalados por 100 (ou seja, em percentual), como acima. O arch até emitirá um DataScaleWarning se você esquecer. Tudo o que você lê do modelo está então em unidades de percentual ou percentual ao quadrado, e você deve desescalar consistentemente:

sigma_pct     = np.sqrt(res.forecast(horizon=1).variance.iloc[-1, 0])
sigma_decimal = sigma_pct / 100.0
print(f"1-day-ahead conditional vol: {sigma_decimal:.2%}")

Misturar quantidades escaladas e não escaladas — alimentar uma volatilidade percentual em uma fórmula de dimensionamento de posição que espera decimais, digamos — produz erros de exatamente 100x, que são fáceis de passar despercebidos porque o código roda sem falhas. Escolha uma convenção (eu mantenho tudo decimal fora do ajuste e só escalo na fronteira do arch) e nunca a cruze.

Previsão de Variância Condicional

Um modelo ajustado só é útil se prevê. O GARCH dá previsões analíticas e limpas em qualquer horizonte.

Um passo à frente. No momento TT (o final da amostra) conhecemos εT\varepsilon_T e σT2\sigma_T^2, então a próxima variância é determinística:

σT+12=ω+αεT2+βσT2.\sigma_{T+1}^2 = \omega + \alpha\,\varepsilon_T^2 + \beta\,\sigma_T^2.

Nenhuma esperança necessária — tudo no lado direito é observado.

Múltiplos passos à frente. Para h2h \ge 2 ainda não conhecemos os choques intermediários, então tomamos esperanças condicionais. Usando ET[εT+k2]=ET[σT+k2]\mathbb{E}_T[\varepsilon_{T+k}^2] = \mathbb{E}_T[\sigma_{T+k}^2] (porque E[z2]=1\mathbb{E}[z^2]=1), a recursão colapsa em um simples AR(1) na variância prevista:

ET[σT+h2]=ω+(α+β)ET[σT+h12].\mathbb{E}_T[\sigma_{T+h}^2] = \omega + (\alpha + \beta)\,\mathbb{E}_T[\sigma_{T+h-1}^2].

Iterando isso a partir da previsão de um passo dá a forma fechada, que é o resultado de reversão à média que derivamos anteriormente escrito explicitamente:

ET[σT+h2]=σˉ2+(α+β)h1(σT+12σˉ2),σˉ2=ω1αβ.\mathbb{E}_T[\sigma_{T+h}^2] = \bar{\sigma}^2 + (\alpha+\beta)^{\,h-1}\bigl(\sigma_{T+1}^2 - \bar{\sigma}^2\bigr), \qquad \bar{\sigma}^2 = \frac{\omega}{1-\alpha-\beta}.

Leia isso com cuidado, porque é a geometria de toda previsão GARCH. A estrutura a termo da variância começa na variância condicional de hoje σT+12\sigma_{T+1}^2 e decai geometricamente em direção ao nível de longo prazo σˉ2\bar{\sigma}^2. Se hoje está mais calmo que a média, a curva de previsão sobe em direção a σˉ2\bar\sigma^2; se hoje é uma crise, ela desce em direção a ele. A velocidade desse decaimento é definida inteiramente por (α+β)(\alpha+\beta) — e no regime quase-IGARCH de cripto, onde α+β0.99\alpha+\beta \approx 0.99, o decaimento é tão lento que para horizontes abaixo de duas semanas a previsão mal se move do nível de hoje. Vale a pena internalizar isso: para períodos de posse curtos, a previsão de GARCH em cripto é essencialmente "amanhã parece com hoje, revertendo apenas muito lentamente."

Agregando para um horizonte de posse. Traders raramente se importam com a variância de um único dia futuro. Se você mantém uma posição por HH dias e os retornos são condicionalmente não correlacionados (o fato estilizado do início), a variância do retorno cumulativo de HH dias é a soma das variâncias previstas de um dia:

σT2(H)=h=1HET[σT+h2],σT(H)=σT2(H).\sigma_{T}^{2}(H) = \sum_{h=1}^{H} \mathbb{E}_T[\sigma_{T+h}^2], \qquad \sigma_T(H) = \sqrt{\sigma_T^2(H)}.

Este é o número contra o qual você realmente dimensiona — a volatilidade do P&L ao longo do seu período de posse. Note que isso não é a escala ingênua HσT+1\sqrt{H}\,\sigma_{T+1}, que só está correta se a variância for constante. Quando a variância de hoje está acima de σˉ2\bar\sigma^2, a previsão de reversão à média torna a verdadeira volatilidade de HH dias menor do que a regra da raiz quadrada; quando hoje está calmo, ela é maior. Acertar isso é a diferença entre um stop que respeita a estrutura a termo e um que não respeita.

Em código:

H = 10
fc = res.forecast(horizon=H, reindex=False)

var_path_pct2 = fc.variance.iloc[-1].values        # [E_T sigma^2_{T+1}, ..., T+H]
var_path      = var_path_pct2 / (100.0 ** 2)       # back to decimal variance

daily_vol   = np.sqrt(var_path)
print("Forecast daily vol path:", np.round(daily_vol * 100, 2), "%")

H_day_var = var_path.sum()
H_day_vol = np.sqrt(H_day_var)
print(f"{H}-day holding-period vol: {H_day_vol:.2%}")

naive = np.sqrt(var_path[0] * H)
print(f"Naive sqrt(H) * sigma_1:   {naive:.2%}")

Para horizontes mais longos, o GARCH também suporta previsões de simulação (method="simulation"), que propagam a distribuição de inovação para frente e dão a você a densidade completa de previsão, não apenas sua variância — útil quando as inovações são não gaussianas, como serão assim que passarmos para distribuições Student-t e assimétricas na Parte 2. Para as quantidades lineares na variância acima, o caminho analítico é exato e gratuito.

Diagnósticos: O Modelo Realmente Funcionou?

Ajustar um modelo não é o mesmo que validá-lo. Todo o objetivo do GARCH é absorver a heterocedasticidade condicional — o agrupamento de volatilidade — de modo que o que resta seja (quase) i.i.d. A verificação correta é, portanto, observar os resíduos padronizados

z^t=rtμ^σ^t\hat{z}_t = \frac{r_t - \hat\mu}{\hat\sigma_t}

e perguntar: o agrupamento desapareceu? Se o modelo capturou a dinâmica de variância, os z^t\hat z_t deveriam ter variância unitária e, crucialmente, seus quadrados z^t2\hat z_t^2 não deveriam mostrar autocorrelação remanescente. Executamos três testes.

1. Ljung-Box nos resíduos padronizados. Verifica que nenhuma autocorrelação linear resta no nível de z^t\hat z_t (isso na verdade testa o modelo de média, não o modelo de variância). Não deveria rejeitar.

2. Ljung-Box nos resíduos padronizados ao quadrado. Este é o importante. Se z^t2\hat z_t^2 ainda tem autocorrelação significativa, o modelo de variância falhou em remover o agrupamento — há estrutura que o GARCH(1,1) não capturou, e você pode precisar de uma ordem maior, uma variante assimétrica, ou uma distribuição de inovação diferente. Não deveria rejeitar.

3. Teste ARCH-LM (teste do multiplicador de Lagrange de Engle). Regride z^t2\hat z_t^2 sobre seus próprios lags e testa significância conjunta. É essencialmente uma versão formal do teste 2 e pergunta diretamente "há efeito ARCH remanescente?" Um resultado não significativo confirma que a heterocedasticidade condicional foi eliminada pela modelagem.

from statsmodels.stats.diagnostic import acorr_ljungbox
from arch.unitroot.cointegration import engle_granger  # (unrelated; shown for import clarity)

z  = res.std_resid.dropna()          # standardized residuals
z2 = z ** 2

lb_z  = acorr_ljungbox(z,  lags=[10, 20], return_df=True)
lb_z2 = acorr_ljungbox(z2, lags=[10, 20], return_df=True)
print("Ljung-Box on standardized residuals:\n", lb_z, "\n")
print("Ljung-Box on SQUARED standardized residuals:\n", lb_z2, "\n")

lm = res.arch_lm_test(lags=10, standardized=True)
print(lm)

print(f"\nStd-resid excess kurtosis: {stats.kurtosis(z):.2f}")

Como se parece um bom resultado: os p-valores de Ljung-Box em z^t2\hat z_t^2 saltam de próximo de zero (nos retornos ao quadrado brutos) para confortavelmente acima de 0,05, e o teste ARCH-LM falha em rejeitar. Essa é a sua evidência de que o modelo fez seu trabalho no segundo momento.

Como se parece um resultado imperfeito — e o que você deve esperar com um GARCH(1,1) gaussiano simples em cripto — é que os testes de agrupamento passam mas a curtose dos resíduos padronizados ainda está elevada (digamos, 4-6 em vez de 0). O GARCH remove o agrupamento, mas uma única distribuição incondicional de cauda gorda permanece, porque inovações gaussianas não conseguem reproduzir as caudas. Essa cauda gorda residual não é um bug a ser corrigido aqui; é a motivação para a Parte 2, GARCH assimétrico e o efeito alavancagem em cripto, onde inovações Student-t e skewed-t e o termo de assimetria GJR/EGARCH tratam exatamente disso.

Aplicação: Dimensionamento e Stops Escalados por Volatilidade

Agora temos uma previsão da volatilidade de amanhã (e dos próximos HH dias). O que fazemos com ela? Os dois usos mais simples e de maior valor são dimensionamento de posição e posicionamento de stop. Mantemos ambos deliberadamente básicos aqui — a estratégia completa de vol-targeting com toda a sua maquinaria prática é a Parte 4.

Dimensionamento de posição direcionado por volatilidade

A ideia é manter uma posição cuja contribuição de risco seja aproximadamente constante ao longo do tempo, em vez de uma posição cujo valor nominal seja constante. Se você sempre implanta o mesmo tamanho em dólares, seu risco infla em regimes de alta volatilidade e encolhe em regimes calmos — o oposto do que você quer. O volatility targeting inverte isso: mire em uma volatilidade alvo fixa do P&L, e deixe a previsão ditar o tamanho.

Para uma volatilidade anualizada alvo σtarget\sigma_{\text{target}} (digamos, 20%) e uma volatilidade anualizada prevista σ^t\hat\sigma_t, o peso da posição é

wt=σtargetσ^t.w_t = \frac{\sigma_{\text{target}}}{\hat{\sigma}_t}.

Quando a volatilidade prevista é alta, você reduz a escala; quando é baixa, você aumenta. Esse é todo o mecanismo. Como σ^t\hat\sigma_t é prevista — conhecida em tt antes do retorno em t+1t+1 ser realizado — não há look-ahead, desde que você seja disciplinado quanto ao timing (mais sobre isso nas armadilhas).

def vol_target_weight(sigma_forecast_annual, sigma_target_annual=0.20,
                      w_max=3.0):
    """Volatility-scaled position weight. Inputs/outputs in decimals.
    w_max caps leverage so a tiny forecast vol can't demand insane size."""
    w = sigma_target_annual / sigma_forecast_annual
    return float(np.clip(w, 0.0, w_max))

sigma_1d   = np.sqrt(res.forecast(horizon=1).variance.iloc[-1, 0]) / 100.0
sigma_ann  = sigma_1d * np.sqrt(365)
w          = vol_target_weight(sigma_ann, sigma_target_annual=0.20)
print(f"Forecast annual vol: {sigma_ann:.1%}  ->  position weight: {w:.2f}x")

Isso é um primo próximo das regras adequadas de alocação de capital. O volatility targeting responde "quanto o risco deveria escalar com a volatilidade", enquanto o critério de Kelly responde "quanto o risco deveria escalar com a vantagem" — e os dois se multiplicam juntos em uma pilha completa de dimensionamento: tamanho \propto vantagem / variância. Note que o termo de variância de Kelly é exatamente a previsão GARCH que você acabou de calcular, o que é por que um modelo de volatilidade ao vivo aprimora materialmente o dimensionamento de Kelly em relação a uma estimativa histórica estática. Se sua estimativa de vantagem carrega incerteza quantificada, a predição conforme oferece uma forma livre de distribuição de ampliar ou reduzir o tamanho para corresponder, e se compõe de forma limpa com o volatility targeting.

O limite w_max não é opcional. No regime quase-IGARCH, um período tranquilo pode empurrar a volatilidade prevista bastante baixo, e σtarget/σ^t\sigma_{\text{target}}/\hat\sigma_t vai exigir uma alavancagem que é boa no papel e ruinosa quando a calmaria quebra — o que, pelo agrupamento de volatilidade, eventualmente acontece, frequentemente de forma abrupta. Limitar a alavancagem é o reconhecimento tosco mas eficaz de que sua previsão é uma média condicional, não uma garantia, e que o payoff de estar errado é assimétrico. Essa assimetria — uma conta explodida não é recuperável por um ganho simétrico — é exatamente a assimetria entre perda e lucro que deveria torná-lo sistematicamente mais conservador do que uma regra baseada apenas em variância sugere.

Stops escalados por volatilidade

Um stop de porcentagem fixa tem a mesma doença que um tamanho de posição fixo: um stop de 3% é um gatilho sensível em um mercado calmo e um erro de arredondamento em um violento. Isso faz você ser eliminado de boas posições por ruído comum durante regimes de alta volatilidade e devolve demais durante transições. A correção é definir a distância do stop em unidades de volatilidade prevista.

distaˆncia do stopt=kσ^t(H)\text{distância do stop}_t = k \cdot \hat\sigma_t^{(H)}

onde σ^t(H)\hat\sigma_t^{(H)} é a volatilidade prevista sobre seu horizonte de posse esperado HH (a quantidade agregada da seção de previsão) e kk é um múltiplo — tipicamente 1,5 a 3 — escolhido de modo que o stop fique fora da flutuação normal mas dentro de um movimento adverso genuíno.

def vol_scaled_stop(entry_price, side, sigma_H, k=2.0):
    """
    entry_price : fill price
    side        : +1 long, -1 short
    sigma_H     : forecast volatility over the holding horizon (decimal)
    k           : stop width in vol units
    Returns the stop price.
    """
    stop_frac = k * sigma_H
    return entry_price * (1.0 - side * stop_frac)

var_path = res.forecast(horizon=10, reindex=False).variance.iloc[-1].values / (100.0 ** 2)
sigma_H  = np.sqrt(var_path.sum())

entry = float(px.iloc[-1])
stop  = vol_scaled_stop(entry, side=+1, sigma_H=sigma_H, k=2.0)
print(f"Entry {entry:,.0f}  |  10-day vol {sigma_H:.2%}  |  2-sigma stop {stop:,.0f}")

Como σ^t(H)\hat\sigma_t^{(H)} usa a previsão de estrutura a termo que reverte à média em vez de um número histórico fixo, o stop automaticamente se alarga ao entrar em regimes turbulentos e se estreita conforme a volatilidade diminui — a estrutura a termo faz a adaptação por você. Esta é a mesma previsão alimentando tanto o tamanho quanto o stop, o que é uma característica: em um regime de alta volatilidade você simultaneamente mantém menos e dá à posição mais espaço, e os dois efeitos se compõem em um risco de cauda materialmente menor. Dimensionamento e stops são duas projeções de uma visão de volatilidade, não dois controles independentes.

Isso é o quanto levamos a aplicação na Parte 1. Uma estratégia real precisa lidar com custos de transação de rebalanceamento constante, o timing de quando a previsão é calculada versus quando o trade é colocado, controle de turnover e — acima de tudo — avaliação honesta fora da amostra. Tudo isso é a Parte 4: a estratégia GARCH de volatility targeting, onde construímos e testamos com walk-forward o pacote completo.

Armadilhas

O GARCH é fácil de ajustar e fácil de se enganar. Os modos de falha são consistentes.

Escala do retorno. Coberto acima, mas é o bug número um, então vale a pena repetir: ajuste o arch em retornos × 100, e desescale toda saída (variância por 1002100^2, volatilidade por 100100). Um erro silencioso de 100x aqui envenena todo cálculo subsequente de dimensionamento e stop.

Look-ahead no ajuste. O assassino sutil. Se você ajusta o modelo em todo o histórico e depois calcula "previsões" sobre esse mesmo histórico, cada previsão secretamente viu o futuro — os parâmetros foram estimados usando dados de depois da data de previsão. O ajuste dentro da amostra parecerá maravilhoso e o desempenho ao vivo não se parecerá em nada com ele. Toda previsão em backtest deve vir de um modelo ajustado apenas em dados disponíveis naquele momento: reajuste em uma janela expansiva ou móvel, preveja um passo, avance. Isso é inegociável e é o assunto inteiro de otimização walk-forward. A diferença entre um GARCH dentro da amostra e um propriamente walk-forward é a diferença entre uma demonstração e um sistema que sobrevive ao contato com mercados ao vivo — veja também paridade entre backtest e produção ao vivo.

Timing da previsão. Relacionado mas distinto. A previsão para o dia t+1t+1 deve ser calculada a partir de informação disponível no fechamento do dia tt (ou sempre que sua barra fechar), e a posição deve ser executável a um preço que você realmente conseguiria obter. Calcular a previsão usando o fechamento do dia t+1t+1 e depois "negociar" na abertura do dia t+1t+1 é um look-ahead que infla silenciosamente todo resultado.

Sobreajuste com ordens altas. O GARCH(1,1) quase sempre é suficiente. A tentação de ajustar GARCH(2,2) ou GARCH(3,1) porque empurra a log-verossimilhança dentro da amostra para cima geralmente é ajuste de ruído; os parâmetros extras raramente melhoram as previsões fora da amostra e frequentemente tornam o otimizador instável perto da fronteira. Prefira o modelo parcimonioso, e se você precisar comparar ordens, compare-as pela perda de previsão fora da amostra em uma divisão walk-forward, não pelo AIC dentro da amostra. Quando os diagnósticos de resíduos ainda mostram um problema, a correção geralmente é uma melhor distribuição de inovação ou um termo de assimetria (Parte 2), não uma ordem maior.

Quebras estruturais lidas como persistência. Como observado, uma mudança permanente no nível de volatilidade (um novo regime de mercado, uma mudança na microestrutura de mercado) pode ser absorvida pelo GARCH como persistência espuriamente alta, empurrando α+β\alpha+\beta em direção a 1. Se sua estimativa de volatilidade de longo prazo parece instável entre janelas, suspeite de uma quebra em vez de confiar na estimativa pontual quase-IGARCH. Reajustes móveis e, quando apropriado, um modelo de regime explícito protegem contra isso.

Tratar previsões de volatilidade como previsões de retorno. O GARCH prevê a magnitude dos movimentos, não sua direção. Ele informa quão grande a oscilação de amanhã provavelmente será, não em qual sentido. É exatamente por isso que seu lar natural é a gestão de risco — dimensionamento, stops, VaR — em vez da geração de sinais. Não confunda uma boa previsão de variância com uma vantagem.

Para Onde Isso Vai Agora

O GARCH(1,1) é a base, e é deliberadamente incompleto. A série se constrói sobre ele em três direções:

  • Assimetria e caudas pesadas — a volatilidade real de cripto responde mais a movimentos de baixa do que de alta (o efeito alavancagem), e inovações gaussianas não conseguem reproduzir as caudas. GJR-GARCH, EGARCH e inovações Student-t / skewed-t são a Parte 2.
  • Volatilidade multivariada — as correlações entre ativos cripto são elas mesmas variáveis no tempo e disparam em crashes. Modelar toda a matriz de covariância dinamicamente é a Parte 3: DCC-GARCH, que se conecta diretamente com Markowitz média-variância e alocação baseada em CVaR uma vez que a covariância é dinâmica.
  • A estratégia completa — dimensionamento, stops, custos, turnover e avaliação walk-forward honesta se unem na Parte 4.

E onde as marginais GARCH alimentam o risco conjunto: o modelo de variância condicional univariado aqui é exatamente o primeiro estágio do pipeline GARCH-EVT-copula para VaR/CVaR de portfólio. Uma vez que você tem resíduos padronizados de um ajuste GARCH por ativo, você os transforma e os une com uma cópula — as marginais são GARCH, a dependência é a cópula. Essa construção, incluindo dependência de cauda e o tratamento de cauda EVT, é abordada em profundidade em modelos de cópula para risco conjunto em cripto; este artigo é o motor univariado que fica embaixo dele.

Resumo

  • Os retornos de cripto exibem agrupamento de volatilidade, caudas pesadas e nenhuma autocorrelação de retorno mas forte autocorrelação de retorno ao quadrado. Qualquer ferramenta que assuma volatilidade constante — Black-Scholes com um único σ\sigma, VaR estático, stops de porcentagem fixa — está mal especificada em relação a esses fatos.
  • O GARCH(1,1), σt2=ω+αεt12+βσt12\sigma_t^2 = \omega + \alpha\varepsilon_{t-1}^2 + \beta\sigma_{t-1}^2, modela variância condicional variável no tempo com três parâmetros: uma base ω\omega, uma reação a choques α\alpha, e uma persistência β\beta. É um ARCH(\infty) com memória de decaimento geométrico, o que é por que supera o ARCH de ordem alta.
  • A estacionariedade requer α+β<1\alpha+\beta<1; a variância de longo prazo é ω/(1αβ)\omega/(1-\alpha-\beta), a persistência é α+β\alpha+\beta, e a meia-vida da volatilidade é ln0.5/ln(α+β)\ln 0.5 / \ln(\alpha+\beta). Cripto se situa no regime quase-IGARCH (α+β0.99\alpha+\beta\approx 0.99): muito persistente, lento para reverter à média, e com uma estimativa frágil de variância de longo prazo.
  • Estime por máxima verossimilhança. A log-verossimilhança gaussiana é uma soma de densidades um-passo; ajuste com arch_model(r*100, vol="Garch", p=1, q=1). Lembre-se da escala ×100 e desescale toda saída consistentemente.
  • As previsões revertem à média geometricamente em direção à variância de longo prazo à taxa (α+β)h1(\alpha+\beta)^{h-1}. Agregue previsões de variância diária para obter a volatilidade do horizonte de posse — não a regra ingênua de H\sqrt{H}.
  • Valide com Ljung-Box nos resíduos padronizados ao quadrado e o teste ARCH-LM. Passar nesses confirma que o agrupamento foi eliminado pela modelagem; caudas gordas residuais que permanecem motivam a Parte 2.
  • Aplique-o ao dimensionamento direcionado por volatilidade (wt=σtarget/σ^tw_t = \sigma_{\text{target}}/\hat\sigma_t, limitado) e stops escalados por volatilidade (kσ^t(H)k\cdot\hat\sigma_t^{(H)}). Uma previsão conduz ambos, então regimes de alta volatilidade recebem tamanho menor e stops mais largos simultaneamente.
  • As armadilhas que importam: escala de retorno, look-ahead no ajuste (ajuste apenas em dados passados, sempre walk-forward), timing de previsão, sobreordenação, e nunca confundir uma previsão de variância com uma previsão de direção.

Referências:

  • Engle, R. F. (1982). Autoregressive Conditional Heteroscedasticity with Estimates of the Variance of United Kingdom Inflation. Econometrica, 50(4), 987-1007. DOI
  • Bollerslev, T. (1986). Generalized Autoregressive Conditional Heteroskedasticity. Journal of Econometrics, 31(3), 307-327. DOI
  • Mandelbrot, B. (1963). The Variation of Certain Speculative Prices. The Journal of Business, 36(4), 394-419. DOI
  • Nelson, D. B. (1991). Conditional Heteroskedasticity in Asset Returns: A New Approach. Econometrica, 59(2), 347-370. DOI
  • Katsiampa, P. (2017). Volatility estimation for Bitcoin: A comparison of GARCH models. Economics Letters, 158, 3-6. DOI
  • Chu, J., Chan, S., Nadarajah, S., & Osterrieder, J. (2017). GARCH Modelling of Cryptocurrencies. Journal of Risk and Financial Management, 10(4), 17. DOI
  • Sheppard, K. (2023). arch: Autoregressive Conditional Heteroskedasticity (ARCH) and other tools for financial econometrics in Python. GitHub.
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.