
Del básico al intermedio: Arrays y cadenas (I)
Introducción
El contenido expuesto aquí tiene un propósito puramente didáctico. En ningún caso debe considerarse una aplicación final cuyo objetivo no sea el estudio de los conceptos expuestos.
En el artículo anterior, «Del básico al intermedio: Precedencia de operadores», hablamos un poco sobre las precauciones que debemos tomar al utilizar factorizaciones en nuestros códigos. No es raro encontrar códigos que aparentemente son correctos, pero que generan resultados extraños en ciertos momentos. Normalmente, este tipo de problema está directamente relacionado con la forma en que se realizan las factorizaciones. Aunque hacer que un código produzca resultados coherentes parece una tarea trivial, sin el conocimiento adecuado —como se demostró en aquel artículo—, las probabilidades de que falle catastróficamente aumentan a medida que se implementan factorizaciones cada vez más arbitrarias.
Como la parte teórica sobre cómo crear adecuadamente las factorizaciones puede resultar tediosa y aburrida, no nos detendremos en ella. Haremos las cosas de manera práctica. Sin embargo, te aconsejo, querido lector, que experimentes siempre que sea posible modificando un poco los códigos que estoy proporcionando e intentando crear factorizaciones diferentes o incluso un control de flujo de ejecución distinto al de los archivos anexos.
Hacer esto es muy importante para que empieces a practicar diferentes formas de conseguir un mismo resultado siguiendo un camino diferente, diseñado por ti mismo. Al realizar este tipo de ejercicio, que muchos consideran una pérdida de tiempo, estarás practicando de la mejor manera posible. Esto se debe a que, en el anexo, tendrás un código que funciona y genera un tipo de resultado concreto. El desafío consiste en crear un código diferente que produzca el mismo resultado. Con la práctica, te prepararás para crear tus propias soluciones, incluso si al principio no te parecen tan profesionales.
Muy bien, dada esta pequeña introducción sobre cómo puedes estudiar el trabajo con operadores, pasemos al tema que se abordará en este artículo. Hay un requisito previo para este artículo. Para cumplirlo, necesitas tener pleno dominio del tema relacionado con la declaración y uso de variables y constantes. Aunque el tema que trataremos aquí tiene mucho más que ver con los operadores que con cualquier otra cosa, para comprender lo que se explicará es fundamental tener conocimientos y dominio sobre cómo declarar, inicializar y utilizar variables y constantes. A continuación, hablaremos sobre algunos tipos de datos especiales. En esta sección, haré todo lo posible por no limitarnos únicamente a la parte teórica. Este tema, junto con las reglas de precedencia vistas en el artículo anterior, es probablemente uno de los más complicados, especialmente a medida que profundicemos en él. Sin embargo, en este primer momento trataremos los aspectos más simples posibles para presentar el tema. No obstante, es algo realmente necesario antes de abordar un tema aún más complejo. Así que, como de costumbre, vamos al grano.
Arrays y cadenas
Sin duda, este es uno de los temas que más confusión y abandono provoca entre los nuevos programadores al usar lenguajes tipados. Esto se debe a que los lenguajes no tipados, como Python y JavaScript, gestionan este tipo de cosas de manera casi transparente, por lo que el programador no necesita preocuparse por definirlas: simplemente las utiliza.
Por otro lado, lenguajes como C y C++ complican mucho este tema, precisamente por la forma en que estas dos entidades son tratadas dentro de dichos lenguajes. En este caso, no se tratan como dos entidades separadas, sino como una sola, y dependiendo de cómo se trabaje con ellas, puede surgir una tercera o incluso una cuarta entidad dentro de este mismo tema. Es decir, una complicación que dificulta aún más el trabajo de los nuevos programadores.
Sin embargo, en MQL5 nos encontramos en un punto intermedio entre lo que serían lenguajes tipados como C y C++ y lenguajes no tipados como Python o JavaScript. ¿Por qué digo esto? La razón es que, a diferencia de C y C++, donde podemos ignorar el tipo de dato presente en un array y, en algunos casos, también en cadenas, en MQL5 esto no es posible. Al menos no sin realizar ciertas manipulaciones. Esto hace que el aprendizaje sea un poco más sencillo. No obstante, sin una base sólida y bien consolidada, se vuelve prácticamente imposible crear ciertos tipos de manipulación de datos en MQL5 de la misma forma sencilla en que se haría en C y C++. Sin embargo, a pesar de esto, es mucho más difícil que, como programador principiante, termines creando algo en MQL5 que escape de tu control. A diferencia de lo que ocurre en C y C++, donde cualquier pequeño error puede convertirse en una bomba de tiempo lista para explotar ante el más mínimo descuido.
Pero, entre nosotros, aprender MQL5 es considerablemente más fácil que aprender a hacer lo mismo en C o C++. Por eso, me alegra mucho compartir y traducir mi conocimiento de C y C++ para que pueda utilizarse en MQL5. Y, de paso, tal vez pueda enseñar a alguno de ustedes a alcanzar un buen nivel de conocimientos de programación.
Pero basta de charla, empecemos con nuestro tema principal. Para ello, aclararemos primero una cosa. En cierto modo, los arrays y las cadenas son la misma cosa. Esto se refiere a los datos presentes en la memoria. Para ser exactos, una cadena no es más que un array, aunque es un array especial. Lo llamo especial debido a una característica que solo existe en las cadenas, pero no en cualquier otro tipo de array. Este detalle es un marcador que nos indica dónde termina la cadena.
Para ilustrarlo, haré un pequeño paralelo con otros lenguajes de programación, algo simple, solo para aclarar de qué estamos hablando. Algunos lenguajes de programación, como los basados en BASIC —sí, el viejo y antiguo BASIC que surgió en la época del MS-DOS—, utilizan como primer carácter de la cadena un dato que indica el número de caracteres o valores presentes en dicha cadena. Este enfoque permite usar cualquier carácter dentro de la cadena, ya que su tamaño siempre se especifica en el primer carácter. Sin embargo, este primer carácter, que puede ocupar más de un byte, nunca será visible para el usuario. Es invisible y solo puede detectarse mediante el código. Esto nos permite usar cualquier carácter o valor numérico dentro de la cadena. Sin embargo, esta libertad tiene un límite: la capacidad en términos de bits del primer carácter, donde se almacena la longitud de la cadena.
Los lenguajes basados en C y C++ utilizan un método diferente. En este caso, se emplea un carácter o valor especial que indica dónde termina la cadena. En realidad, el tipo string no existe en C y C++. Normalmente, el carácter o valor utilizado es un null o cero. Cuando este valor aparece en la cadena, señala su final. Por un lado, esto permite crear una cadena que ocupe toda la memoria disponible del equipo. Por otro lado, nos limita a la hora de usar cierto valor dentro de una cadena.
Al estar basado en C y C++, MQL5 también utiliza este mismo enfoque. Sin embargo, a diferencia de estos últimos, en MQL5 existe un tipo llamado string. Por esta razón, no podemos hacer ciertas cosas usando exclusivamente el tipo string en cualquier código. Lo ideal sería utilizar un array. Sin embargo, al hacerlo, surgen otros inconvenientes. Afortunadamente, la biblioteca de MQL5 es lo suficientemente extensa como para sortear dichos inconvenientes. En algunos casos, de manera sencilla; en otros, de forma un poco más complicada.
¿Por qué estoy hablando de esto? La razón es simple: si no comprendes adecuadamente este tipo de modelado, te quedarás limitado y atrapado en un número finito de opciones, por lo que no podrás realizar ciertas tareas. Especialmente si requieren un nivel más avanzado en términos de programación. No es raro ver a personas quejarse de que no se puede hacer esto o aquello con MQL5. Pero, cuando se analiza el nivel de conocimiento de esos programadores, se observa que están completamente atrapados en ciertos conceptos e ideas que les impiden ir más allá de lo que ofrece la biblioteca estándar.
No se trata de que usar la biblioteca estándar implique una falta de conocimiento. Todo lo contrario. Pero si no comprendes cómo están realmente relacionadas las cosas, siempre te estarás quejando de que no puedes hacer lo que te gustaría.
Así que, querido lector, comprende lo siguiente: los arrays son, por así decirlo, una cadena genérica donde se puede colocar cualquier cosa. Una cadena, por su parte, es una construcción que tiene limitaciones y, en muchos casos, restricciones. Si realmente quieres hacer algo y no conoces las limitaciones o restricciones de un array o una cadena, no lo conseguirás. Tal vez lo que complica el uso de arrays es el hecho de que una cadena es un array del tipo uchar o ushort, dependiendo del código de caracteres que estemos utilizando. Sin embargo, un array puro puede ser de cualquier tipo, desde una clase hasta un booleano. Esto realmente complica las cosas a quienes están comenzando a aprender programación. Pero como quiero mostrarte un camino que puedas seguir, empezaremos con el más básico. Es decir, empezaremos con las cadenas.
Datos del tipo cadena (Strings)
Cuando creamos o declaramos algo como una cadena, le estamos indicando al compilador que queremos crear un array. Pero no un array cualquiera, sino uno especial, donde habrá un carácter o valor que indicará dónde termina la cadena. En un sentido más profundo, al usar una variable del tipo string, no es necesario preocuparse por la asignación de memoria. Este trabajo lo realiza el código automáticamente, ajustando la cantidad de memoria utilizada según sea necesario.
Esto nos permite hacer muchas cosas sin demasiadas complicaciones. Por otro lado, existen algunas limitaciones, pero no nos centraremos en ellas ahora. En su lugar, nos centraremos en lo que sí se puede hacer. Recuerda que para dominarlos tendrás que practicar mucho. Aquí solo tocaremos la superficie. Así que comencemos con nuestro primer código, que se muestra a continuación.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. string sz0 = "Hello world !!!", 07. sz1 = "My first operation with strings...", 08. sz2; 09. 10. sz2 = sz0 + sz1; 11. 12. Print(sz2); 13. } 14. //+------------------------------------------------------------------+
Código 01
Ahora presta atención, querido lector. Aquí estamos creando tres variables del tipo cadena de caracteres. Dos de ellas se declaran e inicializan en el momento de su creación. La tercera, por su parte, recibe la unión de las otras dos, creando así una nueva cadena. En la línea 12 simplemente imprimimos el resultado en el terminal, como puedes ver a continuación.
Imagen 01
El detalle clave aquí es que se observa que en la línea 10 se está utilizando un operador de suma. Este es uno de los pocos, si no el único, operador que, por defecto, realiza algo específico con un tipo cadena. En este caso, une una cadena con otra. Sin embargo, ten mucho cuidado con este concepto, porque los operadores no siempre actúan como esperamos. Este tema se tratará y explicará en mayor detalle en otro momento. Por ahora, simplemente ten precaución al trabajar con código que no conoces.
Bien, tenemos una frase que se muestra en el terminal. Pero, ¿qué sucede si queremos separar las cosas en líneas? ¿Cómo podríamos hacerlo? Bueno, querido lector, una forma sería hacer dos llamadas al procedimiento Print. Sin embargo, si prefieres incluir un salto de línea directamente en la cadena, puedes hacerlo utilizando alguno de los marcadores especiales.
Existen varios marcadores especiales que pueden aparecer en una cadena. Todos ellos, al menos los que se pueden utilizar en MQL5, derivan de C y C++. Así que, si quieres agregar un salto de línea en algún punto, basta con añadir lo que se muestra a continuación.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. string sz0 = "Hello world !!!", 07. sz1 = "My first operation with strings...", 08. sz2; 09. 10. sz2 = sz0 + "\n" + sz1; 11. 12. Print(sz2); 13. } 14. //+------------------------------------------------------------------+
Código 02
Aquí podemos ver uno de estos marcadores en acción. Estos marcadores, como "\n", se conocen como secuencias de escape. Si investigas, encontrarás muchos de estos pequeños códigos. Al incluir este tipo de marcador en la cadena, el comportamiento del código cambiará y obtendremos un resultado como el que se muestra a continuación.
Imagen 02
Sin embargo, este tipo de marcador no solo sirve para eso. Por ejemplo, podemos omitir parte de un texto si usamos el marcador NULL, como puedes observar en el siguiente ejemplo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. string sz0 = "Hello world !!!", 07. sz1 = "My first operation \0with strings...", 08. sz2; 09. 10. sz2 = sz0 + "\n" + sz1; 11. 12. Print(sz2); 13. } 14. //+------------------------------------------------------------------+
Código 03
Al ejecutar este código 03, obtendremos la salida mostrada en la siguiente imagen en el terminal de MetaTrader 5.
Imagen 03
Observa lo fácil y sencillo que resulta. Pero no solo eso, también podemos crear cadenas con valores numéricos. Para ello, necesitamos recurrir a funciones de la biblioteca estándar de MQL5, lo que facilita la conversión. Tal vez en el futuro explique cómo puedes crear tu propia versión para un propósito similar. Sin embargo, eso lo dejaremos para otro momento. Usando las funciones de conversión disponibles en MQL5, podemos convertir números a cadenas y cadenas a números.
Esta operación es muy útil y necesaria en muchos casos, especialmente a la hora de crear sistemas de análisis de datos. A continuación, se muestra un ejemplo sencillo de ello.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. int i_value = 65538; 07. double d_value = 0.25; 08. color cor = clrRed; 09. string sz0; 10. 11. sz0 = "Color: " + ColorToString(cor) + "\nInteger: " + IntegerToString(i_value) + "\nDouble: " + DoubleToString(d_value); 12. 13. Print(sz0); 14. } 15. //+------------------------------------------------------------------+
Código 04
Al ejecutar este código 04, verás algo similar a lo que se muestra en la siguiente imagen.
Imagen 04
Como podemos observar, hemos logrado crear una cadena con diversas informaciones. Sin embargo, en algunos casos necesitamos que el formato de la cadena que estamos creando sea muy específico. Esto puede deberse al tipo de información que queremos mostrar o a la necesidad de aplicar un formateo concreto a los datos que se van a utilizar. En este caso, debemos hacer las cosas de manera algo diferente a como se ha mostrado hasta ahora. Pero, debido a la naturaleza de lo que veremos a continuación, creo que será mejor tratarlo en un nuevo apartado. De esta forma, te resultará más fácil estudiar y practicar los conocimientos presentados aquí.
Formateo de cadenas
Cuando hablamos de formatear texto, muchas personas piensan en los editores de texto. Sin embargo, cuando nos referimos a este concepto en el contexto de la programación, nos referimos al hecho de que cierta información debe cumplir criterios específicos antes de ser utilizada o impresa.
Dichos criterios constituyen lo que se conoce como el formateo de una cadena. A primera vista, este tipo de operación es relativamente simple y fácil de usar, permitiéndonos crear cadenas con información muy específica de una manera bastante sencilla. Sin embargo, hay ciertos aspectos que, como programador, debes tener en cuenta. Entre estos aspectos está el uso y la construcción de los parámetros de salida. Si están bien configurados, estos parámetros facilitan mucho la vida de un programador, incluso si es principiante, ya que reemplazan en gran medida el tipo de montaje que vimos en el tema anterior. Al mismo tiempo, permiten ajustar y ofrecer una buena flexibilidad para construir cadenas bien definidas.
De acuerdo, es probable que ya hayas visto en algún código el uso del procedimiento de la biblioteca PrintFormat. Este procedimiento nos permite mostrar en el terminal de MetaTrader 5 algún tipo de información con formato, generalmente una cadena. Sin embargo, no siempre queremos o resulta deseable enviar esa información o cadena al terminal. Muchas veces queremos o necesitamos usar esa información en otro contexto, como almacenarla en un archivo, lanzarla o utilizarla en un objeto presente en el gráfico. En estos casos, el procedimiento PrintFormat no siempre es útil. Afortunadamente, existe una función que se adapta de forma sublime a estas necesidades: StringFormat.
La función StringFormat utiliza el mismo tipo de parametrización que PrintFormat. Sin embargo, a diferencia de PrintFormat, su salida puede ser dirigida a una cadena. Esto hace que su uso sea realmente interesante en una amplia variedad de situaciones.
Teniendo esto en cuenta, podemos generar una salida basada en lo que vimos en el código 04, pero en un estado ya formateado. Es posible que en este momento te sientas algo confundido respecto a algunos de los parámetros involucrados. Por eso, te recomiendo que estudies cada uno de los parámetros con calma. Revisa la documentación de la sección relacionada con el procedimiento PrintFormat. Allí encontrarás una serie de detalles que explican cómo crear el formato de la cadena que deseas obtener en la salida. Para ilustrarlo, vamos a modificar el código 04 para que quede formateado. Así obtendremos el código que se muestra a continuación.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. int i_value = 65538; 07. double d_value = 0.25; 08. color cor = clrRed; 09. string sz0; 10. 11. sz0 = StringFormat("Color: %s\nInteger: %d\nDouble : %.2f", ColorToString(cor), i_value, d_value); 12. 13. Print(sz0); 14. } 15. //+------------------------------------------------------------------+
Código 05
Cuando ejecutes este código 05, observarás en el terminal de MetaTrader 5 un resultado similar al de la imagen siguiente.
Imagen 05
Observa las diferencias entre las imágenes 04 y 05. Aunque ambos casos utilizan algo muy similar, la información de la imagen 05 está en un formato que se definió específicamente en nuestro código, concretamente durante la implementación de la línea 11. Podrías argumentar que este tipo de ajuste no es necesario aquí, pero piensa en un escenario donde necesites trabajar con valores hexadecimales. Muchos programas suelen utilizar este tipo de valores en situaciones donde se manejan bits. Entonces, si quisieras visualizar este tipo de dato para verificar que todo ocurre como se espera, ¿cómo lo harías?
La forma de hacerlo puede variar, pero, en general, se puede usar el formato aplicado en el código 05 para visualizar valores hexadecimales. Algunos incluso podrían sugerir que sería mejor crear un código específico para esta tarea. Sin embargo, en mi opinión, se trata más de una cuestión de preferencias personales que de una necesidad real. En cualquier caso, cada programador es libre de tomar sus propias decisiones. Pero, como tú, querido lector, estás comenzando en la programación, lo ideal es que te apoyes en las funciones y procedimientos proporcionados por la biblioteca estándar. En este caso, usaremos la función StringFormat para crear la representación de los valores hexadecimales que se mostrarán posteriormente. Para lograrlo, seguiremos usando el código 05, pero modificaremos la forma en que se formatee la cadena que se creará. Esto es muy fácil y directo: basta con reemplazar la línea 11 por la línea que se muestra a continuación.
sz0 = StringFormat("Color: 0x%X\nInteger: 0x%X\nDouble : %.2f", cor, i_value, d_value);
Al ejecutar nuevamente el código tras realizar este cambio, el resultado será el que se muestra a continuación.
Imagen 06
Es interesante, ¿verdad? Sin embargo, aquí tenemos un pequeño problema, por eso mencioné que debes prestar atención a los detalles relacionados con el formateo de cadenas. El problema en este caso está en el valor del color. Observa que se muestra en formato hexadecimal, pero este valor en la imagen 06 no indica necesariamente que el color es rojo. Este valor podría representar otro color. Recuerda que el formato del color es "RGB" y, en algunos casos, "ARGB". Por lo tanto, simplemente observando este valor no podemos determinar con precisión de qué se trata. Sin embargo, con un pequeño ajuste, podemos cambiar el valor para que sea realmente representativo. Para ello, basta con modificar el código tal como se muestra a continuación.
sz0 = StringFormat("Color: 0x%06X\nInteger: 0x%X\nDouble : %.2f", cor, i_value, d_value);
Al ejecutar el código con esta modificación, obtendrás un resultado similar al de la siguiente imagen.
Imagen 07
¡Espera un momento! Ese no es el color rojo, desde luego. Lo que aparece ahí es el color azul. ¿Qué ocurrió aquí? ¿Será que el problema radica en que estamos añadiendo algunos ceros antes del valor que se muestra para crear el formato deseado? Más o menos, pero no es exactamente como podrías haber imaginado al principio. Lo que realmente sucedió aquí es algo un poco más complejo de explicar sin mostrar otro ejemplo que aplique el mismo concepto de formateo al valor del color para presentarlo en formato hexadecimal.
Para ilustrar lo ocurrido, vamos modificar el valor de la variable ""i_value"" y pedir que se formatee de la misma manera que formateamos el valor del color. Es decir, podría haber algunos ceros delante, dependiendo del valor que se deba mostrar. Para mayor claridad, observa el código que se muestra a continuación.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. int i_value = 0xF; 07. double d_value = 0.25; 08. color cor = clrRed; 09. string sz0; 10. 11. sz0 = StringFormat("Color :\t0x%06X\t=>\t%s\n" + 12. "Integer:\t0x%06X\t=>\t%d\n" + 13. "Double :\t%.2f", cor, ColorToString(cor), i_value, i_value, d_value); 14. 15. Print(sz0); 16. } 17. //+------------------------------------------------------------------+
Código 06
Cuando ejecutes este código 06, verás algo similar a la imagen que se muestra a continuación.
Imagen 08
Aquí he dividido las cosas para que puedas entender lo que quiero mostrarte. Observa que en las líneas 11 y 12 del código imprimiremos dos valores. Esto se hace para que veas por qué el valor hexadecimal del color se muestra de esta manera. Verás que el valor de i_value parece correcto. Entonces, sustituiremos el valor de i_value por uno mayor. Como se indica en la línea siguiente, al realizar esta modificación el resultado sigue siendo coherente, tal como lo verás en la imagen siguiente.
int i_value = 0xDA09F;
Imagen 09
Es decir, la formatación funciona perfectamente. Pero ¿por qué no muestra el valor hexadecimal del color de forma correcta? La razón es que, aunque el formato esperado es RGB, internamente se utiliza BGR. Es decir, los valores están invertidos respecto a lo que imaginamos. Por eso, el valor que aparece en el campo hexadecimal parece incorrecto, pero es correcto. ¿Podemos cambiar esto y presentar los valores de una manera que se corresponda con nuestras expectativas? Sí, querido lector, podemos hacerlo. Gracias al conocimiento mostrado en los artículos anteriores, lograrlo resulta bastante sencillo. A continuación se muestra un posible código que cumple este objetivo.
01. //+------------------------------------------------------------------+ 02. #property copyright "Daniel Jose" 03. //+------------------------------------------------------------------+ 04. void OnStart(void) 05. { 06. int i_value = 0xDA09F; 07. double d_value = 0.25; 08. color cor = clrRoyalBlue; 09. string sz0; 10. 11. sz0 = StringFormat("Color :\t0x%06X\t=>\t%s\n" + 12. "Integer:\t0x%06X\t=>\t%d\n" + 13. "Double :\t%.2f", cor, ColorToString(cor), i_value, i_value, d_value); 14. 15. Print(sz0); 16. PrintFormat("Color value in hexadecimal (RGB format): %s", ColorToStrHex(cor)); 17. } 18. //+------------------------------------------------------------------+ 19. string ColorToStrHex(const color arg) 20. { 21. return StringFormat("0x%02X%02X%02X", (arg & 0xFF), ((arg >> 8) & 0xFF), (arg >> 16) & 0xFF); 22. } 23. //+------------------------------------------------------------------+
Código 07
Observa que estamos creando una pequeña función en la línea 19. Esta función es bastante sencilla de comprender, basándose en los conceptos explicados hasta ahora en mis artículos. Al ejecutarla, obtendremos como retorno una cadena en formato hexadecimal, pero esta vez el valor se mostrará como esperábamos al analizar el color en formato RGB. Al ejecutar este código 07, verás en el terminal algo similar a la imagen siguiente.
Imagen 10
Ahora observa algo interesante. En la primera línea de esta imagen 10 tenemos el valor del color expresado. Sin embargo, el valor hexadecimal no se corresponde con lo que esperábamos encontrar. Pero si miramos la última línea de esta misma imagen, veremos que allí sí aparece el valor que esperábamos encontrar al interpretar el color como RGB. Es decir, los valores que aparecen en la primera línea están representados en orden inverso en el formato hexadecimal. Sin embargo, podemos reorganizarlos para que estén en el orden esperado. Un detalle importante: el valor que se muestra en la última línea de la imagen 10 no representa el color que se informa en la línea ocho del código 07. Esta representación muestra simplemente el valor esperado basado en los resultados devueltos por la función ColorToString. Por lo tanto, querido lector, no te confundas. Cambié el color para que la información tuviera sentido y pudiera explicarse correctamente.
Consideraciones finales
En este artículo se mostró la primera parte de algo mucho más profundo y avanzado de lo que podría parecer a simple vista. Soy consciente de que muchos pueden estar algo confundidos respecto a lo que se explicó y presentó aquí. Pero te aseguro, querido y estimado lector, que si comienzas a estudiar este material con atención y practicas lo suficiente, podrás desarrollar aplicaciones interesantes desde el punto de vista de la comunicación con el usuario.
Aunque lo visto aquí es solo un breve adelanto de lo que se puede hacer, ya tienes bastante material para estudiar y practicar. En el próximo artículo abordaremos contenido un poco más avanzado que, sin duda, será fundamental para explicar otros temas que veremos más adelante. Espero que te diviertas con los archivos incluidos en el anexo y nos vemos en el próximo artículo.
Traducción del portugués realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/pt/articles/15441





- 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