English Русский 中文 Deutsch 日本語 Português
preview
De novato a experto: EA de informes — Configuración del flujo de trabajo

De novato a experto: EA de informes — Configuración del flujo de trabajo

MetaTrader 5 — Ejemplos |
143 0
Clemence Benjamin
Clemence Benjamin

Contenido:



Introducción

La inspiración para este concepto surgió cuando comencé a recibir confirmaciones diarias de mis operaciones por correo electrónico. Estos resúmenes ofrecían una visión general clara y profesional de la actividad de trading y ponían de relieve el potencial para el análisis estadístico del rendimiento. Al explorar la terminal MetaTrader 5, descubrí que incluye una completa herramienta de generación de informes en su versión actual, capaz de exportar informes detallados tanto en formato HTML como en PDF. Sin embargo, carece de la funcionalidad para la entrega automática de informes y la gestión centralizada. En este análisis, nuestro objetivo es explorar el papel de los informes de operaciones, aclarar los términos clave que implican y destacar su importancia práctica para todo trader que busque tomar decisiones informadas. 

En definitiva, planeamos implementar un sistema de informes personalizado utilizando MQL5 en colaboración con Python y otras herramientas externas. Esta solución generará informes detallados, garantizará la compatibilidad con múltiples formatos de archivo y permitirá la entrega automatizada mediante métodos prácticos y fiables.

Tras examinar los documentos exportados desde MetaTrader 5, quedó claro que contienen información valiosa y métricas precalculadas que ofrecen a los traders una visión matemática de su rendimiento; información que puede influir directamente en las decisiones de trading y en los ajustes de comportamiento.

Actualmente, los informes en MetaTrader 5 se obtienen normalmente mediante navegación manual. Sin embargo, al trabajar con Asesores Expertos (AE), tenemos la oportunidad de controlar programáticamente la generación y la entrega de estos informes. Si bien algunos brókeres ya envían estos informes automáticamente, nuestro objetivo en esta discusión es desarrollar un sistema que nos permita programar la entrega de informes según nuestras propias preferencias, personalizando tanto la frecuencia como el contenido.

Mientras trabajamos para resolver este problema, exploraremos la importancia práctica de los informes de operaciones utilizando una de mis propias experiencias como ejemplo. También analizaremos los términos comunes que se encuentran en estos informes y discutiremos cómo se pueden utilizar para mejorar tanto las estrategias de negociación manual como la evaluación del rendimiento de los Asesores Expertos.

En MetaTrader 5, puedes acceder a los informes de operaciones seleccionando «Informes» en el menú «Ver» o utilizando el atajo de teclado Alt+E. La ventana de informes muestra diversos aspectos de su actividad de trading en un formato claro y organizado. Desde esta ventana, también tiene la opción de guardar sus informes en formato HTML o PDF, como se muestra en la imagen a continuación:

Acceso a los informes de la terminal de cuenta de MetaTrader 5

Acceso a informes en MetaTrader 5

La ilustración anterior destaca algunos de los componentes clave que suelen encontrarse en los informes de operaciones. Si bien esta información es muy valiosa, muchos traders tienden a centrarse únicamente en los gráficos y la ejecución de las operaciones, y a menudo descuidan la revisión periódica de sus registros de rendimiento. Es fundamental comprender claramente estos informes, ya que refuerzan la disciplina y favorece una mentalidad de trading más saludable al extraer conclusiones de la actividad pasada.

Tras revisar mi informe de operaciones, tomé la iniciativa de investigar los términos clave que contenía y recopilé notas junto con ejemplos prácticos para que fueran más fáciles de entender. En la siguiente sección, encontrará cinco bloques estructurados de ideas clave, cada una de las cuales ofrece una explicación breve pero significativa. Estos elementos sirven de base para el plan de implementación que exploraremos más adelante en el artículo. Para cuando lleguemos a la fase de desarrollo técnico, el objetivo es garantizar una comprensión sólida de estos conceptos del informe. Si ya estás familiarizado con ellos, puedes pasar directamente a la etapa de implementación.


Comprender los informes de operaciones en MQL5

1. Resumen de desempeño

ROI:

  • Mide cuánto crece el saldo de la cuenta en relación con su capital inicial.
  • Consideremos comenzar con 5.000 dólares y terminar con 12.000 dólares; eso produce un aumento del 140%, lo que significa que cada dólar arriesgado se convirtió en 2,40 dólares.

Drawdown:

  • Captura el descenso porcentual más pronunciado desde un nivel máximo hasta el siguiente nivel mínimo.
  • Imagine que el capital de la cuenta alcanza un máximo de 12000 dólares y luego cae a 9600 dólares, un retroceso del 20 % que pone de manifiesto el mayor revés antes de la recuperación.

Métricas de actividad:

  • Reflejan el ritmo y la consistencia de las operaciones: número de operaciones por semana, tasa de éxito y duración media de las mismas.
  • A modo de ejemplo, completar 80 operaciones en ocho semanas equivale a 10 por semana; ganar 32 de ellas resulta en una tasa de éxito del 40%; y un total de 160 días en el mercado da un promedio de mantenimiento de 2 días.

Índice de Sharpe:

  • Indica cuánto rendimiento adicional se obtiene por cada unidad de volatilidad soportada.
  • Para ilustrarlo, comparemos dos sistemas que generan un rendimiento anual del 15%: el que oscila ±2% diariamente tendrá un índice de Sharpe notablemente superior al que oscila ±6%, lo que refleja una evolución más fluida del capital.

Factor de beneficio:

  • Expresa el beneficio bruto dividido por la pérdida bruta para mostrar la eficiencia de los ganadores frente a los perdedores.
  • Consideremos el caso de 8.000 dólares en operaciones ganadoras frente a 5.000 dólares en pérdidas, lo que arroja una proporción de 1,6; es decir, por cada dólar perdido se compensa con 1,60 dólares ganados.

Factor de recuperación:

  • Compara el beneficio neto con la mayor caída experimentada.
  • Supongamos que una estrategia genera una ganancia neta de 4000 dólares y, en su peor momento, registra una pérdida de 1000 dólares; un factor de recuperación de 4 indica que las ganancias fueron cuatro veces mayores que la pérdida máxima.

2. Desglose de ganancias y pérdidas

Beneficio bruto y pérdida bruta:

  • La suma de las operaciones ganadoras y perdedoras establece el beneficio bruto antes de los costes.
  • Por ejemplo, 15000 dólares en ganancias frente a 6000 dólares en pérdidas generan una ventaja bruta de 9000 dólares.

Comisiones y beneficio neto:

  • Al restar las comisiones, los swaps y otros cargos de los resultados brutos, se obtienen las ganancias reales.
  • Para ponerlo en perspectiva, restar 1200 dólares en comisiones de una ventaja de 9000 dólares deja una ganancia neta de 7800 dólares.

Tendencias mensuales:

  • La representación gráfica de los resultados netos mes a mes revela cambios en el rendimiento.
  • Como ejemplo, ver un aumento de +$4000 en enero, +$3000 en febrero, +$800 en marzo y -$500 en abril pone de manifiesto una trayectoria descendente que exige atención.

3. Análisis de riesgos

Drawdown máximo:

  • Define la mayor caída porcentual desde un pico hasta el siguiente valle.
  • Imagínese una cuenta que cae de 20000 dólares a 14000 dólares antes de recuperarse: una caída del 30 % en el peor de los casos.

Victorias y derrotas consecutivas:

  • Las rachas más largas de resultados positivos o negativos ponen a prueba tanto la estabilidad del sistema como la psicología del trader.
  • Imagínese sufrir siete derrotas seguidas frente a conseguir cinco victorias consecutivas; cada racha moldea la confianza, la disciplina y la gestión del tamaño de la posición.

Máxima Excursión Favorable (Maximum Favorable Excursion, MFE):

  • Registra el beneficio no realizado más alto alcanzado durante la vida útil de una operación.
  • Para ilustrarlo, una posición podría alcanzar un valor máximo de 600 dólares antes de que se activen las órdenes de salida.

Máxima Excursión Adversa (Maximum Adverse Excursion, MAE):

  • Registra la pérdida más profunda e irrealizada experimentada antes del cierre.
  • Tenga en cuenta que la misma operación podría caer 200 dólares antes de cerrar con ganancias, lo que indicaría dónde podrían ser útiles los ajustes de stop-loss.

4. Rendimiento por instrumento/símbolo

Tasa de éxito por activo:

  • Los porcentajes de éxito por mercado revelan dónde se encuentra la ventaja más sólida.
  • Por ejemplo, el par EURUSD podría obtener ganancias en el 48% de las operaciones, mientras que el USDJPY lo hace en el 60%, lo que sugiere señales más fuertes en este último.

Contribución a las ganancias:

  • Los beneficios netos por instrumento muestran de dónde provienen realmente las ganancias.
  • Tomemos como ejemplo el caso del EURUSD, que suma 9600 dólares al resultado final, mientras que el XAUUSD resta 1100 dólares, lo que orienta la asignación de recursos.

Riesgo de concentración:

  • Destaca la porción de capital o el número de operaciones vinculadas a un solo mercado.
  • Supongamos que el 40% de los fondos están invertidos en EURUSD; un movimiento repentino del euro podría afectar desproporcionadamente al rendimiento general.

Factor de beneficio por símbolo:

  • Compara las ganancias brutas con las pérdidas de cada mercado, lo que permite clarificar la eficiencia.
  • Para ilustrarlo, el par USDJPY puede presumir de una relación de 1,8, mientras que el AUDCAD se sitúa en 0,9, lo que determina qué pares priorizar o evitar.

5. Patrones de actividad y comportamiento

Distribución de operaciones:

  • El equilibrio entre posiciones largas y cortas revela una tendencia direccional.
  • Por ejemplo, mantener un 70% de posiciones largas sugiere una postura principalmente alcista que puede flaquear en mercados laterales.

Automatización frente a manual:

  • La comparación entre las operaciones realizadas mediante algoritmos y las introducidas manualmente revela dónde reside la verdadera ventaja competitiva.
  • Considérese que el 65% del beneficio neto proviene de entradas automatizadas frente al 35% de las manuales, lo que subraya la solidez del sistema.

Análisis de tiempo:

  • El desglose de los resultados por hora y día de la semana permite identificar los periodos óptimos y los más vulnerables.
  • Como ejemplo, la mayoría de las pérdidas pueden ocurrir entre las 11:00 y las 12:00 GMT, lo que indica que es mejor evitar la franja horaria del mediodía.

Métricas de estilo:

  • La duración media de las posiciones y el volumen de negociación semanal definen el enfoque.
  • Para ilustrarlo, una duración media de las posiciones de cuatro horas, combinado con aproximadamente 25 operaciones por semana, caracteriza una estrategia intradiaria de ritmo moderado.


Implementación

En esta etapa, procedemos a configurar nuestro flujo de trabajo. Gracias a la sección anterior, que proporcionó una comprensión profunda de la terminología de los informes de operaciones, le resultará más fácil seguir esta parte, ya que contiene menos conceptos desconocidos.

Para lograr el objetivo de este artículo, desarrollaremos un Asesor Experto (EA) que gestione la exportación de datos y prepare los registros necesarios. Este Asesor Experto (EA) servirá de puente entre MetaTrader 5 (MQL5) y las bibliotecas de Python responsables de procesar los datos históricos de negociación y generar un informe final en un formato portátil, similar a las herramientas de generación de informes integradas en la terminal MetaTrader 5.

Comenzaremos presentando un diagrama de flujo que describe todo el proceso, seguido de un desglose de las herramientas necesarias y la configuración del entorno para que todo funcione correctamente. Todos los componentes de este proyecto se basan en tecnologías de código abierto, lo que garantiza la accesibilidad para todos.

Flujo del proceso de informes de EA

Flujo del proceso

Para empezar, asegúrese de tener MetaTrader 5 instalado en su sistema. A continuación, proceda a configurar el entorno de Python, lo cual explicaré en detalle más adelante. Consulte la tabla a continuación para obtener una lista simplificada de los requisitos y las herramientas utilizadas en este flujo de trabajo.

Componente Herramientas de código abierto Costo Notas de implementación
Extracción de datos Asesor experto de MetaTrader 5 (ReporterEA.mq5) Gratis Exportación CSV personalizada con filtrado por rango de fechas
Motor de programación Eventos del temporizador de MetaTrader 5 (OnTimer()) Gratis Programación interna dentro del terminal MetaTrader 5
Procesamiento Python 3.10+ (pandas, FPDF) Gratis Ejecutado por el EA mediante ShellExecute
Entrega de informes smtplib + Gmail SMTP Gratis Muchos correos electrónicos gratuitos al día desde un script de Python
Mantenimiento Funciones de limpieza automática de EA Gratis Rotación de archivos y manejo de errores en MQL5/Python


Desarrollo de un Asesor Experto para informes

En esta etapa, comenzamos a desarrollar el Asesor Experto (EA) según lo previsto. Te guiaré a través de cada componente del código, explicándote cómo funcionan juntos para formar un sistema completo y funcional. El objetivo es construir un EA robusto que cumpla su propósito sin problemas. Acompáñanos mientras desglosamos el proceso de desarrollo en pasos claros y manejables, asegurándonos de que cada parte sea fácil de entender y contribuya de manera significativa al producto final.

En MetaEditor 5, abra un archivo nuevo y seleccione la plantilla "Expert Advisor". Recomiendo eliminar cualquier sección del código autogenerado que no sea relevante para nuestros objetivos de desarrollo actuales, para que podamos centrarnos únicamente en lo que importa. Siga los pasos numerados a continuación mientras comenzamos a construir el Asesor Experto paso a paso.

1. Metadatos del archivo y directivas de compilación

En la parte superior del archivo, las directivas #property declaran metadatos para el Asesor Experto (EA). Estas propiedades incluyen la información de derechos de autor y los enlaces, que aparecen en el cuadro "Acerca de" del terminal MetaTrader 5, así como el número de versión y el modo de compilación estricto. El modo estricto impone reglas de compilación y comprobación de tipos más rigurosas, lo que ayuda a prevenir errores sutiles al no permitir conversiones implícitas y exigir conversiones explícitas.

#property copyright "Clemence Benjamin"
#property link      "https://www.mql5.com/go?link=https://www.mql5.com/en/users/billionaire2024/seller"
#property version   "1.00"
#property strict

2. Constantes e importaciones de la API de Windows

Las declaraciones #define crean nombres simbólicos para valores constantes de uso común (SW_HIDE para ocultar las ventanas de la consola e INVALID_FILE_ATTRIBUTES para la comprobación de errores). A continuación, el código importa dos bibliotecas del sistema Windows mediante #import: kernel32.dll para las funciones de atributos de archivo (GetFileAttributesW) y shell32.dll para la ejecución de procesos externos (ShellExecuteW). Al llamar a estas funciones DLL nativas, el EA amplía las capacidades integradas de MetaTrader 5 para verificar la existencia de archivos e iniciar el intérprete de Python.

#define SW_HIDE                 0
#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF

//--- Windows API imports
#import "kernel32.dll"
uint   GetFileAttributesW(string lpFileName);
#import

#import "shell32.dll"
int    ShellExecuteW(int hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd);
#import

3. Entradas de usuario para la configuración

Las declaraciones de entrada exponen parámetros personalizables en el cuadro de diálogo de configuración del EA. Los usuarios pueden especificar la ruta absoluta al ejecutable de Python (PythonPath), el script de Python que se va a ejecutar (ScriptPath), la hora y el minuto en los que debe ejecutarse el informe diario (ReportHour, ReportMinute), si se envían notificaciones push (EnableEmail) y si se realiza una prueba inicial al iniciar el programa (TestOnInit). Al exponer estos parámetros como entradas, los usuarios que no son programadores pueden modificar el comportamiento sin editar el código fuente.

//--- User inputs
input string PythonPath   = "C:\\Users\\BTA24\\AppData\\Local\\Programs\\Python\\Python312\\python.exe";
input string ScriptPath   = "C:\\Users\\BTA24\\Documents\\BENJC_TRADE_ADVISOR\\Scripts\\processor.py";
input int    ReportHour   = 15;    // Hour (24h) to run report
input int    ReportMinute = 55;    // Minute after the hour
input bool   EnableEmail  = true;  // Send push notification
input bool   TestOnInit   = true;  // Immediately run export+Python on init

4. Gestión del Estado Global

