Português
preview
Del básico al intermedio: Subventanas (III)

Del básico al intermedio: Subventanas (III)

MetaTrader 5 — Ejemplos |
14 0
CODE X
CODE X

Introducción

En el artículo anterior, Del nivel básico al intermedio: Subventanas (II), se mostraron algunos fallos y problemas que podemos llegar a tener al intentar utilizar un indicador en una subventana. Y, más que eso, también vimos cómo MetaTrader 5 fue implementado de forma bastante ingeniosa para gestionar los indicadores. Todo ello con el fin de evitar posibles conflictos entre la información que dichos indicadores nos proporcionarán durante su uso.

Como se demostró en el artículo anterior, siempre que tengamos los conocimientos necesarios, podemos hacer muchas cosas dentro de MetaTrader 5. Y todo ello utilizando MQL5 puro y simple. Sin ningún tipo de florituras ni cosas sin pies ni cabeza. Como muchos ya habrán notado, no me gusta demasiado seguir una lógica rígida. Me gusta ir más allá y observar aquello que muchos ni siquiera imaginan que se puede hacer o que puede llegar a ocurrir. Por eso, sé que muchos de ustedes ya deben estar deseando empezar a implementar cosas más complejas. Pero, como diría un sabio, vayamos con calma.

Así que vamos a centrarnos en lo que se explicará en este artículo, dejando de lado cualquier cosa que pueda distraernos durante la lectura. Porque aquí veremos que no todo es como muchos imaginan.


Subventanas (III)

Las subventanas son bastante útiles, sobre todo cuando se utilizan correctamente, ya que nos permiten organizar una serie de cosas de una forma muy sencilla, fácil y práctica. Sin embargo, por simplicidad, dentro de MetaTrader 5 estamos limitados a un único modo de presentación de las subventanas. Aunque esto pueda resultar algo restrictivo en cuanto al tipo de cosas que podemos llegar a construir, en las manos adecuadas esta limitación es solo un pequeño detalle, ya que podemos trabajar dentro de ella y hacer que sea precisamente eso: un simple detalle y no una verdadera limitación, sino un desafío que debemos superar.

Bien, parece que la verdadera limitación es nuestra imaginación y nuestro grado de conocimiento sobre lo que realmente podemos hacer dentro de MQL5 para controlar MetaTrader 5 de una determinada manera. Así que vamos a empezar por el escenario más sencillo, que es precisamente cuando le indicamos al compilador de MQL5 que queremos utilizar una subventana.

Esto se vio al final del artículo anterior. Sin embargo, allí solo se mostró una pequeña parte de lo que realmente podemos hacer. Para que todo quede bien claro, tenemos que volver a un punto mucho más sencillo que el visto anteriormente. De este modo, la forma más básica de indicarle a MetaTrader 5 que queremos utilizar una subventana, o incluso crear una, consiste simplemente en utilizar el código que aparece a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. #property indicator_separate_window
07. //+------------------------------------------------------------------+
08. int OnInit(void)
09. {
10.     return INIT_SUCCEEDED;
11. };
12. //+------------------------------------------------------------------+
13. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
14. {
15.     return rates_total;
16. };
17. //+------------------------------------------------------------------+

Código 01

Este código 01 tiene como único y verdadero objetivo crear una subventana en cualquier gráfico. Para hacerlo, utilizamos la línea seis, donde modificamos la propiedad del propio indicador para que se coloque en una subventana. Aunque esta es la manera más sencilla de hacerlo, no es la única, como veremos dentro de poco.

Pero, antes de verlo, necesito explicar otra cuestión muy importante. Y tú puedes, y deberías, probarlo utilizando este código 01 mostrado anteriormente. La cuestión es precisamente que, cada vez que añada una instancia de este código 01 al gráfico, se creará una nueva subventana. Y, dependiendo del tipo de tarea que este indicador tenga que realizar, estas instancias adicionales pueden terminar generando muchos más problemas de los que ayudan a resolver.

Y como, en la mayoría de los casos, podemos querer poner estos códigos a disposición de otros operadores que realmente no saben cómo deben utilizarlos, no es raro que estos otros operadores coloquen el indicador más de una vez en el mismo gráfico, generando así muchos más problemas de los que tú, como desarrollador del código, habías previsto.

Cuando nuestro código se coloca en una ventana principal, MetaTrader 5 utiliza a menudo, de forma bastante ingeniosa, los datos de configuración que empleará nuestro código para comprobar si estamos intentando añadir una instancia que ya está presente en el gráfico. Si es así, la nueva instancia que estamos intentando crear será descartada. Sin embargo, si MetaTrader 5 detecta que realmente estamos creando una instancia completamente nueva y diferente, permitirá que aparezca una nueva instancia de nuestro código en el gráfico.

Bueno, básicamente eso es lo que ocurre. Sin embargo, cuando utilizamos un código que crea o genera una nueva subventana en el gráfico, este mecanismo utilizado por MetaTrader 5 no entra en acción. De ahí que puedas colocar varias instancias del código 01 en el mismo gráfico, generando así una cascada de subventanas en el gráfico del símbolo actual.

Bien, pero ¿y si no queremos que esto ocurra? ¿Cómo podemos evitar que el código que ya se está ejecutando en el símbolo actual cree nuevas subventanas? Para ello tendremos que recurrir a MQL5 para analizar qué tipo de situación existe en el gráfico actual. Recuerda que lo que veremos aquí es solo lo más básico de algo mucho más amplio.

Para empezar, necesitamos una forma de comprobar si nuestro código está presente o no en el gráfico. Para ello, debemos añadir algo muy concreto a nuestro código. Esto puede verse en el código que aparece a continuación, que sería una especie de actualización del código 01 que vimos hace poco.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. #property indicator_separate_window
07. //+------------------------------------------------------------------+
08. int OnInit(void)
09. {
10.     IndicatorSetString(INDICATOR_SHORTNAME, "Test 123.");
11.     
12.     return INIT_SUCCEEDED;
13. };
14. //+------------------------------------------------------------------+
15. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
16. {
17.     return rates_total;
18. };
19. //+------------------------------------------------------------------+

Código 02

Ahora observa lo siguiente, mi estimado lector. En este código 02 añadimos la llamada que aparece en la línea diez. Esta llamada tiene un objetivo muy especial. Hará que nuestro código tenga un nombre dentro del gráfico. El nombre en cuestión es el que vemos entre comillas dobles. Naturalmente, deberías intentar que este nombre sea único, ya que será precisamente el nombre que comprobaremos después para determinar si nuestro código está presente o no en el gráfico.

Pero espera un momento. ¿No sería más fácil utilizar el nombre del ejecutable para comprobar si tenemos o no una instancia de nuestro código en el gráfico? Bueno, en teoría sí, sería más sencillo. Sin embargo, existe un problema. Cuando compilamos el código, este puede tener un determinado nombre como nombre del ejecutable. Pero ese nombre podría entrar en conflicto con el de otros archivos, ya que es posible que tú distribuyas tu código a otras personas. Y, en ese momento, el nombre del ejecutable podría modificarse, echando por tierra cualquier intento de comprobar si nuestro código ya está presente o no en el gráfico actual.

Sin embargo, utilizando esta llamada que aparece en la línea diez de este código 02 evitamos este tipo de problema, ya que, una vez compilado, difícilmente un usuario podrá modificar la cadena que estamos definiendo aquí. Recuerda que puedes utilizar cualquier valor, preferiblemente uno que consideres único. Y esta es la parte importante: que esta cadena sea única.

Bien, pero ¿cómo nos ayudará esta cadena a saber si ya tenemos o no una instancia abierta en el gráfico actual? Bueno, ahora viene la parte divertida.

Partiendo del hecho de que esta cadena nos permite identificar si nuestro código está presente o no en el gráfico, añadiremos un código para comprobarlo. Pero, antes de hacerlo, necesito que entiendas otra cosa. Esto se hace utilizando el código que aparece a continuación.

1. //+------------------------------------------------------------------+
2. #property copyright "Daniel Jose"
3. //+------------------------------------------------------------------+
4. void OnStart(void)
5. {
6.     Print(ChartGetInteger(0, CHART_WINDOWS_TOTAL));  
7. }
8. //+------------------------------------------------------------------+

Código 03

Este código simplemente nos dirá cuántas ventanas existen actualmente en el gráfico en el que se ejecute. Presta atención a esto, mi estimado lector, porque necesito que entiendas muy bien adónde vamos a llegar dentro de poco. Al ejecutar este código 03, obtendremos como respuesta algo parecido a lo que se muestra a continuación.

Imagen 01

Ahora, al añadir algunas subventanas, tendremos lo que se muestra en la imagen siguiente.

Imagen 02

Hmm, interesante. Entonces podemos utilizar MQL5 para saber cuántas subventanas existen en un gráfico. Pero ¿qué ocurre si queremos saber qué tipo de indicador está presente allí? Bueno, para ello modificamos el código 03 y obtenemos algo parecido a lo que se muestra a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     for (int c0 = 0; c0 < (int)(ChartGetInteger(0, CHART_WINDOWS_TOTAL)); c0++)
07.         for (int c1 = (ChartIndicatorsTotal(0, c0) - 1); c1 >= 0; c1--)
08.             PrintFormat("In the sub window [%d] was found this indicator >>%s<<", c0, ChartIndicatorName(0, c0, c1));
09. }
10. //+------------------------------------------------------------------+

Código 04

Ahora, cuando ejecutamos este código 04, el resultado es el que podemos ver a continuación.

Imagen 03

Observa ahora algo interesante en esta imagen 03. En ella podemos ver el nombre de todos los indicadores presentes en el gráfico, incluida la ventana en la que se muestra cada uno de ellos. Sin embargo, si consultas la lista de indicadores, verás lo que aparece en la imagen siguiente.

Imagen 04

Lo que podemos observar en la imagen anterior es bastante interesante. Fíjate en que, en esta imagen 04, tenemos los nombres de los ejecutables que están en el gráfico. Sin embargo, el nombre de cada indicador aparece de forma diferente en la imagen 03. Por tanto, creo que empieza a quedar claro que el nombre del ejecutable no tiene por qué estar necesariamente vinculado al nombre del indicador. De hecho, este tipo de recurso simplifica bastante ciertas tareas. Y sí, deberías agradecer al equipo que ideó e incorporó este tipo de funcionalidad en MetaTrader 5, porque realmente nos permitirá hacer algunas cosas en el futuro. Sin embargo, mi objetivo aquí es precisamente ayudarte a comprender estos pequeños detalles y, de esta forma, ayudarte a crear tus propias soluciones.

Bien, pero ¿qué ocurriría si no hubiéramos utilizado aquella línea diez del código 02? Bueno, mi estimado lector, para mostrarlo vamos a utilizar el código 01. Así, después de añadirlo al gráfico y ejecutar nuevamente el código 04, obtendríamos el resultado que aparece a continuación.

Imagen 05

Ahora, al abrir la lista de indicadores, podemos ver lo siguiente:

Imagen 06

Hmm, no lo entiendo. ¿Qué ha ocurrido aquí? Bueno, mi estimado lector, puedes observar que en ambas imágenes estoy destacando una determinada información. Fíjate ahora en que, al no haber definido un nombre para nuestro indicador, el nombre del ejecutable pasó a utilizarse como referencia cuando intentamos averiguar qué tipo de indicador está presente en cada ventana. Sin embargo, vuelvo a insistir en que este tipo de situación, como la que aparece en las imágenes anteriores, debería evitarse siempre que sea posible. Sobre todo cuando realmente queremos mantener cierto control sobre nuestro código. Como ya hemos dicho, el usuario puede cambiar el nombre del ejecutable y, si lo hace, terminaremos perdiendo por completo el control sobre determinadas cuestiones relacionadas con nuestro código. Por eso, saber cómo y cuándo definir un nombre corto, que es precisamente lo que hace la línea diez del código 02, resulta muy importante.

Existen otros motivos para utilizar nombres cortos en los indicadores. Pero no entraré ahora en esos otros motivos, ya que, para comprenderlos, tendríamos que hacer algo para lo que todavía no considero que haya llegado el momento adecuado.

Bien, dicho esto y después de haber realizado una demostración básica de algunas cuestiones relacionadas con las subventanas, podemos empezar a trabajar en algo un poco más elaborado. Esto se debe a que existen situaciones en las que no debemos utilizar las cosas de la forma convencional. Realmente tenemos que hacer que se creen de otra manera.

Pero ¿qué pretendes hacer? Bueno, mi estimado lector, normalmente, cuando trabajamos con indicadores, no queremos, o mejor dicho, no necesitamos que se dupliquen. Son muy pocas las situaciones en las que necesitamos que un determinado indicador tenga una segunda instancia en el mismo gráfico. Cuando surge realmente este tipo de situación, tenemos que saber cómo sortear el sistema. Esto se debe a que MetaTrader 5, de una forma muy sagaz, evita que un indicador se duplique. Puedes comprobarlo utilizando el código que aparece a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. const struct stAverange
07. {
08.     int            nPeriods;
09.     ENUM_MA_METHOD Method;
10.     color          cor;
11. }Averange[] = 
12. {
13.     {20, MODE_SMA, clrDodgerBlue}
14. };
15. //+----------------+
16. #property indicator_chart_window
17. #property indicator_applied_price   PRICE_CLOSE
18. #property indicator_buffers         Averange.Size();
19. #property indicator_plots           Averange.Size();
20. //+------------------------------------------------------------------+
21. struct stInfos
22. {
23.     double  Buff_iMA[],
24.             f_Expo;
25. }Infos[Averange.Size()];
26. //+------------------------------------------------------------------+
27. int OnInit(void)
28. {
29.     for (uint c = 0; c < Averange.Size(); c++)
30.     {
31.         SetIndexBuffer(c, Infos[c].Buff_iMA, INDICATOR_DATA);
32.         Infos[c].f_Expo = (double) (2.0 / (1.0 + Averange[c].nPeriods));
33.         PlotIndexSetInteger(c, PLOT_DRAW_TYPE, DRAW_LINE);
34.         PlotIndexSetInteger(c, PLOT_LINE_STYLE, STYLE_SOLID);
35.         PlotIndexSetInteger(c, PLOT_LINE_WIDTH, 2);
36.         PlotIndexSetInteger(c, PLOT_LINE_COLOR, Averange[c].cor);
37.         PlotIndexSetString(c, PLOT_LABEL, StringFormat("%s of %d", (Averange[c].Method == MODE_EMA ? "Exponential" : "Arithmetica"), Averange[c].nPeriods));
38.     }
39. 
40.     return INIT_SUCCEEDED;
41. };
42. //+------------------------------------------------------------------+
43. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
44. {
45.     int c0 = 0;
46.     double value;
47. 
48.     for (uint c = 0; c < Averange.Size(); c++) switch (Averange[c].Method)
49.     {
50.         case MODE_SMA:
51.             for (int i = rates_total - 1; i > prev_calculated; i--)
52.             {
53.                 value = 0;
54.                 for (int j = 0; (i - j) > 0 && j < Averange[c].nPeriods; j++)
55.                     value += price[i - j];
56.                 Infos[c].Buff_iMA[i] = value / Averange[c].nPeriods;
57.             }
58.             break;
59.     }
60. 
61.     return rates_total;
62. };
63. //+------------------------------------------------------------------+

Código 05

Por mucho que lo intentes, no conseguirás colocar dos instancias de este código 05 en el mismo gráfico. Esto se debe simplemente a que, para MetaTrader 5, la presencia de una segunda instancia en este caso sería completamente innecesaria. Sin embargo, vamos a hacer una pequeña modificación, añadiendo una cadena para poder analizar esto con más calma. La cadena que añadiremos será algo parecido a lo que aparece en la línea diez del código 02. Con ello, nuestro código 05 quedaría modificado como se muestra en el fragmento siguiente.

                   .
                   .
                   .
26. //+------------------------------------------------------------------+
27. int OnInit(void)
28. {
29.     IndicatorSetString(INDICATOR_SHORTNAME, "Averange 20 SMA.");
30. 
31.     for (uint c = 0; c < Averange.Size(); c++)
                   .
                   .
                   .

Fragmento 01

Ahora añadimos este nuevo código al gráfico y, una vez más, por mucho que lo intentes, no conseguirás crear una segunda instancia. Pero añadimos la línea 29, que aparece en el fragmento 01, precisamente para que, cuando ejecutemos el script mostrado en el código 04, obtengamos lo que aparece en la imagen siguiente.

Imagen 07

Pero esto ya era de esperar teniendo en cuenta lo que vimos antes. Sí, mi estimado lector. Pero ¿sabes realmente por qué no conseguimos colocar una segunda instancia del código 05 en el mismo gráfico? Claro que lo sé. Ya he intentado hacerlo y, como no tenemos forma de cambiar el tipo de media ni tampoco la forma en que se está calculando, MetaTrader 5 termina considerando este código 05 como algo inmutable. Por tanto, si intentamos colocar una segunda instancia sin modificar algo en el código que haga que MetaTrader 5 lo interprete de otra manera, no podremos crear una segunda instancia en el mismo gráfico.

Muy bien, básicamente has dado una descripción perfecta. Pero existe otro motivo, y está relacionado con la línea dieciséis de este código 05. Ahora presta atención. Tu descripción del motivo por el que MetaTrader 5 no nos permite colocar una segunda instancia de un indicador en el gráfico es, de hecho, correcta. Sin embargo, cuando modificamos la propiedad del propio indicador, esto deja de ser una regla y obtenemos otro tipo de comportamiento. Para comprobarlo, bastará con modificar el código 05 de la forma que aparece en el fragmento siguiente.

                   .
                   .
                   .
11. }Averange[] = 
12. {
13.     {20, MODE_SMA, clrDodgerBlue}
14. };
15. //+----------------+
16. #property indicator_separate_window
17. #property indicator_applied_price   PRICE_CLOSE
18. #property indicator_buffers         Averange.Size();
19. #property indicator_plots           Averange.Size();
20. //+------------------------------------------------------------------+
21. struct stInfos
22. {
23.     double  Buff_iMA[],
24.             f_Expo;
25. }Infos[Averange.Size()];
26. //+------------------------------------------------------------------+
27. int OnInit(void)
28. {
29.     IndicatorSetString(INDICATOR_SHORTNAME, "Averange 20 SMA.");
30. 
31.     for (uint c = 0; c < Averange.Size(); c++)
                   .
                   .
                   .

Fragmento 02

Observa que, aunque estoy mostrando una sección más amplia de código en este fragmento 02, nuestro punto central sigue siendo precisamente la línea dieciséis. Y fíjate en que, en la línea veintinueve, seguimos indicando una cadena para utilizarla de la forma vista anteriormente. Una vez compilado el código 05 con esta modificación que aparece en el fragmento 02, podremos ejecutarlo de forma que, cuando ejecutemos el código 04, el resultado general será el que aparece en la imagen siguiente.

Imagen 08

Pero espera un momento. ¿Por qué esta vez MetaTrader 5 no impidió que se creara una segunda instancia? Bueno, mi estimado lector, el motivo es precisamente que modificamos la propiedad del código para que crease una subventana. Como normalmente, y esto ya lo vimos en el artículo anterior, podemos utilizar una subventana para realizar un tipo de análisis más sofisticado, realizando el trazado de alguna media. No tendría ningún sentido que MetaTrader 5 restringiera la adición de un nuevo indicador al gráfico hasta el punto de impedirnos crear una segunda instancia, ya que esta nueva instancia podría utilizarse precisamente para crear lo que podríamos considerar un trazado algo más sofisticado.

Sin embargo, no siempre queremos realmente que un usuario u operador que esté utilizando uno de nuestros códigos pueda crear una segunda instancia de un determinado indicador. Y, aun así, por cuestiones de orden, queremos crear, o mejor dicho, utilizar una subventana en un gráfico. Si somos nosotros mismos quienes utilizamos un indicador basado en este tipo de estructura, sabemos que no debemos intentar crear una segunda instancia. Pero otras personas pueden intentarlo por un motivo u otro. Por ello, debemos crear mecanismos que impidan que se genere una segunda instancia de nuestro indicador, precisamente para evitar que aparezca una segunda subventana.

Esto es algo que veremos en detalle dentro de poco. Pero, antes, ¿qué tal si jugamos un poco con este código 05 que crea una segunda subventana? Existen algunos detalles que pueden resultar útiles en el futuro, y esta es una excelente oportunidad para mostrar determinados controles que podemos ejercer sobre algunas de las propiedades de una subventana.

Por ejemplo: ¿sabías que podemos indicar, en nuestro código fuente, cuál debe ser la altura de una subventana? De este modo, todo quedará correctamente distribuido desde el principio, lo que hace que la experiencia del usuario sea mucho más agradable y menos engorrosa.

Para conseguirlo, tenemos que añadir algo a este código 05. Y lo que vamos a hacer aparece en el fragmento siguiente.

                   .
                   .
                   .
11. }Averange[] = 
12. {
13.     {20, MODE_SMA, clrDodgerBlue}
14. };
15. //+----------------+
16. #property indicator_separate_window
17. #property indicator_height          50
18. #property indicator_applied_price   PRICE_CLOSE
19. #property indicator_buffers         Averange.Size();
20. #property indicator_plots           Averange.Size();
21. //+------------------------------------------------------------------+
22. struct stInfos
23. {
                   .
                   .
                   .

Fragmento 03

Ahora, cuando ejecutemos el código 05 con los cambios mostrados en este fragmento 03, el resultado será el que podemos ver a continuación.

Imagen 09

Este tipo de recurso resulta extremadamente útil en las situaciones más diversas, mi estimado lector. Esto se debe a que, cuando utilizamos lo que aparece en la línea diecisiete de este fragmento 03, definimos un valor para la altura de la subventana. Esta altura NO PODRÁ SER MODIFICADA por el operador o usuario de nuestro indicador, porque MetaTrader 5 impedirá que se modifique.

Naturalmente, no utilizarás este tipo de construcción si estás creando una media móvil. Lo hago aquí únicamente para demostrar que es posible. Sin embargo, donde sí es habitual utilizar este tipo de construcción es al implementar y añadir controles u objetos a una subventana. En ese caso, utilizar esta línea diecisiete tiene todo el sentido, ya que no queremos que el usuario u operador modifique la altura de la subventana. De hacerlo, podría terminar ocultando algunos de los controles u objetos presentes allí o dificultando su uso. Este tipo de recurso es realmente interesante y puedes explorarlo bastante.

Existe otra propiedad bastante útil en diversas situaciones. Podemos utilizarla de una forma muy sencilla. Esto puede demostrarse utilizando un indicador vacío, como el que aparece en el código siguiente.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. #property indicator_separate_window
07. #property indicator_height          150
08. #property indicator_maximum         80
09. #property indicator_minimum         15
10. #property indicator_plots           0
11. //+------------------------------------------------------------------+
12. int OnInit(void)
13. {
14.     return INIT_SUCCEEDED;
15. };
16. //+------------------------------------------------------------------+
17. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
18. {
19.     return rates_total;
20. };
21. //+------------------------------------------------------------------+

Código 06

Esto es realmente interesante. Muy interesante, mi estimado lector. Muchas veces puedes perder una buena cantidad de tiempo intentando hacer determinadas cosas. Sin embargo, con este sencillo recurso que se muestra en el código 06, podemos hacer muchas cosas con gran rapidez. Pero, antes de hablar de ello, observa el resultado de la ejecución en la imagen siguiente.

Imagen 10

Lo que nos interesa aquí son estos valores que aparecen en el lado derecho de la subventana. Ahora presta atención a algo, mi estimado lector, porque puede resultarte bastante útil. Observa que, en la línea ocho de este código 06, estamos definiendo un valor que se indicará como el valor máximo de la subventana. Del mismo modo, en la línea nueve indicamos el valor mínimo. Naturalmente, en muchas ocasiones no es necesario definir realmente el valor mínimo, ya que, de forma predeterminada, MetaTrader 5 lo establecerá en cero. Así que podemos hacer algo bastante interesante aquí. Para ello, veamos este código 06 modificado de la forma que aparece a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. #property description "DEMO Indicator"
05. //+------------------------------------------------------------------+
06. #property indicator_separate_window
07. #property indicator_height          150
08. #property indicator_maximum         indicator_height
09. #property indicator_plots           0
10. //+------------------------------------------------------------------+
11. int OnInit(void)
12. {
13.     return INIT_SUCCEEDED;
14. };
15. //+------------------------------------------------------------------+
16. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
17. {
18.     return rates_total;
19. };
20. //+------------------------------------------------------------------+

Código 07

Pero ¿qué locura estás pensando hacer? Calma, mi estimado lector, enseguida lo entenderás. Primero vamos a ejecutar este código 07. Y el resultado es el que podemos ver a continuación.

Imagen 11

Ahora fíjate en que estoy destacando deliberadamente algo en esta imagen 11. ¿Y qué significa esto en la práctica? Pues bien, mi estimado lector, ¿recuerdas que mencioné que en determinadas ocasiones resulta conveniente que un indicador tenga una altura determinada? Pues eso es precisamente lo que nos está indicando esta imagen 11. Observa que, en la línea siete del código 07, estamos indicando la altura en píxeles de la subventana. Inmediatamente después, en la línea ocho, le estamos indicando al compilador que utilice esa misma altura como límite máximo que deberá aplicarse y mostrarse en el indicador.

¿Y qué? ¿En qué puede ayudarnos esto en la práctica? Fíjate en lo que acabamos de hacer, mi estimado lector. Como la subventana tiene una altura definida en la línea siete, al utilizar esa misma altura como valor máximo del indicador, cada píxel pasará a corresponder a un determinado valor que podremos visualizar fácilmente utilizando este mismo indicador.

Hmm, todavía no lo he entendido. ¿Podrías explicarlo un poco mejor? Bueno, no voy a explicarlo; voy a mostrártelo, porque así será mucho más interesante. Observa la animación que aparece a continuación.

Animación 01

Observa los valores del lado derecho cuando estamos dentro de la subventana. Ahora piensa en lo siguiente: quieres alinear diversos controles dentro de una subventana para que queden distribuidos de la mejor manera posible. ¿Cuál es la forma más sencilla de hacerlo? ¿Programando? Sí, quizá. Pero será mucho más rápido implementar una interfaz gráfica utilizando diversos botones, textos y gráficos. Si puedes ir hasta la subventana y, utilizando lo que se muestra en esta animación 01, tomar los valores que aparecen en el lado derecho y aplicarlos a los controles, ¿no estás de acuerdo? Esto te permitirá distribuir los objetos gráficos con mucha rapidez, ya que únicamente tendrás que comprobar qué valor se está mostrando e indicarlo como posición del control.

Existe una forma mucho más rápida de hacer esto. Y esa forma fue abordada en dos artículos bastante antiguos que publiqué aquí en la comunidad. Puedes verlos en:

Múltiples indicadores en un gráfico (Parte 05): Transformando MetaTrader 5 en un sistema RAD (I)

Múltiples indicadores en un gráfico (Parte 06): Transformando MetaTrader 5 en un sistema RAD (II)

Es cierto que, cuando escribí aquellos artículos, no era consciente de que muchos de quienes los leerían no eran, y quizá todavía no sean, programadores. Debido a ello, buena parte de aquellas explicaciones quedó demasiado superficial, lo que impidió que muchos de ustedes pudieran aprovechar realmente los conocimientos que allí se mostraban.

Lo mismo ocurrió con otros de mis primeros artículos. A lo largo de las semanas y meses posteriores a aquellas publicaciones, muchos de ustedes, que hoy siguen mis publicaciones, me pidieron que explicara mejor determinados detalles relacionados con muchos de mis códigos. Por ello se decidió crear esta serie. Espero que les esté gustando y que estén consiguiendo aprender con ella.


Consideraciones finales

En este artículo hemos explorado algunas de las posibilidades que determinan y nos permiten decidir si utilizar o no una subventana cuando nuestro objetivo es trabajar de la forma más sencilla, rápida y práctica posible dentro de MQL5. Sin embargo, y este es precisamente el núcleo de toda la cuestión, no siempre podremos seguir estos caminos más simples y fáciles. Existen muchas situaciones en las que realmente tendremos que adoptar un enfoque algo más profundo y en las que necesitaremos contar con un nivel de conocimiento un poco mayor.

Sin embargo, lo que realmente marcará la diferencia en el tiempo necesario para construir una determinada aplicación no será el nivel de conocimientos de uno u otro programador en particular, sino su grado de creatividad para ver soluciones donde nadie más las ve. Y esto es algo que no puedo transmitir ni a ti ni a nadie, mi estimado lector. Depende única y exclusivamente de que intentes desarrollar tu creatividad hasta el punto de conseguir simplificar tareas que para otros resultarían mucho más trabajosas.

En el próximo artículo empezaremos a tratar precisamente este tipo de problema, en el que la solución más sencilla no siempre será la más adecuada.

Archivo MQ5Descripción
Indicators\Code 01Demostración básica
Indicators\Code 02Demostración básica
Indicators\Code 03Demostración básica
Indicators\Code 04Demostración básica
Indicators\Code 05Demostración básica
Indicators\Code 06Demostración básica
Scripts\Code 01Demostración básica
Scripts\Code 02Demostración básica

Traducción del portugués realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/pt/articles/17117

Archivos adjuntos |
Anexo.zip (4.31 KB)
Arbitraje estadístico mediante acciones cointegradas (Parte 2): Asesor Experto, pruebas retrospectivas y optimización Arbitraje estadístico mediante acciones cointegradas (Parte 2): Asesor Experto, pruebas retrospectivas y optimización
Este artículo presenta un ejemplo de implementación de un asesor experto para operar con una cesta de cuatro acciones del Nasdaq. Las acciones se filtraron inicialmente a partir de pruebas de correlación de Pearson. A continuación, se evaluó la cointegración del grupo filtrado mediante pruebas de Johansen. Por último, se verificó la estacionariedad del spread cointegrado mediante las pruebas ADF y KPSS. A continuación veremos algunas notas sobre este proceso y los resultados de las pruebas retrospectivas tras una pequeña optimización.
Red neuronal en la práctica: Nacimiento de C_Neuron Red neuronal en la práctica: Nacimiento de C_Neuron
El artículo muestra cómo encapsular una neurona en MQL5 mediante la clase C_Neuron, con pesos, sesgo y un número de entradas definido por un parámetro. Detallamos el cálculo del costo por mínimos cuadrados y la disposición de los datos de entrenamiento en arrays. Así resulta sencillo cambiar las entradas y repetir experimentos sin modificar la implementación.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Dominando los registros (Parte 10): Cómo evitar la repetición de registros implementando un sistema de supresión Dominando los registros (Parte 10): Cómo evitar la repetición de registros implementando un sistema de supresión
Hemos creado un sistema de supresión de registros en la biblioteca Logify. En él se detalla cómo la clase CLogifySuppression reduce el ruido en la consola mediante la aplicación de reglas configurables para evitar mensajes repetitivos o irrelevantes. También abarcamos el marco de configuración externa, los mecanismos de validación y las pruebas exhaustivas para garantizar la solidez y la flexibilidad en la captura de registros durante el desarrollo del robot de trading o del indicador.