Guest

Redes LSTM para Predecir Precios Forex con PyTorch: Guía Completa 2026

Redes LSTM para Predecir Precios Forex con PyTorch: Guía Completa 2026

Los modelos estadísticos clásicos como ARIMA llevan décadas intentando predecir el mercado Forex con resultados modestos. Las redes neuronales recurrentes, y en particular las LSTM (Long Short-Term Memory), cambiaron las reglas del juego al poder capturar patrones temporales complejos en series de precios. En 2026, con acceso libre a PyTorch, datos históricos de alta calidad y GPUs asequibles, construir tu propio modelo predictivo ya no es exclusivo de los quants de Wall Street.


¿Por Qué LSTM y No Otro Modelo?

Las series de precios financieros tienen una característica que hace fallar a los modelos tradicionales: la dependencia temporal a largo plazo. Un precio de hoy no solo depende del precio de ayer, sino de patrones que ocurrieron hace días, semanas o incluso meses.

Comparativa de modelos para predicción de precios:

 

ModeloMemoria temporalCaptura no linealidadComplejidad
ARIMACorta❌ NoBaja
Random ForestNinguna✅ SíMedia
RNN VanillaCorta✅ SíMedia
LSTMLarga✅ SíMedia-Alta
TransformerMuy larga✅ SíMuy alta

La LSTM supera a la RNN vanilla gracias a sus compuertas de olvido, entrada y salida que regulan qué información retener a lo largo del tiempo, resolviendo el problema del gradiente desvaneciente que destruye el entrenamiento en secuencias largas.


Preparación del Dataset: OHLCV desde MetaTrader 5

Antes de escribir una sola línea de red neuronal, necesitas datos limpios. Usaremos la librería oficial MetaTrader5 de Python para extraer datos directamente desde MT5.

 

python
import MetaTrader5 as mt5
import pandas as pd
import numpy as np
from datetime import datetime

# Conectar a MetaTrader 5
mt5.initialize()

# Extraer 3 años de datos EURUSD en H1
rates = mt5.copy_rates_from_pos("EURUSD", mt5.TIMEFRAME_H1, 0, 26280)
mt5.shutdown()

# Convertir a DataFrame
df = pd.DataFrame(rates)
df['time'] = pd.to_datetime(df['time'], unit='s')
df.set_index('time', inplace=True)

# Seleccionar solo precio de cierre para el modelo base
df = df[['close', 'open', 'high', 'low', 'tick_volume']]
print(df.tail())
print(f"Total de velas: {len(df)}")

Alternativa sin MT5: Si no tienes MT5 instalado, usa yfinance:

 

python
import yfinance as yf
df = yf.download("EURUSD=X", start="2023-01-01", end="2026-01-01", interval="1h")
df = df[['Close', 'Open', 'High', 'Low', 'Volume']].rename(
    columns={'Close':'close','Open':'open','High':'high','Low':'low','Volume':'tick_volume'}
)

Normalización y Creación de Secuencias

Las redes LSTM son sensibles a la escala de los datos. Normalizar entre 0 y 1 con MinMaxScaler es el estándar para series de precios financieros.

 

python
from sklearn.preprocessing import MinMaxScaler
from torch.utils.data import Dataset, DataLoader
import torch

# Normalizar datos
scaler = MinMaxScaler(feature_range=(0, 1))
datos_norm = scaler.fit_transform(df[['close']].values)

# Crear secuencias: X = últimos N cierres, y = siguiente cierre
def crear_secuencias(datos, ventana=60):
    X, y = [], []
    for i in range(len(datos) - ventana):
        X.append(datos[i:i + ventana])
        y.append(datos[i + ventana])
    return np.array(X), np.array(y)

VENTANA = 60  # 60 velas H1 = últimas 60 horas
X, y = crear_secuencias(datos_norm, VENTANA)

# Split: 80% train, 20% test
split = int(len(X) * 0.80)
X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]

