Quant500 Academy

1. La optimización, el corazón del machine learning

Nivel 10: Machine Learning Aplicado al Trading

El machine learning lleva despertando interés desde los años sesenta, pero mucha gente tiene miedo de empezar, sobre todo porque parece exigir un conocimiento profundo de álgebra lineal y de cálculo. La intención de este nivel es quitarte ese miedo de encima y enseñarte que, con relativamente poco esfuerzo, se pueden construir modelos prácticos que resuelven problemas reales. Eso sí, conviene decirlo desde el principio para no vender humo: construir modelos verdaderamente precisos sigue siendo una tarea compleja y exigente.

El machine learning se apoya en tres pilares:

De los tres, uno merece una frase destacada: la optimización está en el corazón de casi todos los algoritmos de machine learning. Cuando decimos que un modelo aprende, lo que realmente está ocurriendo es que un procedimiento numérico busca los valores de los parámetros que minimizan una función de error. En regresión se minimiza la suma de errores al cuadrado; en clasificación, la entropía cruzada; en optimización de carteras al estilo Markowitz, se minimiza la varianza para un retorno objetivo. Cambian el modelo y la función objetivo, pero la maquinaria conceptual es la misma: define un error, calcula en qué dirección disminuye, y muévete en esa dirección.

Ese mover es el descenso de gradiente: calculas la derivada de la función de error respecto a cada parámetro y das un pequeño paso en sentido contrario al gradiente. Vamos a escribirlo a mano, sin librerías de ML, sobre un problema financiero mínimo: predecir el retorno de mañana a partir del retorno de hoy.

import numpy as np

rng = np.random.default_rng(42)

# Serie sintética de retornos diarios con una pizca de autocorrelación
r_hoy = rng.normal(0, 0.01, 2000)
r_manana = 0.15 * r_hoy + rng.normal(0, 0.01, 2000)

# Escalamos la variable de entrada: la optimización es MUY sensible a la escala
x = (r_hoy - r_hoy.mean()) / r_hoy.std()
y = r_manana

w, b = 0.0, 0.0      # parámetros a aprender
lr = 0.1             # tasa de aprendizaje

for epoca in range(500):
    pred = w * x + b
    error = pred - y
    grad_w = 2 * np.mean(error * x)
    grad_b = 2 * np.mean(error)
    w -= lr * grad_w
    b -= lr * grad_b
    if epoca % 100 == 0:
        print(epoca, 'MSE =', float(np.mean(error ** 2)))

print('w aprendido:', round(w, 6), '| b aprendido:', round(b, 8))

Fíjate en el detalle del escalado. Si entrenas directamente sobre retornos con desviación típica de 0.01, la curvatura de la función de error respecto a w es diminuta y el algoritmo tarda una eternidad en moverse, mientras que b converge enseguida. No es un fallo del modelo: es un fallo de la optimización. Ese tipo de problemas, invisibles si solo llamas a una función de una librería, son la razón por la que merece la pena entender qué ocurre por debajo.

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.