Una única variable global, lastRunTime, almacena la marca de tiempo de la ejecución exitosa más reciente del informe. Al comparar TimeCurrent() con lastRunTime, el EA garantiza que el informe se ejecute solo una vez cada 24 horas, aunque la función de devolución de llamada del temporizador realice comprobaciones con mayor frecuencia.

//--- Globals
datetime lastRunTime = 0;

5. Lógica de inicialización (OnInit)

La función OnInit() realiza todas las rutinas de inicio. En primer lugar, imprime mensajes de estado en el registro de Expertos. Comprueba los atributos de archivo del ejecutable y del script de Python e imprime advertencias si faltan. A continuación, comprueba los permisos de escritura creando, escribiendo, cerrando y eliminando un archivo ficticio en el directorio MQL5\Files. A continuación, configura un evento de temporizador recurrente cada 30 segundos a través de EventSetTimer(30). Finalmente, si TestOnInit es verdadero, llama inmediatamente a RunDailyExport() para validar el flujo de trabajo completo de exportación y Python, registrando la hora actual en lastRunTime.

int OnInit()
{
   Print(">> Reporting EA initializing…");

   // Verify Python executable
   if(GetFileAttributesW(PythonPath) == INVALID_FILE_ATTRIBUTES)
      Print("!! Python executable not found at: ", PythonPath);
   else
      Print("✔ Found Python at: ", PythonPath);

   // Verify Python script
   if(GetFileAttributesW(ScriptPath) == INVALID_FILE_ATTRIBUTES)
      Print("!! Python script not found at:   ", ScriptPath);
   else
      Print("✔ Found script at:   ", ScriptPath);

   // Test write permission
   int h = FileOpen("test_perm.txt", FILE_WRITE|FILE_COMMON|FILE_ANSI);
   if(h==INVALID_HANDLE)
      Print("!! Cannot write to MQL5\\Files directory!");
   else
   {
      FileWrite(h, "OK");
      FileClose(h);
      FileDelete("test_perm.txt");
      Print("✔ Write permission confirmed.");
   }

   // Set timer
   EventSetTimer(30);
   Print(">> Timer set to 30 seconds.");

   // Test run on init
   if(TestOnInit)
   {
      Print(">> Test mode: running initial export.");
      RunDailyExport();
      lastRunTime = TimeCurrent();
   }

   return(INIT_SUCCEEDED);
}

6. Lógica de desinicialización (OnDeinit)

Cuando se elimina el EA o se apaga la plataforma, se invoca OnDeinit(). Su única responsabilidad es limpiar el sistema deteniendo el temporizador (EventKillTimer()) y registrando un mensaje de desinicialización. La correcta liberación de los recursos del temporizador evita las llamadas de retorno huérfanas y los posibles fallos del sistema.

void OnDeinit(const int reason)
{
   EventKillTimer();
   Print(">> Reporting EA deinitialized.");
}

7. Función de devolución de llamada del temporizador para la programación (OnTimer)

Cada 30 segundos, se ejecuta OnTimer() y se recupera la hora y los minutos actuales a través de la estructura MqlDateTime. Comprueba si la hora actual coincide o supera la hora de informe configurada (ReportHour, ReportMinute) y si han transcurrido al menos 86 400 segundos (24 horas) desde lastRunTime. Esta doble verificación garantiza que el informe se ejecute una vez al día, a la hora programada o después.

void OnTimer()
{
   MqlDateTime dt; TimeToStruct(TimeCurrent(), dt);

   if(dt.hour==ReportHour && dt.min>=ReportMinute && (TimeCurrent()-lastRunTime)>86400)
   {
      RunDailyExport();
      lastRunTime = TimeCurrent();
   }
}

8. Flujo de trabajo principal: Exportación e invocación de Python (RunDailyExport)

  1. Esta función engloba los pasos principales de la función de generación de informes del EA.
  2. Calcula la ruta absoluta al directorio MQL5\Files de MetaTrader 5 usando TerminalInfoString.
  3. Genera nombres de archivo con marca de fecha tanto para la exportación CSV como para el archivo de registro, formateando la fecha actual y eliminando los puntos.
  4. Llame a ExportHistoryToCSV() para escribir el historial de operaciones de los últimos 30 días en el archivo CSV. Si esto falla, la función finaliza.
  5. Crea una cadena de comandos que invoque al intérprete de Python con el script y el nombre del archivo CSV, redirigiendo tanto la salida estándar como el error estándar al archivo de registro. El formato de cadena y StringFormat garantizan el uso correcto de comillas para rutas que contienen espacios.
  6. Llama al envoltorio ShellExecute() de EA para ejecutar cmd.exe /c<pythonCmd> , capturando el código de retorno entero para el registro de diagnóstico.
  7. Haga una pausa de 3 segundos con Sleep(3000) para permitir que el proceso externo de Python finalice.
  8. Compruebe la existencia del archivo de registro, lea su contenido e imprímalo línea por línea en el registro de Expertos.
  9. Por último, redacte un mensaje de notificación que resuma la ruta del archivo CSV y, si está habilitado, envíelo mediante SendNotification() a los terminales móviles del usuario.