# Convertir a tensores PyTorch
X_train = torch.FloatTensor(X_train)
y_train = torch.FloatTensor(y_train)
X_test  = torch.FloatTensor(X_test)
y_test  = torch.FloatTensor(y_test)

print(f"Train: {X_train.shape} | Test: {X_test.shape}")

Arquitectura de la Red LSTM en PyTorch

El diseño de la red determina su capacidad de aprendizaje. Para predicción de precios Forex con H1, esta arquitectura ofrece un buen balance entre complejidad y generalización:

 

python
import torch.nn as nn

class LSTMForex(nn.Module):
    def __init__(self, input_size=1, hidden_size=128, num_layers=2, dropout=0.2):
        super(LSTMForex, self).__init__()

        self.hidden_size = hidden_size
        self.num_layers  = num_layers

        # Capa LSTM con dropout entre capas
        self.lstm = nn.LSTM(
            input_size  = input_size,
            hidden_size = hidden_size,
            num_layers  = num_layers,
            batch_first = True,
            dropout     = dropout
        )

        # Capa densa de salida
        self.fc = nn.Sequential(
            nn.Linear(hidden_size, 64),
            nn.ReLU(),
            nn.Dropout(0.1),
            nn.Linear(64, 1)
        )

    def forward(self, x):
        # Inicializar estados ocultos en cero
        h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)
        c0 = torch.zeros(self.num_layers, x.size(0), self.hidden_size)

        # Forward pass por LSTM
        out, _ = self.lstm(x, (h0, c0))

        # Solo usamos la salida del último timestep
        out = self.fc(out[:, -1, :])
        return out

# Instanciar modelo
modelo = LSTMForex(input_size=1, hidden_size=128, num_layers=2, dropout=0.2)
print(modelo)
print(f"Parámetros totales: {sum(p.numel() for p in modelo.parameters()):,}")

Entrenamiento del Modelo

 

python
from torch.optim import Adam
from torch.optim.lr_scheduler import ReduceLROnPlateau

# Configuración de entrenamiento
criterio   = nn.MSELoss()
optimizador = Adam(modelo.parameters(), lr=0.001, weight_decay=1e-5)
scheduler  = ReduceLROnPlateau(optimizador, patience=5, factor=0.5, verbose=True)

EPOCHS     = 100
BATCH_SIZE = 64

# DataLoader
dataset_train = torch.utils.data.TensorDataset(X_train, y_train)
loader_train  = DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=False)

historial_loss = []

for epoch in range(EPOCHS):
    modelo.train()
    loss_epoch = 0

    for X_batch, y_batch in loader_train:
        optimizador.zero_grad()
        prediccion = modelo(X_batch)
        loss = criterio(prediccion, y_batch)
        loss.backward()
        # Gradient clipping para estabilidad
        nn.utils.clip_grad_norm_(modelo.parameters(), max_norm=1.0)
        optimizador.step()
        loss_epoch += loss.item()

    loss_promedio = loss_epoch / len(loader_train)
    historial_loss.append(loss_promedio)
    scheduler.step(loss_promedio)

    if (epoch + 1) % 10 == 0:
        print(f"Epoch [{epoch+1}/{EPOCHS}] — Loss: {loss_promedio:.6f}")

Evaluación: MAE, RMSE y Visualización

 

python
from sklearn.metrics import mean_absolute_error, mean_squared_error
import matplotlib.pyplot as plt

modelo.eval()
with torch.no_grad():
    pred_test = modelo(X_test).numpy()

# Desnormalizar para obtener precios reales
pred_real  = scaler.inverse_transform(pred_test)
y_real     = scaler.inverse_transform(y_test.numpy())

# Métricas
mae  = mean_absolute_error(y_real, pred_real)
rmse = np.sqrt(mean_squared_error(y_real, pred_real))
mape = np.mean(np.abs((y_real - pred_real) / y_real)) * 100

print(f"MAE:  {mae:.5f}  → Error promedio en pips: {mae*10000:.1f}")
print(f"RMSE: {rmse:.5f}")
print(f"MAPE: {mape:.2f}%")

