Quant500 Academy

1. Preparar datos de series temporales: del precio al retorno

Nivel 8: Series Temporales - Estacionariedad

En este nivel entramos en la metodología de predicción de series temporales univariantes apoyándonos en las herramientas principales del ecosistema Python. Pandas ofrece capacidades muy sólidas para manipular datos temporales, y Statsmodels aporta lo necesario para diseccionar los datos, estimar modelos estadísticos y ejecutar contrastes de hipótesis.

El investigador cuantitativo busca discernir tendencias, fluctuaciones estacionales y dependencias en datos financieros históricos aplicando técnicas estadísticas de series temporales. La aspiración final es generar señales de trading accionables. Mejorar la rentabilidad de nuestros algoritmos exige métodos estadísticos rigurosos que reconozcan comportamientos consistentes del activo, aprovechables como oportunidad. Eso implica examinar a fondo cómo evolucionan en el tiempo las propiedades del precio.

Para empezar, descargamos el S&P 500 (^GSPC) de Yahoo Finance. El objetivo de todo el nivel será entender y, más adelante, predecir este índice.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import datetime
import yfinance as yf
import warnings
import statsmodels.api as sm
import statsmodels.tsa.api as smt
import scipy.stats as scs
from statsmodels.tsa.stattools import coint, adfuller
warnings.filterwarnings('ignore')

plt.rc('figure', figsize=(18, 3))
pd.set_option('display.float_format', lambda x: '%.2f' % x)

Cargamos casi siete años de historia diaria:

start = datetime.datetime(2016, 1, 1)
end = datetime.datetime(2022, 12, 30)
df = yf.download('^GSPC', start=start, end=end, auto_adjust=True)['Close']

df.head()
df.dropna(axis='index', how='all', inplace=True)
df.index[:5]   # el índice ya viene en formato datetime, que es lo que queremos

Ese índice de tipo datetime no es un detalle cosmético: es lo que convierte un DataFrame corriente en una serie temporal. Pandas representa una serie temporal como un objeto Series, un array unidimensional con una etiqueta de tiempo por fila.

El segundo paso, y el más importante conceptualmente, es pasar del precio al retorno logarítmico:

Re = np.log(df).diff().dropna()   # equivale a np.log(df / df.shift(1))
Re.head()

La diferencia del logaritmo es la primera diferencia de la serie en escala logarítmica. Trabajamos con retornos y no con niveles de precio por tres motivos: los retornos son aproximadamente estacionarios mientras que los precios no lo son, son aditivos en el tiempo (la suma de retornos logarítmicos de varios días es el retorno logarítmico del periodo completo), y son comparables entre activos con precios de escala muy distinta. El .dropna() es obligatorio porque la primera diferencia siempre deja un valor nulo en la primera fila: no hay día anterior con el que compararla.

Con la serie ya creada, pandas permite consultarla usando el índice de fechas directamente, sin necesidad de posiciones numéricas:

ts = pd.Series(df, index=df.index)

df[:'2017'].tail(10)        # todo hasta el final de 2017
df['2020-06':'2020-07']     # dos meses concretos
df.size                     # número de observaciones
df.describe()               # estadísticos descriptivos

Ojo con describe() sobre precios: te devolverá una media y una desviación típica perfectamente calculadas y completamente inútiles. Si la serie tiene tendencia, esa media no describe ningún estado real del mercado, sino una mezcla de estados distintos en momentos distintos. Es la primera pista de por qué la estacionariedad, que veremos más adelante, va a ser el concepto central del nivel.

El resto de Quant500

Lo que estás aprendiendo, aplicado al índice todos los días:

La cartera del modelo, cada semana en tu correo

Cada sábado, su semana en un minuto: cómo fue, lo mejor y lo peor, y qué directivos compraron con su dinero. Y el día que el modelo se rehace, qué entra y qué sale. Es una simulación, no un consejo. Como mucho un correo a la semana, sin publicidad y sin cuenta; te das de baja con un clic. Lo hace una persona: Pol Gracia.

Cartera modelo con resultados simulados, no una recomendación personalizada. Tu correo se usa solo para esto: privacidad.

Detrás de la Academia y del resto de Quant500 hay una sola persona: Pol Gracia Serrahima.