1. Regresión lineal en Python: tres librerías, tres filosofías
Nivel 6: Regresión y Modelos de Pricing
La regresión lineal es probablemente la herramienta más usada de todo el trading cuantitativo. Antes de entrar en la teoría de los modelos de pricing, conviene saber con qué herramientas se estima una regresión en Python, porque no todas sirven para lo mismo.
Estas son las tres opciones que vas a encontrar en el 95% del código financiero:
- statsmodels: la clase
statsmodels.api.OLS()(o la interfaz de fórmulasstatsmodels.formula.api.ols()). Es la librería de los econometristas. - scikit-learn: la clase
sklearn.linear_model.LinearRegression(). Es la librería de los que hacen machine learning. - NumPy: la función
numpy.polyfit()con grado 1. Es la opción minimalista.
Y hay más (TensorFlow con la API de Keras, PyTorch...), pero la elección depende del problema concreto, de la familiaridad con la librería y de la preferencia personal.
La diferencia práctica es enorme y conviene entenderla desde el principio. statsmodels está pensado para inferencia: quiere que respondas a preguntas como si el beta de una acción es estadísticamente distinto de cero, cuál es su intervalo de confianza o si el alfa de un fondo es real o ruido. Por eso su método .summary() te devuelve coeficientes, errores estándar, estadísticos t, p-valores y R cuadrado. scikit-learn está pensado para predicción: te da .fit() y .predict(), un .coef_ con las pendientes, y punto. No hay p-valores porque en el paradigma de machine learning lo que importa es el error fuera de muestra, no la significatividad de cada parámetro. NumPy no está pensado para nada de eso: te ajusta una recta y te devuelve dos números.
import numpy as np
import statsmodels.api as sm
from sklearn.linear_model import LinearRegression
# x: retornos del mercado, y: retornos de la accion
# 1. NumPy: minimalista. Devuelve los coeficientes de mayor a menor grado.
slope, intercept = np.polyfit(x, y, 1)
# 2. scikit-learn: orientado a prediccion.
modelo = LinearRegression().fit(x.reshape(-1, 1), y)
print(modelo.coef_, modelo.intercept_)
# 3. statsmodels: orientado a inferencia. Ojo: hay que anadir la constante a mano.
X = sm.add_constant(x)
resultado = sm.OLS(y, X).fit()
print(resultado.summary())Hay un detalle que causa muchísimos errores silenciosos: statsmodels no añade el término constante por ti. Si llamas a sm.OLS(y, x) sin sm.add_constant(x), estás forzando a que la recta pase por el origen. En un modelo de pricing eso significa imponer que el alfa es exactamente cero, que es justo la hipótesis que querías contrastar. scikit-learn sí lo añade por defecto (fit_intercept=True), y np.polyfit con grado 1 también estima la ordenada en el origen.
En este nivel usaremos sobre todo statsmodels, porque los modelos de pricing (CAPM, Fama-French) no se usan para predecir: se usan para descomponer un retorno en partes explicables y averiguar si queda algo sin explicar.