
Indicadores múltiplos em um gráfico (Parte 04): Iniciando pelo EA
Introducción
En artículos anteriores, expliqué cómo crear un indicador con múltiples subventanas, lo que se vuelve interesante cuando se utiliza un indicador personalizado, la cosa es bastante simple de hacer, pero cuando tratamos de hacer esto en un programa EA, todo comienza a ser un poco más complejo, al no tener los mismos medios que tenemos en un indicador personalizado, en este punto se hace necesaria la programación, y saber crear el código adecuado para tener una subventana es primordial, aunque no es una tarea tan trivial, visto que saber poner una subventana en un EA no implica mucha codificación, sino sólo un cierto conocimiento de cómo funciona MQL5.
Planificación
Ya tenemos nuestro indicador personalizado funcionando, es decir, nuestra clase objeto ya es funcional, y al ser una clase objeto podemos transportarla fácilmente a otros modelos, no obstante el simple hecho de declarar e intentar utilizar la clase en nuestro EA no hará que las cosas funcionen de la misma manera que lo hicimos en nuestro indicador personalizado, y la razón es que no contamos con la posibilidad de una sub ventana en nuestro EA. Pero luego pensamos: "¿qué pasa si utilizo el indicador personalizado que ya está compilado y funcionando y lo llamo desde el EA a través del comando iCustom? ¿Podría funcionar?" Bueno, en realidad podría funcionar, ya que no seria necesaria una subventana, y el comando se vería así:
#property copyright "Daniel Jose" //+------------------------------------------------------------------+ input string user01 = ""; //Indicadores que se usarán input string user02 = ""; //Activos que se acompañarán //+------------------------------------------------------------------+ int OnInit() { int m_handleSub; //... Código do EA ... if ((m_handleSub = iCustom(NULL, 0, "Chart In SubWindows\\Chart In SubWindow.ex5", user01, user02)) == INVALID_HANDLE) return INIT_FAILED; if (!ChartIndicatorAdd(ChartID(), 0, m_handleSub)) return INIT_FAILED; //... Código del EA ... ChartRedraw(); return(INIT_SUCCEEDED); } //...Resto del código del EA ...
Este simple fragmento de código sí es capaz de cargar nuestro indicador personalizado, aunque no funcionará correctamente, porque no tenemos la presencia de una subventana, en este caso cuando el código se ejecute en el EA, aplicará nuestro indicador directamente en la ventana principal, lo que significa que nuestro gráfico quedará oculto por los templates cargados por el indicador, y esto definitivamente no es lo que estamos deseando.
Así que nuestro verdadero y principal problema es crear una subventana que pueda ser utilizada para que podamos usar nuestro indicador ya funcional. Pero, ¿por qué crear una subventana para ejecutar nuestro indicador después? Esto no tiene sentido, es mejor añadir las funcionalidades directamente en nuestro EA y así superar cualquier limitación que pueda ocurrir.
Teniendo esto en cuenta, tenemos que realizar algunas tareas:
Tarea | Objetivo |
---|---|
1 => Crear un indicador de uso general, es decir, genérico | Permitir crear y utilizar el comando iCustom sin contaminar el gráfico en absoluto |
2 => Incluir este indicador en el EA de alguna manera | Esto le permitirá transportar el EA con plena funcionalidad sin problemas |
3 => Crear una clase de objeto genérico para las subventanas | Permitir añadir subventanas a través de nuestro EA |
4 => Hacer que nuestra clase C_TemplateChart se vincule a la clase de ventanas | Esto nos permitirá controlar el contenido de las subventanas sin cambiar nada en el código que ya funciona. |
Aunque parezca laborioso, las dificultades son bastante sencillas de resolver. Así que vamos a abordar cada uno de los puntos.
Implementación: Creación de un indicador de propósito general
Esta parte se puede resolver creando un código totalmente limpio pero funcional de un indicador personalizado. En este caso, el código sería el siguiente:
#property copyright "Daniel Jose" #property version "1.00" #property description "Este archivo sólo sirve como soporte de indicadores en SubWin" #property indicator_chart_window #property indicator_plots 0 //+------------------------------------------------------------------+ int OnInit() { return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[]) { return rates_total; } //+------------------------------------------------------------------+
Solo esto y nada más. Vamos a guardar este archivo como SubSupport.mq5, sólo que no estará junto con otros indicadores, lo transferimos al directorio RESOURCE de nuestro EA, entonces la estructura del archivo se vería como la imagen de abajo:
Implementación: Inclusión del indicador genérico en la EA
Para conseguirlo tendremos que añadir el siguiente código al principio de nuestro EA.
//+------------------------------------------------------------------+ #define def_Resource "Resources\\SubSupport.ex5" //+------------------------------------------------------------------+ #resource def_Resource //+------------------------------------------------------------------+
Esto incorporará el código compilado del indicador genérico en nuestro EA, una vez hecho esto el indicador genérico puede tener el archivo .ex5 eliminado, ya que no es necesario. Ahora hay que tener en cuenta un hecho, si en el momento de compilar el código del EA no se encuentra el ejecutable SubSupport.ex5, el compilador compilará automáticamente el código de nuestro indicador genérico SubSupport.mq5 y añadirá este ejecutable recién compilado a nuestro EA, es decir, si modificamos por cualquier motivo el archivo SubSupport.mq5 y queremos añadir los cambios al EA, borremos el archivo SubSupport.ex5, de lo contrario los cambios no se añadirán.
Es muy importante tener en cuenta este detalle, porque en algunos casos hay que saber cómo añadir los nuevos cambios a un recurso.
Bien, el indicador genérico ya forma parte de nuestro EA, así que pasemos a la siguiente tarea.
Implementación: Creación de una clase objeto de subventanas
Esta parte es igualmente sencilla, aunque debemos decidir algunas cosas antes de codificar, y son las siguientes: ¿Qué funciones necesitaremos realmente en esta clase? Decidí utilizar inicialmente las siguientes:
Función | Descripción |
---|---|
Init | Permitir añadir subventanas a través de nuestro EA |
Close | Permitir añadir subventanas a través de nuestro EA |
Estas funciones no harán pruebas, así que me imagino que serán llamadas una sola vez durante toda la vida del EA. Pero como nuestro EA está creciendo es bueno pensar en hacerlo aún más práctico para el futuro, entonces vamos a disparar una nueva clase objeto que se llamará C_Terminal, esta clase soportará varias cosas vinculadas al terminal gráfico, pero no te preocupes por esto por ahora, veamos entonces la última tarea, ya que no hay manera de implementar una solución de manera parcial.
Implementación: Herencia de la clase C_TemplateChart
Cuando decidí crear cosas usando POO (Programación Orientada a Objetos) lo hice por ya saber que hay grandes ventajas en usar dicho enfoque, entre ellas están la seguridad y la herencia, aunque también tenemos el polimorfismo, pero esto lo usaremos más adelante cuando creemos un sistema de órdenes cruzadas, mientras que aquí usaremos una de las cosas buenas que trae la POO, la herencia. Pues bien, nuestra clase C_TemplateChart ya es totalmente funcional, y viendo eso, no queremos tener el trabajo de reprogramar todo de nuevo, o correr el riesgo de añadir código a la clase, y que este código impida que la clase sea utilizada en otro lugar. La solución es utilizar la herencia y así añadir nuevos códigos o características sin cambiar de ninguna manera el código original.
El uso de la herencia nos aporta varios beneficios, entre ellos tenemos: El código ya probado se mantiene probado; la complejidad crece sin un crecimiento igual en la cantidad de código; sólo las nuevas características realmente necesitan ser probadas; lo que no cambia simplemente se hereda asegurando la estabilidad, en resumen, la cosa mejora con un esfuerzo mínimo pero con la máxima seguridad, para entenderlo vamos a ver el esquema de abajo.
La clase abuelo es la clase más básica, donde tenemos un nivel de manipulación de datos en menor escala, pero cuando la clase padre hereda cosas de la clase abuelo, todas las cosas declaradas como públicas en la clase abuelo pueden ser vistas y usadas por la clase padre, aunque también podemos hacer adiciones de cosas nuevas a la clase padre, si bien esto no afecta en absoluto a lo heredado y mantenido durante la herencia, pero si la clase padre ya está terminada y funcionando y queremos ampliar las cosas aún más sin cambiar nada en las clases de abajo, entonces creamos una clase hija y ésta ahora tendrá todas las características de las clases anteriores, eso sí, podemos cambiar el funcionamiento, y esto es lo interesante de la herencia, y al hacer estos cambios las otras clases no se verán afectadas. Sin embargo hay una limitación aquí, a diferencia de C++ que permite la herencia múltiple, es decir, el hijo podrá heredar características tanto del lado paterno como del materno, en MQL5 esto no es posible, por lo que la estructura siempre está un poco rezagada, pero aún así se obtiene algún beneficio de la herencia. A continuación se puede ver un ejemplo de herencia múltiple:
Bien, ¿entonces cómo hacemos esto en MQL5? ¿Cómo declaramos la herencia para poder aprovecharla? La forma más clara de entenderlo es leyendo el contenido Programación Orientada a Objetos ( POO ), pero aquí iremos directamente al grano. La herencia se realizará mediante las siguientes líneas:
#include "C_TemplateChart.mqh" //+------------------------------------------------------------------+ class C_SubWindow : public C_TemplateChart { // ... Código da classe };
Vea que la clase C_SubWindow heredará públicamente la clase C_TemplateChart, por lo que a partir de este momento podremos utilizar la clase C_SubWindow para acceder a la funcionalidad de la clase C_TemplateChart.
En el fragmento de código anterior, he resaltado una cosa, nótese que está entre comillas ( " ) y no como es habitual utilizar ( < > ) y ¿por qué he hecho esto? Al igual que el lenguaje C++, MQL5 tiene algunas cosas muy interesantes, pero que confunden a quien está empezando a aprender el arte de la programación, cuando ponemos un archivo de cabecera entre los signos mayor y menor ( < > ) nos estamos refiriendo a una ruta absoluta, es decir el compilador seguirá exactamente la ruta que le indiquemos, pero cuando usamos comillas como se hizo, el compilador usará una ruta relativa, o para que lo entiendas mejor, primero empezará en el directorio actual donde está el archivo de trabajo. Esto puede sonar extraño, pero hay casos en los que tendremos el mismo nombre para archivos cuyo contenido es diferente, y estarán en diferentes directorios, de todos modos queremos referirnos al directorio actual, así que usamos las comillas para hacerlo.
Las dos funciones que pensábamos utilizar antes, INIT y CLOSE, pueden verse a continuación:
//+------------------------------------------------------------------+ bool Init(void) { if (m_handleSub != INVALID_HANDLE) return true; if ((m_handleSub = iCustom(NULL, 0, "::" + def_Resource)) == INVALID_HANDLE) return false; m_IdSub = (int) ChartGetInteger(Terminal.Get_ID(), CHART_WINDOWS_TOTAL); if (!ChartIndicatorAdd(Terminal.Get_ID(), m_IdSub, m_handleSub)) return false; return true; } //+------------------------------------------------------------------+ void Close(void) { ClearTemplateChart(); if (m_handleSub == INVALID_HANDLE) return; IndicatorRelease(m_IdSub); ChartIndicatorDelete(Terminal.Get_ID(), m_IdSub, ChartIndicatorName(Terminal.Get_ID(), m_IdSub, 0)); ChartRedraw(); m_handleSub = INVALID_HANDLE; } //+------------------------------------------------------------------+
Vean el código es súper simple y corto, pero hay algo con lo que debemos tener cuidado, observen la parte resaltada. Hay que tener cuidado de no cometer el error al añadir esta parte, porque si no se deja exactamente así, el ejecutable SubSupport.ex5 que pedimos añadir al EA no se verá dentro del EA, sino fuera del EA. Basta con leer sobre Recursos para entender esto, pero básicamente es lo siguiente: Si se utiliza ( :: ) esto indicará que el EA debe utilizar el recurso interno presente en él, pero si sólo nombramos el recurso el EA lo buscará dentro del directorio MQL5, por lo que si el archivo no existe en la ubicación indicada la función fallará, incluso si el archivo fue añadido como un recurso del EA.
Luego, una vez cargado el recurso, comprobamos el número de subventanas presentes y añadimos un indicador en esta subventana.
Lo que este código hace en realidad se puede ver a continuación:
input string user01 = ""; //Indicadores que serán usados input string user02 = ""; //Activos que serán acompañados //+------------------------------------------------------------------+ int OnInit() { int m_handleSub; //... if ((m_handleSub = iCustom(NULL, 0, "Chart In SubWindows\\Chart In SubWindow.ex5", user01, user02)) == INVALID_HANDLE) return INIT_FAILED; if (!ChartIndicatorAdd(ChartID(), (int) ChartGetInteger(ChartID(), CHART_WINDOWS_TOTAL), m_handleSub)) return INIT_FAILED; //... ChartRedraw(); return(INIT_SUCCEEDED); } //...Resto del código del EA ...
Ambos códigos funcionarán de forma idéntica, pero la versión de la clase objeto nos permitirá añadir más cosas con el tiempo, ahora bien, la versión mostrada anteriormente es una versión ya consolidada y no cambiará, pero ambas realizan lo mismo, crean una subventana desde el EA y ponen en esta subventana todos los indicadores personalizados previamente creados. Obsérvese que el código sufrió únicamente una modificación del código visto al principio del artículo y que está resaltado.
Conclusión
Es muy interesante y curioso como decidimos seguir un camino para lograr nuestras metas, varias veces nos enfrentamos e imaginamos que es difícil lograr los objetivos, pero con un poco de paciencia y dedicación podemos superar los obstáculos que inicialmente parecían insuperables. En este artículo demuestro cómo se puede extender la funcionalidad de una clase sin necesidad de modificarla gracias a la herencia, y al mismo tiempo muestro cómo se pueden añadir indicadores a los gráficos, para que funcionen como ya se ha probado. Añadimos un programa ex5 dentro de nuestro EA y lo utilizamos sin tener que transportar el ex5 original, sólo cargando el EA.
El archivo adjunto contiene todas las mejoras desarrolladas hasta ahora, pero pronto tendremos aún más cosas interesantes en este código. 😁👍
Traducción del portugués realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/pt/articles/10241
Advertencia: todos los derechos de estos materiales pertenecen a MetaQuotes Ltd. Queda totalmente prohibido el copiado total o parcial.
Este artículo ha sido escrito por un usuario del sitio web y refleja su punto de vista personal. MetaQuotes Ltd. no se responsabiliza de la exactitud de la información ofrecida, ni de las posibles consecuencias del uso de las soluciones, estrategias o recomendaciones descritas.





- 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
Se ha publicado el nuevo artículo Múltiples indicadores en un gráfico (Parte 04): Comenzando con EA:
El autor: Daniel José
Hola Daniel, estoy siguiendo tus artículos, pero ¿qué pasa con la parte 03?
Hubo un pequeño problema en el momento que se solicitó la liberación para la publicación, pero ya se autorizó la publicación de la Parte 03, pronto estará disponible también, este problema fue causado más por la cantidad de artículos que ya envío ... actualmente tengo otros 15 artículos para que los analicen, todos involucrados en el desarrollo de este EA y en cada uno la cosa se va haciendo más compleja .... pero gracias por estar siguiendo la serie... esperen grandes noticias del artículo 05, a partir de ahí la cosa valdrá realmente la pena, porque se convertirá en algo grande la gente, estos primeros son solo para presentar lo que vendrá por delante...😁👍
Hola Daniel,
Estoy teniendo problemas con los indicadores multicolor y tus artículos, que me están gustando, me indican que quizás conozcas su solución.
Quiero producir una función que establezca todos los atributos del indicador sin utilizar las opciones #property,por ejemplo #property indicador_color1 clrCrimson,clrWhite,clrLime
Lo que estoy encontrando en el programa de prueba a continuación es que con el #property indicator_color1 clrCrimson,clrWhite,clrLime incluido, el programa funciona correctamente mientras que si lo comento, entonces el programa no funciona correctamente.En este caso parece que está trazando sólo algunos de los puntos de datos como si estuviera utilizando un marco de tiempo "superior" o saltándose varios puntos de datos. Sospecho que la directiva property color está estableciendo más atributos que no he identificado cuando se especifican varios colores.
El segundo problema es que, obviamente, no entiendo los detalles y requisitos de la utilización de gráficos multicolor. He buscado en la documentación y no he encontrado ningún artículo que proporcione una visión general de cómo utilizar indicadores multicolor. Mientras que el primer gráfico cambia de color correctamente, el segundo, que traza los mínimos, no cambia de color de acuerdo con mi llamada a la función. Este gráfico requiere las tres propiedades: type2, color2, & width2, para funcionar correctamente. También estoy perplejo por qué las declaraciones de propiedades utilizan 2 en lugar de 3. Utilicé el indicador Laguerre Adaptive Filter de Mladen para identificar que los indicadores de propiedades utilizan el número de gráfico,2, no el número de indicador 3 para mostrarse correctamente.
Cualquier sugerencia, referencia o ayuda será muy apreciada
Saludos, CapeCoddah
Cualquier sugerencia, referencia o ayuda será muy apreciada.
Atentamente, CapeCoddah
Usted está un poco confundido, puedo entender ... pero toda la confusión está en el hecho de que usted no está realmente mirando los detalles en su código. Voy a tratar de explicar algunos de los detalles que están en el comentario, entonces voy a hablar un poco acerca de su code....
El primer punto es que incluso puedes producir un indicador multicolor sin usar #property indicator_colorN pero para el usuario e incluso para ti es más práctico, seguro y sencillo de entender y modificar el código, porque lo único que tienes que hacer es ir a las propiedades es modificar los colores ahí presentes, y para el usuario es más sencillo porque solo tendrá que elegir el color a modificar y hacer el cambio, esto en la ventana estándar que MT5 crea para los indicadores. De alguna manera ya estas haciendo lo correcto al usar el comando PlotIndexSetInteger para generar los cambios de color, y esto es así cuando no usamos #property indicator_colorN, pero cuando usamos las propiedades muchas veces no tiene sentido usar el comando PlotIndexSetInteger para establecer otros colores, esto se debe a que la cosa puede ser más complicada de mantener y más confusa para el usuario, ya que puede no entender realmente lo que el estándar de color está tratando de decir, incluso si el código es tuyo y serás el único en utilizar el indicador, no tiene mucho sentido, a menos que en casos raros crees un patrón de color dinámico.
Ahora sobre el segundo punto: El problema en este caso es que estas confundiendo el numero de cosas que trazara el indicador ( 2 para 2 lineas ) con las propiedades del objeto ( en este caso linea ) y para que la linea sea trazada, en realidad necesitas declarar al menos 3 datos, que son TipoN, ColorN, AnchoN, donde la N indica el numero del objeto, con la practica y el tiempo terminaras entendiendo estas pequeñas diferencias entre la propiedad del indicador y las propiedades de los objetos que utiliza.... No te rindas... sigue estudiando y pronto las cosas se verán más claras.... 😁👍
Ahora veamos algo de tu código.... No voy a mostrarte exactamente cómo arreglarlo (si lo hago no será divertido... .... 😁👍✌ ) quiero que prestes atención al siguiente hecho, y esto es importante:
Fíjate que he marcado dos cosas en tu código... ahora vamos a ver qué pasa cuando se reproduce en la gráfica....
Observa que solo una de las etiquetas esta como la declaraste en el codigo, solo la HIGH .... y la LOW ?!?!! ¿¡¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿???????!!!!!!!!!!!!!!!!!!!!!, este es el primer punto que debes corregir, porque el hecho de que no se este mostrando la etiqueta LOW indica que el patrón de color que se esta utilizando es el que esta declarado en #property indicator_color2, es decir, tienes un fallo en este punto, si intentas eliminar las propiedades del indicador 2 que realmente crean la linea LOW, aun manteniendo el resto del codigo, la linea HIGH se graficara, pero la linea LOW no....¿por qué? porque en realidad no está definiendo la información necesaria para trazar la línea BAJA, esto dinámicamente a través del uso de la llamada PlotIndexSetInteger... parece extraño ... pero esto es lo que está sucediendo ....
Cuando consigas arreglar esto, si realmente quieres usar la forma dinámica de declarar los datos del objeto fila usando PlotIndexSetInteger, podrás eliminar los comandos de compilación #property indicator_color de la escena, ya que los datos necesarios se establecerán dinámicamente, pero si no quieres hacer tal esfuerzo, está bien....
Ahora quiero que mires la imagen de arriba y la compares con los colores que estás usando en #property indicator_color... observa estos colores con mucho cuidado .... si haces esto notarás algo raro ahí .... de nuevo no te diré que no pierdas la gracia, pero intenta usar colores diferentes, sin repetir ninguno... cuando los repites se hace más difícil entender dónde está el error.... 😁👍
Ahora un último detalle: El hecho de que creas que está trazando sólo unos puntos y saltándose otros puede ser por dos motivos: El patrón de colores no está contrastando con el fondo de la gráfica, intenta usar colores que contrasten con el fondo de la gráfica, y la segunda, pero no creo que sea realmente el caso, es que puede haber un fallo en el evento OnCalcule, estás devolviendo -1 o el valor de i, lo correcto es devolver rates_total, así que cambia esto en el código para evitar problemas futuros....
Hola Daniel,
Estaba confundido. Pensaba que las características de dibujo se definían usando la especificación del buffer como MQ4 mientras que, al menos para las especificaciones DRAW_COLOR... las características de dibujo se definen usando el identificador de trazado secuencial. No he determinado si las especificaciones DRAW_LINE etc también requieren especificaciones de trazado. Además, la propiedad indicator_colorX en realidad tiene dos funciones, primero para contar y establecer el número de colores y luego para establecer cada color especificado en su posición de matriz adecuada.Estoy adjuntando dos archivos, Color Test que ahora está funcionando correctamente aunque, requiere más refinamientos, en segundo lugar MACD Original2_1 de MLADEN ligeramente modificado. El programa de Mladen es interesante ya que había definido dos parcelas, pero sólo utiliza un búfer de índice de color.
Gracias por su ayuda