GARCH(1,1): pronóstico de la volatilidad en cripto
Abre un gráfico de retornos diarios de BTC y notarás algo para lo que los libros de texto sobre paseos aleatorios nunca te prepararon: la calma y el caos vienen en grupos. Un día con caída del 6% rara vez está solo. Se encuentra dentro de una semana de oscilaciones del 4-8%, y luego el mercado exhala y transita un mes de sesiones somnolientas del 1% antes de la siguiente tormenta. Los retornos en sí mismos parecen casi impredecibles — no puedes decir con fiabilidad si mañana subirá o bajará — pero su magnitud es profundamente predecible. La turbulencia de hoy te dice mucho sobre la de mañana.
Casi todas las herramientas de riesgo que un trader utiliza asumen silenciosamente que esto no es cierto. Black-Scholes valora una opción con un único constante. Un número estático de Value-at-Risk multiplica una sola estimación de volatilidad por un cuantil normal. Un stop-loss fijo del 3% trata un martes muerto y lateral y las horas alrededor de un dato de la FOMC o un de-peg de un exchange importante como si conllevaran el mismo riesgo. Cada una de estas herramientas falla exactamente de la misma manera: colapsa una cantidad variable en el tiempo en una constante, y luego se sorprende cuando la constante resulta moverse.
Este artículo es la Parte 1 de una serie de cuatro partes sobre modelado de volatilidad para cripto. Construye la base: el modelo GARCH(1,1), por qué se ajusta tan bien a los retornos de cripto, cómo estimarlo honestamente por máxima verosimilitud con la librería arch, y cómo convertir un pronóstico de varianza condicional en dos cosas inmediatamente útiles — un tamaño de posición y un ancho de stop que respiran junto con el mercado. La Parte 2 añade asimetría y colas pesadas, la Parte 3 pasa a lo multivariado, y la Parte 4 ensambla el backtest completo de targeting de volatilidad. Aquí mantenemos la aplicación deliberadamente simple; la estrategia honesta, validada con walk-forward, es el tema de la Parte 4.
Los hechos estilizados de los retornos en cripto
Antes de modelar nada, conviene ser precisos sobre lo que estamos tratando de reproducir. Los retornos financieros empíricos — acciones, FX y especialmente cripto — comparten un pequeño conjunto de regularidades estadísticas robustas que se han documentado durante décadas. Usualmente se llaman hechos estilizados, y tres de ellos impulsan todo lo que sigue.
1. Agrupamiento de volatilidad (volatility clustering). Los movimientos grandes tienden a ser seguidos por movimientos grandes (de cualquier signo), y los movimientos pequeños por movimientos pequeños. Mandelbrot notó esto en los precios del algodón en 1963. Formalmente, mientras que los retornos están cerca de no estar correlacionados serialmente, los retornos al cuadrado (un proxy de la varianza realizada) muestran una autocorrelación positiva fuerte y de decaimiento lento.
2. Colas pesadas (leptocurtosis). La distribución incondicional de los retornos tiene mucha más masa en los extremos que una gaussiana. Donde una distribución normal tiene curtosis 3, los log-retornos diarios de BTC se sitúan rutinariamente por encima de 8-10, y los retornos de cripto de mayor frecuencia pueden ser peores. Los días de seis sigmas, que un modelo normal dice que deberían ocurrir aproximadamente una vez cada millón de años, aparecen varias veces por década.
3. Sin autocorrelación lineal en los retornos, fuerte autocorrelación en los retornos al cuadrado. Esta es la huella que separa un proceso de volatilidad genuino de una tendencia trivial. Si regresas sobre sus propios rezagos no obtienes nada explotable. Si regresas sobre sus rezagos, encuentras una señal clara y persistente. Esta es precisamente la estructura que un modelo de varianza debería capturar — y precisamente lo que un modelo de constante descarta.
Podemos observar los tres a simple vista en unas pocas líneas. Nada aquí requiere una fuente de datos especial; usa ccxt en producción, pero para un fragmento reproducible yfinance funciona bien.
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]))
La lectura típica (ilustrativa — tu ventana será diferente): curtosis en exceso muy por encima de 3, un p-valor de Ljung-Box sobre los retornos crudos que no rechaza "sin autocorrelación," y un p-valor sobre los retornos al cuadrado que es efectivamente cero. Ese último contraste es todo el juego. No hay nada que operar en el signo de los retornos al horizonte diario, pero hay una gran cantidad de estructura en su varianza, y esa estructura es pronosticable.
Una nota sobre la naturaleza 24/7 de cripto. A diferencia de las acciones, no hay salto nocturno (overnight gap) ni cierre de fin de semana, así que el "día" es una barra limpia de 24 horas y el factor de anualización es , no . El agrupamiento de volatilidad también sobrevive a escalas intradía, lo cual importa si ejecutas GARCH sobre barras horarias — los cambios en las funding rates y las cascadas de liquidación inyectan ráfagas de varianza agrupadas y agudas que un modelo diario suaviza.
De ARCH a GARCH
El problema ahora está planteado con nitidez: modelar una varianza que no es constante sino que depende del pasado reciente. El primer modelo en hacer esto correctamente fue el ARCH de Engle (Autoregressive Conditional Heteroskedasticity, 1982), que le valió el Premio Nobel en 2003.
Escribamos el retorno como una media condicional más un shock:
Aquí es la varianza condicional — la varianza de dado todo lo conocido hasta el tiempo — y es una innovación estandarizada (normal estándar en el caso más simple). La palabra "condicional" hace todo el trabajo: incondicionalmente la varianza puede ser constante, pero condicionada al día anterior, se mueve.
El ARCH() de Engle hace que la varianza de hoy sea una suma ponderada de los últimos shocks al cuadrado:
con y para mantener la varianza positiva. Esto captura el agrupamiento directamente: un shock grande empuja hacia arriba , lo cual eleva la probabilidad de otro shock grande, lo cual mantiene la varianza elevada. El problema es el decaimiento empírico. La persistencia de la volatilidad en los mercados reales se extiende a lo largo de muchos rezagos, así que para ajustarla un modelo ARCH necesita un grande — a menudo 8, 10, o más — y eso significa estimar un vector largo e inestable de que tiende a sobreajustar.
La idea de Bollerslev en 1986 fue añadir un término que absorbiera toda esa persistencia con un único parámetro. La recursión del GARCH(1,1) — Generalized ARCH — es:
Tres parámetros, tres interpretaciones limpias:
- — la base o piso. Una constante que ancla el nivel de largo plazo de la varianza. La varianza nunca decae por debajo de lo que sostiene.
- — la reacción a las noticias. Cuán violentamente responde la varianza a la sorpresa de ayer . Un grande significa que la varianza condicional es nerviosa y sensible a los shocks.
- — la persistencia o memoria. Cuánto de la varianza de ayer se traslada a hoy. Un grande significa que la volatilidad es suave y lenta para desvanecerse — la calma se mantiene calma, las tormentas se mantienen tormentosas.
La elegancia está en la recursión. Como ya contenía un término , expandiendo hacia atrás se muestra que GARCH(1,1) es un ARCH() con pesos que decaen geométricamente sobre los shocks al cuadrado pasados:
Así que el único te compra una memoria infinita y exponencialmente ponderada de los shocks pasados. Por esto un mero GARCH(1,1) — tres parámetros — rutinariamente supera a modelos ARCH con diez, y por qué se convirtió en el caballo de batalla del modelado de volatilidad aplicado. De hecho, es un primo cercano del estimador de varianza EWMA de RiskMetrics, que es el caso especial , con fijo en 0.94. GARCH lo generaliza dejando que los datos elijan , , y un nivel de reversión a la media genuino.
Propiedades: estacionariedad, varianza de largo plazo y vida media
La recursión GARCH(1,1) tiene algunas propiedades que vale la pena derivar, porque son las que te permiten razonar sobre el modelo en lugar de simplemente ajustarlo a ciegas.
Varianza incondicional (de largo plazo). Asume que el proceso es estacionario en covarianza de modo que la varianza incondicional existe y es constante en el tiempo. Toma la esperanza de ambos lados de la recursión. Dado que :
Este es el nivel al que la volatilidad revierte a la media. Solo existe — y solo es positivo — cuando .
Condición de estacionariedad. Esa misma desigualdad,
es la condición de estacionariedad en covarianza para GARCH(1,1). La cantidad es la persistencia del proceso de varianza: es el coeficiente AR(1) que gobierna cómo un shock de varianza decae de vuelta hacia . Si , la varianza incondicional es infinita (o indefinida) y los shocks nunca se desvanecen por completo.
Podemos ver la reversión a la media explícitamente. Define la desviación de varianza . Un poco de álgebra sobre la recursión (sustituyendo ) da, en esperanza:
La brecha entre la varianza actual y su nivel de largo plazo se reduce en un factor de en cada paso. Este es exactamente el pronóstico multi-paso que usamos más adelante.
Vida media de la volatilidad. ¿Cuánto tiempo tarda un shock de varianza en decaer a la mitad de vuelta a la normalidad? Fija y resuelve:
Para la vida media es de aproximadamente 13.5 días; para es de aproximadamente 34 días; para es de aproximadamente 69 días. Este único número suele ser más intuitivo que los parámetros crudos — te dice, en las unidades de tus barras, cuán pegajosa es la volatilidad.
El problema del casi-IGARCH en cripto. Aquí está la particularidad específica de cripto. Cuando ajustas GARCH(1,1) a los retornos de BTC o ETH, casi siempre encuentras muy cerca de 1 — valores de 0.98, 0.99, a veces 0.995 son rutinarios. Este es el régimen casi-IGARCH (Integrated GARCH). Tiene consecuencias reales:
- La vida media se vuelve enorme (semanas a meses), así que el modelo trata la volatilidad como muy persistente y apenas revirtiendo a la media.
- La estimación de se vuelve extremadamente sensible: un pequeño cambio en de 0.99 a 0.995 duplica la varianza de largo plazo implícita. Nunca confíes en la estimación puntual de la volatilidad de largo plazo en este régimen sin un intervalo de confianza.
- Los pronósticos multi-paso revierten a la media tan lentamente que, para horizontes prácticos de menos de unas pocas semanas, GARCH se comporta casi como un paseo aleatorio en la varianza (que es lo que asume EWMA).
Si la casi-integración es genuina o un artefacto de rupturas estructurales (un cambio permanente en el nivel de volatilidad que el modelo lee como un único episodio persistente y largo) es un debate real. Es una razón más para reajustar en ventanas móviles en lugar de ajustar una sola vez sobre todo el historial, un punto al que volvemos en las trampas. La estructura de régimen específicamente se maneja mejor con un modelo de cambio de régimen explícito — ver detección de régimen con modelos ocultos de Markov, que es complementario a GARCH en lugar de un reemplazo.
Estimación por máxima verosimilitud
Los parámetros de GARCH se estiman por máxima verosimilitud. La lógica es directa: dado , la recursión produce una trayectoria completa de varianzas condicionales , y bajo una distribución asumida para las innovaciones podemos escribir cuán probables son los retornos observados. Luego elegimos para maximizar esa verosimilitud.
Asume innovaciones gaussianas , así que . La densidad condicional de una observación es
Debido a que el modelo está escrito condicionalmente, la verosimilitud conjunta se factoriza en un producto de densidades un-paso-adelante, y el log-verosimilitud es una suma simple:
Dos hechos estructurales para notar. Primero, aparece tanto como una penalización ( — el modelo es penalizado por reclamar alta varianza) como en el residuo estandarizado ( — el modelo es penalizado por ser sorprendido). El óptimo equilibra ambos, que es lo que hace que la varianza siga la pista. Segundo, la recursión necesita una semilla ; la elección usual es la varianza muestral de los retornos, y con unos pocos miles de observaciones la semilla apenas importa.
No hay forma cerrada para el maximizador, así que optimizamos numéricamente (arch usa un método cuasi-Newton con gradientes analíticos o numéricos). La superficie de verosimilitud generalmente se comporta bien para GARCH(1,1), pero dos cosas muerden en la práctica: las restricciones de positividad () y el comportamiento cerca del límite cuando , donde el optimizador puede avanzar lentamente. Ambas son manejadas por una buena librería — y deberías usar una. Programar a mano un MLE de GARCH es un buen ejercicio de aprendizaje pero una mala elección para producción.
La librería arch
El paquete arch de Kevin Sheppard es la herramienta estándar en Python. Todo el ajuste son cuatro líneas.
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())
Una palabra sobre los nombres de los argumentos, porque son una fuente común de confusión. En arch, p es el número de varianzas rezagadas (términos , el orden GARCH) y q es el número de residuos al cuadrado rezagados (términos , el orden ARCH). Así que p=1, q=1 es el GARCH(1,1) que derivamos. (La notación original de Bollerslev lo escribe GARCH() con para el orden ARCH — las dos convenciones están transpuestas. Confía en la documentación propia de la librería, no en tu memoria.)
Leyendo el resumen, la tabla de coeficientes se ve aproximadamente así (valores ilustrativos para retornos diarios de BTC, no un 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
==========================================================
Cómo leerlo:
alpha[1] + beta[1]= 0.0912 + 0.8994 = 0.9906. Persistencia justo por debajo de 1 — el régimen casi-IGARCH, exactamente como se advirtió. Vida media días.omega= 0.4821, así que la varianza de largo plazo es en unidades de porcentaje al cuadrado, es decir, una volatilidad diaria de largo plazo de , o aproximadamente anualizado. Ese es un número plausible para BTC.- Tanto
alphacomobetason fuertemente significativos. Quealphasea pequeño en relación conbetaes típico: la varianza de cripto es principalmente persistencia (memoria), con una reacción modesta pero real a los shocks nuevos.
La trampa de la escala ×100
Esta es la forma número uno más común de obtener disparates de arch, así que se merece su propia subsección. El optimizador funciona mejor cuando los números que ve son a . Los log-retornos diarios son , así que sus cuadrados son y tiene que estar alrededor de — abajo en un rango donde los gradientes numéricos pierden precisión y el ajuste puede fallar silenciosamente en converger o devolver errores estándar basura.
La solución es ajustar sobre retornos escalados por 100 (es decir, en porcentaje), como arriba. arch incluso emitirá un DataScaleWarning si lo olvidas. Todo lo que leas del modelo estará entonces en unidades de porcentaje o porcentaje al cuadrado, y debes 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%}")
Mezclar cantidades escaladas y no escaladas — alimentar una volatilidad en porcentaje a una fórmula de dimensionamiento de posición que espera decimales, por ejemplo — produce errores de exactamente 100x, que son fáciles de pasar por alto porque el código se ejecuta sin problemas. Elige una convención (yo mantengo todo en decimal fuera del ajuste y solo escalo en la frontera de arch) y nunca la cruces.
Pronóstico de la varianza condicional
Un modelo ajustado solo es útil si pronostica. GARCH da pronósticos limpios y analíticos a cualquier horizonte.
Un paso adelante. En el tiempo (el final de la muestra) conocemos y , así que la siguiente varianza es determinística:
No se necesita esperanza — todo en el lado derecho es observado.
Multi-paso adelante. Para todavía no conocemos los shocks intermedios, así que tomamos esperanzas condicionales. Usando (porque ), la recursión colapsa a un simple AR(1) en la varianza pronosticada:
Iterando esto desde el pronóstico de un paso da la forma cerrada, que es el resultado de reversión a la media que derivamos antes escrito explícitamente:
Lee esto con cuidado, porque es la geometría de todo pronóstico GARCH. La estructura temporal de la varianza comienza en la varianza condicional de hoy y decae geométricamente hacia el nivel de largo plazo . Si hoy está más calmado que el promedio, la curva de pronóstico sube hacia ; si hoy es una crisis, cae hacia él. La velocidad de ese decaimiento está fijada enteramente por — y en el régimen casi-IGARCH de cripto, donde , el decaimiento es tan lento que para horizontes menores a un par de semanas el pronóstico apenas se mueve del nivel de hoy. Vale la pena internalizar eso: para períodos de tenencia cortos, el pronóstico GARCH de cripto es esencialmente "mañana se parece a hoy, revirtiendo solo muy lentamente."
Agregando a un horizonte de tenencia. A los traders rara vez les importa la varianza de un único día futuro. Si mantienes una posición durante días y los retornos están condicionalmente no correlacionados (el hecho estilizado del principio), la varianza del retorno acumulado de días es la suma de los pronósticos de varianza de un día:
Este es el número contra el que realmente dimensionas — la volatilidad del P&L durante tu período de tenencia. Nota que enfáticamente no es el escalamiento ingenuo , que solo es correcto si la varianza es constante. Cuando la varianza de hoy está por encima de , el pronóstico que revierte a la media hace que la verdadera volatilidad de días sea menor que la regla de raíz cuadrada; cuando hoy está calmado, es mayor. Acertar con esto es la diferencia entre un stop que respeta la estructura temporal y uno que no lo hace.
En 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 más largos, GARCH también soporta pronósticos por simulación (method="simulation"), que propagan la distribución de innovaciones hacia adelante y te dan la densidad de pronóstico completa, no solo su varianza — útil cuando las innovaciones no son gaussianas, como lo serán una vez que nos movamos a distribuciones Student-t y asimétricas en la Parte 2. Para las cantidades lineales en varianza mencionadas arriba, la trayectoria analítica es exacta y gratuita.
Diagnósticos: ¿funcionó realmente el modelo?
Ajustar un modelo no es lo mismo que validarlo. Todo el punto de GARCH es absorber la heterocedasticidad condicional — el agrupamiento de volatilidad — de modo que lo que queda sea (cercano a) i.i.d. La verificación correcta es entonces mirar los residuos estandarizados
y preguntar: ¿desapareció el agrupamiento? Si el modelo capturó la dinámica de la varianza, los deberían tener varianza unitaria y, crucialmente, sus cuadrados no deberían mostrar autocorrelación remanente. Ejecutamos tres pruebas.
1. Ljung-Box sobre residuos estandarizados. Verifica que no quede autocorrelación lineal en el nivel de (esto en realidad está probando el modelo de la media, no el modelo de varianza). No debería rechazar.
2. Ljung-Box sobre residuos estandarizados al cuadrado. Esta es la importante. Si todavía tiene autocorrelación significativa, el modelo de varianza falló en eliminar el agrupamiento — hay estructura que GARCH(1,1) no capturó, y puede que necesites un orden más alto, una variante asimétrica, o una distribución de innovación diferente. No debería rechazar.
3. Prueba ARCH-LM (prueba del multiplicador de Lagrange de Engle). Regresa sobre sus propios rezagos y prueba significancia conjunta. Es esencialmente una versión formal de la prueba 2 y pregunta directamente "¿queda efecto ARCH residual?" Un resultado no significativo confirma que la heterocedasticidad condicional ha sido modelada y eliminada.
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}")
Cómo se ve una buena salida: los p-valores de Ljung-Box sobre saltan de cerca de cero (sobre los retornos crudos al cuadrado) a cómodamente por encima de 0.05, y la prueba ARCH-LM falla en rechazar. Esa es tu evidencia de que el modelo hizo su trabajo sobre el segundo momento.
Cómo se ve una salida imperfecta — y lo que deberías esperar con un GARCH(1,1) gaussiano simple sobre cripto — es que las pruebas de agrupamiento pasan pero la curtosis del residuo estandarizado sigue elevada (digamos 4-6 en lugar de 0). GARCH elimina el agrupamiento pero permanece una única distribución incondicional de colas pesadas, porque las innovaciones gaussianas no pueden reproducir las colas. Esa persistencia de colas pesadas no es un error a corregir aquí; es la motivación de la Parte 2, GARCH asimétrico y el efecto apalancamiento en cripto, donde las innovaciones Student-t y skewed-t y el término de asimetría GJR/EGARCH abordan exactamente esto.
Aplicación: dimensionamiento y stops escalados por volatilidad
Ahora tenemos un pronóstico de la volatilidad de mañana (y de los siguientes días). ¿Qué hacemos con él? Los dos usos más simples y de mayor valor son el dimensionamiento de posiciones y la colocación de stops. Mantenemos ambos deliberadamente básicos aquí — la estrategia completa de vol-targeting con toda su maquinaria práctica es la Parte 4.
Dimensionamiento de posiciones con objetivo de volatilidad
La idea es mantener una posición cuya contribución al riesgo sea aproximadamente constante a lo largo del tiempo, en lugar de una posición cuyo nocional sea constante. Si siempre despliegas el mismo tamaño en dólares, tu riesgo se dispara en regímenes de alta volatilidad y se encoge en los calmados — lo opuesto de lo que quieres. El targeting de volatilidad invierte esto: apunta a una volatilidad objetivo fija del P&L, y deja que el pronóstico dicte el tamaño.
Para una volatilidad anualizada objetivo (digamos 20%) y una volatilidad anualizada pronosticada , el peso de la posición es
Cuando la volatilidad pronosticada es alta, reduces la escala; cuando es baja, la aumentas. Ese es todo el mecanismo. Debido a que es pronosticada — conocida en antes de que se realice el retorno en — no hay look-ahead, siempre que seas disciplinado sobre el timing (más sobre esto en las trampas).
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")
Esto es un primo cercano de las reglas propias de asignación de capital. El targeting de volatilidad responde "cuánto debería escalar el riesgo con la volatilidad," mientras que el criterio de Kelly responde "cuánto debería escalar el riesgo con el edge" — y los dos se multiplican juntos en una pila de dimensionamiento completa: tamaño edge / varianza. Nota que el término de varianza de Kelly es exactamente el pronóstico GARCH que acabas de calcular, por lo que un modelo de volatilidad en vivo agudiza materialmente el dimensionamiento de Kelly sobre una estimación histórica estática. Si tu propia estimación de edge lleva incertidumbre cuantificada, la predicción conforme da una manera libre de distribución de ampliar o reducir el tamaño para ajustarse a ella, y se compone limpiamente con el targeting de volatilidad.
El límite w_max no es opcional. En el régimen casi-IGARCH un tramo tranquilo puede empujar la volatilidad pronosticada bastante baja, y demandará apalancamiento que está bien en papel y es ruinoso cuando la calma se rompe — lo cual, según el agrupamiento de volatilidad, eventualmente sucede, a menudo abruptamente. Limitar el apalancamiento es el reconocimiento crudo pero efectivo de que tu pronóstico es una media condicional, no una garantía, y que el payoff de estar equivocado es asimétrico. Esa asimetría — una cuenta reventada no es recuperable por una ganancia simétrica — es exactamente la asimetría pérdida-versus-ganancia que debería hacerte sistemáticamente más conservador de lo que una regla basada solo en varianza sugiere.
Stops escalados por volatilidad
Un stop de porcentaje fijo tiene la misma enfermedad que un tamaño de posición fijo: un stop del 3% es un gatillo sensible en un mercado calmado y un error de redondeo en uno violento. Te saca de buenas posiciones por ruido ordinario durante regímenes de alta volatilidad y devuelve demasiado durante las transiciones. La solución es fijar la distancia del stop en unidades de volatilidad pronosticada.
donde es la volatilidad pronosticada durante tu horizonte de tenencia esperado (la cantidad agregada de la sección de pronóstico) y es un múltiplo — típicamente 1.5 a 3 — elegido para que el stop se ubique fuera de la fluctuación normal pero dentro de un movimiento adverso genuino.
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}")
Debido a que usa el pronóstico de estructura temporal que revierte a la media en lugar de un número histórico plano, el stop se amplía automáticamente entrando en regímenes turbulentos y se ajusta a medida que la volatilidad disminuye — la estructura temporal hace la adaptación por ti. Este es el mismo pronóstico alimentando tanto el tamaño como el stop, lo cual es una característica: en un régimen de alta volatilidad simultáneamente mantienes menos y le das a la posición más espacio, y los dos efectos se combinan en un riesgo de cola materialmente menor. El dimensionamiento y los stops son dos proyecciones de una visión de volatilidad, no dos controles independientes.
Eso es hasta donde llevamos la aplicación en la Parte 1. Una estrategia real tiene que manejar los costos de transacción del rebalanceo constante, el timing de cuándo se calcula el pronóstico versus cuándo se coloca la operación, el control de rotación (turnover), y — sobre todo — una evaluación honesta fuera de muestra. Todo eso es la Parte 4: la estrategia GARCH de targeting de volatilidad, donde construimos y probamos con walk-forward la totalidad.
Trampas
GARCH es fácil de ajustar y fácil para engañarte a ti mismo. Los modos de falla son consistentes.
Escalamiento de retornos. Cubierto arriba, pero es el bug número uno, así que merece repetirse: ajusta arch sobre retornos × 100, y desescala cada salida (varianza por , volatilidad por ). Un error silencioso de 100x aquí envenena cada cálculo posterior de dimensionamiento y stop.
Look-ahead en el ajuste. El asesino sutil. Si ajustas el modelo sobre todo el historial y luego calculas "pronósticos" sobre ese mismo historial, cada pronóstico ha visto secretamente el futuro — los parámetros fueron estimados usando datos posteriores a la fecha del pronóstico. El ajuste dentro de muestra se verá maravilloso y el rendimiento en vivo no se le parecerá en absoluto. Cada pronóstico backtested debe provenir de un modelo ajustado solo con datos disponibles en ese momento: reajustar en una ventana expansiva o móvil, pronosticar un paso, avanzar. Esto no es negociable y es el tema completo de la optimización walk-forward. La brecha entre un GARCH dentro de muestra y uno propiamente walk-forward es la brecha entre una demo y un sistema que sobrevive el contacto con mercados en vivo — ver también paridad backtest-en vivo.
Timing del pronóstico. Relacionado pero distinto. El pronóstico para el día debe calcularse a partir de información disponible al cierre del día (o cuando sea que cierre tu barra), y la posición debe ser ejecutable a un precio que realmente pudieras obtener. Calcular el pronóstico usando el cierre del día y luego "operar" en la apertura del día es un look-ahead que infla silenciosamente cada resultado.
Sobreajuste con órdenes altos. GARCH(1,1) casi siempre es suficiente. La tentación de ajustar GARCH(2,2) o GARCH(3,1) porque empuja hacia arriba el log-verosimilitud dentro de muestra suele ser ajuste de ruido; los parámetros extra rara vez mejoran los pronósticos fuera de muestra y a menudo hacen que el optimizador sea inestable cerca del límite. Prefiere el modelo parsimonioso, y si debes comparar órdenes, compáralos por pérdida de pronóstico fuera de muestra en una partición walk-forward, no por AIC dentro de muestra. Cuando los diagnósticos de residuos aún muestran un problema, la solución suele ser una mejor distribución de innovación o un término de asimetría (Parte 2), no un orden más alto.
Rupturas estructurales leídas como persistencia. Como se señaló, un cambio permanente en el nivel de volatilidad (un nuevo régimen de mercado, un cambio en la microestructura del mercado) puede ser absorbido por GARCH como persistencia espuriamente alta, empujando hacia 1. Si tu estimación de volatilidad de largo plazo se ve inestable a través de ventanas, sospecha de una ruptura en lugar de confiar en la estimación puntual casi-IGARCH. Los reajustes móviles y, donde sea apropiado, un modelo de régimen explícito protegen contra esto.
Tratar los pronósticos de volatilidad como pronósticos de retorno. GARCH pronostica la magnitud de los movimientos, no su dirección. Te dice cuán grande es probable que sea la oscilación de mañana, no hacia qué lado. Esto es exactamente por qué su hogar natural es la gestión de riesgo — dimensionamiento, stops, VaR — en lugar de la generación de señales. No confundas un buen pronóstico de varianza con un edge.
Hacia dónde va esto
GARCH(1,1) es la base, y está deliberadamente incompleto. La serie construye sobre ella en tres direcciones:
- Asimetría y colas pesadas — la volatilidad real de cripto responde más a movimientos a la baja que a movimientos al alza (el efecto apalancamiento), y las innovaciones gaussianas no pueden reproducir las colas. GJR-GARCH, EGARCH, e innovaciones Student-t / skewed-t son la Parte 2.
- Volatilidad multivariada — las correlaciones entre activos de cripto son en sí mismas variables en el tiempo y se disparan en las caídas. Modelar la matriz de covarianza completa dinámicamente es la Parte 3: DCC-GARCH, que se conecta directamente con Markowitz media-varianza y la asignación basada en CVaR una vez que la covarianza es dinámica.
- La estrategia completa — dimensionamiento, stops, costos, rotación, y evaluación honesta walk-forward se juntan en la Parte 4.
Y hacia dónde los marginales de GARCH alimentan el riesgo conjunto: el modelo de varianza condicional univariado aquí es exactamente la primera etapa del pipeline GARCH-EVT-cópula para VaR/CVaR de cartera. Una vez que tienes los residuos estandarizados de un ajuste GARCH por activo, los transformas y los unes con una cópula — los marginales son GARCH, la dependencia es la cópula. Esa construcción, incluyendo la dependencia de colas y el tratamiento de colas EVT, se cubre en profundidad en modelos de cópula para riesgo conjunto de cripto; este artículo es el motor univariado que se sitúa debajo de él.
Resumen
- Los retornos de cripto exhiben agrupamiento de volatilidad, colas pesadas, y ninguna autocorrelación de retornos pero fuerte autocorrelación de retornos al cuadrado. Cualquier herramienta que asuma volatilidad constante — Black-Scholes con un único , VaR estático, stops de porcentaje fijo — está mal especificada frente a estos hechos.
- GARCH(1,1), , modela la varianza condicional variable en el tiempo con tres parámetros: una base , una reacción a los shocks , y una persistencia . Es un ARCH() con memoria de decaimiento geométrico, que es por qué supera al ARCH de orden alto.
- La estacionariedad requiere ; la varianza de largo plazo es , la persistencia es , y la vida media de la volatilidad es . Cripto se sitúa en el régimen casi-IGARCH (): muy persistente, lento para revertir a la media, y con una estimación frágil de la varianza de largo plazo.
- Estima por máxima verosimilitud. El log-verosimilitud gaussiano es una suma de densidades de un paso; ajústalo con
arch_model(r*100, vol="Garch", p=1, q=1). Recuerda el escalamiento ×100 y desescala cada salida consistentemente. - Los pronósticos revierten a la media geométricamente hacia la varianza de largo plazo a la tasa . Agrega los pronósticos de varianza diaria para obtener la volatilidad del horizonte de tenencia — no la regla ingenua de .
- Valida con Ljung-Box sobre residuos estandarizados al cuadrado y la prueba ARCH-LM. Aprobar esto confirma que el agrupamiento fue modelado y eliminado; las colas pesadas residuales que permanecen motivan la Parte 2.
- Aplícalo al dimensionamiento con objetivo de volatilidad (, con límite) y a los stops escalados por volatilidad (). Un pronóstico impulsa ambos, así que los regímenes de alta volatilidad obtienen tamaño menor y stops más amplios simultáneamente.
- Las trampas que importan: escalamiento de retornos, look-ahead en el ajuste (ajustar solo con datos pasados, siempre walk-forward), timing del pronóstico, sobre-ordenamiento, y nunca confundir un pronóstico de varianza con un pronóstico de dirección.
Referencias:
- 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
Investigación Cuantitativa y Estrategia