/ Proyectos / Finanzas / Markowitz con ML

Markowitz con ML para carteras de inversión: LSTM + CAPM + Optimización

Pipeline cuantitativo completo: predicción de precios de activos con redes LSTM, selección de acciones con CAPM y construcción de la Frontera Eficiente con la Teoría Moderna de Carteras de Markowitz.

25 min de lectura Python · TensorFlow · Keras · yfinance · scipy Datos: precios históricos reales vía Yahoo Finance API Aplicable a tesis de finanzas, economía e ingeniería financiera

Punto de partidaBrief del proyecto

"Eres analista cuantitativo en un family office. Tu jefe quiere diversificar la cartera de renta variable en acciones tech de EE.UU. y te pide lo siguiente: dame una cartera que maximice el retorno esperado, controlando el riesgo. Tienes una semana. ¿Por dónde empiezas?"

El problema clásico de construcción de portafolios tiene tres subproblemas que hay que resolver en secuencia: ¿qué rendimiento espero de cada activo?, ¿qué activos incluyo?, y ¿cuánto peso le asigno a cada uno?. Este proyecto los resuelve con herramientas modernas: LSTM para el primero, CAPM para el segundo y Markowitz para el tercero.

Qué está en juego

Una mala estimación de rendimientos esperados puede generar una cartera óptima en papel que falla en producción. Si usas medias históricas como proxy del futuro, asumes que el mercado no cambia — una premisa débil. La decisión de cómo estimar rendimientos esperados es la decisión de mayor impacto en todo el pipeline.

Mapa del proyecto

1
Obtención de datos históricos reales (yfinance)
2
Predicción de precios futuros por activo con LSTM
3
Selección de activos con filtro CAPM
4
Optimización de pesos con Teoría de Markowitz
5
Visualización: Frontera Eficiente y distribución del portafolio

Resultados de aprendizajeLo que aprendes aplicando este caso

3

Disciplinas integradas: Deep Learning, teoría financiera y optimización numérica en un solo pipeline.

10

Acciones reales de alta capitalización con datos históricos desde 2020 vía Yahoo Finance.

4

Indicadores técnicos construidos a mano: SMA, Bollinger, RSI y autocorrelación.

1

Decisión clave que lo cambia todo: cómo estimar rendimientos esperados para Markowitz.

Al terminar este proyecto sabrás hacer esto

No son conceptos abstractos. Son decisiones que podrás tomar y justificar en una tesis, en una entrevista o en un proyecto real.

Construir un pipeline completo de finanzas cuantitativas de inicio a fin
Calcular indicadores técnicos (SMA, Bollinger, RSI) desde cero con pandas
Diseñar y entrenar una arquitectura LSTM con Dropout y regularización L2
Aplicar el modelo CAPM para filtrar activos con riesgo sistemático no compensado
Optimizar pesos de portafolio con scipy.optimize (SLSQP) y trazar la Frontera Eficiente
Justificar por qué usar predicciones LSTM en lugar de medias históricas como rendimientos esperados
Identificar las limitaciones reales del modelo y proponer extensiones para una tesis
Conectar los resultados del modelo al contexto de negocio, no solo reportar métricas
Modos de uso: Tesis — contribución original comparando LSTM vs. medias históricas en Markowitz · Trabajo — pipeline replicable con cualquier universo de acciones · Portafolio — demuestra integración de Deep Learning, finanzas y optimización

Resumen del proyecto¿Qué construyes?

¿Qué encontrarás en este proyecto?

  • Descarga de precios históricos de 10 acciones tecnológicas y financieras vía Yahoo Finance API.
  • Predicción del precio futuro de cada activo con redes LSTM entrenadas con indicadores técnicos (SMA, Bollinger, RSI, autocorrelación).
  • Filtrado de activos con el modelo CAPM: beta, costo de equity y selección de acciones con rendimiento esperado atractivo.
  • Optimización del portafolio con la Teoría Moderna de Carteras de Markowitz: Frontera Eficiente y portafolio de mínima volatilidad.

Este proyecto integra tres pilares de las finanzas cuantitativas modernas en un solo pipeline: predicción de series temporales con Deep Learning, selección de activos basada en riesgo sistemático y optimización matemática de carteras. El resultado es un portafolio con pesos óptimos que maximiza el retorno ajustado al riesgo según las predicciones del modelo LSTM.

El universo de inversión son 10 acciones de alta capitalización bursátil (AAPL, MSFT, GOOGL, AMZN, TSLA, META, NFLX, NVDA, JPM, JNJ), con datos históricos desde el 1 de enero de 2020. La red neuronal predice el precio para los próximos 30 días usando los precios de cierre ajustados — un precio que incorpora dividendos, splits y consolidaciones, permitiendo comparaciones históricas precisas.

Decisión clave antes de empezar

¿Esto es un problema de regresión o de clasificación?

Predecir el precio futuro de una acción es regresión — el target es un valor continuo (el precio). Algunos proyectos convierten esto en clasificación (¿sube o baja?), lo cual simplifica pero pierde información clave para Markowitz, que necesita magnitudes, no solo dirección.

Se eligió regresión: el precio predicho se convierte directamente en el rendimiento esperado que entra al optimizador de Markowitz.

Insight de experto

La pregunta más importante de todo el pipeline no es técnica — es conceptual: ¿los rendimientos esperados son correctos? Markowitz es tan bueno como los inputs que recibe. Si los rendimientos esperados son malos, el portafolio óptimo también lo es. Aquí es donde el LSTM aporta su valor diferencial sobre el enfoque clásico de medias históricas.

Arquitectura del pipeline

  • Obtención de datos: descarga de precios ajustados de cierre con yfinance para 10 acciones desde 2020 a la fecha actual.
  • Predicción LSTM: entrenamiento de un modelo por acción con indicadores técnicos como features. Los últimos 30 días son el conjunto de prueba; el modelo predice los precios futuros que se usarán como rendimientos esperados.
  • Selección CAPM: cálculo de betas con regresión lineal sobre el S&P 500, aplicación del CAPM y filtrado de acciones cuyo retorno esperado ajustado por riesgo supera el exceso de retorno de mercado.
  • Optimización Markowitz: cálculo de la matriz de covarianza, trazado de la Frontera Eficiente y obtención de los pesos óptimos que minimizan la volatilidad del portafolio.

Stack tecnológico

  • Python 3.10+ — lenguaje principal
  • yfinance — descarga de datos históricos de Yahoo Finance
  • TensorFlow / Keras — arquitectura LSTM con capas de Dropout y regularización L2
  • scikit-learn — MinMaxScaler, StandardScaler, mean_squared_error
  • scipy — optimización numérica con minimize (SLSQP) y regresión lineal (stats.linregress)
  • pandas / numpy — manipulación de datos y álgebra matricial
  • matplotlib — visualización de precios, curvas de pérdida y Frontera Eficiente

Setup del entornoCómo correr este proyecto

El proyecto puede ejecutarse en Google Colab o localmente. Se recomienda Colab por el acceso a GPU gratuita para acelerar el entrenamiento de los modelos LSTM, especialmente cuando se entrena un modelo por acción.

Error común — setup

Usar la versión incorrecta de TensorFlow. La API de Keras cambió en TF 2.x. Si ves errores como module 'keras' has no attribute 'Sequential', verifica que estás usando tensorflow >= 2.10 y que importas desde tensorflow.keras, no desde keras directamente.

Instalación de dependencias

Terminal — instalar dependencias
pip install yfinance tensorflow scikit-learn scipy pandas numpy matplotlib

Descarga de datos con yfinance

Python — configuración inicial y descarga
import yfinance as yf
import pandas as pd
from datetime import datetime

symbols      = ['AAPL','MSFT','GOOGL','AMZN','TSLA','META','NFLX','NVDA','JPM','JNJ']
fecha_inicial = '2020-01-01'
fecha_final   = datetime.today().strftime('%Y-%m-%d')

# Descargar datos históricos
main_data = yf.download(symbols, start=fecha_inicial, end=fecha_final)

# Extraer precios de cierre ajustados
closing_prices = main_data['Adj Close']

print(f"Período: {fecha_inicial} → {fecha_final}")
print(f"Shape: {closing_prices.shape}")
print(closing_prices.tail(3))
Python — visualización de precios históricos
import matplotlib.pyplot as plt

closing_prices.plot(figsize=(12, 6))
plt.title('Precios de Cierre Ajustados — 10 Acciones (2020 a la fecha)')
plt.xlabel('Fecha')
plt.ylabel('Precio de Cierre Ajustado (USD)')
plt.legend(loc='upper left', fontsize=8)
plt.tight_layout()
plt.show()

Checkpoint — Setup

  • El DataFrame tiene 10 columnas (una por acción) sin NaN en el rango temporal
  • Los precios son de cierre ajustado, no de cierre simple
  • La visualización muestra tendencias coherentes con lo que conoces del mercado 2020–2024

Deep Learning para series temporalesCómo preparar datos para este problema

Las redes LSTM (Long Short-Term Memory) son especialmente adecuadas para series temporales financieras porque pueden capturar dependencias de largo plazo entre observaciones — algo que las redes neuronales estándar no logran. Se entrena un modelo LSTM independiente por cada acción del universo.

Decisión clave — features del modelo

¿Solo precio de cierre o con indicadores técnicos?

Solo precio: simple, menos overfitting, pero pierde señales de momentum y volatilidad.
Con indicadores: más información, mejor poder predictivo — pero hay que calcularlos correctamente y manejar los NaN que generan las ventanas móviles.

Se eligió: 4 indicadores técnicos (SMA 20d, Bollinger, RSI 14d, autocorrelación lag-1). La ganancia en predicción justifica la complejidad adicional.

División de datos e indicadores técnicos

Los datos de entrenamiento incluyen todos los registros excepto los últimos 30 días. Los últimos 30 días forman el conjunto de prueba. Sobre cada serie se calculan cuatro indicadores técnicos que enriquecen las features del modelo:

  • SMA de 20 días — suaviza las fluctuaciones e identifica la tendencia general. Un valor alto o bajo puede indicar niveles de soporte o resistencia.
  • Bandas de Bollinger (20 días, 2σ) — miden la volatilidad del mercado. Precios que tocan las bandas sugieren condiciones de sobrecompra o sobreventa.
  • RSI de 14 días — oscila entre 0 y 100. RSI > 70 indica sobrecompra; RSI < 30 indica sobreventa. Útil para anticipar cambios de tendencia.
  • Autocorrelación lag-1 — mide si el precio de hoy está correlacionado con el de ayer. Detecta patrones repetitivos y ciclos.
Python — cálculo de indicadores técnicos
import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler

def calculate_technical_indicators(data, stock_name):
    """Calcula SMA, Bandas de Bollinger, RSI y autocorrelación."""
    data = pd.DataFrame(data.copy())

    # SMA de 20 días
    data['SMA_20'] = data[stock_name].rolling(window=20).mean()

    # Bandas de Bollinger (20 días, desviación estándar de 2)
    rolling_mean = data[stock_name].rolling(window=20).mean()
    rolling_std  = data[stock_name].rolling(window=20).std()
    data['BB_upper'] = rolling_mean + 2 * rolling_std
    data['BB_lower'] = rolling_mean - 2 * rolling_std

    # RSI de 14 días
    delta = data[stock_name].diff()
    gain  = (delta.where(delta > 0, 0)).rolling(window=14).mean()
    loss  = (-delta.where(delta < 0, 0)).rolling(window=14).mean()
    RS    = gain / loss
    data['RSI_14'] = 100 - (100 / (1 + RS))

    # Autocorrelación lag-1 (valor escalar — se usa como referencia)
    autocorr_value = data[stock_name].autocorr()

    return data.dropna()

def preprocess_data(data):
    """Elimina NaNs y normaliza con MinMaxScaler al rango [0, 1]."""
    data.dropna(inplace=True)
    scaler = MinMaxScaler(feature_range=(0, 1))
    scaled_data = scaler.fit_transform(data)
    return scaled_data, scaler

Error común — preprocesamiento

Aplicar MinMaxScaler sobre todo el dataset antes de dividir en train/test. Esto genera data leakage: el scaler aprende los valores del conjunto de test, que en producción no existirían todavía. Siempre ajusta el scaler solo sobre los datos de entrenamiento y úsalo para transformar el test.

Arquitectura de la red LSTM

La red usa un modelo secuencial de Keras con tres capas LSTM apiladas y capas de Dropout para reducir el sobreajuste. La capa densa de salida tiene regularización L2 para penalizar pesos grandes.

Decisión clave — arquitectura

¿Cuántas capas LSTM y cuántas unidades?

Una sola capa: simple, rápida, pero puede no capturar patrones complejos.
Tres capas: más capacidad de representación — con el riesgo de sobreajustar si no se regulariza.

Se eligió: 3 capas con 50 unidades cada una + Dropout(0.2) entre capas. El Dropout actúa como regularizador que obliga a la red a no depender de neuronas específicas, mejorando la generalización.

Python — definición y entrenamiento del modelo LSTM
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense, Dropout
from tensorflow.keras.regularizers import L2

def build_lstm_model(input_shape):
    model = Sequential([
        # Primera capa LSTM — devuelve secuencias para la siguiente capa
        LSTM(units=50, return_sequences=True, input_shape=input_shape),

        # Segunda capa LSTM con Dropout del 20%
        LSTM(units=50, return_sequences=True),
        Dropout(0.2),

        # Tercera capa LSTM — solo devuelve la última salida
        LSTM(units=50, return_sequences=False),
        Dropout(0.1),

        # Capa densa de salida con regularización L2
        Dense(units=1, kernel_regularizer=L2(0.01))
    ])
    model.compile(optimizer='adam', loss='mean_squared_error')
    return model

Checkpoint — LSTM

  • El scaler se ajustó solo sobre datos de entrenamiento
  • La validation loss desciende junto con la training loss (sin divergencia severa)
  • Los 30 días de test no se usaron en ningún momento durante el entrenamiento
  • Las predicciones tienen el mismo orden de magnitud que los precios reales tras la inversa del scaler

Filtro de riesgo sistemáticoSelección de activos con CAPM

El CAPM (Capital Asset Pricing Model) es un modelo financiero que calcula el rendimiento esperado de un activo en función de su exposición al riesgo de mercado (beta). Se usa como filtro para seleccionar las acciones que pasarán al optimizador de Markowitz.

Decisión clave — por qué CAPM antes de Markowitz

¿Incluir todos los activos en Markowitz o filtrar antes?

Todos los activos: Markowitz puede asignar peso cero a los malos — pero es más inestable y sensible a errores de estimación cuando hay muchas acciones.
Filtrar con CAPM: reduce el universo a activos que tienen premio por riesgo justificado, haciendo que el optimizador trabaje con un subconjunto más robusto.

Se eligió: filtrar primero. Las acciones cuyo costo de equity supera el exceso de retorno de mercado se excluyen antes de la optimización.

Error común — CAPM

Usar la tasa libre de riesgo nominal en lugar de real. Si usas la tasa de bonos del Tesoro a 10 años sin ajustar por inflación, el CAPM puede excluir activos atractivos porque el umbral de selección está inflado. En períodos de alta inflación (como 2022–2023), este error sesga el filtro de forma significativa.

Checkpoint — CAPM

  • El beta de cada acción se calculó con regresión sobre el S&P 500, no estimado de memoria
  • La tasa libre de riesgo refleja el periodo de análisis (no un valor genérico fijo)
  • Al menos 3 acciones pasan el filtro — si ninguna pasa, revisar el umbral o el periodo

