2. Ajustar un AR en Python: el orden con AIC y BIC
Nivel 9: Series Temporales - ARIMA y GARCH
La libreria statsmodels ofrece el modelo autorregresivo listo para usar. La clase moderna es AutoReg (las antiguas AR y statsmodels.tsa.arima_model.ARIMA están obsoletas; si ves código con ellas, actualízalo).
Partimos de los retornos logarítmicos del S&P 500 y hacemos una partición que respeta el orden temporal. Nada de train_test_split con shuffle=True: en series temporales barajar es hacer trampas.
import numpy as np
import yfinance as yf
from statsmodels.tsa.api import AutoReg
df = yf.download('^GSPC', start='2016-01-01', end='2022-12-30')['Close']
Re = np.log(df).diff().dropna() # retornos logaritmicos
X = Re.values
train_size = int(len(X) * 0.66)
train, test = X[1:train_size], X[train_size:]Ajustar un AR con 30 retardos y leer el resumen:
max_lag = 30
model = AutoReg(train, lags=max_lag, trend='n').fit()
print(model.summary())
aic_value = model.aic
print('Valor AIC:', aic_value)Dos detalles que importan más de lo que parece:
trend='n'significa *no constante*: no se estima término independiente. Tiene sentido con retornos logarítmicos, cuya media es prácticamente cero. Si usastrend='c'(el valor por defecto),model.params[0]será la constante y los coeficientes de los retardos empiezan en el índice 1. Confundir esa numeración es la causa número uno de predicciones manuales que salen mal.- El AIC (criterio de información de Akaike) mide el equilibrio entre ajuste y complejidad: penaliza añadir parámetros. No mide capacidad predictiva fuera de muestra, mide verosimilitud penalizada dentro de muestra.
Antes de elegir el orden conviene mirar los residuos del modelo ajustado:
_ = tsplot(model.resid, lags=max_lag) # serie, ACF, PACF, QQ y probplotSi los residuos parecen ruido blanco discreto, el modelo ha capturado la estructura lineal. Si aún queda autocorrelación, el orden es insuficiente.
Selección del orden por rejilla. En lugar de fijar p a ojo, recorremos los órdenes posibles y nos quedamos con el de menor AIC:
max_lag = 30
best_aic = np.inf
best_order = 0
best_model = None
for lag in range(1, max_lag + 1):
model = AutoReg(train, lags=lag, trend='n').fit()
if model.aic < best_aic:
best_aic = model.aic
best_order = lag
best_model = model
print('Mejor orden AR:', best_order)
print('Mejor AIC:', best_aic)
print(best_model.summary())Fíjate en que el bucle reajusta el modelo desde cero en cada iteración: cada AR(lag) es una regresión distinta, no un modelo anidado que se va ampliando.
El mismo esquema sirve con BIC (criterio bayesiano) cambiando result.aic por result.bic. La diferencia práctica: el BIC penaliza los parámetros extra con más dureza porque su penalización crece con el logaritmo del tamaño muestral. Con series financieras largas, el BIC casi siempre elige un orden más pequeño que el AIC. En trading eso suele ser una virtud: menos parámetros significa menos sobreajuste al ruido de la muestra y una estrategia más robusta cuando el régimen de mercado cambia.
Una advertencia honesta: elegir el orden por AIC sobre el conjunto de entrenamiento y después medir el error en test es correcto. Elegirlo mirando el error en test y luego presentar ese mismo error como resultado del backtest no lo es: es sesgo de selección, y es una de las formas más comunes de inflar resultados sin darse cuenta.
Para ampliar esta lección
- PER estimado (forward)en el glosario
- S&P 500en el glosario
- Qué es el PER y cómo compararlo con su sectorguía