English Русский 中文 Deutsch 日本語 Português
preview
Todo lo que necesita saber sobre la estructura de un programa MQL5

Todo lo que necesita saber sobre la estructura de un programa MQL5

MetaTrader 5Trading | 15 enero 2024, 09:47
411 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Introducción

Cualquier programa en un lenguaje de programación tiene una estructura. Una vez que la dominemos podremos crear y mejorar libremente nuestros propios programas. Los programas MQL5 también tienen su propia estructura y el desarrollador deberá comprenderla para alcanzar los objetivos de su proyecto de forma fluida y eficiente. Hoy analizaremos la estructura de un programa desarrollado en MQL5, abarcando los siguientes temas:

Después de leer el presente artículo, comprenderá muy bien la estructura de los programas MQL5 y podrá crear o desarrollar cualquier software basado en esta estructura de forma fluida y eficiente.

¡Atención! Toda la información del presente artículo se ofrece «tal cual», únicamente con fines ilustrativos, y no supone ningún tipo de recomendación. El artículo no garantiza ningún resultado en absoluto. Todo lo que ponga en práctica usando este artículo como base, lo hará bajo su propia cuenta y riesgo; el autor no garantiza resultado alguno.


Preprocesador

En esta parte, estudiaremos con detalle el preprocesador como concepto de programación. El preprocesador (preparación previa) supone un paso importante en el proceso de compilación. Entra en juego antes de que el programa sea realmente compilado. Durante la fase de preprocesamiento, se realizan diversas acciones, como la inclusión de archivos, la definición de propiedades del software, la definición de constantes y la importación de funciones.

Todas las directivas del preprocesador comienzan con (#). Dichas directivas no se consideran declaraciones lingüísticas. Es decir, no deberán terminar en punto y coma (;). Incluir un punto y coma al final de una directiva de preprocesador puede provocar errores dependiendo del tipo de directiva.

En otras palabras, podemos afirmar que un preprocesador está diseñado para preparar el código fuente de un programa antes del proceso de compilación. Existen muchos tipos de directivas de preprocesador según los parámetros que debamos definir en un programa MQL5, por ejemplo:

  • Macrosustitución (#define)
  • Propiedades del programa (#property)
  • Inclusión de archivos (#include)
  • Importación de funciones (#import)
  • Compilación condicional (#ifdef, #ifndef, #else, #endif)

Macrosustitución (#define):

La directiva de preprocesador #define se puede usar para crear constantes simbólicas o para definir constantes que se utilizarán en un programa. Una constante es un identificador cuyo valor no cambia. La directiva #define se puede utilizar para asignar nombres mnemotécnicos a constantes, ya que usaremos un valor de sustitución para un identificador específico. El primer formato de esta directiva de preprocesador será igual al siguiente:

#define identifier replacement-value

Entonces, en nuestro programa habrá una línea de código que significará que antes de compilar el programa, el identificador será reemplazado por un valor de sustitución. Este formato supone una directiva #define sin parámetros, o un formato sin parámetros. Hay otro formato en MQL5, el formato paramétrico con un máximo de ocho parámetros que se pueden usar con la directiva #define, como se muestra a continuación:

#define identifier (param1, param2,... param5)

Las mismas reglas de variables rigen los identificadores constantes:

  • El valor puede ser de cualquier tipo, como entero, doble o string.
  • Una expresión puede constar de varios tokens. Termina cuando finaliza la línea y no se puede llevar a la siguiente línea de código.

A continuación le mostramos un ejemplo:

//Parameter-free format
#define INTEGER               10                                     //int
#define DOUBLE                10.50                                  //double
#define STRING_VALUE      "MetaQuotes Software Corp."                //str
#define INCOMPLETE_VALUE INTEGER+DOUBLE                              //Incomlete
#define COMPLETE_VALUE (INTEGER+DOUBLE)                              //complete
//Parametic format
#define A 2+3
#define B 5-1
#define MUL(a, b) ((a)*(b))
double c=MUL(A,B);
//function to print values
void defValues()
  {

   Print("INTEGER Value, ",INTEGER);         //result: INTEGER Value, 10
   Print("DOUBLE Value, ",DOUBLE);           //result: DOUBLE Value, 10.50
   Print("STRING Value, ",STRING_VALUE);     //result: STRING Value, MetaQuotes Software Corp.
   Print("INCOMPLETE Value, ",INCOMPLETE_VALUE*2);     //result: INCOMPLETE Value, 31
   Print("COMPLETE Value, ",COMPLETE_VALUE*2);     //result: STRING Value, 41
   Print("c= ",c);                                  //result: c= 41
  }

También existe una directiva de preprocesador (#undef) que anula lo que se ha declarado o definido previamente.

Propiedades del programa (#property):

Al crear un programa, es posible que necesitemos especificar algunos parámetros adicionales. Podemos hacer esto usando #property. Las propiedades deben especificarse en el archivo principal MQL5, no en el archivo de inclusión, mientras que las especificadas en los archivos de inclusión se ignorarán. Por tanto, la directiva #property especificará propiedades adicionales para el programa. Si se pregunta qué necesitamos especificar en este contexto, le responderé que tenemos muchas cosas, como por ejemplo indicadores, scripts, información descriptiva y propiedades de la biblioteca. Al igual que otras directivas de preprocesador, #property aparecerá en la parte superior del código fuente y se representará en la pestaña general de la ventana del programa cuando se ejecute.

A continuación le mostramos un ejemplo de una directiva de preprocesador de este tipo:

#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property description "Property preprocessor"

Podemos ver estos valores en la ventana del programa:

property

Como vemos en la figura anterior, tenemos ciertas propiedades que necesitamos en la pestaña general al iniciar el asesor. Texto Copyright 2023, MetaQuotes Ltd. - este es un hipervínculo. Cuando pasamos el cursor sobre él, vemos a dónde conduce (la propiedad link).

Inclusión de archivos (#include):

Como es habitual, todas las directivas #include se colocan al inicio del programa. Estas indican un archivo que debe incluirse en un programa para utilizar su contenido, por ejemplo variables, funciones y clases.

Existen dos formatos de inclusión de archivos usando la directiva #include:

#include <File_Name.mqh>
#include "File_Name.mqh"

La diferencia entre estos dos formatos es lugar donde el compilador debe buscar el archivo de inclusión: el primero le permite al compilador buscar un archivo en la carpeta Include de la instalación de MetaTrader 5 o en el archivo de encabezado de la biblioteca estándar, mientras que el segundo formato le permite al compilador buscar un archivo en el mismo directorio que el archivo del programa.

Importación de funciones (#import):

La directiva #import se usa para importar funciones al programa desde módulos MQL5 compilados (archivos *.ex5) y desde módulos del sistema operativo (archivos *.dll). La función deberá estar completamente descrita y su formato tendrá que ser igual al siguiente:

#import "File_Name"
    func1 define;
    func2 define;
    ...
    funcN define;
#import

Compilación condicional (#ifdef, #ifndef, #else, #endif):

La compilación condicional nos permite controlar la ejecución de directivas de preprocesamiento además de la compilación del programa. Esto nos permite controlar la compilación u omitir parte del código del programa según una determinada condición, que puede estar en uno de los siguientes formatos:

#ifdef identifier
   //If the identifier has been defined, the code here will be compiled.
#endif
#ifndef identifier
   // If the identifier is not defined, the code here will be compiled.
#endif

Como ya hemos dicho, si pasamos a una nueva línea, las directivas del preprocesador no continuarán, pero en este caso, a una directiva de este tipo le pueden seguir cualquier número de líneas usando #else y #endif. Si es true, las líneas entre #else y #endif se ignorarán, pero si no se cumple la condición, las líneas entre la comprobación y #else (o #endif si falta la primera) se ignorarán.

Podrá obtener más información sobre el preprocesador en MQL5 en la documentación.


Variables de entrada y globales

En esta parte, identificaremos otros componentes de la estructura del programa MQL5 tras las directivas del preprocesador, que son las variables globales y de entrada. Comenzaremos con las variables de entrada, que definen una variable externa. Después de escribir el modificador de entrada, especificaremos el tipo de datos. Entonces tendremos un modificador de entrada y el valor de la variable de entrada. El modificador de entrada no se puede cambiar dentro del programa MQL5, y los valores solo pueden ser modificados por el usuario del programa desde la ventana "Parámetros de entrada" o la pestaña de propiedades del programa. Cuando definimos estas variables externas con un modificador de entrada, siempre se inicializan nuevamente antes de llamar a OnInIt().

A continuación le mostramos el formato de las variables de entrada:

input int            MA_Period=20;
input int            MA_Shift=0;
input ENUM_MA_METHOD MA_Method=MODE_SMA;

Después de ello podemos encontrar la ventana de entrada definida por el usuario:

inputs

Como vemos, es posible establecer el periodo, el desplazamiento y el tipo de media móvil. También podemos definir cómo se verán los parámetros de entrada en la pestaña "Parámetros de entrada" colocando un comentario con lo que queremos ver en la ventana, como se muestra a continuación para el mismo ejemplo anterior:

input int            MA_Period=20;        //Moving Average Period 
input int            MA_Shift=0;          //Moving Average Shift
input ENUM_MA_METHOD MA_Method=MODE_SMA;  //Moving Average Type

En la pestaña "Parámetros de entrada" podemos encontrar los siguientes parámetros:

inputs1

Como vemos, los parámetros tienen un aspecto diferente al de la figura anterior. Podrá obtener más información sobre las variables de entrada en MQL5 en la documentación.

Las variables globales deberán crearse fuera de los manejadores de eventos o crear funciones en el mismo nivel de función:

int Globalvar;   // Global variable before or outside the event handler and functions
int OnInit()
  {
   ...
  }

Entonces, podemos decir que el alcance de las variables globales abarca todo el programa y estas son accesibles desde todas las funciones del mismo; se inicializan una vez cuando se carga el programa y antes de procesar el evento OnInit o el evento OnStart(). Hablaremos de los manejadores de eventos más adelante. Aquí solo los menciono para presentar la posición de las variables globales en la estructura de un programa MQL5.

Podrá obtener más información sobre las variables globales en MQL5 en la documentación.


Funciones, clases

En esta parte hablaremos de otros componentes de la estructura del programa MQL5: las funciones y las clases. Las funciones se describen detalladamente en uno de mis artículos anteriores: "Funciones en las aplicaciones MQL5". También le recomiendo leer el artículo sobre las clases en el contexto de la programación orientada a objetos (POO) en MQL5: "Programación orientada a objetos (OOP) en MQL5". Espero que le resulten de utilidad.

Aquí mencionaremos la posición de este importante componente en cualquier programa, ya que podemos definirlos en cualquier parte del programa, incluso en los archivos de inclusión, que se pueden incluir usando la directiva #include. Podemos colocarlos antes o después de los manejadores de eventos, así como después de las variables globales y de entrada.

El formato de las funciones será el siguiente:

returnedDataType functionName(param1, param2)
{
        bodyOfFunction
}

El formato de las clases será el siguiente:

class Cobject
{
   int var1;       // variable1
   double var2;    // variable1
   void method1(); // Method or function1
};

Podrá obtener más información sobre funciones y clases en MQL5 en la documentación.


Manejadores de eventos

En esta sección veremos los manejadores de eventos, que son componentes muy importantes de los programas MQL5. Un manejador de eventos es una función ejecutable. Cuando ocurre un determinado evento, como una nueva cotización de precio, que representa un nuevo evento de tick, el manejador de eventos OnTick() se vuelve ejecutable porque posee un cuerpo de código que se puede ejecutar al obtener un nuevo precio o tick.

Dependiendo del tipo de programa, existen diferentes manejadores de eventos:

Manejador de eventos Descripción Formato 
OnStart Se puede utilizar en programas de tipo script para llamar a una función cuando ocurre un evento desencadenante.
  • Versión con valor retornado: 
int  OnStart(void);
  • Versión sin valor retornado:
void  OnStart(void);
OnInit Se puede utilizar en programas de asesores e indicadores para llamar a una función cuando se inicializa un programa.
  •  Versión con valor retornado:
int  OnInit(void);
  • Versión sin valor retornado:
void  OnInit(void);

OnDeinit Se puede utilizar en programas de asesores e indicadores para llamar a una función cuando se desinicializa un programa.
void  OnDeinit(
   const int  reason         // deinitialization reason code
   );
OnTick Se puede utilizar en asesores e indicadores para llamar a una función cuando se reciben nuevas cotizaciones.
void  OnTick(void);
OnCalculate Se puede utilizar en indicadores para llamar a una función cuando se envía el evento Init y siempre que cambien los datos de precio.
  • Cálculos basados ​​en el array de datos.
int  OnCalculate(
   const int        rates_total,       // price[] array size
   const int        prev_calculated,   // number of handled bars at the previous call
   const int        begin,             // index number in the price[] array meaningful data starts from
   const double&    price[]            // array of values for calculation
   );
  • Cálculos basados ​​en la serie temporal del periodo actual.
int  OnCalculate(
   const int        rates_total,       // size of input time series
   const int        prev_calculated,   // number of handled bars at the previous call
   const datetime&  time{},            // Time array
   const double&    open[],            // Open array
   const double&    high[],            // High array
   const double&    low[],             // Low array
   const double&    close[],           // Close array
   const long&      tick_volume[],     // Tick Volume array
   const long&      volume[],          // Real Volume array
   const int&       spread[]           // Spread array
   );
OnTimer Se puede utilizar en asesores e indicadores para llamar a una función cuando ocurre un evento de temporizador.
void  OnTimer(void);
OnTrade Se puede utilizar en asesores para llamar a una función al completar una transacción comercial en el servidor comercial.
void  OnTrade(void);
OnTradeTransaction Se puede utilizar en asesores para llamar a una función al realizar determinadas acciones en una cuenta comercial.
void  OnTradeTransaction()
   const MqlTradeTransaction&    trans,     // trade transaction structure
   const MqlTradeRequest&        request,   // request structure
   const MqlTradeResult&         result     // response structure
   );
OnBookEvent Se puede utilizar en asesores para llamar a una función cuando cambia la profundidad de mercado.
void  OnBookEvent(
   const string&  symbol         // symbol
   );
OnChartEvent Se puede utilizar en indicadores para llamar a una función cuando el usuario está trabajando con un gráfico.
void  OnChartEvent()
   const int       id,       // event ID 
   const long&     lparam,   // long type event parameter
   const double&   dparam,   // double type event parameter
   const string&   sparam    // string type event parameter
   );
OnTester Se puede utilizar en asesores para llamar a una función después de probar el asesor con datos históricos.
double  OnTester(void);
OnTesterInit Se puede utilizar en asesores para llamar a una función con el inicio de la optimización en el simulador de estrategias antes de la primera pasada de optimización.
  • Versión con valor retornado
int  OnTesterInit(void);
  • Versión sin valor retornado
void  OnTesterInit(void);
OnTesterDeinit Se puede utilizar para llamar a una función después de que se complete la optimización del asesor en el simulador de estrategias.
void  OnTesterDeinit(void);
OnTesterPass Se puede utilizar en asesores para llamar a una función cuando se obtienen nuevos datos.
void  OnTesterPass(void);

Podrá obtener más información sobre el procesamiento de eventos en la documentación de MQL5.


Ejemplo de programa en MQL5

En esta sección, aplicaremos lo que hemos aprendido para crear una aplicación sencilla usando la estructura MQL5 correcta. Hemos mencionado que podemos utilizar componentes de la estructura MQL5 según el tipo de programa y la tarea requerida. No estamos obligados a utilizar algunos de estos componentes, como el preprocesador #include, ya que puede no ser necesario incluir ningún componente externo. Lo mismo ocurre con #property. También es posible que no sea necesario crear clases o funciones personalizadas en el programa. En cualquier caso, el lector utilizará lo necesario para su programa. A continuación le mostramos ejemplos sencillos de la aplicación de todos los componentes estructurales necesarios basados ​​en diferentes tipos de programas.

Script:

A continuación le mostramos un ejemplo simple de un programa-script en MQL5 que es capaz de calcular y sumar dos números ingresados ​​por el usuario con la ayuda de la introducción de datos, e imprimiremos el resultado en la pestaña Expertos usando la función Print. Luego añadiremos la propiedad #property, que nos permitirá mostrar los datos de entrada del script para que el usuario ingrese números.

//+------------------------------------------------------------------+
//|                                       Script program example.mq5 |
//|                                   Copyright 2023, MetaQuotes Ltd.|
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
//property preprocessor
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property script_show_inputs
//inputs
input int userEntryNum1;
input int userEntryNum2;
//global variable
int result;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
//event handler
void OnStart()
  {
   result=userEntryNum1+userEntryNum2;
   Print("Result: ", result);
  }
//+------------------------------------------------------------------+

Si queremos crear otro asesor o indicador, necesitaremos usar diferentes manejadores de eventos según el tipo de programa. Por ejemplo, un asesor puede realizar una acción al recibir un nuevo tick usando el manejador OnTick().

Ahora que hemos definido la estructura de un programa MQL5, veremos que algunos componentes difieren según el tipo de programa y sus objetivos. Esta comprensión nos ayudará a determinar la posición de cada componente en el programa.

Para aplicar estos conocimientos, podemos comenzar con un programa de script simple, como mencionamos anteriormente.


Conclusión

Hoy hemos analizado la estructura de los programas MQL5, y ahora podemos determinar qué necesitamos como componentes:

  • Preprocesador
    • Macrosustitución (#define)
    • Propiedades del programa (#property)
    • Inclusión de archivos (#include)
    • Importación de funciones (#import)
    • Compilación condicional (#ifdef, #ifndef, #else, #endif)
  • Variables de entrada y globales
  • Funciones y clases
  • Manejadores de eventos
    • OnStart
    • OnInit
    • OnDeinit
    • OnTick
    • OnCalculate
    • OnTimer
    • OnTrade
    • OnTradeTransaction
    • OnBookEvent
    • OnChartEvent
    • OnTester
    • OnTesterInit
    • OnTesterDeinit
    • OnTesterPass

Espero que haya encontrado útil el artículo. Si desea obtener más información sobre la creación de sistemas comerciales usando indicadores técnicos populares, puede consultar mis otros artículos.

Además, he escrito sobre la creación y el uso de indicadores personalizados en cualquier asesor experto y otros temas importantes de programación MQL5, como la programación orientada a objetos (POO) y las funciones. Creo que estos artículos le serán útiles para formarse y comerciar.

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

Archivos adjuntos |
Redes neuronales: así de sencillo (Parte 51): Actor-crítico conductual (BAC) Redes neuronales: así de sencillo (Parte 51): Actor-crítico conductual (BAC)
Los dos últimos artículos han considerado el algoritmo SAC (Soft Actor-Critic), que incorpora la regularización de la entropía en la función de la recompensa. Este enfoque equilibra la exploración del entorno y la explotación del modelo, pero solo es aplicable a modelos estocásticos. El presente material analizará un enfoque alternativo aplicable tanto a modelos estocásticos como deterministas.
Teoría de categorías en MQL5 (Parte 14): Funtores con orden lineal Teoría de categorías en MQL5 (Parte 14): Funtores con orden lineal
Este artículo de la serie sobre la implementación de la teoría de categorías en MQL5 está dedicado a los funtores. Hoy veremos cómo asignar el orden lineal a un conjunto utilizando funtores al analizar dos conjuntos de datos que parecen no tener relación entre sí.
La técnica comercial RSI Deep Three Move La técnica comercial RSI Deep Three Move
El presente artículo muestra la técnica comercial RSI Deep Three Move en MetaTrader 5. El artículo se basa en una nueva serie de estudios que demuestran varias técnicas comerciales basadas en el RSI, así como un indicador técnico para medir la fuerza y el impulso de los valores, incluidas las acciones, las divisas y las materias primas.
Análisis de ciclos usando el algoritmo de Goertzel Análisis de ciclos usando el algoritmo de Goertzel
En el artículo presentamos utilidades que implementan el algoritmo de Goertzel en MQL5 y dos formas de aplicar este método al analizar cotizaciones de precios para el desarrollo de estrategias.