Teoría Moderna de CarterasOptimización con Markowitz

La Teoría Moderna de Carteras de Markowitz busca el portafolio que minimiza la volatilidad para un nivel de retorno dado — o equivalentemente, maximiza el retorno para un nivel de riesgo dado. El resultado es la Frontera Eficiente: el conjunto de portafolios óptimos.

Decisión clave — función objetivo

¿Minimizar volatilidad o maximizar ratio de Sharpe?

Mínima volatilidad: más conservador, más estable numéricamente, fácil de interpretar. El portafolio resultante es el punto más a la izquierda de la Frontera Eficiente.
Máximo Sharpe: busca el mejor balance retorno/riesgo — pero es más sensible a los inputs de rendimientos esperados.

Se eligió: minimizar volatilidad como objetivo principal. Es más robusto cuando los rendimientos esperados tienen incertidumbre (que siempre la tienen).

Insight de experto

Markowitz no te dice qué acciones son buenas — te dice cómo combinarlas. Una acción con alta volatilidad individual puede ser valiosa en el portafolio si tiene baja correlación con las demás. La diversificación matemática es el núcleo del modelo: no es elegir los mejores activos, sino los que mejor se complementan entre sí.

Checkpoint — Markowitz

  • Los pesos óptimos suman 1 (restricción de presupuesto verificada)
  • Ningún peso es negativo (si permites short-selling, esto cambia — documéntalo)
  • La Frontera Eficiente tiene forma de "bala" — si es recta o cóncava, hay un error en la matriz de covarianza
  • El portafolio de mínima volatilidad está en el extremo izquierdo de la frontera

Interpretación de resultadosEvaluación

Decisión clave — qué métrica reportar

¿RMSE, MAE o ratio de Sharpe?

RMSE del LSTM: mide el error de predicción de precios — útil para validar el modelo, pero no conecta directamente con la calidad del portafolio.
Ratio de Sharpe out-of-sample: mide si el portafolio resultante realmente superó al benchmark en un período de validación — esto es lo que importa al cliente.

Reporta ambos: RMSE para el componente técnico, Sharpe para el componente financiero. Son para audiencias distintas.

Error común — evaluación

Evaluar el portafolio solo en datos de entrenamiento. El backtesting debe hacerse en un período que el modelo no vio. Si optimizas con datos 2020–2024 y evalúas con los mismos datos, los resultados son ilusoriamente buenos. Separa al menos 6 meses como período de validación out-of-sample.


Resultados visualesFrontera Eficiente y distribución del portafolio

La visualización final muestra dos gráficos: la Frontera Eficiente con el portafolio óptimo marcado y la distribución de pesos en un gráfico de torta.

Python — visualización de la Frontera Eficiente
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 2, figsize=(16, 6))

# Frontera Eficiente
axes[0].plot([p[1] for p in efficient_frontier], [p[0] for p in efficient_frontier],
             'b-', linewidth=2, label='Frontera Eficiente')
axes[0].scatter(optimal_portfolio['Volatilidad'], optimal_portfolio['Retorno'],
                color='red', s=200, zorder=5, label='Portafolio Óptimo')
axes[0].set_xlabel('Volatilidad (Riesgo)')
axes[0].set_ylabel('Retorno Esperado')
axes[0].set_title('Frontera Eficiente de Markowitz')
axes[0].legend()

# Gráfico de torta: distribución del portafolio
axes[1].pie(w_optimal, labels=selected_stocks, autopct='%1.1f%%',
            startangle=90, pctdistance=0.85)
axes[1].set_title('Distribución del Portafolio')

plt.tight_layout()
plt.show()

Checkpoint — Visualización

  • El portafolio óptimo (punto rojo) está sobre la Frontera Eficiente, no por debajo
  • Los pesos del gráfico de torta suman 100%
  • La distribución tiene al menos 2–3 activos con peso significativo (no concentración total en uno)

Conclusiones y trabajo futuroHallazgos

Hallazgos principales

Hallazgo 1

LSTM captura patrones de corto plazo con precisión razonable

La pérdida de validación desciende de 0.154 a 0.047 en 50 épocas sin sobreajuste significativo. La diferencia entre training loss y validation loss se mantiene pequeña, lo que indica que la arquitectura de tres capas LSTM con Dropout tiene capacidad de generalización adecuada para horizontes de 30 días. Los indicadores técnicos (especialmente RSI y Bandas de Bollinger) enriquecen el poder predictivo respecto a usar solo el precio de cierre.

Hallazgo 2

El CAPM elimina activos con riesgo sistemático no compensado

El filtro CAPM reduce el universo de 10 a 4–7 acciones según las condiciones de mercado. Las acciones con beta muy alto (como TSLA o NVDA en períodos de alta volatilidad) pueden ser excluidas si su exceso de retorno predicho no justifica el riesgo que añaden. Esto protege la cartera de concentrar peso en activos altamente volátiles cuya prima de riesgo no está siendo compensada.

Hallazgo 3

Markowitz concentra el peso en activos de baja covarianza

El optimizador de mínima volatilidad tiende a asignar pesos altos a pares de acciones con baja correlación entre sí — por ejemplo, una acción tecnológica (MSFT o GOOGL) junto con una financiera o defensiva (JPM o JNJ). Esta diversificación matemática es la ventaja central de Markowitz: no se trata de elegir los mejores activos individualmente, sino los que combinados reducen el riesgo global.

Hallazgo 4

Usar predicciones LSTM como rendimientos esperados mejora la relevancia del modelo

El enfoque clásico de Markowitz usa medias históricas de rendimientos como estimadores de retornos esperados futuros — lo cual asume que el pasado predice el futuro directamente. Sustituir esas medias históricas por las predicciones del modelo LSTM introduce una estimación dinámica que reacciona a condiciones recientes del mercado, lo que puede generar portafolios más adaptados al contexto actual.

Limitaciones y trabajo futuro

  • El modelo LSTM predice solo precio, no distribución de probabilidad — una extensión con predicción de intervalo de confianza (Bayesian LSTM o Monte Carlo Dropout) cuantificaría la incertidumbre de los rendimientos esperados.
  • El horizonte de predicción es fijo en 30 días. Una arquitectura multi-step (predicción de múltiples pasos futuros de forma directa) permitiría ajustar el horizonte del portafolio de manera más flexible.
  • No se incorpora rebalanceo periódico del portafolio. En producción, el pipeline debería ejecutarse periódicamente (mensual o trimestralmente) para actualizar predicciones LSTM y pesos óptimos.
  • El universo se limita a 10 acciones. Ampliar a un índice completo (S&P 500) requeriría técnicas de clustering para agrupar acciones y entrenar modelos por cluster, reduciendo el costo computacional.
  • SHAP aplicado sobre el modelo LSTM permitiría explicar qué indicadores técnicos contribuyen más a cada predicción individual, mejorando la interpretabilidad para el analista.

Lo que realmente aprendiste

Qué te llevas: la diferencia entre estimar rendimientos esperados con medias históricas vs. con un modelo predictivo — y por qué eso cambia la calidad del portafolio.

Qué repetirías: el filtro CAPM antes de Markowitz. Reduce inestabilidad numérica y hace más robusto el resultado.

Qué evitarías: optimizar con el mismo período de datos con el que evaluarás. El backtesting fuera de muestra es obligatorio antes de presentar cualquier resultado.

¿Cómo adaptar este proyecto a tu tesis? El pipeline completo es replicable con cualquier universo de acciones disponible en Yahoo Finance. Para una tesis de ingeniería financiera, la contribución original puede ser la comparación empírica entre rendimientos esperados basados en LSTM vs. medias históricas como entrada del modelo de Markowitz, evaluando cuál genera un portafolio con mejor ratio de Sharpe out-of-sample durante un período de backtesting de 12 meses.