void RunDailyExport()
{
   string filesDir = TerminalInfoString(TERMINAL_DATA_PATH) + "\\MQL5\\Files\\";
   
   string dateStr = TimeToString(TimeCurrent(), TIME_DATE);
   StringReplace(dateStr, ".", "");
   
   string csvName = "History_" + dateStr + ".csv";
   string logName = "ProcLog_" + dateStr + ".txt";
   
   string csvFull  = filesDir + csvName;
   string logFull  = filesDir + logName;

   // 3) Export CSV
   if(!ExportHistoryToCSV(csvName))
   {
      Print("!! CSV export failed: ", csvFull);
      return;
   }
   Print("✔ CSV exported: ", csvFull);

   // 4) Build Python command
   string pythonCmd = StringFormat(
      "\"%s\" \"%s\" \"%s\" >> \"%s\" 2>&1",
      PythonPath,
      ScriptPath,
      csvFull,
      logFull
   );
   string fullCmd = "/c " + pythonCmd;
   PrintFormat("→ Launching: cmd.exe %s", fullCmd);

   // 5) Execute
   int result = ShellExecute(" " + fullCmd);
   PrintFormat("← ShellExecute returned: %d", result);

   // 6) Wait
   Sleep(3000);

   // 7) Read log
   if(GetFileAttributesW(logFull) == INVALID_FILE_ATTRIBUTES)
      Print("!! Log file not created: ", logFull);
   else
   {
      Print("=== Python Log Start ===");
      int fh = FileOpen(logName, FILE_READ|FILE_COMMON|FILE_TXT);
      while(fh!=INVALID_HANDLE && !FileIsEnding(fh))
         Print("PY: ", FileReadString(fh));
      if(fh!=INVALID_HANDLE) FileClose(fh);
      Print("=== Python Log End ===");
   }

   // 8) Notification
   string msg = "Report & log generated: " + csvFull;
   Print(msg);
   if(EnableEmail) SendNotification(msg);
}

9. Generación de CSV (ExportHistoryToCSV)

Esta función auxiliar automatiza la extracción del historial de transacciones a un archivo CSV. Selecciona todo el historial de los últimos 30 días (HistorySelect), itera a través de cada ticket de transacción, recupera las propiedades (tiempo, tipo, símbolo, volumen, precio, ganancia, comisión, swap) utilizando las funciones HistoryDealGet* y las escribe como valores separados por comas con FileWrite. Tras generar una fila de encabezado, el bucle construye cada línea utilizando DoubleToString y TimeToString, lo que garantiza una precisión numérica y un formato de marca de tiempo consistentes. Una correcta comprobación de errores en FileOpen evita fallos silenciosos.

bool ExportHistoryToCSV(string filename)
{
   datetime end   = TimeCurrent();
   datetime start = end - 2592000; // last 30 days

   HistorySelect(start, end);
   int total = HistoryDealsTotal();

   int fh = FileOpen(filename, FILE_WRITE|FILE_CSV|FILE_COMMON|FILE_ANSI, ",");
   if(fh==INVALID_HANDLE)
   {
      Print("!! FileOpen failed for: ", filename);
      return(false);
   }

   FileWrite(fh, "Ticket,Time,Type,Symbol,Volume,Price,Profit,Commission,Swap");

   for(int i=0; i<total; i++)
   {
      ulong deal = HistoryDealGetTicket(i);
      if(deal==0) continue;

      long    tr = HistoryDealGetInteger(deal, DEAL_TIME);
      datetime t = (datetime)tr;
      int     tp = (int)HistoryDealGetInteger(deal, DEAL_TYPE);

      string  sym = HistoryDealGetString (deal, DEAL_SYMBOL);
      double  vol = HistoryDealGetDouble (deal, DEAL_VOLUME);
      double  prc = HistoryDealGetDouble (deal, DEAL_PRICE);
      double  pf  = HistoryDealGetDouble (deal, DEAL_PROFIT);
      double  cm  = HistoryDealGetDouble (deal, DEAL_COMMISSION);
      double  sw  = HistoryDealGetDouble (deal, DEAL_SWAP);

      FileWrite(fh,
         deal,
         TimeToString(t, TIME_DATE|TIME_SECONDS),
         tp,
         sym,
         DoubleToString(vol,2),
         DoubleToString(prc,5),
         DoubleToString(pf,2),
         DoubleToString(cm,2),
         DoubleToString(sw,2)
      );
   }

   FileClose(fh);
   return(true);
}

10. Envoltorio de comandos de shell (ShellExecute)

La función ShellExecute actúa como una capa de abstracción simple alrededor de la llamada a la API ShellExecuteW importada. Al estandarizar la invocación de cmd.exe, se oculta la complejidad de la API nativa y siempre se utiliza SW_HIDE para suprimir las ventanas de la consola. Devolver el código de resultado entero permite al EA detectar y registrar posibles errores al ejecutar comandos externos.

int ShellExecute(string command)
{
   return(ShellExecuteW(0, "open", "cmd.exe", command, NULL, SW_HIDE));
}


Desarrollo del script del procesador Python

Comenzamos configurando Python e instalando las bibliotecas necesarias. Primero, abre el Símbolo del sistema y ejecuta los comandos de instalación necesarios. Después de eso, puedes preparar tu script de Python usando un editor de texto. Personalmente prefiero Notepad++, una herramienta de código abierto, pero puedes usar cualquier IDE de Python que prefieras.

Configuración

1. Para preparar la parte de Python, comience instalando un intérprete de Python 3.x reciente (por ejemplo, 3.10 o 3.12). Crea y activa un entorno virtual en la carpeta de tu proyecto:

python -m venv venv  

source venv/Scripts/activate    # Windows  

# or  

source venv/bin/activate        # macOS/Linux  

2. Una vez activado, instale los paquetes necesarios con:

pip install pandas fpdf

  • pandas se encarga de leer archivos CSV y analizar datos,
  • FPDF (o cualquier otra biblioteca de PDF de su elección) genera el informe.

3. Si planea enviar alertas por correo electrónico, instale también una biblioteca SMTP como yagmail o utilice la biblioteca smtplib integrada de Python. 

Ahora es el momento de desarrollar el script de Python. Procederemos siguiendo los siguientes pasos para implementar cada parte.

1. Encabezado del script e importaciones

El script comienza con una línea shebang al estilo Unix para permitir su ejecución en sistemas que la respeten, seguida de la importación de bibliotecas clave:

  • sys, os y traceback para interactuar con el sistema operativo, manejar argumentos e imprimir errores;
  • Pandas para la carga y manipulación de datos;
  • datetime y timedelta para cálculos de fechas;
  • FPDF del paquete fpdf para generar informes en formato PDF.

#!/usr/bin/env python

import sys, os, traceback

import pandas as pd

from datetime import datetime, timedelta

from fpdf import FPDF

2. Flujo de trabajo principal: Validación de argumentos y comprobación de archivos

La función main(csv_path) es el orquestador. Imprime el archivo CSV que se está procesando e inmediatamente verifica que el archivo exista; de no existir, genera un error FileNotFoundError. Esto refleja las comprobaciones preliminares que realiza el propio EA de MQL5 para las rutas de los scripts y ejecutables de Python.

def main(csv_path):

    print(f"Processing CSV: {csv_path}")

    if not os.path.isfile(csv_path):

        raise FileNotFoundError(f"CSV not found: {csv_path}")

3. Carga y análisis del archivo CSV

Mediante pandas.read_csv, el script carga el archivo CSV del historial de operaciones generado por el EA. A continuación, convierte la columna 'Time' en objetos datetime con pd.to_datetime, lo que garantiza que los cálculos posteriores basados en el tiempo sean precisos. Esto es similar al formato de horas que utiliza EA con TimeToString.

# 1. Cargar y analizar

    df = pd.read_csv(csv_path)

    df['Time'] = pd.to_datetime(df['Time'])

4. Cálculo de métricas resumidas

El script agrega las métricas clave de rendimiento en un diccionario de informes:

  • 'date': la fecha de hoy como cadena;
  • 'net_profit': la suma de la columna «Beneficios»;
  • 'trade_count': número total de filas del DataFrame;
  • 'top_symbol': el símbolo con mayor beneficio acumulado, utilizando «groupby» e «idxmax».

Estas métricas coinciden con el contenido del archivo CSV de EA y permiten que el PDF resuma con exactitud lo que se exportó.

 # 2. Análisis

    report = {

        'date'       : datetime.now().strftime("%Y-%m-%d"),

        'net_profit' : df['Profit'].sum(),

        'trade_count': len(df),

        'top_symbol' : df.groupby('Symbol')['Profit'].sum().idxmax()

    }

5. Generación del informe PDF

El script crea la ruta de salida en el mismo directorio MQL5\Files que el archivo CSV, nombrando el PDF por fecha. Luego llama a generate_pdf(report, pdf_file). Esto encaja perfectamente con el registro de la salida de Python por parte de EA y la expectativa de que cualquier artefacto (tanto CSV como PDF) se guarde en la carpeta de archivos comunes.

# 3. Generar PDF

    dirpath = os.path.dirname(csv_path)

    pdf_file = os.path.join(dirpath, f"Report_{report['date']}.pdf")

    generate_pdf(report, pdf_file)


    print(f"PDF written: {pdf_file}")

    return 0

6. Construcción de PDF con FPDF

La función generate_pdf utiliza la sencilla API de FPDF: crea un documento, añade una página, configura la fuente y escribe líneas para cada métrica. El parámetro ln=True pasa automáticamente a la siguiente línea. Esta herramienta modular mantiene separadas las cuestiones de formato PDF de la lógica de datos.

def generate_pdf(report, output_path):

    pdf = FPDF()

    pdf.add_page()

    pdf.set_font("Arial", size=12)

    pdf.cell(0, 10, f"Report Date: {report['date']}", ln=True)

    pdf.cell(0, 10, f"Total Trades: {report['trade_count']}", ln=True)

    pdf.cell(0, 10, f"Net Profit:    ${report['net_profit']:.2f}", ln=True)

    pdf.cell(0, 10, f"Top Symbol:    {report['top_symbol']}", ln=True)

    pdf.output(output_path)

7. Mantenimiento: Limpieza de informes antiguos

Para evitar que el disco se sature, clean_old_reports elimina cualquier PDF con una antigüedad superior a un número configurable de días (por defecto, 30). Solo se ejecuta cuando el EA invoca el script los domingos (weekday() == 6) y recibe la ruta CSV en sys.argv[1], lo que garantiza que se dirija al directorio correcto. Este mantenimiento es similar al sistema de nomenclatura basado en fechas y a la lógica de bloqueo de 24 horas del propio EA.

def clean_old_reports(days=30):

    now = datetime.now()

    cutoff = now - timedelta(days=days)

    dirpath = os.path.dirname(sys.argv[1])

    for fname in os.listdir(dirpath):

        if fname.startswith("Report_") and fname.endswith(".pdf"):

            full = os.path.join(dirpath, fname)

            if datetime.fromtimestamp(os.path.getmtime(full)) < cutoff:

                os.remove(full)

                print(f"Deleted old report: {full}")

8. Punto de entrada del script y manejo de errores

El bloque «if __name__ == «__main__»:» obliga a utilizar exactamente un argumento (la ruta completa al archivo CSV). Envuelve la llamada a «main» en un bloque «try/except» para detectar cualquier excepción, mostrar un «traceback» y salir con un código distinto de cero, del mismo modo que el EA captura las salidas «stdout» y «stderr» de Python y registra cualquier error en sus propios registros. El mantenimiento opcional se realiza semanalmente antes de la salida.

if __name__ == "__main__":

    if len(sys.argv) != 2:

        print("Usage: processor.py <full_csv_path>")

        sys.exit(1)

    try:

        ret = main(sys.argv[1])

        # Optional maintenance

        if datetime.now().weekday() == 6:

            clean_old_reports(30)

        sys.exit(ret)

    except Exception as e:

        print("ERROR:", e)

        traceback.print_exc()

        sys.exit(1)

Interacción entre el Asesor Experto (EA) de MetaTrader 5 y un script de Python.

  1. Convenciones para nombres de archivo: EA crea un archivo CSV con formato de fecha (History_YYYYMMDD.csv) y el script de Python espera exactamente un argumento que apunte a ese archivo.
  2. Alineación de directorios: Ambos componentes operan en la carpeta MQL5\Files de MetaTrader 5, lo que garantiza una detección de archivos sin problemas.
  3. Propagación de errores: El EA redirige la salida estándar (stdout) y el error estándar (stderr) de Python a un archivo de registro con marca de tiempo; cualquier excepción en el script (por ejemplo, archivo CSV faltante, error de análisis) es capturada por el lector de registros del EA y se imprime en el registro de la pestaña Experts.
  4. Programación: La lógica del temporizador de 24 horas del EA determina cuándo se ejecuta Python; el script en sí permanece sin estado más allá del procesamiento de su entrada, dependiendo del EA para que lo llame en los momentos adecuados.
  5. Coordinación de mantenimiento: La limpieza semanal de archivos PDF se activa desde el script, pero solo cuando se llama los domingos, coincidiendo con la comprobación semanal del EA si esta se extiende.


Pruebas

En esta sección, implementaremos el Asesor Experto (EA) de informes en un gráfico de MetaTrader 5. En un ordenador con Windows, es fundamental habilitar la importación de DLL para permitir la ejecución de procesos externos. Durante las pruebas, el EA cumplió su objetivo de exportar el historial a CSV y activar el script de Python encargado de procesar los datos. A continuación, el script genera las métricas del informe necesarias y las exporta como un documento PDF bien presentado, listo para ser enviado por correo electrónico o archivado para su revisión.

Implementación de Reporting EA

Implementación de Reporting EA

Registro de informes de los expertos de EA:

2025.07.24 20:44:57.061 Reporting EA (GBPJPY.0,M1)      >> Reporting EA initializing…
2025.07.24 20:44:57.061 Reporting EA (GBPJPY.0,M1)      !! Python executable not found at: C:\path_to\python.exe
2025.07.24 20:44:57.061 Reporting EA (GBPJPY.0,M1)      !! Python script not found at:   C:\path_to\reports_processor.py
2025.07.24 20:44:57.062 Reporting EA (GBPJPY.0,M1)      ✔ Write permission confirmed.
2025.07.24 20:44:57.062 Reporting EA (GBPJPY.0,M1)      >> Timer set to 30 seconds.
2025.07.24 20:44:57.062 Reporting EA (GBPJPY.0,M1)      >> Test mode: running initial export.
2025.07.24 20:44:57.063 Reporting EA (GBPJPY.0,M1)      ✔ CSV exported: C:\TERMINAL_PATH\MQL5\Files\History_20250724.csv
2025.07.24 20:44:57.063 Reporting EA (GBPJPY.0,M1)      → Launching: cmd.exe /c "C:\path_to\python.exe" "C:\path_to\reports_processor.py" "C:\TERMINAL_PATH\MQL5\Files\History_20250724.csv" >> "C:\TERMINAL_PATH\MQL5\Files\ProcLog_20250724.txt" 2>&1
2025.07.24 20:44:57.124 Reporting EA (GBPJPY.0,M1)      ← ShellExecute returned: 42
2025.07.24 20:45:00.124 Reporting EA (GBPJPY.0,M1)      !! Log file not created: C:\Users\TERMINAL_PATH\MQL5\Files\ProcLog_20250724.txt
2025.07.24 20:45:00.124 Reporting EA (GBPJPY.0,M1)      Report & log generated: C:\Users\TERMINAL_PATH\Files\History_20250724.csv

El registro de expertos que se muestra arriba revela un intento de inicialización del EA de informes, donde el sistema no pudo localizar el ejecutable y el script de Python especificados. Esto sucedió porque las rutas de los archivos se renombraron deliberadamente en el código (por ejemplo, C:\ruta_a\python.exe y C:\ruta_a\reports_processor.py) con fines demostrativos o como marcadores de posición. Como resultado, el EA no pudo ejecutar el script de Python ni generar el registro de salida esperado (ProcLog_20250724.txt). A pesar de esto, el EA confirmó correctamente los permisos de escritura y exportó el historial de operaciones como un archivo CSV.

Esta prueba pone de relieve la importancia de configurar correctamente las rutas de archivo en su EA (apuntando al intérprete de Python y al script de procesamiento reales) para garantizar una generación de informes integral y sin problemas. Siempre verifique dos veces y utilice rutas absolutas válidas que coincidan con la configuración de su sistema local para evitar este tipo de problemas y aprovechar plenamente la funcionalidad de la herramienta de informes.


Conclusión

Esta discusión se centró principalmente en comprender los informes de operaciones, establecer un flujo de trabajo funcional y desarrollar las herramientas necesarias para entregar informes de operaciones personalizados en formato PDF. Las etapas finales del envío del PDF generado por correo electrónico se han reservado para una publicación futura, para no sobrecargar esta presentación. Sin embargo, el proceso de generación de PDF, basado en el archivo CSV exportado, se gestionó con éxito utilizando bibliotecas de Python. En la próxima sesión se presentarán mejoras adicionales, como la inclusión de gráficos y funciones avanzadas de generación de informes.

