English Русский 中文 Deutsch 日本語
preview
Integración de un modelo de IA en una estrategia de trading MQL5 ya existente

Integración de un modelo de IA en una estrategia de trading MQL5 ya existente

MetaTrader 5Trading |
48 1
Hlomohang John Borotho
Hlomohang John Borotho

Introducción

En este artículo, vamos a integrar un modelo de IA en una estrategia de trading de MQL5 ya existente; para ello, utilizaremos «Order Block» combinado con niveles de Fibonacci del artículo anterior. Muchas estrategias de trading MQL5 existentes se basan en indicadores fijos, umbrales rígidos o patrones predefinidos que pueden no ser efectivos en diferentes ciclos de mercado. Estas estrategias carecen de la capacidad de aprender de datos pasados, reconocer patrones complejos o ajustar sus decisiones de forma dinámica en función de las condiciones cambiantes.

La incorporación de un modelo de IA a una estrategia de trading MQL5 puede ayudar a superar los desafíos existentes al dotar al sistema de adaptabilidad basada en aprendizaje automático. Mediante el uso de técnicas como la memoria a largo y corto plazo (LSTM) o el análisis predictivo, la IA puede analizar extensos conjuntos de datos históricos y en tiempo real para generar decisiones de trading más inteligentes. A diferencia de las estrategias rígidas y predefinidas, los sistemas mejorados con IA adaptan y perfeccionan dinámicamente sus enfoques aprendiendo de las condiciones cambiantes del mercado. Esto permite una mejor precisión en el timing de entrada, una mitigación de riesgos más eficaz y una mayor rentabilidad a lo largo del tiempo.


Empezando

Para empezar, el primer paso es portar el código MQL5 existente a Python. Dado que estamos integrando la inteligencia artificial en la estrategia de trading, contar con una versión basada en Python de la lógica MQL5 original es esencial. Esta conversión garantiza que podamos incorporar sin problemas mejoras basadas en IA sin interrumpir la funcionalidad principal de la estrategia. La versión en Python del código debe replicar con precisión el comportamiento del script MQL5, incluyendo la lógica de ejecución de operaciones, los cálculos de indicadores, la gestión de órdenes y cualquier regla de gestión de riesgos. Esto garantiza que el modelo de IA interactuará con un sistema que se comporta de forma idéntica al que se ejecuta en MetaTrader 5, lo que permite realizar pruebas y optimizaciones precisas antes de la integración completa. Una vez completado este paso, podemos proceder a integrar modelos de aprendizaje automático, entrenar la IA con datos de mercado y, en última instancia, crear un sistema de negociación inteligente y adaptativo que mejore la toma de decisiones y el rendimiento.

Código MQL5:

#include <Trade/Trade.mqh>
#include <Arrays\ArrayObj.mqh>
CTrade trade;

#define BullOB clrLime
#define BearOB clrRed

//+------------------------------------------------------------------+
//|                           Global vars                            |
//+------------------------------------------------------------------+
double Lots = 0.01;
int takeProfit = 170;
int length = 100;
input double stopLoss = 350;
input double Mgtn = 0.85;

bool isBullishOB = false; 
bool isBearishOB = false;

input int Time1Hstrt = 3;
input int Time1Hend = 4;

class COrderBlock : public CObject {
public:
   int direction;
   datetime time;
   double high;
   double low;
   bool traded;

   string rectName;  
   string tradeRectName; 

   COrderBlock(int dir, datetime t, double h, double l) {
      direction = dir;
      time = t;
      high = h;
      low = l;
      traded = false;
      rectName = "";
      tradeRectName = "";
      
   }

   void draw(datetime tmS, datetime tmE, color clr) {
      rectName = "OB REC" + TimeToString(time);
      ObjectCreate(0, rectName, OBJ_RECTANGLE, 0, time, low, tmS, high);
      ObjectSetInteger(0, rectName, OBJPROP_FILL, true);
      ObjectSetInteger(0, rectName, OBJPROP_COLOR, clr);

      tradeRectName = "OB trade" + TimeToString(time);
      ObjectCreate(0, tradeRectName, OBJ_RECTANGLE, 0, tmS, high, tmE, low);
      ObjectSetInteger(0, tradeRectName, OBJPROP_FILL, true);
      ObjectSetInteger(0, tradeRectName, OBJPROP_COLOR, clr);
   }
   
   void removeDrawings() {
      if (ObjectFind(0, rectName) != -1) {
         ObjectDelete(0, rectName); // Delete the main rectangle
      }
      if (ObjectFind(0, tradeRectName) != -1) {
         ObjectDelete(0, tradeRectName); // Delete the trade rectangle
      }
   }
};
// Pointer to CArrayObj

// Declare the dynamic array to hold order blocks
CArrayObj *orderBlocks; 
color OBClr;
datetime T1;
datetime T2;

int OnInit() {
   orderBlocks = new CArrayObj(); // Allocate memory for the array
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason) {
   ObjectsDeleteAll(0, "OB");
   
   // Clear and free the order blocks
   if (orderBlocks != NULL) {
      orderBlocks.Clear(); // This will delete objects inside
      delete orderBlocks; // Free the array memory
      orderBlocks = NULL;
   }
}

void OnTick() {
   if (isNewBar()) {
      static int prevDay = 0;
      
      MqlDateTime structTime;
      TimeCurrent(structTime);
      structTime.min = 0;
      structTime.sec = 0;
      
      structTime.hour = Time1Hstrt;
      datetime timestrt = StructToTime(structTime);
      
      structTime.hour = Time1Hend;
      datetime timend = StructToTime(structTime);
      
      getOrderB();
      double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

      for (int i = orderBlocks.Total() - 1; i >= 0; i--) {
         COrderBlock *OB = (COrderBlock *)orderBlocks.At(i);

         if (CheckPointer(OB) != POINTER_INVALID && !OB.traded) {
         
            if(OB.direction > 0 && Ask < OB.high){
               double entry = Ask;
               double tp = getHigh(iHighest(_Symbol, PERIOD_CURRENT, MODE_HIGH, iBarShift(_Symbol, PERIOD_CURRENT, OB.time)));
               double sl = NormalizeDouble(OB.low - Mgtn, _Digits);
   
               T2 = getTime(0);
               OB.draw(T1, T2, BullOB);
               trade.Buy(Lots, _Symbol, entry, sl, tp, "OB buy");
               OB.traded = true;
               //OB.removeDrawings();
               orderBlocks.Delete(i); // Delete from array
               delete OB; // Free memory
               
               
            }
         }
         if(CheckPointer(OB) != POINTER_INVALID && !OB.traded){
            if (OB.direction < 0 && Bid > OB.low) {
                  double entry = Bid;
                  double tp = getLow(iLowest(_Symbol, PERIOD_CURRENT, MODE_LOW, iBarShift(_Symbol, PERIOD_CURRENT, OB.time)));
                  double sl = NormalizeDouble(OB.high + Mgtn, _Digits);
      
                  T2 = getTime(0);
                  OB.draw(T1, T2, BearOB);
                  trade.Sell(Lots, _Symbol, entry, sl, tp, "OB sell");
                  OB.traded = true;
                  //OB.removeDrawings();
                  orderBlocks.Delete(i); // Delete from array
                  delete OB; // Free memory
                  

            }
         }
      }
   }
}

void getOrderB(){

   static int prevDay = 0;
   
   MqlDateTime structTime;
   TimeCurrent(structTime);
   structTime.min = 0;
   structTime.sec = 0;
   
   structTime.hour = Time1Hstrt;
   datetime timestrt = StructToTime(structTime);
   
   structTime.hour = Time1Hend;
   datetime timend = StructToTime(structTime);
   
   int visibleBars = (int)ChartGetInteger(0,CHART_VISIBLE_BARS);
         
   for(int i = 1; i <= visibleBars; i++){
      if(getOpen(i) < getClose(i)){ // index is i since the loop starts from i which is = 1 "for(int i = 1)..."
         if(getOpen(i + 2) < getClose(i + 2)){
            if(getOpen(i + 3) > getClose(i + 3) && getOpen(i + 3) < getClose(i + 2)){
               Print("Bullish Order Block confirmed at: ", TimeToString(getTime(i + 2), TIME_DATE||TIME_MINUTES));
               //isBullishOB = true;
               //OB = new COrderBlock();
               int direction = 1;
               datetime time = getTime(i + 3);
               double high = getHigh(i + 3);
               double low = getLow(i + 3);
               isBullishOB = true;
               
               OBClr = isBullishOB ? BullOB : BearOB;
               
               // specify strt time
               T1 = time;
               // reset BULLOB flag
               isBullishOB = false;
               // crucial
               COrderBlock *newOB = new COrderBlock(direction, time, high, low);
               orderBlocks.Add(newOB);
               break;
               
               //delete newOB;
            }
         }
      }
      if(getOpen(i) > getClose(i)){
         if(getOpen(i + 2) > getClose(i + 2)){
            if(getOpen(i + 3) < getClose(i + 3) && getOpen(i + 3) < getClose(i + 2)){
               Print("Bearish Order Block confirmed at: ", TimeToString(getTime(i + 2), TIME_DATE||TIME_MINUTES));
               //isBearishOB = true;
               //OB = new COrderBlock();
               int direction = -1;
               datetime time = getTime(i + 3);
               double high = getHigh(i + 3);
               double low = getLow(i + 3);
               isBearishOB = true;
               
               OBClr = isBearishOB ? BearOB : BullOB;
               
               T1 = time;
               
               // reset the BEAROB flag
               isBearishOB = false;
               // crusssial
               COrderBlock *newOB = new COrderBlock(direction, time, high, low);
               orderBlocks.Add(newOB);
               break;
               
               //delete newOB;
            }
         }
      }
    }
      
}

double getHigh(int index) {
    return iHigh(_Symbol, _Period, index);
}

double getLow(int index) {
    return iLow(_Symbol, _Period, index);
}

double getOpen(int index){
   return iOpen(_Symbol, _Period, index);
}

double getClose(int index){
   return iClose(_Symbol, _Period, index);
}

datetime getTime(int index) {
    return iTime(_Symbol, _Period, index);
}

bool isNewBar() {
   // Memorize the time of opening of the last bar in the static variable
   static datetime last_time = 0;
   
   // Get current time
   datetime lastbar_time = (datetime)SeriesInfoInteger(Symbol(), Period(), SERIES_LASTBAR_DATE);

   // First call
   if (last_time == 0) {
      last_time = lastbar_time;
      return false;
   }

   // If the time differs (new bar)
   if (last_time != lastbar_time) {
      last_time = lastbar_time;
      return true;
   }

   // If no new bar, return false
   return false;
}

void deler(){
   static int prevDay = 0;
   
   MqlDateTime structTime;
   TimeCurrent(structTime);
   structTime.min = 0;
   structTime.sec = 0;
   
   structTime.hour = Time1Hstrt;
   datetime timestrt = StructToTime(structTime);
   
   structTime.hour = Time1Hend;
   datetime timend = StructToTime(structTime);

}

En nuestro artículo anterior, analizamos la funcionalidad principal y el diseño de este código, que implementa una estrategia de trading algorítmica centrada en la identificación y negociación de "bloques de órdenes" (Order blocks): Patrones específicos de velas japonesas que se cree que señalan posibles cambios de tendencia en el mercado. Diseñado como un Asesor Experto (EA, por sus siglas en inglés), combina el análisis de price action con la ejecución automatizada de operaciones. El código aprovecha la programación orientada a objetos a través de la clase `COrderBlock` para almacenar datos críticos de patrones (marcas de tiempo, límites de precios, dirección) y gestionar las anotaciones visuales de los gráficos. Un array dinámico `CArrayObj` realiza un seguimiento de los bloques de órdenes activas, lo que garantiza una gestión eficiente de la memoria y una monitorización de patrones en tiempo real en múltiples instancias del gráfico.

La función `getOrderB()` impulsa el reconocimiento de patrones al escanear velas japonesas históricas en busca de secuencias alcistas/bajistas específicas. Los bloques de órdenes alcistas se identifican cuando tres velas alcistas consecutivas siguen a una vela bajista, mientras que los patrones bajistas requieren tres velas bajistas después de una alcista. Los patrones detectados se instancian como objetos `COrderBlock` con indicadores direccionales (1 para alcista, -1 para bajista) y se almacenan en el array. El código incorpora filtros de tiempo configurables por el usuario (`Time1Hstrt`, `Time1Hend`) para centrarse en sesiones de negociación específicas, lo que mejora la relevancia de los patrones.

En cada nueva barra (detectada mediante `isNewBar()`), el EA procesa los bloques de órdenes activas en la función `OnTick()`. Para patrones alcistas, abre posiciones largas cuando la acción del precio rompe por encima del máximo del order block, estableciendo stop losses por debajo del mínimo del patrón menos un margen (`Mtgn`). Las operaciones bajistas se activan con rupturas por debajo de los mínimos del patrón, con stops por encima de los máximos. El EA utiliza `CTrade` para la gestión de órdenes, calculando los niveles de toma de ganancias en función de los máximos y mínimos recientes. Las operaciones ejecutadas eliminan automáticamente sus bloques de órdenes y gráficos asociados para evitar señales duplicadas.

El sistema emplea múltiples medidas de seguridad: las distancias de stop-loss se normalizan según los requisitos de dígitos del bróker, el tamaño de la posición permanece fijo en `Lots`, y los indicadores visuales (rectángulos de colores) facilitan la validación visual de la estrategia. Los usuarios pueden personalizar parámetros clave como la distancia de stop-loss (StopLoss), los márgenes de beneficio (Mtgn) y la duración de la sesión mediante variables de entrada. El código equilibra la automatización con elementos discrecionales: si bien la detección de patrones es algorítmica, la ejecución de las operaciones respeta las restricciones específicas del bróker, como las distancias mínimas de stop y las consideraciones sobre el spread.

Versión de Python:

Antes de empezar, como siempre, necesitamos datos históricos del mercado. Estos datos sirven de base para entrenar nuestro modelo de IA y validar la precisión de nuestra estrategia. Supongo que a estas alturas ya está familiarizado con la obtención de datos históricos. No obstante, si tienes dudas o necesitas un repaso, consulta la primera parte de mi guía sobre la integración de MQL5 con paquetes de procesamiento de datos. A continuación, simplemente cargamos los datos históricos.

import pandas as pd

# Load historical data
file_path = '/home/int_junkie/Documents/DataVisuals/AI inside MQL5/XAUUSD_H1.csv'
data = pd.read_csv(file_path)

# Display the first few rows and column names
print(data.head())
print(data.columns)

Al estructurar la versión en Python del código, nos aseguramos de que esté diseñada para procesar datos históricos del mercado de manera efectiva, lo que sirve de base para el entrenamiento de nuestro modelo de IA. El primer paso consiste en establecer un pipeline de datos que permita al script ingerir, preprocesar y organizar datos históricos de precios, incluyendo características clave como precios de apertura, máximo, mínimo y cierre, volumen y cualquier indicador técnico relevante. Este formato estructurado permite que el modelo de IA aprenda patrones significativos a partir del comportamiento histórico del mercado.

Además, integramos la funcionalidad para entrenar un modelo de memoria a largo y corto plazo (LSTM), un tipo especializado de red neuronal recurrente (RNN) conocida por su capacidad para analizar datos secuenciales y capturar dependencias a largo plazo. El proceso de entrenamiento está alineado con la lógica de compra y venta existente de la estrategia MQL5 original, lo que garantiza que el modelo aprenda a tomar decisiones de trading basadas en la evolución histórica de los precios. Al relacionar los datos históricos con las señales de compra y venta correspondientes, el modelo LSTM perfecciona gradualmente sus capacidades predictivas, lo que le permite anticipar los posibles movimientos del mercado de forma más eficaz. Este enfoque estructurado nos permite acortar la brecha entre el trading basado en reglas y el trading impulsado por IA y la toma de decisiones impulsada por IA, mejorando en última instancia la adaptabilidad y la precisión del sistema de negociación.

import pandas as pd
import numpy as np
from datetime import datetime
from keras.models import Sequential
from keras.layers import LSTM, Dense
import tensorflow as tf

# Constants
LOTS = 0.01
TAKE_PROFIT = 170
STOP_LOSS = 350
MGTN = 0.85
TIME1_HSTRT = 3
TIME1_HEND = 4

# Helper functions
def get_high(data, index):
    return data.iloc[index]['<HIGH>']

def get_low(data, index):
    return data.iloc[index]['<LOW>']

def get_open(data, index):
    return data.iloc[index]['<OPEN>']

def get_close(data, index):
    return data.iloc[index]['<CLOSE>']

def get_time(data, index):
    return data.iloc[index]['DATETIME']  # Combined datetime column

def is_new_bar(current_time, last_time):
    return current_time != last_time

class OrderBlock:
    def __init__(self, direction, time, high, low):
        self.direction = direction
        self.time = time
        self.high = high
        self.low = low
        self.traded = False

def get_order_blocks(data):
    order_blocks = []
    visible_bars = len(data)

    for i in range(1, visible_bars - 3):  # Adjusted to avoid index errors
        if get_open(data, i) < get_close(data, i):  # Bullish condition
            if get_open(data, i + 2) < get_close(data, i + 2):
                if get_open(data, i + 3) > get_close(data, i + 3) and get_open(data, i + 3) < get_close(data, i + 2):
                    print(f"Bullish Order Block confirmed at: {get_time(data, i + 2)}")
                    direction = 1
                    time = get_time(data, i + 3)
                    high = get_high(data, i + 3)
                    low = get_low(data, i + 3)
                    order_blocks.append(OrderBlock(direction, time, high, low))
                    break

        if get_open(data, i) > get_close(data, i):  # Bearish condition
            if get_open(data, i + 2) > get_close(data, i + 2):
                if get_open(data, i + 3) < get_close(data, i + 3) and get_open(data, i + 3) < get_close(data, i + 2):
                    print(f"Bearish Order Block confirmed at: {get_time(data, i + 2)}")
                    direction = -1
                    time = get_time(data, i + 3)
                    high = get_high(data, i + 3)
                    low = get_low(data, i + 3)
                    order_blocks.append(OrderBlock(direction, time, high, low))
                    break

    return order_blocks

def simulate_trading(data, order_blocks):
    trades = []
    last_time = None

    for i, row in data.iterrows():
        current_time = row['DATETIME']
        if is_new_bar(current_time, last_time):
            last_time = current_time

            bid = row['<CLOSE>']  # Assuming bid price is close price
            ask = row['<CLOSE>']  # Assuming ask price is close price

            for ob in order_blocks:
                if not ob.traded:
                    if ob.direction > 0 and ask < ob.high:  # Buy condition
                        entry = ask
                        tp = data.iloc[:i]['<HIGH>'].max()  # Take profit as highest high
                        sl = ob.low - MGTN  # Stop loss
                        trades.append({
                            'time': current_time,
                            'direction': 'buy',
                            'entry': entry,
                            'tp': tp,
                            'sl': sl
                        })
                        ob.traded = True

                    if ob.direction < 0 and bid > ob.low:  # Sell condition
                        entry = bid
                        tp = data.iloc[:i]['<LOW>'].min()  # Take profit as lowest low
                        sl = ob.high + MGTN  # Stop loss
                        trades.append({
                            'time': current_time,
                            'direction': 'sell',
                            'entry': entry,
                            'tp': tp,
                            'sl': sl
                        })
                        ob.traded = True

    return trades

Aquí, el código implementa una estrategia de trading basada en la detección de bloques de órdenes y la simulación de operaciones utilizando datos históricos del mercado. Comienza importando bibliotecas esenciales, como Pandas para la manipulación de datos, NumPy para operaciones numéricas y Keras/TensorFlow para una posible integración con inteligencia artificial. El script define parámetros clave de negociación, como el tamaño del lote (LOTS), el objetivo de ganancias (TAKE_PROFIT), el límite de pérdidas (STOP_LOSS) y un factor de gestión de riesgos (MGTN). Las funciones auxiliares extraen los puntos de precios clave (apertura, máximo, mínimo, cierre) y los valores de marca de tiempo del conjunto de datos, lo que garantiza un acceso estructurado a los datos históricos. La clase OrderBlock se introduce para almacenar información sobre los bloques de órdenes alcistas o bajistas detectados, que son áreas críticas en las operaciones de acción del precio donde las instituciones pueden haber colocado órdenes significativas.

La función get_order_blocks analiza los datos históricos de precios para detectar posibles bloques de órdenes basándose en una serie de movimientos de precios alcistas o bajistas. Identifica patrones donde se produce un cambio en la acción del precio, almacenando la hora y los valores máximos y mínimos de los bloques de órdenes detectados. Una vez identificados los bloques de órdenes, la función simulate_trading ejecuta operaciones simuladas. El sistema itera a través de datos históricos, comprobando si aparecen nuevas barras (velas) y si las condiciones de precio coinciden con los criterios de compra o venta en función de los bloques de órdenes detectados. Si se cumple una condición de compra o venta, la función registra una operación, estableciendo un precio de entrada, un objetivo de ganancias y un límite de pérdidas de forma dinámica en función de los valores máximos y mínimos anteriores. Esta configuración permite realizar pruebas retrospectivas de la estrategia analizando cómo se habrían comportado las operaciones históricamente, sentando las bases para integrar la IA y optimizar aún más la ejecución de las operaciones.

# Columns: ['<DATE>', '<TIME>', '<OPEN>', '<HIGH>', '<LOW>', '<CLOSE>']
data = pd.read_csv('/home/int_junkie/Documents/DataVisuals/AI inside MQL5/XAUUSD_H1.csv', delimiter='\t')

# Combine DATE and TIME into a single DATETIME column
data['DATETIME'] = pd.to_datetime(data['<DATE>'] + ' ' + data['<TIME>'])

# Drop the original DATE and TIME columns
data.drop(columns=['<DATE>', '<TIME>'], inplace=True)

# Step 1: Detect order blocks
order_blocks = get_order_blocks(data)

# Step 2: Simulate trading based on order blocks
trades = simulate_trading(data, order_blocks)

Tras la fusión, se eliminan las columnas originales de fecha y hora para mantener el conjunto de datos limpio. A continuación, el script llama a `get_order_blocks(data)`, que analiza los datos de precios para identificar posibles bloques de órdenes alcistas y bajistas, áreas clave donde se pueden haber colocado importantes reversiones de precios u órdenes institucionales. Una vez detectados los bloques de órdenes, `simulate_trading(data, order_blocks)` ejecuta un backtesting comprobando si las condiciones del mercado activan alguno de estos bloques de órdenes, ejecutando operaciones simuladas de compra o venta basadas en reglas predefinidas de entrada, toma de ganancias y stop loss. Básicamente, evaluamos la efectividad de la estrategia de trading utilizando datos históricos de la evolución de los precios.

# Features: Historical OHLC data
# Labels: Buy (1), Sell (-1), Hold (0)
labels = []
for i, row in data.iterrows():
    label = 0  # Hold by default
    for trade in trades:
        if trade['time'] == row['DATETIME']:
            label = 1 if trade['direction'] == 'buy' else -1
    labels.append(label)

data['label'] = labels

# Step 4: Train LSTM model (example using Keras)
from keras.models import Sequential
from keras.layers import LSTM, Dense

# Prepare data for LSTM
def create_sequences(data, seq_length):
    X, y = [], []
    for i in range(len(data) - seq_length):
        X.append(data.iloc[i:i + seq_length][['<OPEN>', '<HIGH>', '<LOW>', '<CLOSE>']].values)
        y.append(data.iloc[i + seq_length]['label'])
    return np.array(X), np.array(y)

seq_length = 50  # Sequence length for LSTM
X, y = create_sequences(data, seq_length)

# Build LSTM model
model = Sequential()
model.add(LSTM(50, input_shape=(seq_length, 4)))  # 4 features: open, high, low, close
model.add(Dense(1, activation='tanh'))  # Output: -1 (sell), 0 (hold), 1 (buy)
model.compile(optimizer='adam', loss='mse')

# Train the model
model.fit(X, y, epochs=20, batch_size=32)

# Save the model
model.save('lstm_trading_model.h5')


Resultado:


Este fragmento de código entrena un modelo LSTM para predecir decisiones de negociación utilizando datos históricos de precios. El conjunto de datos está etiquetado con tres posibles señales: 1 (comprar), -1 (vender) o 0 (mantener). Las etiquetas se asignan analizando las marcas de tiempo históricas: si se produjo una operación en un momento concreto, la etiqueta refleja su dirección; de lo contrario, el valor predeterminado es 0 (sin acción). Esto crea un marco de aprendizaje supervisado en el que el modelo aprende a asociar secuencias de datos históricos del mercado con las operaciones bursátiles posteriores.

Para el entrenamiento de la LSTM, los datos se reestructuran en secuencias de 50 pasos de valores OHLC (apertura, máximo, mínimo, cierre). Cada secuencia sirve como entrada para predecir la etiqueta en el siguiente paso temporal. La arquitectura del modelo incluye:

  • Una capa LSTM (50 unidades) para analizar los patrones temporales en la entrada de 4 características (OHLC).
  • Una capa de salida densa con función de activación tanh para generar predicciones entre -1 y 1.

El modelo se entrena durante 20 épocas utilizando el optimizador Adam y la función de pérdida del error cuadrático medio (MSE). Una vez entrenado, se guarda como «lstm_trading_model.h5», listo para su implementación en estrategias de trading con el fin de generar señales en tiempo real.



Implementar el modelo

Ahora que tu modelo LSTM está serializado en un archivo .h5, el siguiente paso consiste en ponerlo en funcionamiento dentro del ecosistema MQL5. Para ello, es necesario crear una capa de interoperabilidad entre el marco de aprendizaje automático de Python y la infraestructura de negociación nativa de MQL5, ya que no se admite la integración directa de Python. Una solución habitual consiste en implementar un microservicio basado en Python (utilizando marcos ligeros como Flask o FastAPI) para alojar el modelo entrenado. Este servidor actúa como un punto final de predicción: recopila datos de mercado formateados de MQL5, realiza inferencias basadas en LSTM y devuelve señales de trading en tiempo real. En el entorno de MQL5, tu asesor experto utiliza la API `WebRequest()` para enviar datos de precios secuenciales a este punto final y analizar sus respuestas JSON, transformando así las predicciones sin procesar en acciones ejecutables.

Tras la exitosa implementación de este puente, la atención se centra en la integración de la estrategia en tiempo real. El Asesor Experto transmitirá de forma autónoma lotes de datos seleccionados (por ejemplo, secuencias OHLC de 50 barras) al servidor de inferencia a intervalos configurables. El servicio de Python preprocesa esta entrada, ejecuta operaciones tensoriales a través de la arquitectura LSTM y devuelve directivas comerciales probabilísticas (comprar/vender/mantener) con métricas de confianza. Estas señales se incorporan al proceso de toma de decisiones del EA, donde se combinan con parámetros de riesgo predefinidos (umbrales dinámicos de stop-loss, ratios de beneficio-objetivo y algoritmos de dimensionamiento de posiciones) para ejecutar operaciones gestionadas. Para mitigar los riesgos operativos, implemente un despliegue por fases: valide el sistema en un entorno de demostración aislado, supervise continuamente la latencia de inferencia y la desviación del modelo, e incorpore protocolos de contingencia (por ejemplo, recurrir a estrategias basadas en indicadores técnicos) para mantener la funcionalidad durante las interrupciones del servidor o las anomalías en las predicciones.


Conclusión

En este proyecto, tomamos una estrategia de trading MQL5 existente y la mejoramos integrando un proceso de toma de decisiones impulsado por IA mediante una red neuronal de memoria a largo y corto plazo (LSTM). Comenzamos traduciendo la lógica central de la estrategia MQL5 a Python, replicando su comportamiento utilizando datos históricos de OHLC. A partir de ahí, identificamos señales comerciales clave, como bloques de órdenes, y simulamos operaciones para generar datos etiquetados para entrenar el modelo de IA. A continuación, entrenamos el modelo LSTM con secuencias de datos históricos de precios para predecir si el siguiente movimiento del mercado debería ser de compra, venta o mantenimiento. Finalmente, el modelo se guardó como un archivo `.h5`, listo para ser implementado para operaciones comerciales en tiempo real o semiautomatizadas.

La integración de la IA en una estrategia tradicional basada en reglas aporta poderosas ventajas a los operadores. A diferencia de la lógica estática, que sigue condiciones fijas, el modelo LSTM puede aprender comportamientos de precios complejos y adaptarse a la dinámica cambiante del mercado a lo largo del tiempo. Esto hace que la estrategia sea más flexible, potencialmente más precisa y menos propensa a las señales falsas en las que podrían caer los sistemas rígidos. Los operadores se benefician de un sistema que combina lo mejor de ambos mundos: la estructura y la fiabilidad de las reglas técnicas con la adaptabilidad y las capacidades de aprendizaje del aprendizaje automático.

Este enfoque híbrido mejora las decisiones de entrada y salida y abre la puerta a una gestión de riesgos más inteligente y basada en datos en las operaciones en tiempo real. A diferencia de la lógica estática, que sigue condiciones fijas, el modelo LSTM puede aprender comportamientos de precios complejos y adaptarse a la dinámica cambiante del mercado a lo largo del tiempo. Esto hace que la estrategia sea más flexible, potencialmente más precisa y menos propensa a las señales falsas en las que podrían caer los sistemas rígidos. Los operadores se benefician de un sistema que combina lo mejor de ambos mundos: la estructura y la fiabilidad de las reglas técnicas con la adaptabilidad y las capacidades de aprendizaje del aprendizaje automático. Este enfoque híbrido no solo mejora las decisiones de entrada y salida, sino que también abre la puerta a una gestión de riesgos más inteligente y basada en datos en las operaciones en tiempo real.

Nombre del archivo
Descripción
FIB_OB.mq5 Archivo que contiene la estrategia MQL5 original.
FIB_OB to AI.ipynb
Archivo que contiene el cuaderno para convertir la lógica de la estrategia, entrenar el modelo y guardarlo.
XAUUSD_H1.csv
Archivo que contiene datos históricos del precio del XAUUSD.


Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/16973

Archivos adjuntos |
malky3200
malky3200 | 28 abr 2025 en 10:25
Pregunta.... ¿Hay alguna razón por la que la epoch esté fijada en 20?
¿Es posible hacer que la IA aprenda de forma continua?
Redes neuronales en el trading: Extracción eficiente de características para una clasificación precisa (Final) Redes neuronales en el trading: Extracción eficiente de características para una clasificación precisa (Final)
El framework Mantis transforma series temporales complejas en tokens informativos y sirve como una base sólida para un agente comercial inteligente en tiempo real.
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 20): Flujo externo (IV) — Correlation Pathfinder Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 20): Flujo externo (IV) — Correlation Pathfinder
Correlation Pathfinder ofrece un nuevo enfoque para comprender la dinámica de los pares de divisas, como parte de la serie de desarrollo de herramientas de análisis de la acción del precio. Esta herramienta automatiza la recopilación y el análisis de datos, lo que permite comprender cómo interactúan pares como el EUR/USD y el GBP/USD. Mejora tu estrategia de trading con información práctica y en tiempo real que te ayudará a gestionar el riesgo y a detectar oportunidades de forma más eficaz.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Indicador de pronóstico ARIMA en MQL5 Indicador de pronóstico ARIMA en MQL5
En este artículo, crearemos un indicador de pronóstico ARIMA en MQL5. El artículo analiza cómo el modelo ARIMA genera pronósticos y su aplicabilidad al mercado Forex y al mercado de valores en general. También explica qué es la autorregresión AR, cómo se utilizan los modelos autorregresivos para realizar pronósticos y cómo funciona el mecanismo autorregresivo.