English Русский 中文 Deutsch 日本語
preview
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 36): Cómo habilitar el acceso directo desde Python a los flujos de mercado de MetaTrader 5

Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 36): Cómo habilitar el acceso directo desde Python a los flujos de mercado de MetaTrader 5

MetaTrader 5 — Sistemas comerciales |
34 0
Christian Benjamin
Christian Benjamin

Índice


Introducción

En nuestro artículo anterior se mostró cómo un sencillo script de MQL5 podía transferir barras históricas a Python, generar características, entrenar un modelo de aprendizaje automático y, a continuación, enviar señales de vuelta a MetaTrader para su ejecución, eliminando así las exportaciones manuales en formato CSV, los análisis basados en Excel y los problemas de control de versiones. Los operadores obtuvieron un proceso integral que transformaba los datos brutos de barras de un minuto en puntos de entrada basados en criterios estadísticos, con niveles de stop-loss (SL) y take-profit (TP) calculados dinámicamente.

Este sistema abordaba tres de los principales problemas del trading algorítmico:

  1. Fragmentación de datos: se acabó tener que copiar y pegar archivos CSV o lidiar con fórmulas complejas de hojas de cálculo: su gráfico de MetaTrader 5 se comunica directamente con Python.
  2. Señales tardías: la automatización de la ingeniería de características y la inferencia de modelos permitió obtener señales en tiempo real, pasando de un trading reactivo a uno proactivo basado en datos en tiempo real.
  3. Gestión del riesgo inconsistente: la incorporación de SL/TP basados en el ATR tanto en las pruebas retrospectivas como en la operativa en tiempo real garantizó que todas las operaciones siguieran reglas ajustadas a la volatilidad, preservando así su ventaja competitiva.

Sin embargo, recurrir a un Asesor Experto (EA) para enviar datos a Python puede generar latencia y complejidad. La nueva versión aprovecha la capacidad de Python para actuar como cliente de MetaTrader 5, utilizando la biblioteca de MetaTrader 5 para obtener y actualizar datos directamente. Este enfoque elimina la espera del temporizador del Asesor Experto; Python puede ingerir datos bajo demanda, escribir de forma eficiente en un almacén Parquet y ejecutar cálculos pesados de forma asíncrona.

Partiendo de esta base, nuestra herramienta híbrida mejorada de Python y MQL5 ofrece unas prestaciones aún mayores:

  • Parte de Python: ingesta de datos de MetaTrader 5 en tiempo real a través de la biblioteca nativa, ingeniería avanzada de características (por ejemplo, puntuaciones z de picos, diferencias MACD, bandas ATR, deltas de tendencia de Prophet) y una canalización de Gradient Boosting adaptada a series temporales que se reentrena con ventanas móviles; todo ello expuesto mediante una API ligera de Flask.
  • Parte de MQL5: un Asesor Experto robusto basado en sondeos REST con lógica de reintentos, un panel integrado en el gráfico que muestra señales, niveles de confianza y estado de la conexión, marcadores en forma de flecha para entradas y salidas, y ejecución automatizada opcional de órdenes bajo estrictas normas de gestión de riesgos.

Si bien nuestro primer artículo ofrecía una prueba de concepto, este framework orientado a producción reduce considerablemente el tiempo de configuración, acelera los ciclos de retroalimentación y le permite operar con mayor confianza y precisión, respaldado por los datos. Vamos a ello.

Descripción general de la arquitectura del sistema

A continuación se muestra un esquema general de cómo circulan los datos y las señales entre MetaTrader 5 y su servicio de Python, seguido de las funciones principales de cada componente:


Terminal de MetaTrader 5

El terminal de MetaTrader 5 sirve como interfaz principal de mercado y plataforma de gráficos. Contiene y gestiona las barras de precios en tiempo real e históricas del símbolo que usted haya elegido y proporciona el entorno de ejecución para el Asesor Experto (EA). Gracias a su función integrada WebRequest(), el Asesor Experto recopila periódicamente los datos más recientes de barras y muestra las señales entrantes, las líneas de SL/TP y las flechas de entrada y salida directamente en su gráfico. El terminal de MetaTrader 5 se encarga de la colocación de órdenes (cuando está activada), la gestión de objetos locales (paneles, flechas, etiquetas) y la visualización para el usuario de los resultados del sistema.

Fuente de datos de Python

En lugar de recurrir a un Asesor Experto para enviar los datos de las barras, el componente Fuente de datos de Python utiliza la biblioteca oficial de Python para MetaTrader 5 para obtener, bajo demanda, datos OHLC de barras de un minuto tanto históricos como en tiempo real. Inicializa un almacén de datos Parquet comprimido para conservar la evolución de los precios de los últimos días y, a continuación, añade nuevas barras a medida que llegan. Esta configuración elimina la dependencia de los intervalos del temporizador en MQL5 y garantiza que el servicio de Python tenga siempre acceso inmediato y aleatorio al historial completo de precios necesario tanto para los backtests como para la inferencia en tiempo real.

Ingeniería de características

Una vez que las barras sin procesar están disponibles en memoria o en disco, la capa de ingeniería de características las transforma en entradas estadísticamente significativas para el aprendizaje automático. Calcula las puntuaciones z normalizadas de los picos, la diferencia del histograma del MACD, los valores del RSI de 14 períodos, el ATR de 14 períodos para la volatilidad y las bandas de envolvente dinámicas basadas en EMA. Además, utiliza la biblioteca Prophet de Facebook para estimar un delta de tendencia a nivel de minuto, captando el sesgo hacia la reversión a la media frente a la tendencia. Este proceso automatizado garantiza que los datos en tiempo real y los históricos se sometan a un procesamiento idéntico, lo que preserva la fidelidad del modelo.

Modelo de aprendizaje automático

En el núcleo del sistema se encuentra un clasificador Gradient Boosting encapsulado en un Pipeline de scikit-learn con escalado estándar. El modelo se entrena con ventanas deslizantes de barras anteriores, utilizando TimeSeriesSplit para evitar el sesgo de anticipación y RandomizedSearchCV para optimizar los hiperparámetros. Las etiquetas se generan analizando la evolución del precio en los próximos diez minutos y clasificando los movimientos en las categorías «comprar», «vender» o «esperar», en función de un umbral configurable. El estimador entrenado se serializa en model.pkl, lo que garantiza una carga y una inferencia de baja latencia tanto en backtests como en ejecuciones en tiempo real.

API de Flask

La API de Flask actúa como puente entre el ecosistema de ciencia de datos de Python y el Asesor Experto de MQL5. Expone un único endpoint «/analyze» que acepta una carga JSON con los precios de cierre recientes y las marcas de tiempo, aplica el pipeline de características y el modelo cargado para calcular las probabilidades de clase, y devuelve una respuesta JSON concisa que contiene «signal», «sl», «tp» y «conf» (confianza). Esta interfaz REST ligera puede empaquetarse en contenedores o desplegarse en cualquier servidor, lo que desacopla los recursos de cómputo de Python del entorno de ejecución de MetaTrader y simplifica la escalabilidad.

Asesor Experto de MQL5

En el lado del cliente, el Asesor Experto de MQL5 se centra exclusivamente en la interacción con el usuario y la ejecución de operaciones. Consulta periódicamente la API de Flask, analiza el JSON recibido, registra cada señal tanto en la pestaña «Expertos» como en un archivo CSV local, y actualiza un panel gráfico que muestra la señal actual, el nivel de confianza, el estado de la conexión y la marca de tiempo. Cuando se recibe una señal válida de compra, venta o cierre, el EA dibuja flechas y líneas de SL/TP y, si EnableTrading es true, coloca o cierra órdenes mediante la clase CTrade. Al delegar todas las tareas de ciencia de datos a Python, el EA sigue siendo ligero, con buena capacidad de respuesta y fácil de mantener.


Análisis detallado del backend de Python

En la base de nuestro backend hay una sólida canalización de ingesta de datos que utiliza el paquete oficial de Python para MetaTrader 5. La primera vez que se ejecuta, el servicio se «inicializa» recuperando los datos OHLC de barras de un minuto de los últimos días y escribiéndolos en un archivo Parquet comprimido. El formato columnar de Parquet y la compresión Zstandard permiten lecturas ultrarrápidas de segmentos de series temporales, manteniendo al mínimo el uso del disco. A partir de ahí, una sencilla actualización incremental añade únicamente las barras recién formadas, lo que evita descargas redundantes y garantiza que tanto la inferencia en tiempo real como los backtests funcionen sobre una fuente única de referencia, siempre actualizada.

import datetime as dt
import pandas as pd
import MetaTrader5 as mt5
from pathlib import Path

PARQUET_FILE = "hist.parquet.zst"
DAYS_TO_PULL = 60
UTC = dt.timezone.utc

def bootstrap():
    """Fetch last DAYS_TO_PULL days of M1 bars and write to Parquet."""
    now = dt.datetime.utcnow()
    start = now - dt.timedelta(days=DAYS_TO_PULL)
    mt5.initialize()
    mt5.symbol_select("Boom 300 Index", True)
    bars = mt5.copy_rates_range("Boom 300 Index", mt5.TIMEFRAME_M1,
                                start.replace(tzinfo=UTC),
                                now.replace(tzinfo=UTC))
    df = pd.DataFrame(bars)
    df['time'] = pd.to_datetime(df['time'], unit='s')
    df.set_index('time').to_parquet(PARQUET_FILE, compression='zstd')

def append_new_bars():
    """Append only the newest bars since last timestamp."""
    df = pd.read_parquet(PARQUET_FILE)
    last = df.index[-1]
    now = dt.datetime.utcnow()
    new = mt5.copy_rates_range("Boom 300 Index", mt5.TIMEFRAME_M1,
                               last.replace(tzinfo=UTC) + dt.timedelta(minutes=1),
                               now.replace(tzinfo=UTC))
    if new:
        new_df = pd.DataFrame(new)
        new_df['time'] = pd.to_datetime(new_df['time'], unit='s')
        merged = pd.concat([df, new_df.set_index('time')])
        merged[~merged.index.duplicated()].to_parquet(PARQUET_FILE,
                                                      compression='zstd')

Con las barras brutas ya disponibles, nuestro pipeline calcula un conjunto de características diseñadas para captar el impulso, la volatilidad y los movimientos extremos. Normalizamos la primera diferencia del precio en una puntuación «z-spike» dividiéndola por su desviación estándar móvil de 20 barras, lo que permite aislar movimientos bruscos del precio. La diferencia del histograma del MACD y el RSI de 14 períodos cuantifican la tendencia y las condiciones de sobrecompra y sobreventa, respectivamente, mientras que el ATR de 14 períodos mide la volatilidad actual. Una media móvil exponencial (EMA) de 20 períodos define unas bandas de envolvente (EMA × 0,997 y EMA × 1,003) que se adaptan a los regímenes cambiantes del mercado. Por último, la biblioteca Prophet de Facebook procesa toda la secuencia de precios de cierre para pronosticar un delta de tendencia a nivel de minuto, lo que permite captar una estacionalidad y una deriva más matizadas y dependientes del tiempo.

import numpy as np
import pandas as pd
import ta
from prophet import Prophet

def engineer(df: pd.DataFrame) -> pd.DataFrame:
    df = df.copy()
    # z-spike (20-bar rolling std)
    df['r'] = df['close'].diff()
    df['z_spike'] = df['r'] / (df['r'].rolling(20).std() + 1e-9)

    # MACD histogram diff, RSI, ATR
    df['macd'] = ta.trend.macd_diff(df['close'])
    df['rsi']  = ta.momentum.rsi(df['close'], window=14)
    df['atr']  = ta.volatility.average_true_range(df['high'],
                                                  df['low'],
                                                  df['close'],
                                                  window=14)

    # EMA envelopes
    ema = df['close'].ewm(span=20).mean()
    df['env_low'] = ema * 0.997
    df['env_up']  = ema * 1.003

    # Prophet trend delta (minute-level)
    if len(df) > 200:
        m = Prophet(daily_seasonality=False, weekly_seasonality=False)
        m.fit(pd.DataFrame({'ds': df.index, 'y': df['close']}))
        df['delta'] = m.predict(m.make_future_dataframe(periods=0,
                                                        freq='min'))['yhat'] - df['close']
    else:
        df['delta'] = 0.0

    return df.dropna()

Planteamos la predicción como una clasificación de tres clases: «BUY» si el precio sube más de un umbral determinado en los próximos 10 minutos, «SELL» si cae más de ese umbral y «WAIT» en caso contrario. Una vez asignadas las etiquetas, las características y las etiquetas se dividen en ventanas temporales móviles para el entrenamiento. Un pipeline de scikit-learn primero estandariza cada característica y, a continuación, ajusta un GradientBoostingClassifier. Los hiperparámetros (tasa de aprendizaje, número de árboles, profundidad máxima) se optimizan mediante RandomizedSearchCV con un esquema de validación cruzada TimeSeriesSplit, lo que garantiza que no haya fuga de información futura. El mejor modelo se serializa en model.pkl, listo para una inferencia inmediata y de baja latencia.

import numpy as np
import joblib
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import TimeSeriesSplit, RandomizedSearchCV

LOOKAHEAD_MIN   = 10
LABEL_THRESHOLD = 0.0015
FEATS = ['z_spike','macd','rsi','atr','env_low','env_up','delta']

def label_and_train(df: pd.DataFrame):
    # Look-ahead return
    chg = (df['close'].shift(-LOOKAHEAD_MIN) - df['close']) / df['close']
    df['label'] = np.where(chg > LABEL_THRESHOLD, 1,
                   np.where(chg < -LABEL_THRESHOLD, 2, 0))

    X = df[FEATS].dropna()
    y = df.loc[X.index, 'label']

    pipe = Pipeline([
        ('scaler', StandardScaler()),
        ('gb', GradientBoostingClassifier(random_state=42))
    ])
    param_dist = {
        'gb__learning_rate': [0.01, 0.05, 0.1],
        'gb__n_estimators': [300, 500, 700],
        'gb__max_depth': [2, 3, 4]
    }
    cv = TimeSeriesSplit(n_splits=5)
    rs = RandomizedSearchCV(pipe, param_dist, n_iter=12,
                            cv=cv, scoring='roc_auc_ovr',
                            n_jobs=-1, random_state=42)
    rs.fit(X, y)
    joblib.dump(rs.best_estimator_, 'model.pkl')
Para conectar Python y MetaTrader, exponemos un único endpoint de Flask: /analyze. Los clientes envían un payload JSON que contiene el símbolo, un array de precios de cierre y las marcas temporales UNIX correspondientes. El endpoint vuelve a ejecutar nuestro pipeline de generación de características sobre ese payload, carga el modelo preentrenado, calcula las probabilidades de clase, determina la señal con mayor confianza y calcula dinámicamente los niveles de stop-loss y take-profit a partir de la característica ATR. La respuesta es un objeto JSON compacto:
from flask import Flask, request, jsonify
import joblib
import pandas as pd

app = Flask(__name__)
model = joblib.load('model.pkl')

@app.route('/analyze', methods=['POST'])
def analyze():
    payload = request.get_json(force=True)
    closes = payload['prices']
    times  = pd.to_datetime(payload['timestamps'], unit='s')
    df = pd.DataFrame({'close': closes}, index=times)
    # duplicate open/high/low for completeness
    df[['open','high','low']] = df[['close']]

    feat = engineer(df).iloc[-1:]
    probs = model.predict_proba(feat[FEATS])[0]
    p_buy, p_sell = probs[1], probs[2]
    signal = ('BUY' if p_buy > 0.55 else
              'SELL' if p_sell > 0.55 else 'WAIT')
    atr = feat['atr']
    entry = feat['close']
    sl = entry - atr if signal=='BUY' else entry + atr
    tp = entry + 2*atr if signal=='BUY' else entry - 2*atr

    return jsonify(signal=signal,
                   sl=round(sl,5),
                   tp=round(tp,5),
                   conf=round(max(p_buy,p_sell),2))

if __name__ == '__main__':
    app.run(port=5000)


Análisis de la arquitectura del cliente del Asesor Experto en MQL5

El bucle principal del Asesor Experto se ejecuta bien en un evento de temporizador (OnTimer), bien en una comprobación de nueva barra, donde invoca WebRequest() para enviar y recibir mensajes HTTP. En primer lugar, recopila las N barras más recientes mediante CopyRates, convierte el array MqlRates en un payload JSON UTF-8 que contiene el símbolo y la secuencia de precios de cierre, y configura las cabeceras HTTP necesarias. Si WebRequest() falla (devuelve un valor ≤0), el Asesor Experto captura GetLastError(), incrementa un contador de reintentos, registra el error y pospone nuevas solicitudes hasta que se agoten los reintentos o llegue el siguiente tick del temporizador. Las respuestas satisfactorias (estado ≥200) reinician el contador de reintentos y actualizan lastStatus. Este patrón garantiza una recepción robusta y asíncrona de señales sin bloquear el hilo del gráfico ni provocar fallos debido a problemas transitorios de red.

// In OnTimer() or OnNewBar():
MqlRates rates[];
// Copy the last N bars into `rates`
if(CopyRates(_Symbol, _Period, 0, InpBufferBars, rates) != InpBufferBars)
    return;
ArraySetAsSeries(rates, true);

// Build payload
string payload = "{";
payload += StringFormat("\"symbol\":\"%s\",", _Symbol);
payload += "\"prices\":[";
for(int i=0; i<InpBufferBars; i++)
  {
    payload += DoubleToString(rates[i].close, _digits);
    if(i < InpBufferBars-1) payload += ",";
  }
payload += "]}";

// Send request
string headers = "Content-Type: application/json\r\nAccept: application/json\r\n\r\n";
char  req[], resp[];
int   len = StringToCharArray(payload, req, 0, WHOLE_ARRAY, CP_UTF8);
ArrayResize(req, len);
ArrayResize(resp, 8192);

int status = WebRequest("POST", InpServerURL, headers, "", InpTimeoutMs,
                        req, len, resp, headers);
if(status <= 0)
{
  int err = GetLastError();
  PrintFormat("WebRequest error %d (attempt %d/%d)", err, retryCount+1, MaxRetry);
  ResetLastError();
  retryCount = (retryCount+1) % MaxRetry;
  lastStatus = StringFormat("Err%d", err);
  return;
}
retryCount = 0;
lastStatus = StringFormat("HTTP %d", status);

Una vez analizada una respuesta JSON válida y convertida en una señal, sl y tp, el Asesor Experto actualiza su panel de control en el gráfico y traza cualquier flecha o línea nueva. El panel de control consiste en un único elemento OBJ_RECTANGLE_LABEL con cuatro etiquetas de texto que muestran el símbolo, la señal actual, el estado HTTP y la marca de tiempo. En el caso de las operaciones, elimina cualquier objeto existente con prefijo antes de crear una flecha nueva (OBJ_ARROW) al precio actual, utilizando códigos y colores distintos para las flechas de compra (verde hacia arriba), venta (rojo hacia abajo) o cierre (naranja). Las líneas horizontales (OBJ_HLINE) marcan los niveles de Stop-Loss y Take-Profit, identificados con los colores rojo y verde, respectivamente. Al asignar a cada objeto un espacio de nombres con un prefijo único del gráfico y limpiarlos cuando cambian las señales o durante la desinicialización, su gráfico se mantiene nítido y ordenado.

// Panel (rectangle + labels)
void DrawPanel()
{
  const string pid = "SigPanel";
  if(ObjectFind(0, pid) < 0)
    ObjectCreate(0, pid, OBJ_RECTANGLE_LABEL, 0, 0, 0);

  ObjectSetInteger(0, pid, OBJPROP_CORNER, CORNER_LEFT_UPPER);
  ObjectSetInteger(0, pid, OBJPROP_XDISTANCE, PanelX);
  ObjectSetInteger(0, pid, OBJPROP_YDISTANCE, PanelY);
  ObjectSetInteger(0, pid, OBJPROP_XSIZE, PanelW);
  ObjectSetInteger(0, pid, OBJPROP_YSIZE, PanelH);
  ObjectSetInteger(0, pid, OBJPROP_BACK, true);
  ObjectSetInteger(0, pid, OBJPROP_BGCOLOR, PanelBG);
  ObjectSetInteger(0, pid, OBJPROP_COLOR, PanelBorder);

  string lines[4] = {
    StringFormat("Symbol : %s", _Symbol),
    StringFormat("Signal : %s", lastSignal),
    StringFormat("Status : %s", lastStatus),
    StringFormat("Time   : %s", TimeToString(TimeLocal(), TIME_MINUTES))
  };

  for(int i=0; i<4; i++)
  {
    string lbl = pid + "_L" + IntegerToString(i);
    if(ObjectFind(0, lbl) < 0)
      ObjectCreate(0, lbl, OBJ_LABEL, 0, 0, 0);
    ObjectSetInteger(0, lbl, OBJPROP_CORNER, CORNER_LEFT_UPPER);
    ObjectSetInteger(0, lbl, OBJPROP_XDISTANCE, PanelX + 6);
    ObjectSetInteger(0, lbl, OBJPROP_YDISTANCE, PanelY + 4 + i*(TxtSize+2));
    ObjectSetString(0, lbl, OBJPROP_TEXT, lines[i]);
    ObjectSetInteger(0, lbl, OBJPROP_FONTSIZE, TxtSize);
    ObjectSetInteger(0, lbl, OBJPROP_COLOR, TxtColor);
  }
}

// Arrows & SL/TP lines
void ActOnSignal(ESignal code, double sl, double tp)
{
  // remove old arrows/lines
  for(int i=ObjectsTotal(0)-1; i>=0; i--)
    if(StringFind(ObjectName(0,i), objPrefix) == 0)
      ObjectDelete(0, ObjectName(0,i));

  // arrow
  int    arrCode = (code==SIG_BUY ? 233 : code==SIG_SELL ? 234 : 158);
  color  clr     = (code==SIG_BUY ? clrLime : code==SIG_SELL ? clrRed : clrOrange);
  string name    = objPrefix + "Arr_" + TimeToString(TimeCurrent(), TIME_SECONDS);
  ObjectCreate(0, name, OBJ_ARROW, 0, TimeCurrent(), SymbolInfoDouble(_Symbol, SYMBOL_BID));
  ObjectSetInteger(0, name, OBJPROP_ARROWCODE, arrCode);
  ObjectSetInteger(0, name, OBJPROP_COLOR, clr);

  // SL line
  if(sl > 0)
  {
    string sln = objPrefix + "SL_" + name;
    ObjectCreate(0, sln, OBJ_HLINE, 0, 0, sl);
    ObjectSetInteger(0, sln, OBJPROP_COLOR, clrRed);
  }

  // TP line
  if(tp > 0)
  {
    string tpn = objPrefix + "TP_" + name;
    ObjectCreate(0, tpn, OBJ_HLINE, 0, 0, tp);
    ObjectSetInteger(0, tpn, OBJPROP_COLOR, clrLime);
  }
}

El envío real de órdenes está condicionado por un indicador EnableTrading, por lo que usted puede alternar fácilmente entre el modo solo visual y el modo de ejecución real. Antes de cualquier orden de mercado, el Asesor Experto comprueba PositionSelect(_Symbol) para evitar posiciones duplicadas. En caso de una señal BUY, el Asesor Experto invoca CTrade.Buy() con FixedLots, SL y TP; en caso de SELL, CTrade.Sell(); y, en caso de una señal CLOSE, CTrade.PositionClose(). La tolerancia al deslizamiento (SlippagePoints) se aplica a las salidas. Esta lógica mínima y con estado garantiza que usted nunca abra accidentalmente dos veces una posición del mismo lado y que todas las órdenes respeten sus parámetros de riesgo predefinidos.

void ExecuteTrade(ESignal code, double sl, double tp)
{
  if(!EnableTrading) return;

  bool hasPosition = PositionSelect(_Symbol);
  if(code == SIG_BUY && !hasPosition)
    trade.Buy(FixedLots, _Symbol, 0, sl, tp);
  else if(code == SIG_SELL && !hasPosition)
    trade.Sell(FixedLots, _Symbol, 0, sl, tp);
  else if(code == SIG_CLOSE && hasPosition)
    trade.PositionClose(_Symbol, SlippagePoints);
}

Instalación y configuración

Antes de poder empezar a generar señales en tiempo real, tendrá que preparar tanto su entorno de Python como su plataforma MetaTrader 5. Empiece por instalar Python 3.8 o una versión posterior en el mismo ordenador en el que se ejecuta su terminal de MetaTrader 5. Cree y active un entorno virtual (python -m venv venv y, a continuación, en Windows, venv\Scripts\activate, o en macOS/Linux, source venv/bin/activate) e instale todas las dependencias con:
pip install MetaTrader 5 pandas numpy ta prophet scikit-learn flask loguru joblib
Luego configure el cortafuegos de Windows para permitir solicitudes HTTP salientes tanto para python.exe como para terminal64.exe. Si tiene previsto implementar a través de HTTPS en producción, instale su certificado SSL en el almacén de certificados raíz de confianza para que MetaTrader 5 acepte conexiones seguras.

En MetaTrader 5, abra

Herramientas → Opciones → Asesores Expertos, habilite las importaciones de DLL y añada su host de API local

Por ejemplo, (http://127.0.0.1:5000) en la casilla «Permitir WebRequest para las URL indicadas». Este paso de inclusión en la lista de permitidos es fundamental: sin él, MetaTrader 5 descartará silenciosamente todas la cargas POST.

En la carpeta de su proyecto, copie el script del servicio en Python (por ejemplo, market_ai_engine.py) en el directorio de trabajo que elija. Modifique la parte superior del script para configurar su símbolo de trading (MAIN_SYMBOL), sus credenciales de inicio de sesión en MetaTrader 5 (LOGIN_ID, PASSWORD, SERVER) y las rutas de archivo (PARQUET_FILE, MODEL_FILE). Si prefiere utilizar un puerto distinto al predeterminado para el servidor Flask, puede indicarlo mediante --port al iniciar el servicio.
Para desplegar el Asesor Experto, coloque el archivo compilado EA.ex5 (o su archivo fuente .mq5) en su instalación de MetaTrader 5, dentro de MQL5 → Experts.

Reinicie MetaTrader 5 o actualice el Navegador para que el EA aparezca en la lista. Arrástrelo a un gráfico M1 del mismo símbolo que haya configurado en Python. En las entradas del EA, establezca InpServerURL en http://127.0.0.1:5000/analyze, configure InpBufferBars (por ejemplo, 60), InpPollInterval (p. ej., 60 segundos), y InpTimeoutMs (p. ej., 5000 ms). Mantenga EnableTrading desactivado inicialmente para poder verificar las señales sin ejecutar órdenes reales.

Por último, inicie su backend de Python siguiendo esta secuencia:

1. python market_ai_engine.py bootstrap

2. python market_ai_engine.py collect

3. python market_ai_engine.py train

4. python market_ai_engine.py serve --port 5000

Con el servidor Flask en funcionamiento y AutoTrading habilitado en MetaTrader, el EA comenzará a consultar periódicamente señales en vivo, a dibujar flechas y líneas de SL/TP en su gráfico y, cuando usted esté seguro, a abrir operaciones según sus reglas de riesgo predefinidas.

Solución de problemas

Si el Asesor Experto no muestra ningún dato o siempre devuelve «WAIT», compruebe que la URL de su API figure en la lista blanca de la configuración de Asesores Expertos de MetaTrader 5. En entornos mixtos HTTP/HTTPS, utilice HTTP sin cifrar (127.0.0.1) para las pruebas locales y cambie a HTTPS con un certificado de confianza para el entorno de producción. Asegúrese de que los relojes tanto de su servidor como del terminal de MetaTrader 5 estén sincronizados (ya sea ambos en UTC o en la misma zona horaria local) para evitar solicitudes de barras no alineadas. Por último, compruebe que la función «AutoTrading» esté activada y que ningún permiso global ni otros Asesores Expertos estén bloqueando su Asesor Experto.


Evaluación y resultados de rendimiento

Para empezar a trabajar con el sistema híbrido de aprendizaje automático Python–MQL5, el primer paso consiste en inicializar los datos históricos mediante el comando

python market_ai_engine.py bootstrap
Esto inicializa un conjunto de datos local descargando las barras M1 (de 1 minuto) de los últimos 60 días directamente desde MetaTrader 5 mediante la biblioteca nativa de MetaTrader 5 para Python. Los datos se almacenan en un archivo Parquet comprimido (hist.parquet.zst), lo que permite un acceso rápido al disco y un almacenamiento eficiente. Este paso solo hay que realizarlo una vez, a menos que quiera restablecer por completo los datos históricos.
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py bootstrap
2025-08-04 23:39:23 | INFO | Bootstrapped historical data: 86394 rows

Una vez realizada la inicialización, se pueden mantener las actualizaciones continuas ejecutando

python market_ai_engine.py collect
Esto garantiza que el conjunto de datos se mantenga actualizado en tiempo real. Aunque este recopilador puede ejecutarse en segundo plano, solo es imprescindible si desea disponer de un flujo de datos actualizado de forma continua sin necesidad de repetir la inicialización antes de cada entrenamiento.
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py collect
2025-08-04 23:41:01 | INFO | Appended 2 new bars
2025-08-04 23:42:01 | INFO | Appended 1 new bars
2025-08-04 23:43:01 | INFO | Appended 1 new bars

Una vez que se dispone de un conjunto de datos actualizado, el siguiente paso es el entrenamiento del modelo.

python market_ai_engine.py train
Activa todo el pipeline de aprendizaje automático. El script lee el archivo Parquet, aplica técnicas de ingeniería de características (como la detección de picos, los diferenciales de MACD, el RSI, las bandas ATR, las envolventes EMA y las tendencias basadas en Prophet) y, a continuación, utiliza un GradientBoostingClassifier encapsulado con RandomizedSearchCV para entrenar un modelo predictivo en una ventana móvil de datos recientes. El resultado es un modelo serializado guardado como model.pkl, listo para la inferencia.
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py train
23:48:44 - cmdstanpy - INFO - Chain [1] start processing
23:51:24 - cmdstanpy - INFO - Chain [1] done processing
2025-08-05 02:59:08 | INFO | Model training complete

Para evaluar el rendimiento que podría tener el modelo en operaciones reales, puede ejecutar un backtest utilizando el comando

python market_ai_engine.py backtest --days 30
Esto simula la generación de señales y los resultados de las operaciones durante los últimos 30 días, calculando métricas como la precisión de las señales, los ratios de ganancias/pérdidas y la rentabilidad global. Los resultados se guardan en un archivo CSV para facilitar su análisis, lo que permite determinar si la estrategia del sistema se ajusta a sus expectativas.
C:\Users\hp\Desktop\Intrusion Trader>python market_ai_engine.py backtest --days 30
06:57:33 - cmdstanpy - INFO - Chain [1] start processing
06:58:30 - cmdstanpy - INFO - Chain [1] done processing
2025-08-05 06:59:20 | INFO | Backtest results saved to backtest_results_30d.csv

Resultados del backtest

A continuación se muestra una selección de métricas y detalles de las operaciones extraídos de los resultados del backtest de 30 días:

Gráfico del capital acumulado a lo largo del tiempo

Ahora se presenta un resumen de las métricas clave:

*   **Average Entry Price:** 3099.85
*   **Average Exit Price:** 3096.53
*   **Average PNL (Profit and Loss):** 3.32
*   **Total PNL:** 195.69
*   **Average Cumulative Equity:** 96.34
*   **First Trade Time:** 2025-07-11 14:18:00
*   **Last Trade Time:** 2025-07-27 02:00:00

Porcentaje de operaciones ganadoras:

win_rate
72.88135528564453
The win rate is 72.88%. This means that approximately 73% of the trades resulted in a profit.

Una vez que el modelo se haya entrenado y validado, puede iniciar el servidor de inferencia en tiempo real con

python market_ai_engine.py serve --port 5000
Este comando inicia una API ligera de Flask que escucha las solicitudes entrantes procedentes de su Asesor Experto de MQL5. Cuando el Asesor Experto consulta el endpoint /analyze, el servidor recupera al instante la barra más reciente, genera sus características, ejecuta el modelo y devuelve una predicción con los valores correspondientes de SL, TP y confianza en formato JSON. Este servidor funciona como puente operativo en tiempo real entre su gráfico y el motor de IA.
2025-08-05 12:41:53 | INFO | analyze: signal=%s, sl=%.5f, tp=%.5f
127.0.0.1 - - [05/Aug/2025 12:41:53] "POST /analyze HTTP/1.1" 200 -

En el lado de MetaTrader, el Asesor Experto debe estar correctamente configurado para consultar el servidor de Python. En los parámetros de entrada del Asesor Experto, debe definirse la URL del servidor (por ejemplo, http://127.0.0.1:5000/analyze), y el Asesor Experto debe adjuntarse al mismo símbolo y al mismo marco temporal con los que se entrenó el modelo, normalmente M1. Una vez en funcionamiento, el Asesor Experto obtendrá señales periódicamente, las mostrará en forma de flechas en el gráfico y, opcionalmente, ejecutará operaciones siguiendo normas estrictas de gestión de riesgos.

2025.08.05 12:41:53.532 trained model (1) (Boom 300 Index,M1)   >>> JSON: {"symbol":"Boom 300 Index","prices":[2701.855,2703.124,
2704.408,2705.493,2705.963,2696.806,2698.278,2699.877,2701.464,2702.788,2691.762,2693.046,2694.263,2695.587,2696.863,2698.
179,2699.775,2701.328,2702.888,2698.471,2699.887,2695.534,2696.952,2698.426,2699.756,2699.552,2700.954,2702.131,2703.571,
2699.549,2700.868,2702.567,2703.798,2705.067,2706.874,2698.084,2699.538,2700.856,2702.227,2703.692,2705.102,2706.188,2707.609,2709.001,
2710.335,2711.716,2712.919,2712.028,2713.529,2715.052,2716.578,2717.
2025.08.05 12:41:53.943 trained model (1) (Boom 300 Index,M1)   <<< HTTP 200 hdr:
2025.08.05 12:41:53.943 trained model (1) (Boom 300 Index,M1)   {"conf":0.43,"signal":"WAIT","sl":2725.04317,"tp":2720.18266}
2025.08.05 12:41:53.943 trained model (1) (Boom 300 Index,M1)   [2025.08.05 12:41:53] Signal → WAIT | SL=2725.04317 | TP=2720.18266 | Conf=0.43


Conclusión

En este artículo, hemos creado un Asesor Experto de MQL5 que se apoya en las ventajas de Python en el ámbito de la ciencia de datos. Esto es lo que tiene ahora:
  • Canalización de datos: su EA participa en el flujo de señales, mientras Python mantiene el almacenamiento en Parquet.
  • Ingeniería de características: calcula el «spike-z», el MACD, el RSI, el ATR, las bandas de envolvente e incluso los deltas de tendencia basados en Prophet.
  • Modelado y puesta en servicio: usted entrena un modelo de «Gradient Boosting» sensible al tiempo y expone las predicciones a través de Flask.
  • Acción en el gráfico: MQL5 utiliza esas señales para trazar flechas y líneas de SL/TP, y puede ejecutar operaciones de forma automática.
A lo largo del proceso, usted ha sabido lidiar con peculiaridades del mundo real, desde el análisis de JSON con datos adicionales en Flask hasta la limitación de las llamadas HTTP en su Asesor Experto, y ha comprobado cómo la separación de responsabilidades permite que todo sea fácil de mantener y ampliar.
Puede probar a sustituir el algoritmo por otro (XGBoost, LSTM, lo que se le ocurra), afinar sus reglas de gestión de riesgos o empaquetar en contenedores el servicio de Python con Docker para conseguir despliegues más limpios. Con esta base, ya tiene todo listo para perfeccionar sus backtests y llevar sus estrategias automatizadas aún más lejos.






Proyector de gráficos
Comentario analítico
Maestro de analítica
Pronosticador analítico
Navegador de volatilidad
Segador de señales de reversión a la media
Pulso de señal
Panel de métricas
Flujo externo
VWAP
Heikin Ashi FibVWAP
DIVERGENCIA DEL RSI
Stop y reversión parabólica (PSAR)
Script de trazado de cuartos
Detector de intrusiones
Herramienta TrendLoom Panel de cuartos
Analizador ZigZag Explorador de correlaciones Herramienta de detección de cambios en la estructura del mercado
Panel de correlaciones Medidor de fortaleza de divisas
Herramienta de análisis PAQ
Fractal Breaker con doble EMA
Pin bar, patrón envolvente y divergencia del RSI
Barrido de liquidez Herramienta de ruptura del rango de apertura Interceptor de Boom and Crash Asesor Experto CCI Zer-Line
Reconocimiento de velas japonesas Detección de velas japonesas con TA-Lib Herramienta de rango de velas Ingestor de datos de MetaTrader 5 Entrenamiento y despliegue de modelos Uso de la biblioteca de Python

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

Archivos adjuntos |
Aprendiendo MQL5 de principiante a profesional (Parte VII): Principios de depuración de aplicaciones MQL Aprendiendo MQL5 de principiante a profesional (Parte VII): Principios de depuración de aplicaciones MQL
La corrección de errores es una parte indispensable del ciclo de programación. En este artículo se analizan las técnicas habituales para corregir errores (depuración) en cualquier aplicación que se ejecute en el entorno de MetaTrader 5.
Reimaginando las estrategias clásicas (Parte 15): Estrategia de ruptura diaria Reimaginando las estrategias clásicas (Parte 15): Estrategia de ruptura diaria
Los traders humanos llevaban mucho tiempo participando en los mercados financieros antes del auge de los ordenadores, desarrollando reglas prácticas que guiaban sus decisiones. En este artículo, retomamos una estrategia de ruptura bien conocida para comprobar si dicha lógica de mercado, aprendida a través de la experiencia, puede competir de tú a tú con los métodos sistemáticos. Nuestros resultados muestran que, aunque la estrategia original ofrecía una alta tasa de acierto, adolecía de inestabilidad y de un control deficiente del riesgo. Al perfeccionar este enfoque, demostramos cómo los conocimientos discrecionales pueden adaptarse a estrategias de trading algorítmico más sólidas.
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.
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 37): Sentiment Tilt Meter Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 37): Sentiment Tilt Meter
El sentimiento del mercado es una de las fuerzas más ignoradas pero a la vez más poderosas que influyen en el movimiento de los precios. Mientras que la mayoría de los operadores se basan en indicadores rezagados o conjeturas, el Asesor Experto (EA) Sentiment Tilt Meter (STM) transforma los datos brutos del mercado en una guía visual clara, que muestra si el mercado tiende al alza, a la baja o se mantiene neutral en tiempo real. Esto facilita la confirmación de las operaciones, evita las entradas erróneas y permite sincronizar mejor la participación en el mercado.