Dominando los registros (Parte 3): Exploración de controladores para guardar registros
Introducción
En el primer artículo de esta serie, Dominando los registros (Parte 1): Conceptos fundamentales y primeros pasos en MQL5, nos embarcamos en la creación de una librería de log adaptada al desarrollo de Asesores Expertos. En él, exploramos la motivación detrás de la creación de una herramienta tan esencial: superar las limitaciones de los registros nativos de MetaTrader 5 y aportar una solución robusta, personalizable y potente al universo MQL5.
Para resumir los puntos principales tratados, sentamos las bases de nuestra librería estableciendo los siguientes requisitos fundamentales:
- Estructura robusta que utiliza el patrón Singleton, lo que garantiza la coherencia entre los componentes del código.
- Persistencia avanzada para almacenar registros en bases de datos, proporcionando un historial rastreable para auditorías y análisis en profundidad.
- Flexibilidad en las salidas, lo que permite almacenar o mostrar los registros de forma cómoda, ya sea en la consola, en archivos, en el terminal o en una base de datos.
- Clasificación por niveles de registro, diferenciando los mensajes informativos de las alertas críticas y los errores.
- Personalización del formato de salida, para satisfacer las necesidades específicas de cada desarrollador o proyecto.
Con esta base bien establecida, quedó claro que el marco de registro que estamos desarrollando será mucho más que un simple registro de eventos; será una herramienta estratégica para comprender, supervisar y optimizar el comportamiento de las EA en tiempo real.
Ahora, en este tercer artículo, daremos un paso crucial: comprender el concepto de controladores. Si los formateadores organizan los datos, los controladores son responsables de decidir dónde irán los registros. Actúan como "fontaneros", dirigiendo los mensajes a los destinos apropiados, ya sean archivos, consolas, bases de datos o incluso sistemas de notificación. En este artículo, comprenderemos la lógica detrás de los controladores, crearemos ejemplos prácticos para aplicarlos en diferentes escenarios y exploraremos su integración con los formateadores. Al final, dispondrá de todas las herramientas necesarias para crear flujos de registros altamente personalizables y eficientes. ¿Empezamos?
¿Qué son los controladores?
Los controladores son componentes fundamentales que definen dónde deben enviarse los mensajes de registro. Piensa en ellos como «distribuidores de mensajes» que reciben información del registrador y la reenvían al destino adecuado, ya sea la consola, un archivo, un correo electrónico o incluso un servidor remoto.
Imagina que eres el director de una fábrica. Los productos (mensajes de registro) deben transportarse a diferentes destinos: algunos van al almacén, otros al departamento de envíos y otros se almacenan como registros históricos. El despachador es quien decide dónde va cada producto, y esta función la desempeñan los controladores.
Cada controlador puede tener ajustes específicos, como niveles de gravedad (por ejemplo, enviar solo mensajes de error), formatos de salida (por ejemplo, incluir marcas de tiempo o no) y destinos.
Estos componentes desempeñan un papel fundamental a la hora de permitir la separación y el enrutamiento inteligente de los mensajes de registro, lo cual es especialmente importante en aplicaciones de tamaño medio a grande. Los controladores permiten funciones como ayudar a los desarrolladores a depurar errores en tiempo real en la consola, almacenar registros detallados para su análisis futuro, enviar alertas críticas por correo electrónico cuando ocurre algo urgente o reenviar información de supervisión a un servidor central. Todo esto se puede lograr simultáneamente sin necesidad de configuraciones complejas.
Cómo funcionan los controladores
Para comprender cómo funcionan los controladores en la práctica, veamos un ejemplo en la librería. Vea el siguiente diagrama, que muestra el flujo básico del registro de mensajes:

En el flujo actual, la función principal de la clase CLogify es el método Append, que se encarga de recibir los datos de registro, incluyendo el nivel de gravedad, el mensaje, la fuente y la hora de la entrada del registro. Con estos datos, el método Append crea una variable del tipo MqlLogifyModel, que se envía a la consola del terminal mediante la función nativa Print.
Este flujo es funcional, pero tiene limitaciones: todos los registros solo se pueden mostrar en la consola y no hay flexibilidad para gestionar o almacenar estos mensajes en otro lugar.
Ahora, con la implementación de Handlers, el flujo ha mejorado significativamente. Echa un vistazo al nuevo diagrama:

En el nuevo flujo:
- El método Append sigue recibiendo la información del registro (gravedad, mensaje, origen, hora, etc.).
- Crea la misma variable MqlLogifyModel para almacenar los datos.
- En lugar de enviarlo directamente a la consola, el registro ahora se pasa a una lista de controladores representados por una matriz de controladores.
Cada controlador puede procesar los datos de forma independiente, lo que permite que los mensajes de registro se envíen a múltiples destinos.
A continuación se muestran tres ejemplos básicos de controladores que se pueden utilizar en este sistema:
- HandlerTerminal: Muestra los datos de registro directamente en el terminal MetaTrader 5, lo que resulta útil para el diagnóstico y la depuración en tiempo real.
- HandlerFile: Guarda los registros en un archivo con formato .txt o .log, ideal para almacenar historiales de ejecución o crear informes detallados para su análisis futuro.
- HandlerDatabase: Almacena registros en una base de datos, como SQLite, lo que permite realizar consultas de datos avanzadas, incluyendo análisis de tendencias o auditorías más complejas.
Te daré un ejemplo práctico de la utilidad de los controladores. Imagina que has desarrollado un robot de trading que necesita un sistema de registro eficiente para supervisar su ejecución. Puede configurar los controladores de la siguiente manera:
- Guarde solo los mensajes DEBUG e INFO en un archivo para registrar todas las operaciones realizadas, incluidas las entradas y salidas del mercado.
- Muestra los registros en el terminal con mensajes WARN y ERROR, lo que te permite realizar un seguimiento de los problemas en tiempo real.
- Guarde los errores críticos en la base de datos, asegurándose de que los ingenieros o analistas puedan recuperar y analizar la información relevante más adelante.
Esta estructura garantiza un sistema de registro más robusto, organizado y eficiente. Con los controladores, tienes control total sobre cómo y dónde se procesan y almacenan los registros.
Implementación de la clase base CLogifyHandler
Implementemos una clase base, llamada CLogifyHandler, que será la base común (clase padre) para todos los controladores creados posteriormente. Empezamos creando una carpeta llamada Handlers en el directorio raíz de la librería. Dentro de esta nueva carpeta, crea un archivo llamado LogifyHandler. En el archivo creado, se definirá la clase CLogifyHandler, que inicialmente solo tendrá un constructor y un destructor básicos. El código inicial tendrá este aspecto:
//+------------------------------------------------------------------+ //| LogifyHandler.mqh | //| joaopedrodev | //| https://www.mql5.com/en/users/joaopedrodev | //+------------------------------------------------------------------+ #property copyright "joaopedrodev" #property link "https://www.mql5.com/en/users/joaopedrodev" //+------------------------------------------------------------------+ //| class : CLogifyHandler | //| | //| [PROPERTY] | //| Name : CLogifyHandler | //| Heritage : No heritage | //| Description : Base class for all log handlers. | //| | //+------------------------------------------------------------------+ class CLogifyHandler { public: CLogifyHandler(void); ~CLogifyHandler(void); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CLogifyHandler::CLogifyHandler(void) { } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CLogifyHandler::~CLogifyHandler(void) { } //+------------------------------------------------------------------+
En este punto, la clase CLogifyHandler sirve como un «esqueleto» que se ampliará para incluir más funcionalidades.
Ahora añadamos las importaciones necesarias, empezando por el archivo LogifyModel.mqh, que define el modelo de registro que utilizarán los controladores.
//+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "../LogifyModel.mqh"
Este archivo contiene la definición de la clase o estructura MqlLogifyModel, que se utiliza para encapsular los datos de cada mensaje de registro, como el nivel de gravedad, el mensaje y el origen.
El siguiente paso es añadir dos atributos protegidos a la clase:
- m_name: Almacena el nombre del controlador, lo que puede resultar útil para su identificación durante la depuración o la generación de informes.
- m_level: Define el nivel de gravedad que procesará el controlador (por ejemplo, DEBUG, INFO, ERROR).
Además, crearemos métodos públicos para establecer y recuperar estos valores.
class CLogifyHandler { protected: string m_name; ENUM_LOG_LEVEL m_level; public: //--- Set/Get void SetLevel(ENUM_LOG_LEVEL level); string GetName(void); ENUM_LOG_LEVEL GetLevel(void); }; //+------------------------------------------------------------------+ //| Set level | //+------------------------------------------------------------------+ void CLogifyHandler::SetLevel(ENUM_LOG_LEVEL level) { m_level = level; } //+------------------------------------------------------------------+ //| Get name | //+------------------------------------------------------------------+ string CLogifyHandler::GetName(void) { return(m_name); } //+------------------------------------------------------------------+ //| Get level | //+------------------------------------------------------------------+ ENUM_LOG_LEVEL CLogifyHandler::GetLevel(void) { return(m_level); } //+------------------------------------------------------------------+
El atributo m_name solo se puede establecer en clases derivadas a través de sus constructores, lo que garantiza la seguridad y la encapsulación. Por eso no existe el método SetName.
Hay tres métodos básicos que todos los controladores deben implementar:
- Emit(MqlLogifyModel &data): Procesa un mensaje de registro y lo envía al destino especificado (archivo, consola, base de datos, etc.).
- Flush(): Finaliza o borra cualquier operación pendiente.
- Close(): Cierra el controlador y libera cualquier recurso asociado.
Por el momento, estas funciones se definirán como virtuales, con implementaciones predeterminadas vacías. Esto permitirá que cada clase hija personalice el comportamiento según sea necesario.
class CLogifyHandler { public: //--- Handler methods virtual void Emit(MqlLogifyModel &data); // Processes a log message and sends it to the specified destination virtual void Flush(void); // Clears or completes any pending operations virtual void Close(void); // Closes the handler and releases any resources }; //+------------------------------------------------------------------+ //| Processes a log message and sends it to the specified destination| //+------------------------------------------------------------------+ void CLogifyHandler::Emit(MqlLogifyModel &data) { } //+------------------------------------------------------------------+ //| Clears or completes any pending operations | //+------------------------------------------------------------------+ void CLogifyHandler::Flush(void) { } //+------------------------------------------------------------------+ //| Closes the handler and releases any resources | //+------------------------------------------------------------------+ void CLogifyHandler::Close(void) { } //+------------------------------------------------------------------+
En esta etapa, los métodos no hacen nada, ya que corresponde a las clases hijas (como HandlerFile, HandlerDatabase, etc.) implementar el comportamiento específico de cada controlador.
Implementación de los controladores
Una vez implementada la clase base CLogifyHandler, podemos empezar a crear controladores especializados que hereden de ella. Este enfoque sigue los principios fundamentales de la programación orientada a objetos, como la herencia y el polimorfismo, lo que permite modularidad y flexibilidad en el código. Cada controlador especializado será responsable de gestionar los registros de una manera específica, aprovechando la estructura común de la clase base, pero implementando su propia lógica particular para los métodos Emit, Flush y Close.
Antes de implementar los controladores, organicemos mejor nuestro proyecto. Cree tres nuevos archivos dentro de la carpeta Handlers: LogifyHandlerConsole.mqh, LogifyHandlerDatabase.mqh y LogifyHandlerFile.mqh. La estructura final tendrá el siguiente aspecto:

En el archivo LogifyHandlerConsole.mqh, crearemos la clase CLogifyHandlerConsole, que hereda los atributos y métodos de la clase base CLogifyHandler. Una de las primeras modificaciones será el valor de la variable m_name, establecida en «console» en el constructor de la clase. Esto ayudará a identificar claramente al controlador en tiempo de ejecución. Esta es la definición inicial de la clase:
//+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "LogifyHandler.mqh" //+------------------------------------------------------------------+ //| class : CLogifyHandlerConsole | //| | //| [PROPERTY] | //| Name : CLogifyHandlerConsole | //| Heritage : CLogifyHandler | //| Description : Log handler, inserts data into terminal window. | //| | //+------------------------------------------------------------------+ class CLogifyHandlerConsole : public CLogifyHandler { public: CLogifyHandlerConsole(void); ~CLogifyHandlerConsole(void); virtual void Emit(MqlLogifyModel &data); // Processes a log message and sends it to the specified destination virtual void Flush(void); // Clears or completes any pending operations virtual void Close(void); // Closes the handler and releases any resources }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CLogifyHandlerConsole::CLogifyHandlerConsole(void) { m_name = "console"; } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CLogifyHandlerConsole::~CLogifyHandlerConsole(void) { } //+------------------------------------------------------------------+
La función Emit es la principal responsable de procesar un mensaje de registro y enviarlo al destino adecuado. En el caso de la consola, esto simplemente significa mostrar el mensaje formateado en la terminal MetaTrader. Aquí está la implementación del método:
//+------------------------------------------------------------------+ //| Processes a log message and sends it to the specified destination| //+------------------------------------------------------------------+ void CLogifyHandlerConsole::Emit(MqlLogifyModel &data) { if(data.level >= this.GetLevel()) { Print("Console handler: ",data.formated); } } //+------------------------------------------------------------------+
Tenga en cuenta que antes de mostrar el mensaje, comprobamos si el nivel de registro ( data.level ) coincide con el nivel configurado en el controlador. Esto garantiza que solo se muestren los mensajes importantes o relevantes.
Siguiendo el mismo principio que el controlador de consola, podemos crear otros controladores especializados, como los destinados a bases de datos y archivos. Los archivos que hay que cambiar son LogifyHandlerDatabase.mqh y LogifyHandlerFile.mqh. Aunque estos controladores pueden compartir la misma lógica básica, sus implementaciones específicas de Emit pueden variar.
Este controlador está diseñado para almacenar los registros en una base de datos, aunque por ahora mostraremos un mensaje en la consola con fines demostrativos. El código para la función Emit sería:
//+------------------------------------------------------------------+ //| Processes a log message and sends it to the specified destination| //+------------------------------------------------------------------+ void CLogifyHandlerDatabase::Emit(MqlLogifyModel &data) { if(data.level >= this.GetLevel()) { Print("Database handler: ",data.formated); } } //+------------------------------------------------------------------+
El controlador LogifyHandlerFile se utilizará para escribir registros en un archivo específico. Aquí hay una implementación inicial para Emit:
//+------------------------------------------------------------------+ //| Processes a log message and sends it to the specified destination| //+------------------------------------------------------------------+ void CLogifyHandlerFile::Emit(MqlLogifyModel &data) { if(data.level >= this.GetLevel()) { Print("File handler: ",data.formated); } } //+------------------------------------------------------------------+
Aunque hemos definido los métodos Flush y Close en la clase base, no todos los controladores necesitarán implementarlos inmediatamente.
- El método Flush puede resultar útil en controladores más complejos, como operaciones de escritura de archivos o streaming en tiempo real.
- El método Close será esencial para liberar recursos, como conexiones a bases de datos, o cerrar flujos de escritura.
En el caso del controlador de consola, estos métodos se dejan vacíos, ya que no hay operaciones adicionales que realizar. Recuerda que solo estoy mostrando fragmentos de código; la versión completa está disponible para descargar al final del artículo.
Añadir controladores a la clase CLogify
Ahora que hemos implementado los controladores y funcionan de forma aislada, es el momento de integrarlos en la clase principal de la librería, llamada CLogify. Para ello, comenzamos importando la clase base CLogifyHandler, que contiene la estructura necesaria para todos los controladores:
#include "Handlers/LogifyHandler.mqh" #include "Handlers/LogifyHandlerConsole.mqh" #include "Handlers/LogifyHandlerDatabase.mqh" #include "Handlers/LogifyHandlerFile.mqh"
En la implementación de la clase CLogify, añadiremos un atributo privado para almacenar los controladores que se utilizarán. Elegí una matriz de punteros del tipo CLogifyHandler, ya que los controladores se gestionarán dinámicamente.
Además, la clase contará con métodos específicos para gestionar los controladores:
- AddHandler: Añade un nuevo controlador a la matriz.
- HasHandler: Comprueba si ya existe un controlador específico en la lista, utilizando su nombre como criterio.
- GetHandler: Obtiene un controlador, ya sea por nombre o por índice en la matriz.
- SizeHandlers: Devuelve el número total de controladores de la lista.
Aquí está el código actualizado para la clase CLogify, ahora con estos métodos:
class CLogify { private: CLogifyHandler *m_handlers[]; public: //--- Handler void AddHandler(CLogifyHandler *handler); bool HasHandler(string name); CLogifyHandler *GetHandler(string name); CLogifyHandler *GetHandler(int index); int SizeHandlers(void); }; //+------------------------------------------------------------------+ //| Add handler to handlers array | //+------------------------------------------------------------------+ void CLogify::AddHandler(CLogifyHandler *handler) { int size = ArraySize(m_handlers); ArrayResize(m_handlers,size+1); m_handlers[size] = GetPointer(handler); } //+------------------------------------------------------------------+ //| Checks if handler is already in the array by name | //+------------------------------------------------------------------+ bool CLogify::HasHandler(string name) { int size = ArraySize(m_handlers); for(int i=0;i<size;i++) { if(m_handlers[i].GetName() == name) { return(true); } } return(false); } //+------------------------------------------------------------------+ //| Get handler by name | //+------------------------------------------------------------------+ CLogifyHandler *CLogify::GetHandler(string name) { int size = ArraySize(m_handlers); for(int i=0;i<size;i++) { if(m_handlers[i].GetName() == name) { return(m_handlers[i]); } } return(NULL); } //+------------------------------------------------------------------+ //| Get handler by index | //+------------------------------------------------------------------+ CLogifyHandler *CLogify::GetHandler(int index) { return(m_handlers[index]); } //+------------------------------------------------------------------+ //| Gets the total size of the handlers array | //+------------------------------------------------------------------+ int CLogify::SizeHandlers(void) { return(ArraySize(m_handlers)); } //+------------------------------------------------------------------+
Con los métodos de gestión de controladores listos, ajustemos el funcionamiento de la función Append para que utilice los controladores al procesar los registros.
El método Append ahora iterará a través de todos los controladores disponibles en la matriz y llamará al método Emit de cada uno de ellos para que el registro se envíe al destino correspondiente (como la consola, la base de datos, etc.).
Aquí está el código actualizado para el método Append:
//+------------------------------------------------------------------+ //| Generic method for adding logs | //+------------------------------------------------------------------+ bool CLogify::Append(ENUM_LOG_LEVEL level,string msg, string origin = "", string args = "",string filename="",string function="",int line=0) { //--- If the formatter is not configured, the log will not be recorded. if(m_formatter == NULL) { return(false); } //--- Textual name of the log level string levelStr = ""; switch(level) { case LOG_LEVEL_DEBUG: levelStr = "DEBUG"; break; case LOG_LEVEL_INFOR: levelStr = "INFOR"; break; case LOG_LEVEL_ALERT: levelStr = "ALERT"; break; case LOG_LEVEL_ERROR: levelStr = "ERROR"; break; case LOG_LEVEL_FATAL: levelStr = "FATAL"; break; } //--- Creating a log template with detailed information datetime time_current = TimeCurrent(); MqlLogifyModel data("",levelStr,msg,args,time_current,time_current,level,origin,filename,function,line); data.formated = m_formatter.FormatLog(data); //--- Call handlers int size = this.SizeHandlers(); for(int i=0;i<size;i++) { m_handlers[i].Emit(data); } return(true); } //+------------------------------------------------------------------+
Algunas observaciones:
- El registro formateado se almacena en data.formatted, lo que garantiza que toda la información esté disponible para todos los controladores.
- Cada controlador procesa el registro de forma independiente, llamando a su método Emit.
El último ajuste que haré será eliminar los punteros de matriz en el destructor de la clase:
//+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CLogify::~CLogify() { //--- Delete formatter if(m_formatter != NULL) { delete m_formatter; } //--- Delete handlers int size_handlers = ArraySize(m_handlers); for(int i=0;i<size_handlers;i++) { delete m_handlers[i]; } } //+------------------------------------------------------------------+
Probando los controladores
En este ejemplo, utilizaremos el archivo de prueba mencionado anteriormente, llamado LogifyTest.mq5. Nuestro objetivo será demostrar cómo configurar y utilizar dos gestores de registros, cada uno con un nivel de registro diferente, y cómo se registrarán estos registros en función de los filtros configurados.
En primer lugar, creamos dos controladores, que se encargan de registrar los registros en diferentes lugares y niveles:
- Consola: Será una instancia de CLogifyHandlerConsole y se configurará para registrar mensajes de nivel DEBUG, es decir, todos los mensajes, desde los más detallados hasta los errores críticos.
- Archivo: Será una instancia de CLogifyHandlerFile y se configurará para capturar solo mensajes del nivel INFO, filtrando los mensajes DEBUG.
Aquí está el código para configurar estos controladores:
int OnInit() { //--- Console CLogifyHandler *handler_console = new CLogifyHandlerConsole(); handler_console.SetLevel(LOG_LEVEL_DEBUG); //--- File CLogifyHandler *handler_file = new CLogifyHandlerFile(); handler_file.SetLevel(LOG_LEVEL_INFOR); return(INIT_SUCCEEDED); }
Después de configurar los controladores, el siguiente paso es añadirlos a nuestra clase base CLogify, que se encarga de gestionar todos los registros de la aplicación.
Además, añadiremos un formateador para definir cómo se mostrarán los registros. El formateador de este ejemplo formateará los registros con el patrón: «hour:minute:second, [log level], message».
Después de configurar los controladores y el formateador, emitiremos tres mensajes de registro con diferentes niveles. A continuación se muestra el código completo para este paso:
int OnInit() { //--- Console CLogifyHandler *handler_console = new CLogifyHandlerConsole(); handler_console.SetLevel(LOG_LEVEL_DEBUG); //--- File CLogifyHandler *handler_file = new CLogifyHandlerFile(); handler_file.SetLevel(LOG_LEVEL_INFOR); //--- Config logify.SetFormatter(new CLogifyFormatter("hh:mm:ss","{date_time} [{levelname}] {msg}")); logify.AddHandler(handler_console); logify.AddHandler(handler_file); //--- Logs logify.Debug("Debug Message"); logify.Infor("Information Message"); logify.Error("Error Message"); return(INIT_SUCCEEDED); }
Cuando ejecutamos el código anterior, obtendremos el siguiente resultado en la consola:
Console handler: 03:20:05 [DEBUG] Debug Message Console handler: 03:20:05 [INFOR] Information Message File handler: 03:20:05 [INFOR] Information Message Console handler: 03:20:05 [ERROR] Error Message File handler: 03:20:05 [ERROR] Error Message
Comprensión del resultado:
- Console handler ( handler_console ): Este controlador capturó todos los mensajes, desde DEBUG hasta ERROR. Por lo tanto, se registraron tres entradas en la consola, una por cada registro emitido.
- File handler ( handler_file ): Este controlador, a su vez, se configuró para registrar solo mensajes de nivel INFO o superior. Por lo tanto, ignoró el registro DEBUG y solo registró los mensajes INFO y ERROR, con un total de dos entradas en el archivo de registro.
Conclusión
A lo largo de este artículo, hemos dado un paso importante en la creación de nuestra librería de registros MQL5. Hemos explorado el concepto de controladores, comprendiendo su papel esencial como «conductores» de mensajes de registro a diferentes destinos. Hemos visto cómo funcionan junto con los formateadores, formando un sistema de gestión de registros cohesionado y modular.
En la práctica, hemos creado la estructura base de los controladores, definiendo una clase abstracta que servirá como base para todas las implementaciones futuras. También hemos desarrollado tres controladores iniciales: Console, Database y File, responsables de dirigir los registros a la consola, una base de datos y archivos, respectivamente. Aunque, por ahora, todas utilizan la función Print() para la simulación, esta sólida base nos permite ampliar y especializar cada clase con una funcionalidad definitiva en futuros artículos.
En las pruebas, hemos validado la integración entre los controladores y nuestra librería, demostrando cómo se pueden añadir y utilizar de forma flexible. Este proceso reveló el potencial de los controladores como componentes modulares que se pueden personalizar para satisfacer diferentes necesidades de registro.
Todo el código utilizado en este artículo se adjunta a continuación. Aquí hay una tabla con la descripción de cada archivo de la librería:
| Nombre del archivo | Descripción |
|---|---|
| Experts/Logify/LogiftTest.mq5 | Archivo donde probamos las funcionalidades de la librería, conteniendo un ejemplo práctico. |
| Include/Logify/Formatter/LogifyFormatter.mqh | Clase responsable de formatear los registros de registro, reemplazando marcadores de posición con valores específicos. |
| Include/Logify/Handlers/LogifyHandler.mqh | Clase base para administrar controladores de registros, incluida la configuración de niveles y el envío de registros. |
| Include/Logify/Handlers/LogifyHandlerConsole.mqh | Controlador de registros que envía registros formateados directamente a la consola del terminal en MetaTrader. |
| Include/Logify/Handlers/LogifyHandlerDatabase.mqh | Controlador de registros que envía registros formateados a una base de datos (actualmente solo contiene una impresión, pero pronto la guardaremos en una base de datos SQLite real) |
| Include/Logify/Handlers/LogifyHandlerFile.mqh | Controlador de registros que envía registros formateados a un archivo (actualmente solo contiene una impresión, pero pronto lo guardaremos en un archivo real) |
| Include/Logify/Logify.mqh | Clase principal para la gestión de registros, integrando niveles, modelos y formato. |
| Include/Logify/LogifyLevel.mqh | Archivo que define los niveles de registro de la librería Logify, lo que permite un control detallado. |
| Include/Logify/LogifyModel.mqh | Estructura que modela los registros de registro, incluidos detalles como el nivel, el mensaje, la marca de tiempo y el contexto. |
Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/16866
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.
Implementación de los cierres parciales en MQL5
Modelos ocultos de Markov para la predicción de la volatilidad siguiendo tendencias
La estrategia comercial de captura de liquidez
Desarrollo de un kit de herramientas para el análisis de la acción del precio (Parte 7): Signal Pulse EA
- 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