Estructuras en MQL5 y métodos para imprimir sus datos
Contenido
- Introducción
- Estructura MqlDateTime
- MqlDateTime, métodos de impresión
- Funciones para trabajar con los datos de la estructura MqlDateTime
- Funciones auxiliares
- Año en la estructura MqlDateTime
- Mes en la estructura MqlDateTime
- Día en la estructura MqlDateTime
- Horas en la estructura MqlDateTime
- Minutos en la estructura MqlDateTime
- Segundos en la estructura MqlDateTime
- Día de la semana en la estructura MqlDateTime
- Número del día en el año en la estructura MqlDateTime
- Ejemplos de uso
- Estructura MqlTick
- MqlTick, métodos de impresión
- Funciones para trabajar con los datos de la estructura MqlTick
- Funciones auxiliares
- Tiempo en la estructura MqlTick
- Precio Bid en la estructura MqlTick
- Precio Ask en la estructura MqlTick
- Precio de la última transacción (Last) en la estructura MqlTick
- Volumen para el precio Last en la estructura MqlTick
- Tiempo en milisegundos en la estructura MqlTick
- Banderas de ticks en la estructura MqlTick
- Volumen del precio Last con precisión aumentada en la estructura MqlTick
- Ejemplo de uso
- Estructura MqlRates
- MqlRates, métodos de impresión
- Funciones para trabajar con los datos de la estructura MqlRates
- Time
- Open
- High
- Low
- Close
- TickVolume
- Spread
- RealVolume
- Ejemplos de uso
- Estructura MqlBookInfo
- MqlBookInfo, métodos de impresión
- Funciones para trabajar con los datos de la estructura MqlBookInfo
- Tipo de orden en la estructura de la profundidad de mercado MqlBookInfo
- Precio de la orden en la estructura de la profundidad de mercado MqlBookInfo
- Volumen de la orden en la estructura de la profundidad de mercado MqlBookInfo
- Volumen con precisión aumentada
- Ejemplos de uso
- Conclusión
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:
- MqlDateTime se usa para representar la fecha y la hora;
- MqlParam nos permite transmitir los parámetros de entrada al crear un identificador de indicador usando la función IndicatorCreate();
- MqlRates proporciona información sobre los datos históricos que contienen el precio, el volumen y el spread;
- MqlBookInfo se utiliza para obtener la información mostrada en la profundidad de mercado (ventana de cotizaciones);
- MqlTradeRequest sirve para crear una solicitud comercial al realizar operaciones comerciales;
- MqlTradeCheckResult permite comprobar una solicitud comercial preparada antes de enviarla;
- MqlTradeResult contiene la respuesta del servidor comercial a una solicitud comercial enviada por la función OrderSend();
- MqlTradeTransaction contiene una descripción de la transacción comercial;
- MqlTick sirve para obtener rápidamente la información más popular sobre los precios actuales.
- Las estructuras del Calendario Económico se utilizan para recibir información sobre los eventos del Calendario Económico que llegan a la plataforma MetaTrader 5 en tiempo real. Las funciones de Calendario Económico nos permiten analizar indicadores macroeconómicos inmediatamente después de la publicación de los nuevos informes, pues los valores actuales se transmiten directamente desde la fuente sin ninguna demora.
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:
- mostrar datos en formato corto (Día de la semana, Mes, Día, Año, hora);
- 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
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso