English Русский 中文 Deutsch 日本語 Português
preview
Estructuras en MQL5 y métodos para imprimir sus datos

Estructuras en MQL5 y métodos para imprimir sus datos

MetaTrader 5Ejemplos | 10 enero 2024, 04:42
254 0
Artyom Trishkin
Artyom Trishkin

Contenido


Introducción

Las estructuras son una cómoda herramienta para almacenar, registrar y recuperar datos relacionados lógicamente que pertenezcan a cualquier definición de una variable.

El lenguaje MQL5 tiene 12 estructuras predefinidas diseñadas para almacenar y transmitir la información de servicio:

Las estructuras MqlParam y MqlTradeRequest se utilizan para transmitir información técnica para crear indicadores y enviar solicitudes comerciales al servidor. Nosotros mismos completaremos los campos obligatorios de las estructuras según el resultado requerido del envío de datos en la estructura rellenada. Es decir, estas estructuras no necesitan especialmente imprimir los datos con los que el programador ha rellanado los campos de dichas estructuras de forma independiente.
Sin embargo, las estructuras restantes retornarán el resultado de las consultas, mientras que el subsistema del terminal o el servidor comercial completará cada campo. Obtener los datos de estas estructuras, analizar los campos de las estructuras completados de forma programática o imprimirlos en un registro para su posterior análisis manual resulta muy cómodo y necesario tanto para tomar decisiones de forma programática como para comprender y encontrar la ubicación de un error lógico.

Para imprimir todos los campos de una estructura, existe la función estándar ArrayPrint(), que muestra en un cómodo formato tabular los datos contenidos en un array con el tipo de estructura procesada. Pero a veces necesitamos imprimir los datos de la estructura en otro formato, lo cual puede resultar más cómodo que una representación tabular. Por ejemplo, mostrar todos los campos de la estructura en una línea, con los encabezados y datos correspondientes. Esto puede resultar más cómodo al analizar grandes cantidades de datos. Al mismo tiempo, a veces necesitamos tener una representación más detallada, con una descripción de los campos de la estructura y una representación diferente de los datos correspondientes.

Hoy analizaremos algunas herramientas estándar para ver datos de las estructuras y crearemos funciones personalizadas para mostrar los datos de las estructuras en el registro de formas distintas.


Estructura MqlDateTime

La estructura de fechas contiene ocho campos int.

struct MqlDateTime
  {
   int year;           // year
   int mon;            // month
   int day;            // day
   int hour;           // hour
   int min;            // minutes
   int sec;            // seconds
   int day_of_week;    // day of the week (0-Sunday, 1-Monday, ... ,6-Saturday)
   int day_of_year;    // number of a day in the year (1st of January has number 0)
  };

Para completar los campos de la estructura, utilizaremos las funciones estándar TimeCurrent(), TimeGMT(), TimeLocal(), TimeTradeServer() y TimeToStruct().

Las cuatro primeras funciones, además de retornar la fecha actual, la fecha GMT, la hora local del ordenador y la fecha del servidor comercial, tienen una sobrecarga cada una. En los parámetros formales de la función, podemos transmitir una estructura de fechas por referencia, y después de que se ejecute la función, los campos de la estructura transmitida a la función se rellenarán con los datos de la fecha retornada por la función.

La función TimeToStruct() está diseñada específicamente para rellenar una estructura a partir de un valor de tipo datetime (el número de segundos desde el 01/01/1970) en una variable de tipo estructura MqlDateTime.

bool  TimeToStruct(
   datetime      dt,            // date and time
   MqlDateTime&  dt_struct      // structure for accepting values 
   );

Retorna true en caso de éxito, o false en caso contrario. Una vez que funcione, la estructura de fechas se completará con los datos de fecha y hora transmitidos ​​en el primer parámetro de una variable de tipo datetime.

Bien. Nuestra estructura de fechas está completa, pero ¿cómo podemos imprimirla ahora? Existe una función estándar TimeToString() capaz de convertir un valor que contenga el tiempo en segundos desde el 01/01/1970 en una línea con el formato "yyyy.mm.dd hh:min:sec".

Sin embargo, la función no operará con la estructura MqlDateTime, sino con una fecha datetime. Entonces, ¿deberíamos reconvertir la estructura en un valor de tiempo? Claro que no. Cada una de las funciones tiene sus propios fines. De la estructura de fechas, podemos tomar por separado cualquier componente de la fecha y la hora: el año aparte, el mes aparte, la hora, los minutos, el día de la semana, etc. Pero, ¿cómo podemos mostrar todos los datos de la estructura?
La función ArrayPrint() es muy cómoda para esto; genera un array de un tipo simple o una estructura simple en el registro. Muestra los datos en forma de tabla: las columnas son los campos de la estructura, mientras que las filas son cada celda del array. Es decir, para mostrar la estructura de una sola fecha, necesitaremos un array de dimensión 1. Para una semana comercial, siempre que los datos se obtengan del gráfico D1, el tamaño del array será (normalmente) de 5 días comerciales.


MqlDateTime, métodos de impresión

Este script imprimirá una estructura de fechas obtenida a partir de la hora actual en el registro usando ArrayPrint():

void OnStart()
  {
//--- Declare a date structure variable
   MqlDateTime  time;
//--- Get the current time and at the same time fill in the date structure
   TimeCurrent(time);
//--- Declare an array with the MqlDateTime type and write the data of the filled structure into it

   MqlDateTime array[1];
   array[0]=time;
//--- Display the header and time using the standard ArrayPrint()
   Print("Time current (ArrayPrint):");
   ArrayPrint(array);
   /* Sample output:
      Time current (ArrayPrint):
          [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
      [0]   2023     7    17     12     8    37             1           197
   */
  }

Como consecuencia, una función que tome una estructura de fechas y la imprima en un registro se verá así:

//+------------------------------------------------------------------+
//| Take a date structure and display its data to the journal.       |
//| Use ArrayPrint() for display                                     |
//+------------------------------------------------------------------+
void MqlDateTimePrint(const MqlDateTime& time_struct)
  {
//--- Declare an array with the MqlDateTime type and write the data of the obtained structure into it
   MqlDateTime array[1];
   array[0]=time_struct;
//--- Print the array
   ArrayPrint(array);
   /* Sample output:
      Time current (ArrayPrint):
          [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
      [0]   2023     7    17     12     8    37             1           197
   */
  }

Esta función nos permite imprimir en el registro la fecha que se le ha transmitido en la variable time_struct.

Script que registra una estructura de fechas única utilizando la función presentada anteriormente:

void OnStart()
  {
//--- Declare a date structure variable
   MqlDateTime  time;
//--- Get the current time and at the same time fill in the date structure
   TimeCurrent(time);
//--- Display the header and time using the standard ArrayPrint()
   Print("Time current (ArrayPrint):");
   MqlDateTimePrint(time);
   /* Sample output:
      Time current (ArrayPrint):
          [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
      [0]   2023     7    17     12     8    37             1           197
   */
  }


Si necesitamos imprimir un array de fechas (después de todo, ArrayPrint() está hecho para imprimir cómodamente arrays de datos), entonces deberemos transmitir el array de datos datetime a la función, rellenar el array MqlDateTime con ellos e imprimirla.

Función que acepta un array datetime e imprime un array MqlDateTime:

//+------------------------------------------------------------------+
//| Accept the datetime array, convert it into MqlDateTime and       |
//| display converted data into the journal.                         |
//| Use ArrayPrint() for display                                     |
//+------------------------------------------------------------------+
void MqlDateTimePrint(const datetime& array_time[])
  {
//--- Declare a dynamic array of the MqlDateTime type
   MqlDateTime array_struct[];
//--- Get the size of the array passed to the function
   int total=(int)array_time.Size();
//--- If an empty array is passed, report on that and leave the function
   if(total==0)
     {
      PrintFormat("%s: Error. Empty array.",__FUNCTION__);
      return;
     }
//--- Change the size of the MqlDateTime array to match the size of the datetime array
   ResetLastError();
   if(ArrayResize(array_struct,total)!=total)
     {
      PrintFormat("%s: ArrayResize() failed. Error %s",__FUNCTION__,(string)GetLastError());
      return;
     }
//--- Convert dates from the datetime array into the date structure in the MqlDateTime array
   for(int i=0;i<total;i++)
     {
      ResetLastError();
      if(!TimeToStruct(array_time[i],array_struct[i]))
         PrintFormat("%s: [%s] TimeToStruct() failed. Error %s",__FUNCTION__,(string)i,(string)GetLastError());
     }
//--- Print the filled MqlDateTime array
   ArrayPrint(array_struct);
   /* Sample output:
      Time data of the last 10 bars GBPUSD H1 (ArrayPrint):
          [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
      [0]   2023     7    17      7     0     0             1           197
      [1]   2023     7    17      8     0     0             1           197
      [2]   2023     7    17      9     0     0             1           197
      [3]   2023     7    17     10     0     0             1           197
      [4]   2023     7    17     11     0     0             1           197
      [5]   2023     7    17     12     0     0             1           197
      [6]   2023     7    17     13     0     0             1           197
      [7]   2023     7    17     14     0     0             1           197
      [8]   2023     7    17     15     0     0             1           197
      [9]   2023     7    17     16     0     0             1           197
   */
  }


En consecuencia, un script que utilice la función anterior para imprimir un array datetime en un registro sería así:

void OnStart()
  {
//--- Declare a time array
   datetime array[];
//--- Copy the time of the last 10 bars to the array
   ResetLastError();
   if(CopyTime(Symbol(),Period(),0,10,array)<0)
     {
      PrintFormat("CopyTime() failed. Error %s",(string)GetLastError());
      return;
     }
//--- Display the header and the time data array of the last 10 bars using the standard ArrayPrint()
   PrintFormat("Time data of the last 10 bars %s %s (ArrayPrint):",Symbol(),StringSubstr(EnumToString(Period()),7));
   MqlDateTimePrint(array);
   /* Sample output:
      Time data of the last 10 bars GBPUSD H1 (ArrayPrint):
          [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year]
      [0]   2023     7    17      7     0     0             1           197
      [1]   2023     7    17      8     0     0             1           197
      [2]   2023     7    17      9     0     0             1           197
      [3]   2023     7    17     10     0     0             1           197
      [4]   2023     7    17     11     0     0             1           197
      [5]   2023     7    17     12     0     0             1           197
      [6]   2023     7    17     13     0     0             1           197
      [7]   2023     7    17     14     0     0             1           197
      [8]   2023     7    17     15     0     0             1           197
      [9]   2023     7    17     16     0     0             1           197
   */
  }


Funciones para trabajar con datos de la estructura MqlDateTime.

Todo lo que hemos probado antes es cómodo, práctico y conciso, pero a veces se requiere información más completa y, preferiblemente, en la misma presentación concisa, o, por el contrario, una descripción más detallada reduciendo la brevedad y sequedad en la presentación de la información. Por ejemplo, un simple número del día puede resultar confuso, mientras que si vemos escrito "jueves", inmediatamente entenderemos que se trata del jueves. Lo mismo ocurre con el número del mes: a veces es mejor ver "07 (julio)" que "contar con los dedos", calculando qué mes es el séptimo... Claro que estamos exagerando, pero aun así estas pequeñas adiciones hacen el conjunto más cómodo. Estas pequeñas comodidades se suman en una ganancia de tiempo muy tangible al analizar grandes volúmenes de entradas en los registros del programa.

Para añadir dichas comodidades, deberemos escribir nuestra propia función que retorne una descripción de los datos de fechas en el formato MqlDateTime.

La función sería como sigue:

  1. mostrar datos en formato corto (Día de la semana, Mes, Día, Año, hora);
  2. mostrar datos en una representación de tabla (Valor de encabezado de datos);

Antes de comenzar a crear las funciones para devolver las descripciones de los campos de estructura, crearemos funciones auxiliares que retornarán los nombres de los días de la semana y los meses.

Funciones auxiliares.

Para obtener el nombre del día de la semana, escribiremos una función simple que retornará el texto del día de la semana dependiendo del valor ubicado en el campo de estructura que almacena el día de la semana en formato numérico:

//+------------------------------------------------------------------+
//| Return the name of a week day                                    |
//+------------------------------------------------------------------+
string DayWeek(MqlDateTime &date_time)
  {
//--- Define a week day name
   string dw=EnumToString((ENUM_DAY_OF_WEEK)date_time.day_of_week);
//--- Convert all obtained symbols to lower case and replace the first letter from small to capital
   if(dw.Lower())
      dw.SetChar(0,ushort(dw.GetChar(0)-0x20));
//--- Return a resulting string
   return dw;
   /* Sample output:
      Wednesday
   */
  }

Como MQL5 tiene una enumeración con los nombres de los días de la semana, aquí utilizaremos la representación de línea de la constante de esta enumeración. Para asegurarnos de que el texto aparece de forma correcta, convertiremos todos los caracteres de la línea a minúsculas, salvo la primera letra de la palabra.

Para obtener el nombre del mes, escribiremos una función simple que retornará el texto del mes dependiendo del valor ubicado en el campo de estructura que almacena el mes en formato numérico:

//+------------------------------------------------------------------+
//| Return a month name                                              |
//+------------------------------------------------------------------+
string Month(MqlDateTime &date_time)
  {
//--- Define a month name
   switch(date_time.mon)
     {
      case  1  :  return "January";
      case  2  :  return "February";
      case  3  :  return "March";
      case  4  :  return "April";
      case  5  :  return "May";
      case  6  :  return "June";
      case  7  :  return "July";
      case  8  :  return "August";
      case  9  :  return "September";
      case 10  :  return "October";
      case 11  :  return "November";
      case 12  :  return "December";
      default  :  return "Undefined";
     }
   /* Sample output:
      July
   */
  }

En MQL5 no existe una enumeración para seleccionar el mes, por lo que aquí deberemos seleccionar y retornar el texto del nombre del mes en la declaración switch, dependiendo del valor numérico escrito en el campo de estructura.

Estas funciones nos serán útiles para mostrar las descripciones de los días de la semana y del mes, y pueden resultar de utilidad en el futuro para las necesidades de otros proyectos.

Las funciones que retornan las descripciones de los campos de la estructura MqlDateTime tendrán el mismo formato adoptado en el artículo "MqlDateTimeStringFormat(). Panorámica, ejemplos de uso listos para aplicar". Cada línea retornada por la función tendrá un encabezado y datos. El encabezado puede tener una separación respecto al borde izquierdo y podemos darle un anchura para la representación tabular del registro retornado. Transmitiremos los valores de separación y anchura como parámetros a las funciones. Los valores predeterminados para estas opciones serán cero, lo que implicará la ausencia de separación y una anchura igual a la longitud del texto del encabezado + 1.


Año en la estructura MqlDateTime:

//+------------------------------------------------------------------+
//| Return the year as a string from MqlDateTime                     |
//+------------------------------------------------------------------+
string MqlDateTimeYear(MqlDateTime &date_time,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Year:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-lu",indent,"",w,header,date_time.year);
   /* Sample output:
      Year: 2023
   */
  }


Mes en la estructura MqlDateTime:

//+------------------------------------------------------------------+
//| Return the month as a string from MqlDateTime                    |
//+------------------------------------------------------------------+
string MqlDateTimeMonth(MqlDateTime &date_time,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Month:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get a month name
   string mn=Month(date_time);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%02lu (%s)",indent,"",w,header,date_time.mon,mn);
   /* Sample output:
      Month: 07 (July)
   */
  }


Día en la estructura MqlDateTime:

//+------------------------------------------------------------------+
//| Return the day as a string from the MqlDateTime structure        |
//+------------------------------------------------------------------+
string MqlDateTimeDay(MqlDateTime &date_time,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Day:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.day);
   /* Sample output:
      Day: 19
   */
  }



Horas en la estructura MqlDateTime:

//+------------------------------------------------------------------+
//| Return hours as a string from the MqlDateTime structure          |
//+------------------------------------------------------------------+
string MqlDateTimeHour(MqlDateTime &date_time,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Hour:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.hour);
   /* Sample output:
      Hour: 08
   */
  }


Minutos en la estructura MqlDateTime:

//+------------------------------------------------------------------+
//| Return minutes as a string from MqlDateTime                      |
//+------------------------------------------------------------------+
string MqlDateTimeMin(MqlDateTime &date_time,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Minutes:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.min);
   /* Sample output:
      Minutes: 41
   */
  }


Segundos en la estructura MqlDateTime:

//+------------------------------------------------------------------+
//| Return seconds as a string from MqlDateTime                      |
//+------------------------------------------------------------------+
string MqlDateTimeSec(MqlDateTime &date_time,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Seconds:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.sec);
   /* Sample output:
      Seconds: 23
   */
  }


Día de la semana en la estructura MqlDateTime:

//+------------------------------------------------------------------+
//| Return a week day as a string from the MqlDateTime structure     |
//+------------------------------------------------------------------+
string MqlDateTimeDayWeek(MqlDateTime &date_time,const uint header_width=0,const uint indent=0,bool descr=true)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Day of week:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Get a week day name
   string dw=DayWeek(date_time);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-s (%-lu)",indent,"",w,header,dw,date_time.day_of_week);
   /* Sample output:
      Day of week: Wednesday (3)
   */
  }


Número del día en el año en la estructura MqlDateTime:

//+------------------------------------------------------------------+
//|Return a number of a day in a year from MqlDateTime               |
//+------------------------------------------------------------------+
string MqlDateTimeDayYear(MqlDateTime &date_time,const uint header_width=0,const uint indent=0)
  {
//--- Define the header text and the width of the header field
//--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
   string header="Day of year:";
   uint w=(header_width==0 ? header.Length()+1 : header_width);
//--- Return the property value with a header having the required width and indentation
   return StringFormat("%*s%-*s%-lu",indent,"",w,header,date_time.day_of_year);
   /* Sample output:
      Day of year: 199
   */
  }


Ejemplo de uso:

Para mostrar un breve registro de la fecha y hora de la estructura MqlDateTime, escribiremos una función que retorne la fecha en el formato "DW, Month DD, AAAA, HH:MM:SS":

//+------------------------------------------------------------------+
//| Return the date as a string from the MqlDateTime structure       |
//| in the DW, Month DD, YYYY, HH:MM:SS format                       |
//+------------------------------------------------------------------+
string DateTime(MqlDateTime &date_time)
  {
//--- Get the month and the first three characters of a week day
   string mn=Month(date_time);
   string dw=StringSubstr(DayWeek(date_time),0,3);
//--- Return a string in the DW, Month DD, YYYY, HH:MM:SS format
   return StringFormat("%s, %s %02lu, %lu, %02lu:%02lu:%02lu",dw,mn,date_time.day,date_time.year,date_time.hour,date_time.min,date_time.sec);
   /* Sample output:
      Wed, July 19, 2023, 08:41:23
   */
  }

Este es una entrada corta de una línea con todos los datos de la estructura salvo el número de día en el año. La función resulta cómoda para enviar, por ejemplo, un cierto número de barras al registro de tiempo:

void OnStart()
  {
   datetime array[];
   MqlDateTime adt[];
   if(CopyTime(Symbol(),PERIOD_CURRENT,0,10,array)==10)
     {
      int total=(int)array.Size();
      if(ArrayResize(adt,total)==total)
        {
         for(int i=0;i<total;i++)
           {
            ResetLastError();
            if(!TimeToStruct(array[i],adt[i]))
               Print("TimeToStruct failed. Error: ",GetLastError());
            PrintFormat("%s %s [%02u] %s",Symbol(),StringSubstr(EnumToString(Period()),7),i,DateTime(adt[i]));
           }
        }
     }
   /* Sample output:
      GBPUSD H1 [00] Wed, July 19, 2023, 02:00:00
      GBPUSD H1 [01] Wed, July 19, 2023, 03:00:00
      GBPUSD H1 [02] Wed, July 19, 2023, 04:00:00
      GBPUSD H1 [03] Wed, July 19, 2023, 05:00:00
      GBPUSD H1 [04] Wed, July 19, 2023, 06:00:00
      GBPUSD H1 [05] Wed, July 19, 2023, 07:00:00
      GBPUSD H1 [06] Wed, July 19, 2023, 08:00:00
      GBPUSD H1 [07] Wed, July 19, 2023, 09:00:00
      GBPUSD H1 [08] Wed, July 19, 2023, 10:00:00
      GBPUSD H1 [09] Wed, July 19, 2023, 11:00:00
   */
  }


Para registrar todos los campos de la estructura en formatos cortos y tabulares a elegir, escribiremos la siguiente función:

//+------------------------------------------------------------------+
//| Logs descriptions of all fields of the MqlDateTime structure     |
//+------------------------------------------------------------------+
void MqlDateTimePrint(MqlDateTime &date_time,const bool short_entry=true,const uint header_width=0,const uint indent=0)
  {
//--- If it is a short entry, log the date and time in the DW, Month DD, YYYY, HH:MM:SS format
   if(short_entry)
      Print(DateTime(date_time));
   /* Sample output:
      Wed, July 19, 2023, 08:41:23
   */
//--- Otherwise
   else
     {
      //--- create a string describing all the data of the structure with indents and a given width of the header field 
      string res=StringFormat("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s",
                              MqlDateTimeYear(date_time,header_width,indent),
                              MqlDateTimeMonth(date_time,header_width,indent),
                              MqlDateTimeDay(date_time,header_width,indent),
                              MqlDateTimeHour(date_time,header_width,indent),
                              MqlDateTimeMin(date_time,header_width,indent),
                              MqlDateTimeSec(date_time,header_width,indent),
                              MqlDateTimeDayWeek(date_time,header_width,indent),
                              MqlDateTimeDayYear(date_time,header_width,indent)
                             );
      //--- Display the obtained string in the journal
      Print(res);
     }
   /* Sample output:
      Year: 2023
      Month: 07 (July)
      Day: 19
      Hour: 09
      Minutes: 32
      Seconds: 25
      Day of week: Wednesday (3)
      Day of year: 199
   */
  }

Script con un ejemplo de cómo trabajar con esta función. Primero, mostraremos una entrada corta en el registro; luego, una entrada en forma tabular con la separación de los encabezados de los campos y una anchura de los campos de 2 y 14 caracteres, respectivamente:

void OnStart()
  {
   MqlDateTime dt;
   TimeCurrent(dt);
   MqlDateTimePrint(dt,true);
   MqlDateTimePrint(dt,false,14,2);
   /* Sample output:
      Wed, July 19, 2023, 09:33:56
        Year:         2023
        Month:        07 (July)
        Day:          19
        Hour:         09
        Minutes:      33
        Seconds:      56
        Day of week:  Wednesday (3)
        Day of year:  199
   */
  }

Todas las funciones para trabajar con los campos de la estructura MqlDateTime y las funciones auxiliares presentadas anteriormente se pueden utilizar "tal cual" en nuestros programas o se pueden modificar según nuestra propia visión y necesidades.


Estructura MqlTick

Estructura para almacenar los últimos precios de un símbolo. Se ha diseñado para obtener rápidamente la información más popular sobre los precios actuales.

struct MqlTick
  {
   datetime     time;          // Last price update time
   double       bid;           // Current Bid price
   double       ask;           // Current Ask price
   double       last;          // Current price of the last trade (Last)
   ulong        volume;        // Volume for the current Last price
   long         time_msc;      // Last price update time in milliseconds
   uint         flags;         // Tick flags
   double       volume_real;   // Volume for the current Last price
  };

La variable del tipo MqlTick nos permite obtener los valores de Ask, Bid, Last, Volume y el tiempo en milisegundos en una sola llamada a la función SymbolInfoTick() .

Todos los parámetros siempre se completan para cada tick, independientemente de si los datos han cambiado en comparación con el tick anterior. Esto nos permite tener siempre el estado actual de los precios en cualquier momento sin buscar valores anteriores en la historia de ticks. Por ejemplo, con un tick solo podría cambiar el precio Bid, pero además del nuevo precio, en la estructura se indicarán otros parámetros: el precio de Ask anterior, el volumen, etcétera.

Para saber exactamente qué datos han cambiado con el tick actual, deberemos analizar sus banderas:

  • TICK_FLAG_BID – el tick ha cambiado el precio de oferta
  • TICK_FLAG_ASK – el tick ha cambiado el precio de venta
  • TICK_FLAG_LAST – el tick ha cambiado el precio de la última operación
  • TICK_FLAG_VOLUME – el tick ha cambiado el volumen
  • TICK_FLAG_BUY: el tick se ha generado como resultado de una transacción de compra
  • TICK_FLAG_SELL: el tick se ha generado como resultado de una transacción de venta

    MqlTick, métodos de impresión

    Para enviar la estructura al registro, al igual que sucede con MqlDateTime, resulta adecuada la función ArrayPrint():

    void OnStart()
      {
    //--- Declare a variable with the MqlTick type
       MqlTick  tick;
    //--- If failed to get the last tick, display the error message and exit the method
       if(!SymbolInfoTick(Symbol(),tick))
         {
          Print("SymbolInfoTick failed, error: ",(string)GetLastError());
          return;
         }
    //--- Display the tick using standard ArrayPrint()
    //--- To do this, declare an array of dimension 1 with type MqlTick,
    //--- enter the value of the 'tick' variable into it and print it
       MqlTick array[1];
       array[0]=tick;
       Print("Last tick (ArrayPrint):");
       ArrayPrint(array);
       /* Sample output:
          Last tick (ArrayPrint):
                           [time]   [bid]   [ask] [last] [volume]    [time_msc] [flags] [volume_real]
          [0] 2023.07.19 17:02:49 1.28992 1.28996 0.0000        0 1689786169589       6       0.00000
       */
      }
    
    

    Resulta lógico que para imprimir un array, podamos rellenar el array con un rango de ticks:

    void OnStart()
      {
    //--- Declare a dynamic array of the MqlTick type
       MqlTick  array[];
    //--- If failed to get the last 10 ticks, display the error message and exit the method
       if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,10)!=10)
         {
          Print("CopyTicks failed, error: ",(string)GetLastError());
          return;
         }
       Print("Last 10 tick (ArrayPrint):");
       ArrayPrint(array);
       /* Sample output:
          Last 10 tick (ArrayPrint):
                           [time]   [bid]   [ask] [last] [volume]    [time_msc] [flags] [volume_real]
          [0] 2023.07.19 17:24:38 1.28804 1.28808 0.0000        0 1689787478461       6       0.00000
          [1] 2023.07.19 17:24:38 1.28806 1.28810 0.0000        0 1689787478602       6       0.00000
          [2] 2023.07.19 17:24:38 1.28804 1.28808 0.0000        0 1689787478932       6       0.00000
          [3] 2023.07.19 17:24:39 1.28806 1.28810 0.0000        0 1689787479210       6       0.00000
          [4] 2023.07.19 17:24:39 1.28807 1.28811 0.0000        0 1689787479765       6       0.00000
          [5] 2023.07.19 17:24:39 1.28808 1.28812 0.0000        0 1689787479801       6       0.00000
          [6] 2023.07.19 17:24:40 1.28809 1.28813 0.0000        0 1689787480240       6       0.00000
          [7] 2023.07.19 17:24:40 1.28807 1.28811 0.0000        0 1689787480288       6       0.00000
          [8] 2023.07.19 17:24:40 1.28809 1.28813 0.0000        0 1689787480369       6       0.00000
          [9] 2023.07.19 17:24:40 1.28810 1.28814 0.0000        0 1689787480399       6       0.00000
       */
      }
    
    

    Una vez más, querríamos una muestra de valores más significativa. Por ejemplo, el tiempo en milisegundos y las banderas. Probablemente resulte más cómodo verlos de la forma habitual: el tiempo en formato de fecha y hora y las banderas en formato de constantes de enumeración.


    Funciones para trabajar con los datos de la estructura MqlTick.

    Vamos a crear las Funciones para trabajar con los datos de la estructura MqlTick. Al igual que todas las funciones ya creadas para trabajar con la estructura MqlDateTime, las funciones para trabajar con MqlTick retornarán una línea formateada. El formato de línea incluirá la separación izquierda del texto y la anchura del campo del encabezado. Por defecto, los valores de rellenado y anchura de la separación serán cero, lo que significa que no habrá rellenado y la anchura de la separación será igual a la longitud del texto del título + 1.


    Funciones auxiliares.

    Para retornar el tiempo en milisegundos como una línea, ya hemos creado una función. Aquí resultará útil para retornar el tiempo de tick en milisegundos, vamos a usarla:

    //+------------------------------------------------------------------+
    //| Accept a date in ms, return time in Date Time.Msc format         |
    //+------------------------------------------------------------------+
    string TimeMSC(const long time_msc)
      {
       return StringFormat("%s.%.3hu",string((datetime)time_msc / 1000),time_msc % 1000);
       /* Sample output:
          2023.07.13 09:31:58.177
       */
      }
    
    


    Hora en la estructura MqlTick:

    //+------------------------------------------------------------------+
    //| Return the time of the last price update as a string             |
    //+------------------------------------------------------------------+
    string MqlTickTime(const MqlTick &tick,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Time:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-s",indent,"",w,header,(string)tick.time);
       /* Sample output:
          Time: 2023.07.19 20:58:00
       */
      }
    
    


    Precio Bid en la estructura MqlTick:

    //+------------------------------------------------------------------+
    //| Return the Bid price as a string                                 |
    //+------------------------------------------------------------------+
    string MqlTickBid(const string symbol,const MqlTick &tick,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Bid:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.bid);
       /* Sample output:
          Bid: 1.29237
       */
      }
    
    


    Precio Ask en la estructura MqlTick:

    //+------------------------------------------------------------------+
    //| Return the Ask price as a string                                 |
    //+------------------------------------------------------------------+
    string MqlTickAsk(const string symbol,const MqlTick &tick,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Ask:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.ask);
       /* Sample output:
          Ask: 1.29231
       */
      }
    
    


    Precio de la última transacción (Last) en la estructura MqlTick:

    //+------------------------------------------------------------------+
    //| Return the Last price as a string                                |
    //+------------------------------------------------------------------+
    string MqlTickLast(const string symbol,const MqlTick &tick,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Last:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.last);
       /* Sample output:
          Last: 0.00000
       */
      }
    
    


    Volumen para el precio Last en la estructura MqlTick:

    //+------------------------------------------------------------------+
    //| Return the volume for the Last price as a string                 |
    //+------------------------------------------------------------------+
    string MqlTickVolume(const MqlTick &tick,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Volume:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-I64u",indent,"",w,header,tick.volume);
       /* Sample output:
          Volume: 0
       */
      }
    
    


    Tiempo en milisegundos en la estructura MqlTick:

    //+------------------------------------------------------------------+
    //| Return the time in milliseconds as a string                      |
    //+------------------------------------------------------------------+
    string MqlTickTimeMSC(const MqlTick &tick,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Time msc:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-s",indent,"",w,header,TimeMSC(tick.time_msc));
       /* Sample output:
          Time msc: 2023.07.19 21:21:09.732
       */
      }
    
    


    Banderas de ticks en la estructura MqlTick:

    //+------------------------------------------------------------------+
    //| Return tick flags as a string                                    |
    //+------------------------------------------------------------------+
    string MqlTickFlags(const MqlTick &tick,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Flags:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Define a variable to describe tick flags
       string flags="";
    //--- Parse tick flags into components
       if((tick.flags & TICK_FLAG_BID)==TICK_FLAG_BID)
          flags+=(flags.Length()>0 ? "|" : "")+"BID";
       if((tick.flags & TICK_FLAG_ASK)==TICK_FLAG_ASK)
          flags+=(flags.Length()>0 ? "|" : "")+"ASK";
       if((tick.flags & TICK_FLAG_LAST)==TICK_FLAG_LAST)
          flags+=(flags.Length()>0 ? "|" : "")+"LAST";
       if((tick.flags & TICK_FLAG_VOLUME)==TICK_FLAG_VOLUME)
          flags+=(flags.Length()>0 ? "|" : "")+"VOLUME";
       if((tick.flags & TICK_FLAG_BUY)==TICK_FLAG_BUY)
          flags+=(flags.Length()>0 ? "|" : "")+"BUY";
       if((tick.flags & TICK_FLAG_SELL)==TICK_FLAG_SELL)
          flags+=(flags.Length()>0 ? "|" : "")+"SELL";
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-s",indent,"",w,header,flags);
       /* Sample output:
          Flags: BID|ASK
       */
      }
    
    


    Volumen para el precio Last con precisión aumentada en la estructura MqlTick:

    //+------------------------------------------------------------------+
    //| Return the volume for the Last price as a string                 |
    //+------------------------------------------------------------------+
    string MqlTickVolumeReal(const MqlTick &tick,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Volume Real:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.2f",indent,"",w,header,tick.volume_real);
       /* Sample output:
          Volume Real: 0.00
       */
      }
    
    


    Ejemplos de uso.

    Para enviar los datos de ticks al registro, escribiremos una función. Para saber con qué precisión se enviarán los valores de precio al registro, transmitiremos el nombre del símbolo a la función. Como los campos Volume y Real Volume contienen los volúmenes del último precio Last, si Last es cero (no se retransmite), entonces no tendrá sentido mostrar los volúmenes: también serán cero. Para poder especificar e imprimir el índice de un tick tomado de un array de ticks, transmitiremos dicho índice en los parámetros de entrada de la función. Por defecto, su valor será -1 y, con este valor, el índice no se imprimirá.

    //+------------------------------------------------------------------+
    //| Logs descriptions of all fields of the MqlTick structure         |
    //| If Last==0, Last, Volume and Volume Real fields are not displayed|
    //+------------------------------------------------------------------+
    void MqlTickPrint(const string symbol,const MqlTick &tick,const bool short_entry=true,const uint header_width=0,const uint indent=0,int index=WRONG_VALUE)
      {
    //--- Declare the variable for storing the result
       string res="";
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
       string num=(index==WRONG_VALUE ? "" : StringFormat("[%ld] ",index));
    //--- If it is a short entry, log the tick data in the Symbol TimeMSC, Bid, Ask, Last, Vol/VolR, Flags format
       if(short_entry)
         {
          //--- If Last is not zero, display Last, Volume and Volume Real, otherwise they are all zero and there is no point in displaying them
          string last=(tick.last!=0 ? StringFormat(", Last: %.*f, Vol: %I64u/%.2f",dg,tick.last,tick.volume,tick.volume_real) : "");
          res=StringFormat("%sTick %s Time: %s, Bid: %.*f, Ask: %.*f%s, %s",num,symbol,TimeMSC(tick.time_msc),dg,tick.bid,dg,tick.ask,last,MqlTickFlags(tick));
          Print(res);
         }
       /* Sample output (if Last is not zero):
          Tick GBPUSD Time: 2023.07.20 13:57:31.376, Bid: 1.28947, Ask: 1.28951, Last: 1.28947, Vol: 33/33.45, Flags: BID|ASK
          Sample output (if Last is zero):
          Tick GBPUSD Time: 2023.07.20 13:59:33.274, Bid: 1.28956, Ask: 1.28960, Flags: BID|ASK
       */
    //--- Otherwise
       else
         {
          //--- create a string describing all the data of the structure with indents and a given width of the header field 
          res=StringFormat("%s\n%s\n%s%s%s\n%s\n%s%s",
                           MqlTickTime(tick,header_width,indent),
                           MqlTickBid(symbol,tick,header_width,indent),
                           MqlTickAsk(symbol,tick,header_width,indent),
                           (tick.last!=0 ? "\n"+MqlTickLast(symbol,tick,header_width,indent) : ""),
                           (tick.last!=0 ? "\n"+MqlTickVolume(tick,header_width,indent) : ""),
                           MqlTickTimeMSC(tick,header_width,indent),
                           MqlTickFlags(tick,header_width,indent),
                           (tick.last!=0 ? "\n"+MqlTickVolumeReal(tick,header_width,indent) : "")
                          );
          //--- Display the obtained string in the journal
          Print(res);
         }
       /* Sample output (if Last is not zero):
          Time:         2023.07.20 14:42:33
          Bid:          1.28958
          Ask:          1.28962
          Last:         1.28947
          Volume:       33
          Time msc:     2023.07.20 14:42:33.401
          Flags:        BID|ASK
          Volume Real:  33.45
          
          Sample output (if Last is zero):
          Time:         2023.07.20 14:42:33
          Bid:          1.28958
          Ask:          1.28962
          Time msc:     2023.07.20 14:42:33.401
          Flags:        BID|ASK
       */
      }
    
    

    Script que imprime los últimos 10 ticks de un registro de forma breve, indicando los índices de ticks del array:

    void OnStart()
      {
    //--- Declare a dynamic array of the MqlTick type
       MqlTick  array[];
    //--- If failed to get the last 10 ticks, display the error message and exit the method
       if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,10)!=10)
         {
          Print("CopyTicks failed, error: ",(string)GetLastError());
          return;
         }
       Print("Last 10 tick (MqlTickPrint):");
       for(int i=0;i<(int)array.Size();i++)
          MqlTickPrint(Symbol(),array[i],true,0,0,i);
    
       /* Sample output:
          Last 10 tick (MqlTickPrint):
          [0] Tick GBPUSD Time: 2023.07.20 15:36:29.941, Bid: 1.28686, Ask: 1.28690, Flags: BID|ASK
          [1] Tick GBPUSD Time: 2023.07.20 15:36:29.970, Bid: 1.28688, Ask: 1.28692, Flags: BID|ASK
          [2] Tick GBPUSD Time: 2023.07.20 15:36:30.061, Bid: 1.28689, Ask: 1.28693, Flags: BID|ASK
          [3] Tick GBPUSD Time: 2023.07.20 15:36:30.212, Bid: 1.28688, Ask: 1.28692, Flags: BID|ASK
          [4] Tick GBPUSD Time: 2023.07.20 15:36:30.259, Bid: 1.28689, Ask: 1.28693, Flags: BID|ASK
          [5] Tick GBPUSD Time: 2023.07.20 15:36:30.467, Bid: 1.28682, Ask: 1.28686, Flags: BID|ASK
          [6] Tick GBPUSD Time: 2023.07.20 15:36:30.522, Bid: 1.28681, Ask: 1.28685, Flags: BID|ASK
          [7] Tick GBPUSD Time: 2023.07.20 15:36:30.572, Bid: 1.28673, Ask: 1.28677, Flags: BID|ASK
          [8] Tick GBPUSD Time: 2023.07.20 15:36:30.574, Bid: 1.28672, Ask: 1.28676, Flags: BID|ASK
          [9] Tick GBPUSD Time: 2023.07.20 15:36:30.669, Bid: 1.28674, Ask: 1.28678, Flags: BID|ASK
       */
      }
    
    

    Script que imprime los últimos 4 ticks de un array en el registro con una separación a la izquierda de 2 caracteres y una anchura del campo de encabezado de 14 caracteres:

    void OnStart()
      {
    //--- Declare a dynamic array of the MqlTick type
       MqlTick  array[];
    //--- If the last 4 ticks are not received in the array, display an error message and leave
       if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,4)!=4)
         {
          Print("CopyTicks failed, error: ",(string)GetLastError());
          return;
         }
       Print("Last 4 tick (MqlTickPrint):");
       for(int i=0;i<(int)array.Size();i++)
         {
          PrintFormat("Tick[%lu] %s:",i,Symbol());
          MqlTickPrint(Symbol(),array[i],false,14,2);
         }
    
       /* Sample output:
          Last 4 tick (MqlTickPrint):
          Tick[0] GBPUSD:
            Time:         2023.07.20 17:04:51
            Bid:          1.28776
            Ask:          1.28780
            Time msc:     2023.07.20 17:04:51.203
            Flags:        BID|ASK
          Tick[1] GBPUSD:
            Time:         2023.07.20 17:04:51
            Bid:          1.28772
            Ask:          1.28776
            Time msc:     2023.07.20 17:04:51.331
            Flags:        BID|ASK
          Tick[2] GBPUSD:
            Time:         2023.07.20 17:04:51
            Bid:          1.28771
            Ask:          1.28775
            Time msc:     2023.07.20 17:04:51.378
            Flags:        BID|ASK
          Tick[3] GBPUSD:
            Time:         2023.07.20 17:04:51
            Bid:          1.28772
            Ask:          1.28776
            Time msc:     2023.07.20 17:04:51.680
            Flags:        BID|ASK
       */
      }
    
    


    Estructura MqlRates

    Estructura para almacenar las información sobre los precios, volúmenes y spreads.

    struct MqlRates
      {
       datetime time;         // period start time
       double   open;         // open price
       double   high;         // high price for the period
       double   low;          // low price for the period
       double   close;        // close price
       long     tick_volume;  // tick volume
       int      spread;       // spread
       long     real_volume;  // exchange volume
      };
    

    MqlRates, métodos de impresión

    MqlRates es una estructura para almacenar los datos de una barra de datos históricos. La estructura se puede rellenar usando la función CopyRates(). Para obtener los datos de la barra actual, podemos usar la primera forma de llamada a la función, indicando el índice 0 y un número de barras copiadas igual a 1. En cualquier caso, esta función rellenará un array con el tipo MqlRates. Esto nos lleva a la conclusión de que resulta cómodo imprimir este array en el registro usando ArrayPrint():

    void OnStart()
      {
    //---
       MqlRates array[];
       if(CopyRates(Symbol(),PERIOD_CURRENT,0,1,array)!=1)
         {
          Print("CopyRates failed, error: ",(string)GetLastError());
          return;
         }
       Print("Current bar ",Symbol()," ",StringSubstr(EnumToString(Period()),7)," (ArrayPrint):");
       ArrayPrint(array);
       /* Sample output:
          Current bar GBPUSD H1 (ArrayPrint):
                           [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume]
          [0] 2023.07.21 04:00:00 1.28763 1.28765 1.28663 1.28748          2083        7             0
       */
      }
    
    

    En consecuencia, para copiar las últimas diez barras, solo necesitaremos especificar un número de datos a copiar igual a 10:

    void OnStart()
      {
    //---
       MqlRates array[];
       if(CopyRates(Symbol(),PERIOD_CURRENT,0,10,array)!=10)
         {
          Print("CopyRates failed, error: ",(string)GetLastError());
          return;
         }
       Print("Data of the last 10 bars: ",Symbol()," ",StringSubstr(EnumToString(Period()),7)," (ArrayPrint):");
       ArrayPrint(array);
       /* Sample output:
          Data of the last 10 bars: GBPUSD H1 (ArrayPrint):
                           [time]  [open]  [high]   [low] [close] [tick_volume] [spread] [real_volume]
          [0] 2023.07.20 20:00:00 1.28530 1.28676 1.28512 1.28641          2699        4             0
          [1] 2023.07.20 21:00:00 1.28641 1.28652 1.28557 1.28587          1726        3             0
          [2] 2023.07.20 22:00:00 1.28587 1.28681 1.28572 1.28648          2432        3             0
          [3] 2023.07.20 23:00:00 1.28648 1.28683 1.28632 1.28665           768        4             0
          [4] 2023.07.21 00:00:00 1.28663 1.28685 1.28613 1.28682           396        1             0
          [5] 2023.07.21 01:00:00 1.28684 1.28732 1.28680 1.28714           543        8             0
          [6] 2023.07.21 02:00:00 1.28714 1.28740 1.28690 1.28721           814        2             0
          [7] 2023.07.21 03:00:00 1.28721 1.28774 1.28685 1.28761          2058        5             0
          [8] 2023.07.21 04:00:00 1.28763 1.28791 1.28663 1.28774          3480        7             0
          [9] 2023.07.21 05:00:00 1.28774 1.28776 1.28769 1.28774            18        7             0
       */
      }
    
    

    Sí, aquí todo es igual: en el registro hay una larga lista de datos. Si el encabezado de la tabla está oculto tras el borde superior de la ventana del registro, entonces no estará claro a qué se refieren todos los números presentados.

    Vamos a escribir nuestras propias funciones para retornar las descripciones de los campos de la estructura e imprimir estos datos en el registro del terminal.


    Funciones para trabajar con los datos de la estructura MqlRates.

    Nuestras funciones personalizadas retornarán una descripción de texto de cada campo de la estructura. Cada descripción tendrá un encabezado y datos reales. Para la línea retornada por la función, podemos establecer la separación desde el borde izquierdo y la anchura del campo de encabezado.


    Time:

    Time — hora de inicio del periodo. En otras palabras, la hora de apertura de la barra en el símbolo y el periodo del gráfico a partir del cual se han solicitado los datos escritos en la estructura.

    //+------------------------------------------------------------------+
    //| Return the bar opening time as a string                          |
    //+------------------------------------------------------------------+
    string MqlRatesTime(const MqlRates &rates,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Time:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-s",indent,"",w,header,(string)rates.time);
       /* Sample output:
          Time: 2023.07.21 06:00:00
       */
      }
    
    


    Open:

    Precio de apertura de la barra en el símbolo y periodo del gráfico del que se han solicitado los datos registrados en la estructura.

    //+------------------------------------------------------------------+
    //| Return the bar open price as a string                            |
    //+------------------------------------------------------------------+
    string MqlRatesOpen(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Open:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.open);
       /* Sample output:
          Open: 1.28812
       */
      }
    
    


    High:

    Precio High — precio más alto de la barra en el símbolo y periodo del gráfico desde el cual se han solicitado los datos registrados en la estructura.

    //+------------------------------------------------------------------+
    //| Return the High bar price as a string                            |
    //+------------------------------------------------------------------+
    string MqlRatesHigh(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="High:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.high);
       /* Sample output:
          High: 1.28859
       */
      }
    
    


    Low:

    Precio Low — precio más bajo de la barra en el símbolo y periodo del gráfico desde el cual se han solicitado los datos registrados en la estructura.

    //+------------------------------------------------------------------+
    //| Return the bar Low price as a string                             |
    //+------------------------------------------------------------------+
    string MqlRatesLow(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Low:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.low);
       /* Sample output:
          Low: 1.28757
       */
      }
    
    


    Close:

    Precio Close — precio de cierre de la barra en el símbolo y periodo del gráfico desde el cual se han solicitado los datos registrados en la estructura.
    Para la barra actual, el precio de cierre será igual al precio Bid o Last, dependiendo del precio en el que se base el gráfico.

    //+------------------------------------------------------------------+
    //| Return the bar close price as a string                           |
    //+------------------------------------------------------------------+
    string MqlRatesClose(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Close:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.close);
       /* Sample output:
          Close: 1.28770
       */
      }
    
    


    TickVolume:

    Volumen de ticks de la barra.

    //+------------------------------------------------------------------+
    //| Return the tick volume of a bar as a string                      |
    //+------------------------------------------------------------------+
    string MqlRatesTickVolume(const MqlRates &rates,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Tick Volume:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-lld",indent,"",w,header,rates.tick_volume);
       /* Sample output:
          Tick Volume: 963
       */
      }
    
    


    Spread:

    Spread en la barra.

    //+------------------------------------------------------------------+
    //| Return the bar spread as a string                                |
    //+------------------------------------------------------------------+
    string MqlRatesSpread(const MqlRates &rates,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Spread:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-ld",indent,"",w,header,rates.spread);
       /* Sample output:
          Spread: 4
       */
      }
    
    


    RealVolume:

    Volumen bursátil de la barra.

    //+------------------------------------------------------------------+
    //| Return the bar exchange volume as a string                       |
    //+------------------------------------------------------------------+
    string MqlRatesRealVolume(const MqlRates &rates,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Real Volume:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-lld",indent,"",w,header,rates.real_volume);
       /* Sample output:
          Real Volume: 0
       */
      }
    
    


    Ejemplos de uso.

    Para imprimir los datos de las últimas 10 barras del registro, escribiremos el siguiente script:

    void OnStart()
      {
    //--- Copy the last 10 data bars to the MqlRates array
       MqlRates array[];
       if(CopyRates(Symbol(),PERIOD_CURRENT,0,10,array)!=10)
         {
          Print("CopyRates failed, error: ",(string)GetLastError());
          return;
         }
    
    //--- Set the indexing of the array like a timeseries
       ArraySetAsSeries(array,true);
    //--- Print short entries in the journal in a loop through the array with the received bar data
       for(int i=0;i<(int)array.Size();i++)
          MqlRatesPrint(Symbol(),PERIOD_CURRENT,array[i],true,0,0,i);
       
       /* Sample output:
          GBPUSD H1[0]: 2023.07.21 14:00:00, O: 1.28451, H: 1.28541, L: 1.28451, C: 1.28501, S:  4, V:   821, RV: 0
          GBPUSD H1[1]: 2023.07.21 13:00:00, O: 1.28678, H: 1.28685, L: 1.28418, C: 1.28452, S:  1, V:  3602, RV: 0
          GBPUSD H1[2]: 2023.07.21 12:00:00, O: 1.28581, H: 1.28696, L: 1.28557, C: 1.28678, S:  1, V:  4807, RV: 0
          GBPUSD H1[3]: 2023.07.21 11:00:00, O: 1.28695, H: 1.28745, L: 1.28401, C: 1.28581, S:  1, V:  7440, RV: 0
          GBPUSD H1[4]: 2023.07.21 10:00:00, O: 1.28933, H: 1.28960, L: 1.28651, C: 1.28696, S:  1, V:  8883, RV: 0
          GBPUSD H1[5]: 2023.07.21 09:00:00, O: 1.28788, H: 1.29040, L: 1.28753, C: 1.28934, S:  1, V:  5474, RV: 0
          GBPUSD H1[6]: 2023.07.21 08:00:00, O: 1.28794, H: 1.28848, L: 1.28713, C: 1.28787, S:  1, V:  1885, RV: 0
          GBPUSD H1[7]: 2023.07.21 07:00:00, O: 1.28762, H: 1.28808, L: 1.28744, C: 1.28794, S:  4, V:   878, RV: 0
          GBPUSD H1[8]: 2023.07.21 06:00:00, O: 1.28812, H: 1.28859, L: 1.28743, C: 1.28760, S:  3, V:  1112, RV: 0
          GBPUSD H1[9]: 2023.07.21 05:00:00, O: 1.28774, H: 1.28820, L: 1.28747, C: 1.28812, S:  7, V:  1671, RV: 0
       */
      }
    
    

    Después de copiar la cantidad requerida de datos en el array, los indexaremos como una serie temporal, de modo que los datos se muestren de la misma manera que las barras del gráfico en el terminal; los datos con un índice cero se corresponderán con la barra actual.

    Este script imprimirá las últimas 4 barras del registro en forma tabular con un campo de encabezado con una separación de dos caracteres a la izquierda y una anchura del campo de encabezado de 14 caracteres:

    void OnStart()
      {
    //--- Copy the last 4 data bars to the MqlRates array
       MqlRates array[];
       if(CopyRates(Symbol(),PERIOD_CURRENT,0,4,array)!=4)
         {
          Print("CopyRates failed, error: ",(string)GetLastError());
          return;
         }
    
    //--- Set the indexing of the array like a timeseries
       ArraySetAsSeries(array,true);
    //--- Print short entries in the journal in a loop through the array with the received bar data
       for(int i=0;i<(int)array.Size();i++)
          MqlRatesPrint(Symbol(),PERIOD_CURRENT,array[i],false,14,2,i);
       
       /* Sample output:
          GBPUSD H1[0]:
            Time:         2023.07.21 14:00:00
            Open:         1.28451
            High:         1.28541
            Low:          1.28451
            Close:        1.28491
            Tick Volume:  1098
            Spread:       4
            Real Volume:  0
          GBPUSD H1[1]:
            Time:         2023.07.21 13:00:00
            Open:         1.28678
            High:         1.28685
            Low:          1.28418
            Close:        1.28452
            Tick Volume:  3602
            Spread:       1
            Real Volume:  0
          GBPUSD H1[2]:
            Time:         2023.07.21 12:00:00
            Open:         1.28581
            High:         1.28696
            Low:          1.28557
            Close:        1.28678
            Tick Volume:  4807
            Spread:       1
            Real Volume:  0
          GBPUSD H1[3]:
            Time:         2023.07.21 11:00:00
            Open:         1.28695
            High:         1.28745
            Low:          1.28401
            Close:        1.28581
            Tick Volume:  7440
            Spread:       1
            Real Volume:  0
       */
      }
    
    


    Estructura MqlBookInfo

    Estructura que proporciona información a la profundidad de mercado.

    struct MqlBookInfo
      {
       ENUM_BOOK_TYPE   type;            // order type from ENUM_BOOK_TYPE enumeration
       double           price;           // price
       long             volume;          // volume
       double           volume_real;     // volume with increased accuracy
      };
    

    Para utilizar la estructura bastará con declarar una variable de este tipo. La profundidad de mercado no estará disponible para todos los instrumentos financieros. Antes de recibir datos de la profundidad de mercado, deberemos suscribirnos para recibir información de la profundidad a través de MarketBookAdd(). Al finalizar el trabajo, deberemos darnos de baja de la misma: MarketBookRelease(). Para procesar las notificaciones entrantes, el programa del asesor deberá contener la función void OnBookEvent().


    MqlBookInfo, métodos de impresión

    Cada recepción de la profundidad de mercado implicará obtener la lista de órdenes contenidas en la profundidad de mercado. En consecuencia, se tratará de un array de datos. Por ello, podemos imprimir una instantánea de la profundidad de mercado usando ArrayPrint():

    void OnStart()
      {
    //--- Declare an array to store a snapshot of the market depth
       MqlBookInfo array[];
    //--- If unable to open the market depth and subscribe to its events, inform of that and leave
       if(!MarketBookAdd(Symbol()))
         {
          Print("MarketBookAdd failed, error: ",(string)GetLastError());
          return;
         }
    //--- If unable to obtain the market depth entries, inform of that and leave
       if(!MarketBookGet(Symbol(),array))
         {
          Print("MarketBookGet failed, error: ",(string)GetLastError());
          return;
         }
    //--- Print the header in the journal and the market depth snapshot from the array below
       Print("MarketBookInfo by ",Symbol(),":");
       ArrayPrint(array);
    //--- If unable to unsubscribe from the market depth, send an error message to the journal
       if(!MarketBookRelease(Symbol()))
          Print("MarketBookRelease failed, error: ",(string)GetLastError());
       /* Sample output:
          MarketBookInfo by GBPUSD:
              [type] [price] [volume] [volume_real]
          [0]      1 1.28280      100     100.00000
          [1]      1 1.28276       50      50.00000
          [2]      1 1.28275       20      20.00000
          [3]      1 1.28273       10      10.00000
          [4]      2 1.28268       10      10.00000
          [5]      2 1.28266       20      20.00000
          [6]      2 1.28265       50      50.00000
          [7]      2 1.28260      100     100.00000
       */
      }
    
    

    Como podemos ver, los tipos de solicitudes aquí se expresan en valores numéricos, y esto no resulta cómodo para la visualización. Vamos a escribir algunas funciones para retornar las descripciones de los campos de la profundidad de mercado en el estilo ya aceptado para las otras estructuras discutidas anteriormente.


    Funciones para trabajar con los datos de la estructura MqlBookInfo.

    Todas las funciones que retornan una representación de línea de los campos de la estructura MqlBookInfo tendrán el mismo estilo que las funciones descritas anteriormente para describir los campos de las estructuras correspondientes. Veámoslas por orden.


    Tipo de orden en la estructura de la profundidad de mercado MqlBookInfo:

    //+------------------------------------------------------------------+
    //| Return the order type in the market depth as a string            |
    //+------------------------------------------------------------------+
    string MqlBookInfoType(const MqlBookInfo &book,const uint header_width=0,const uint indent=0)
      {
    //--- Get the value of the order type
       ENUM_BOOK_TYPE book_type=book.type;
    //--- "Cut out" the type from the string obtained from enum
       string type=StringSubstr(EnumToString(book_type),10);
    //--- Convert all obtained symbols to lower case and replace the first letter from small to capital
       if(type.Lower())
          type.SetChar(0,ushort(type.GetChar(0)-0x20));
    //--- Replace all underscore characters with space in the resulting line
       StringReplace(type,"_"," ");
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Type:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-s",indent,"",w,header,type);
       /* Sample output:
          Type: Sell
       */
      }
    
    


    Precio de la orden en la estructura de la profundidad de mercado MqlBookInfo:

    //+------------------------------------------------------------------+
    //| Return the order price in the market depth as a string           |
    //+------------------------------------------------------------------+
    string MqlBookInfoPrice(const string symbol,const MqlBookInfo &book,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Price:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Get the number of decimal places
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,book.price);
       /* Sample output:
          Price: 1.28498
       */
      }
    
    


    Volumen de la orden en la estructura de la profundidad de mercado MqlBookInfo:

    //+------------------------------------------------------------------+
    //| Return the order volume in the market depth as a string          |
    //+------------------------------------------------------------------+
    string MqlBookInfoVolume(const MqlBookInfo &book,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Volume:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-lld",indent,"",w,header,book.volume);
       /* Sample output:
          Volume: 100
       */
      }
    
    


    Volumen con precisión aumentada:

    //+------------------------------------------------------------------+
    //| Return the order volume with increased accuracy as a string      |
    //+------------------------------------------------------------------+
    string MqlBookInfoVolumeReal(const MqlBookInfo &book,const uint header_width=0,const uint indent=0)
      {
    //--- Define the header text and the width of the header field
    //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1
       string header="Volume Real:";
       uint w=(header_width==0 ? header.Length()+1 : header_width);
    //--- Return the property value with a header having the required width and indentation
       return StringFormat("%*s%-*s%-.2f",indent,"",w,header,book.volume_real);
       /* Sample output:
          Volume Real: 100.00
       */
      }
    
    


    Ejemplos de uso:

    Ahora escribiremos una función que imprima todos los datos de la estructura MqlBookInfo en el registro. Podremos imprimir de dos formas: en una línea y en forma tabular:

    //+------------------------------------------------------------------+
    //| Logs a description of all fields of the MqlRates structure       |
    //+------------------------------------------------------------------+
    void MqlBookInfoPrint(const string symbol,const MqlBookInfo &book,
                          const bool short_entry=true,const uint header_width=0,const uint indent=0,int index=WRONG_VALUE)
      {
    //--- Declare the variable for storing the result
       string res="";
    //--- Get the number of decimal places and the string index value
       int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
       string num=(index==WRONG_VALUE ? "" : StringFormat("[%02ld]",index));
       
    //--- "Cut out" the type from the order type name string obtained from enum
       string type=StringSubstr(EnumToString(book.type),10);
    //--- Convert all obtained symbols to lower case and replace the first letter from small to capital
       if(type.Lower())
          type.SetChar(0,ushort(type.GetChar(0)-0x20));
    //--- Replace all underscore characters with space in the resulting line
       StringReplace(type,"_"," ");
       
    //--- If it is a short entry, log the market depth data in the [index] Type Price V VR format
       if(short_entry)
         {
          res=StringFormat("%-8s%-11s%- *.*f Volume%- 5lld Real%- 8.2f",
                           num,type,dg+4,dg,book.price,book.volume,book.volume_real);
          Print(res);
         }
       /* Sample output:
          [00]    Sell        1.28598  Volume 100  Real 100.00 
       */
    //--- Otherwise
       else
         {
          //--- create a string describing all the data of the structure with indents and a given width of the header field 
          res=StringFormat("Market Book by %s %s:\n%s\n%s\n%s\n%s",symbol,num,
                           MqlBookInfoType(book,header_width,indent),
                           MqlBookInfoPrice(symbol,book,header_width,indent),
                           MqlBookInfoVolume(book,header_width,indent),
                           MqlBookInfoVolumeReal(book,header_width,indent)
                          );
          //--- Display the obtained string in the journal
          Print(res);
         }
       /* Sample output
          BoolInfo by GBPUSD [00]:
            Type:         Sell
            Price:        1.28588
            Volume:       100
            Volume Real:  100.00
       */
      }
    
    

    El modo principal aquí deberá mostrarse en el registro en una línea, ya que la profundidad de mercado no es una sola orden, y obtendremos una lista de estas órdenes en un array. En consecuencia, podemos imprimir este array en el registro utilizando la siguiente función:

    //+---------------------------------------------------------------------+
    //| Display the market depth entries in the journal in the short format |
    //+---------------------------------------------------------------------+
    void MqlBookInfoPrintShort(const string symbol,const MqlBookInfo &book_array[])
      {
       PrintFormat("Market Book by %s:",symbol);
       for(int i=0;i<(int)book_array.Size();i++)
          MqlBookInfoPrint(symbol,book_array[i],true,0,0,i);
      }
    
    

    La función obtiene una serie de órdenes para la profundidad de mercado y, en un ciclo a través del array, imprime todos los datos de la profundidad de mercado en el registro mediante una muestra corta.

    Script que demuestra cómo utilizar esta función y su resultado:

    void OnStart()
      {
    //--- Declare an array to store a snapshot of the market depth
       MqlBookInfo array[];
    //--- If unable to open the market depth and subscribe to its events, inform of that and leave
       if(!MarketBookAdd(Symbol()))
         {
          Print("MarketBookAdd failed, error: ",(string)GetLastError());
          return;
         }
    //--- If unable to obtain the market depth entries, inform of that and leave
       if(!MarketBookGet(Symbol(),array))
         {
          Print("MarketBookGet failed, error: ",(string)GetLastError());
          return;
         }
    //--- Print in the journal a snapshot of the market depth from the array in the form of strings
       MqlBookInfoPrintShort(Symbol(),array);
    
    //--- If unable to unsubscribe from the market depth, send an error message to the journal
       if(!MarketBookRelease(Symbol()))
          Print("MarketBookRelease failed, error: ",(string)GetLastError());
       
       /* Sample output:
          Market Book by GBPUSD:
          [00]    Sell        1.28674  Volume 100  Real 100.00 
          [01]    Sell        1.28668  Volume 50   Real 50.00  
          [02]    Sell        1.28666  Volume 20   Real 20.00  
          [03]    Sell        1.28664  Volume 10   Real 10.00  
          [04]    Buy         1.28657  Volume 10   Real 10.00  
          [05]    Buy         1.28654  Volume 20   Real 20.00  
          [06]    Buy         1.28653  Volume 50   Real 50.00  
          [07]    Buy         1.28646  Volume 100  Real 100.00 
       */
      }
    
    

    No obstante, a veces es posible que necesitemos mostrar los mismos datos, pero en forma de tabla. Para ello podemos utilizar la siguiente función:

    //+------------------------------------------------------------------------+
    //| Display the market depth entries in the journal in the tabular format  |
    //+------------------------------------------------------------------------+
    void MqlBookInfoPrintTable(const string symbol,const MqlBookInfo &book_array[],const uint header_width=0,const uint indent=0)
      {
       for(int i=0;i<(int)book_array.Size();i++)
          MqlBookInfoPrint(symbol,book_array[i],false,header_width,indent,i);
      }
    
    

    Script que demuestra cómo utilizar esta función y su resultado:

    void OnStart()
      {
    //--- Declare an array to store a snapshot of the market depth
       MqlBookInfo array[];
    //--- If unable to open the market depth and subscribe to its events, inform of that and leave
       if(!MarketBookAdd(Symbol()))
         {
          Print("MarketBookAdd failed, error: ",(string)GetLastError());
          return;
         }
    //--- If unable to obtain the market depth entries, inform of that and leave
       if(!MarketBookGet(Symbol(),array))
         {
          Print("MarketBookGet failed, error: ",(string)GetLastError());
          return;
         }
    //--- Print in the journal a snapshot of the market depth from the array in the form of strings
       MqlBookInfoPrintTable(Symbol(),array,14,2);
    
    //--- If unable to unsubscribe from the market depth, send an error message to the journal
       if(!MarketBookRelease(Symbol()))
          Print("MarketBookRelease failed, error: ",(string)GetLastError());
       
       /* Sample output:
          Market Book by GBPUSD [00]:
            Type:         Sell
            Price:        1.28627
            Volume:       100
            Volume Real:  100.00
          Market Book by GBPUSD [01]:
            Type:         Sell
            Price:        1.28620
            Volume:       50
            Volume Real:  50.00
          Market Book by GBPUSD [02]:
            Type:         Sell
            Price:        1.28618
            Volume:       20
            Volume Real:  20.00
          Market Book by GBPUSD [03]:
            Type:         Sell
            Price:        1.28615
            Volume:       10
            Volume Real:  10.00
          Market Book by GBPUSD [04]:
            Type:         Buy
            Price:        1.28610
            Volume:       10
            Volume Real:  10.00
          Market Book by GBPUSD [05]:
            Type:         Buy
            Price:        1.28606
            Volume:       20
            Volume Real:  20.00
          Market Book by GBPUSD [06]:
            Type:         Buy
            Price:        1.28605
            Volume:       50
            Volume Real:  50.00
          Market Book by GBPUSD [07]:
            Type:         Buy
            Price:        1.28599
            Volume:       100
            Volume Real:  100.00
       */
      }
    
    


    Conclusión

    Vamos a analizar la impresión de los campos de las cuatro estructuras: MqlDateTime, MqlTick, MqlRates y MqlBookInfo. Las funciones creadas retornarán una descripción de los campos de cada estructura en el formato "Encabezado-Datos" como una línea que puede enviarse a imprimir o usarse dentro de otra función. Todas las funciones serán independientes, estarán listas para usar y podrán usarse "tal cual" en nuestros programas. El siguiente paso será la estructura de las transacciones comerciales: su descripción y su muestra en el registro.


    Traducción del ruso hecha por MetaQuotes Ltd.
    Artículo original: https://www.mql5.com/ru/articles/12900

    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.
    Redes neuronales: así de sencillo (Parte 50): Soft Actor-Critic (optimización de modelos) Redes neuronales: así de sencillo (Parte 50): Soft Actor-Critic (optimización de modelos)
    En el artículo anterior, implementamos el algoritmo Soft Actor-Critic (SAC), pero no pudimos entrenar un modelo rentable. En esta ocasión, optimizaremos el modelo creado previamente para obtener los resultados deseados en su rendimiento.
    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í.
    Aproximación por fuerza bruta a la búsqueda de patrones (Parte V): Una mirada desde el otro lado Aproximación por fuerza bruta a la búsqueda de patrones (Parte V): Una mirada desde el otro lado
    En este artículo mostraré al lector un enfoque del trading algorítmico completamente distinto al que he tenido que llegar después de bastante tiempo. Obviamente, todo esto está relacionado con mi programa de fuerza bruta, que ha sufrido una serie de cambios que le permiten resolver varios problemas al mismo tiempo. No obstante, el artículo ha resultado lo más general y sencillo posible, por lo que también resultará apto para quienes no conocen el tema o simplemente están de paso.