# Visualización
plt.figure(figsize=(14, 5))
plt.plot(y_real[-300:],    label='Precio Real',    color='#00d4ff', linewidth=1.5)
plt.plot(pred_real[-300:], label='LSTM Predicción', color='#ff6b35', linewidth=1.5, linestyle='--')
plt.title('LSTM EURUSD H1 — Predicción vs Real (últimas 300 velas)', fontsize=13)
plt.legend()
plt.grid(alpha=0.3)
plt.tight_layout()
plt.savefig('lstm_eurusd_prediccion.png', dpi=150)
plt.show()

Referencia de métricas para EURUSD H1:

 

MétricaResultado aceptableResultado excelente
MAE en pips< 15 pips< 8 pips
RMSE< 0.0015< 0.0008
MAPE< 0.8%< 0.4%

Integrar la LSTM como Señal en MetaTrader 5

La predicción del modelo puede usarse como señal de dirección dentro de un EA en MT5 usando la librería oficial de Python:

 

python
import MetaTrader5 as mt5

def generar_senal_lstm(modelo, scaler, ventana=60):
    """Retorna 1 (compra), -1 (venta) o 0 (no operar)"""
    mt5.initialize()
    rates = mt5.copy_rates_from_pos("EURUSD", mt5.TIMEFRAME_H1, 0, ventana)
    mt5.shutdown()

    cierres = np.array([r['close'] for r in rates]).reshape(-1, 1)
    cierres_norm = scaler.transform(cierres)

    X = torch.FloatTensor(cierres_norm).unsqueeze(0)  # batch=1

    modelo.eval()
    with torch.no_grad():
        pred_norm = modelo(X).item()

    precio_pred  = scaler.inverse_transform([[pred_norm]])[0][0]
    precio_actual = cierres[-1][0]
    diferencia_pips = (precio_pred - precio_actual) * 10000

    if diferencia_pips > 5:    # Predicción: sube más de 5 pips
        return 1   # Señal de compra
    elif diferencia_pips < -5: # Predicción: baja más de 5 pips
        return -1  # Señal de venta
    else:
        return 0   # Sin señal clara

Esta función se llama desde un EA MQL5 usando Python.dll o un socket ZeroMQ, permitiendo que la inteligencia del modelo Python opere directamente en MT5.


Limitaciones Reales: Este Modelo No Es el Santo Grial

La honestidad técnica es fundamental. Una LSTM bien entrenada no predice el futuro — detecta patrones estadísticos que funcionaron en el pasado:

Overfitting — Un modelo con MAE perfecta en train y mala en test solo memorizó el pasado

Non-stationarity — Los mercados cambian de régimen; un modelo entrenado en 2023 puede fallar en 2026

Black Swan events — NFP, guerras, crisis bancarias rompen cualquier patrón estadístico

Lag inherente — Las LSTMs tienden a predecir "el precio de ayer + epsilon", no movimientos reales

La solución correcta: Usar la LSTM como filtro de dirección, no como predictor exacto de precio. Combínala con lógica SMC o estructura de mercado para tener confluencia.


Herramientas y Stack Recomendado

PyTorch 2.3+ — Framework principal para la red neuronal

scikit-learn — Preprocesamiento y métricas de evaluación

MetaTrader5 Python library — Extracción de datos y ejecución de señales

Google Colab Pro / Vast.ai — GPUs asequibles para entrenar en horas

Weights & Biases (wandb) — Tracking de experimentos y comparación de modelos

HydraBlack Market — Notebooks y modelos LSTM pre-entrenados para Forex listos para desplegar


¿Quieres el Notebook Completo Listo para Ejecutar?

Construir y depurar este pipeline desde cero puede tomar días. En HydraBlack Market encuentras el notebook completo con LSTM + integración MT5, documentado, optimizado y listo para ejecutar en Google Colab o tu entorno local.

Descarga el Notebook LSTM Forex en HydraBlack Market

Join the Discussion (0)