Ahora que tanto el Asesor Experto como su correspondiente script de Python están completos, estamos en una buena posición para lograr aún más. En resumen, este proyecto resuelve el problema de recibir informes de operaciones programados y personalizables con funciones centradas en la claridad que facilitan la comprensión por parte del usuario. Así como la contabilidad es esencial para cualquier negocio, la presentación periódica de informes es vital en el trading: fomenta la concienciación sobre el rendimiento, la disciplina y el desarrollo psicológico de los traders.


Lecciones clave

Lección Descripción
1. Diseño modular Separar la lógica de exportación a CSV (MQL5) de la generación de informes (Python) facilita el mantenimiento y permite que cada componente evolucione de forma independiente.
2. Manejo robusto de errores La validación de las rutas de archivo, la captura de excepciones en Python y el registro de fallos garantizan que el sistema falle de forma controlada y siga siendo depurable.
3. Integración entre lenguajes La llamada a scripts externos a través de ShellExecute demuestra cómo las plataformas de negociación pueden aprovechar potentes bibliotecas y ecosistemas externos.
4. Programación automatizada El uso de funciones de devolución de llamada con temporizador en MQL5 para activar las exportaciones diarias garantiza que los informes se ejecuten sin intervención manual, lo que mejora la coherencia y la fiabilidad.
5. Registro centralizado El registro de datos en la pestaña Expertos de MetaTrader 5 y en archivos de texto externos proporciona una visibilidad clara de cada paso del flujo de trabajo.
6. Validación del entorno Comprobar la disponibilidad de Python y los scripts durante la inicialización evita sorpresas en tiempo de ejecución y guía a los usuarios a través de los requisitos de configuración.
7. Herramientas de código abierto El uso de bibliotecas gratuitas y ampliamente adoptadas (pandas, FPDF) y API estándar reduce las barreras de entrada y fomenta la colaboración de la comunidad.
8. Parámetros configurables por el usuario Al permitir configurar rutas, horarios y opciones de notificación como parámetros de entrada, el Asesor Experto (EA) se vuelve flexible y adaptable a diversos entornos de negociación.


Archivos adjuntos

Nombre del archivo Versión Descripción
reporting_processor.py
Script de Python que carga un archivo CSV con el historial de operaciones, calcula análisis resumidos (beneficio neto, número de operaciones, símbolo principal), genera un informe en PDF mediante FPDF y, opcionalmente, limpia los informes antiguos.
Reporting EA.mq5 1.0 Asesor experto de MetaTrader 5 que exporta el historial de operaciones de los últimos 30 días a un archivo CSV, ejecuta processor.py, captura su código de salida, comprueba si se ha generado un PDF y envía una notificación push.

Volver al índice

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

Archivos adjuntos |
Reporting_EA.mq5 (15.06 KB)
Desarrollo de asesores expertos autooptimizables en MQL5 (Parte 10): Factorización de matrices Desarrollo de asesores expertos autooptimizables en MQL5 (Parte 10): Factorización de matrices
La factorización es un proceso matemático que se utiliza para obtener información sobre las características de los datos. Cuando aplicamos la factorización a grandes conjuntos de datos de mercado —organizados en filas y columnas—, podemos descubrir patrones y características del mercado. La factorización es una herramienta muy potente, y en este artículo te mostraremos cómo puedes utilizarla en la plataforma MetaTrader 5, mediante la API de MQL5, para obtener una visión más profunda de tus datos de mercado.
Características del Wizard MQL5 que debe conocer (Parte 77): Uso del oscilador Gator y del oscilador de acumulación/distribución Características del Wizard MQL5 que debe conocer (Parte 77): Uso del oscilador Gator y del oscilador de acumulación/distribución
El oscilador Gator de Bill Williams y el oscilador de acumulación/distribución constituyen otro binomio de indicadores que podría utilizarse de forma armoniosa en un asesor experto de MQL5. Utilizamos el oscilador Gator por su capacidad para corroborar fases de tendencia, mientras que el A/D se utiliza para proporcionar confirmación de las tendencias mediante comprobaciones del volumen. Al explorar esta combinación de indicadores, como siempre, utilizamos el Asistente de MQL5 para montar y poner a prueba una estrategia basada en ambos.
Redes neuronales en el trading: Entrenamiento de metaparámetros basado en la heterogeneidad (Componentes principales) Redes neuronales en el trading: Entrenamiento de metaparámetros basado en la heterogeneidad (Componentes principales)
En este artículo analizamos con detalle los algoritmos para implementar los componentes clave del framework HimNet. Demostramos cómo, con un número mínimo de componentes aprendibles, se consigue una alta coherencia y controlabilidad de todo el sistema. La implementación presentada destaca por su compacidad y transparencia, lo que facilita su adaptación a problemas reales del mercado.
Implementación de módulos prácticos de otros lenguajes en MQL5 (Parte 03): Módulo schedule de Python, una versión mejorada del evento OnTimer Implementación de módulos prácticos de otros lenguajes en MQL5 (Parte 03): Módulo schedule de Python, una versión mejorada del evento OnTimer
El módulo schedule de Python ofrece una forma sencilla de programar tareas repetitivas. Aunque MQL5 carece de una funcionalidad equivalente integrada, en este artículo implementaremos una biblioteca similar para facilitar la configuración de eventos temporizados en MetaTrader 5.