De novato a experto: EA de informes — Configuración del flujo de trabajo
Contenido:
- Introducción
- Comprender los informes de operaciones en MQL5
- Implementación
- Pruebas
- Conclusión
- Lecciones clave
- Archivos adjuntos
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 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
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)
- Esta función engloba los pasos principales de la función de generación de informes del EA.
- Calcula la ruta absoluta al directorio MQL5\Files de MetaTrader 5 usando TerminalInfoString.
- 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.
- 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.
- 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.
- 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.
- Haga una pausa de 3 segundos con Sleep(3000) para permitir que el proceso externo de Python finalice.
- Compruebe la existencia del archivo de registro, lea su contenido e imprímalo línea por línea en el registro de Expertos.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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
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. |
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/18882
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.
Desarrollo de asesores expertos autooptimizables en MQL5 (Parte 10): Factorización de matrices
Características del Wizard MQL5 que debe conocer (Parte 77): Uso del oscilador Gator y del oscilador de acumulación/distribución
Redes neuronales en el trading: Entrenamiento de metaparámetros basado en la heterogeneidad (Componentes principales)
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
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso