GARCH(1,1): Previsão de Volatilidade em Cripto
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 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 são quase não correlacionados serialmente, os retornos ao quadrado (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 sobre seus próprios lags, não obtém nada explorável. Se você regride 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 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 é , não . 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:
Aqui é a variância condicional — a variância de dado tudo o que se sabe até o momento — e é 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() de Engle torna a variância de hoje uma soma ponderada dos últimos choques ao quadrado:
com e para manter a variância positiva. Isso captura o agrupamento diretamente: um grande choque empurra 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 grande — frequentemente 8, 10 ou mais — e isso significa estimar um vetor longo e instável de 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 — é:
Três parâmetros, três interpretações claras:
- — 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 sustenta.
- — a reação às notícias. O quão violentamente a variância responde à surpresa de ontem . Um grande significa que a variância condicional é agitada e sensível a choques.
- — a persistência ou memória. Quanto da variância de ontem carrega para hoje. Um 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 continha um termo , expandir para trás mostra que o GARCH(1,1) é um ARCH() com pesos de decaimento geométrico sobre choques ao quadrado passados:
Então o único 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 , com fixado em 0,94. O GARCH o generaliza deixando os dados escolherem , 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 existe e é constante ao longo do tempo. Tome a esperança de ambos os lados da recursão. Como :
Este é o nível para o qual a volatilidade reverte à média. Ele só existe — e só é positivo — quando .
Condição de estacionariedade. Essa mesma desigualdade,
é a condição de estacionariedade em covariância para o GARCH(1,1). A quantidade é 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 . Se , 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 . Uma pequena álgebra na recursão (substituindo ) dá, em esperança:
A diferença entre a variância atual e seu nível de longo prazo encolhe por um fator de 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 e resolva:
Para a meia-vida é cerca de 13,5 dias; para é cerca de 34 dias; para é 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 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 se torna extremamente sensível: uma pequena mudança em 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 , a recursão produz um caminho completo de variâncias condicionais , e sob uma distribuição assumida para as inovações podemos escrever quão provável são os retornos observados. Então escolhemos para maximizar essa verossimilhança.
Assuma inovações gaussianas , então . A densidade condicional de uma observação é
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:
Dois fatos estruturais a notar. Primeiro, aparece tanto como uma penalidade ( — o modelo é punido por afirmar alta variância) quanto no resíduo padronizado ( — 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 ; 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 () e o comportamento próximo à fronteira quando , 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 , a ordem GARCH) e q é o número de resíduos ao quadrado defasados (termos , a ordem ARCH). Então p=1, q=1 é o GARCH(1,1) que derivamos. (A notação original de Bollerslev o escreve GARCH() com 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 dias.omega= 0,4821, então a variância de longo prazo é em unidades de percentual ao quadrado, ou seja, uma volatilidade diária de longo prazo de , ou aproximadamente anualizado. Esse é um número plausível para o BTC.- Tanto
alphaquantobetasão fortemente significativos.alphasendo pequeno em relação abetaé 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 a . Log-retornos diários são , então seus quadrados são e tem que estar em torno de — 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 (o final da amostra) conhecemos e , então a próxima variância é determinística:
Nenhuma esperança necessária — tudo no lado direito é observado.
Múltiplos passos à frente. Para ainda não conhecemos os choques intermediários, então tomamos esperanças condicionais. Usando (porque ), a recursão colapsa em um simples AR(1) na variância prevista:
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:
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 e decai geometricamente em direção ao nível de longo prazo . Se hoje está mais calmo que a média, a curva de previsão sobe em direção a ; se hoje é uma crise, ela desce em direção a ele. A velocidade desse decaimento é definida inteiramente por — e no regime quase-IGARCH de cripto, onde , 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 dias e os retornos são condicionalmente não correlacionados (o fato estilizado do início), a variância do retorno cumulativo de dias é a soma das variâncias previstas de um dia:
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 , que só está correta se a variância for constante. Quando a variância de hoje está acima de , a previsão de reversão à média torna a verdadeira volatilidade de 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
e perguntar: o agrupamento desapareceu? Se o modelo capturou a dinâmica de variância, os deveriam ter variância unitária e, crucialmente, seus quadrados 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 (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 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 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 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 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 (digamos, 20%) e uma volatilidade anualizada prevista , o peso da posição é
Quando a volatilidade prevista é alta, você reduz a escala; quando é baixa, você aumenta. Esse é todo o mecanismo. Como é prevista — conhecida em antes do retorno em 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 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 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.
onde é a volatilidade prevista sobre seu horizonte de posse esperado (a quantidade agregada da seção de previsão) e é 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 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 , volatilidade por ). 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 deve ser calculada a partir de informação disponível no fechamento do dia (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 e depois "negociar" na abertura do dia é 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 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 , VaR estático, stops de porcentagem fixa — está mal especificada em relação a esses fatos.
- O GARCH(1,1), , modela variância condicional variável no tempo com três parâmetros: uma base , uma reação a choques , e uma persistência . É um ARCH() com memória de decaimento geométrico, o que é por que supera o ARCH de ordem alta.
- A estacionariedade requer ; a variância de longo prazo é , a persistência é , e a meia-vida da volatilidade é . Cripto se situa no regime quase-IGARCH (): 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 . Agregue previsões de variância diária para obter a volatilidade do horizonte de posse — não a regra ingênua de .
- 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 (, limitado) e stops escalados por volatilidade (). 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.
MarketMaker.cc Team
Quantitative Research & Strategy