English Русский 中文 Deutsch 日本語 Português
Dibujo de indicadores de aguja usando la clase CCanvas

Dibujo de indicadores de aguja usando la clase CCanvas

MetaTrader 5Ejemplos | 1 octubre 2015, 14:55
1 565 0
Serhii Shevchuk
Serhii Shevchuk

Contenido

Introducción

Todo comenzó cuando conocí la clase CCanvas por primera vez. Cuando la cosa llegó a la práctica, me surgió la idea de diseñar un instrumento indicador. Los primeros resultados eran primitivos, pero durante el proceso de mejoras los instrumentos se completaban con nuevos elementos y adquirían la apariencia más agradable. Como resultado, he obtenido una pequeña biblioteca que ahora permite añadir fácilmente un instrumento indicador a cualquier indicador o Asesor Experto (EA). En este artículo vamos a considerar la estructura del instrumento indicador, conoceremos las funciones necesarias para el dibujo y configuración de su aspecto visual, también evaluaremos el consumo de recursos.

Indicadores de aguja

Fig. 1. Instrumentos indicadores


1. Coordenadas y anclaje

Hay dos tipos de posicionar un instrumento sobre el gráfico: absoluto y relativo.

En caso del posicionamiento absoluto, las coordenadas representan las distancias en píxeles desde la esquina de anclaje por los ejes X y Y.

En caso del posicionamiento relativo, se crea el principio local de las coordenadas según el tipo especificado del posicionamiento relativo. Cuando se selecciona el tipo vertical, el principio estará ubicado debajo o encima del objeto de referencia (si está seleccionado la esquina de anclaje superior o inferior, respectivamente). Cuando se selecciona el tipo horizontal, el principio estará a la izquierda o a la derecha en la dirección del alejamiento desde la esquina de anclaje. En este caso, las coordenadas especificadas representan el desplazamiento desde el principio local de las coordenadas. En caso de desplazamientos positivos, el objeto va a alejarse del objeto de referencia. En caso de los desplazamientos negativos, va a cubrirlo.

El objeto de referencia puede ser representado sólo por el objeto de otro instrumento indicador. Es importante que ambos objetos tengan la misma esquina de anclaje.

En la imagen 2 se muestra un ejemplo de la posición relativa.

Posicionamiento relativo

Fig. 2. Posicionamiento relativo de instrumentos indicadores

Vamos a analizar las configuraciones de cada instrumento:

  • Instrumento "gg01": posicionamiento relativo desactivado. Desplazamiento horizontal — 40, desplazamiento vertical — 40.
  • Instrumento "gg02": posicionamiento relativo — horizontal, objeto de referencia — "gg01". Desplazamiento desde el principio local de coordenadas (punto A) por la horizontal — 15, desplazamiento por la vertical — 0.
  • Instrumento "gg03": posicionamiento relativo — vertical, objeto de referencia — "gg01". Desplazamiento desde el principio local de coordenadas (punto B) por la horizontal — 0, desplazamiento por la vertical — 15.
  • Instrumento "gg04": posicionamiento relativo — vertical, objeto de referencia — "gg02". Desplazamiento desde el principio local de coordenadas (punto A) por la horizontal — 50, desplazamiento por la vertical — 15.

El posicionamiento relativo facilita la configuración de los parámetros de entrada si en el gráfico se encuentran varios indicadores que contienen el instrumento indicador. Si el tamaño de uno de ellos cambia, las coordenadas de los demás serán recalculados automáticamente.

El tipo y las coordenadas se establecen a través de la función GaugeCreate().


2. Elementos del instrumento indicador

El instrumento indicador se compone de dos objetos gráficos. Uno de ellos se llama la capa de la escala, el otro se llama la capa de la aguja. Ambos objetos gráficos tienen las mismas coordenadas, la capa de la aguja se encuentra por encima de la capa de la escala. El nombre del instrumento que se establece en los parámetros de entrada sirve de prefijo para los nombres de ambos objetos. Por ejemplo, si el nombre de instrumento es "Gauge01", la capa de la escala tendrá el nombre "Gauge01_s", y la capa de la aguja — "Gauge01_n".

En la figura 3 se muestra la estructura del instrumento indicador.

Fig. 3 Estructura del instrumento indicador

Fig. 3. Estructura del instrumento indicador

La capa de la escala contiene los elementos siguientes:

  • borde (1)
  • marcas de graduación de la escala (5, 6, 7)
  • etiquetas de graduaciones de la escala (4)
  • rangos señalados (2, 12)
  • leyendas (3, 10, 11)

Las leyendas se distinguen por su finalidad:

  • descripción del instrumento indicador (3)
  • unidades de medición (11)
  • valor actual (10)
  • multiplicador de las marcas de la escala (omitido)

Las marcas de graduación se dividen en:

  • principales (7)
  • medianas (5)
  • pequeñas (6)

Sólo las marcas principales tienen las etiquetas. El paso de las marcas se establece con un valor numérico. El paso de las marcas medianas se calcula basándose en la cantidad determinada de las marcas medianas entre las principales. El paso de las marcas pequeñas se calcula basándose en la cantidad determinada de las marcas pequeñas entre las medianas. Las marcas de graduación medianas y pequeñas pueden ser omitidas.

La capa de la aguja contiene los elementos siguientes:

  • aguja (8)
  • centro de la aguja (9)


2.1. Tamaños

En la figura 3 se muestran los tamaños de algunos elementos del instrumento indicador:

  • d — tamaño del instrumento que corresponde al diámetro de la línea exterior del contorno del instrumento
  • b — tamaño del borde
  • g — tamaño del espacio entre el borde y elementos de la escala
  • c — tamaño del centro de la aguja.

Importante. El diámetro del instrumento es el único tamaño que se establece en píxeles (en la fig. 3 es el tamaño d). Los demás tamaños de los elementos y fuentes se indican en unidades condicionales y su valor se calcula en porcentaje del diámetro. Ha sido hecho para facilitar el escalamiento. Será suficiente cambiar el diámetro y todos los demás tamaños serán recalculados proporcionalmente. Los coeficientes para el cálculo se listan en la sección “Macro sustituciones” y pueden ser sustituidos según el deseo del usuario.


2.2. Forma del cuerpo

La forma del cuerpo de un instrumento indicador puede ser de dos tipos: círculo y sector. La forma de sector es más conveniente para el uso si el ángulo del rango de la escala es inferior a 180 grados.

Forma del instrumento indicador

Fig. 4. Forma del instrumento indicador

En la imagen 4 se muestra un instrumento redondo (a) y dos instrumentos de sector (b, c). Para indicar la forma necesaria, se utiliza la función GaugeSetCaseParameters().


2.3. Escala

Es el elementos más importante en un instrumento indicador. La legibilidad de los datos depende de su apariencia. La escala no debe parecer sobrecargada, pero al mismo tiempo tiene que ser bastante informativa. La selección de los valores extremos de la escala, así como el paso de las marcas de graduación principales, requiere una atención especial. La función GaugeSetScaleParameters() permite configurar el rango de la escala, su rotación y los valores de puntos extremos (máximo y mínimo). El mínimo puede estar tanto a la izquierda (orden directo), como a la derecha (orden inverso).

El rango de la escala es un ángulo formado por dos radio vectores de los puntos extremos de la escala. El ejemplo se muestra en la figura 5.

Rango de la escala

Fig. 5. Rango de la escala

La rotación de la escala es el ángulo de desvío de la bisectriz del ángulo del rango de la escala del rayo que sale del centro del instrumento verticalmente arriba. El ejemplo se muestra en la figura 6.

Ángulo de rotación de la escala

Fig. 6. Ángulo de rotación de la escala

Al combinar el ángulo del rango de la escala y el ángulo de rotación, se puede configurar la apariencia del instrumento de una forma bastante flexible. En la imagen 4(c) hay un instrumento con el rango de 90 grados y rotación de 45.

Los valores mínimos y máximos de la escala son parámetros importantes que deben seleccionarse dependiendo del rango de valores permitidos de la variable a mostrar. La marca cero puede ser omitida por cuestiones de conveniencia. No hay ninguna razón dibujar la escala desde cero si la variable cambia en el rango de 400 a 600. En la imagen 7 se muestran algunos ejemplos de los valores máximos y mínimos de la escala.

Mínimo y máximo de la escala

Fig. 7. Mínimo y máximo de la escala

  • a) valores de 0 a 500, orden directo
  • b) valores de -200 a 400, orden directo
  • c) valores de -400 a 0, orden directo
  • d) valores de 500 a 0, orden inverso
  • e) valores de 200 a 800, orden directo
  • f) valores de 0 a -800, orden inverso


2.4. Marcas de graduación

La configuración de las marcas de graduación consiste en seleccionar su tamaño y modo de alineación.

La alineación puede ser:

  • por el borde interno de la escala
  • por el borde externo de la escala
  • por el centro

En la imagen 8 se muestran los ejemplos de la alineación de las marcas de graduación de la escala:

  • a — alineación por el centro
  • b — por el borde interno
  • c — por el borde externo

Para la configuración se utiliza la función GaugeSetMarkParameters().

La ubicación de las etiquetas de las marcas de graduación se refiere a la configuración de la escala y se ajusta mediante la función GaugeSetScaleParameters().

En la imagen 8(a) se muestra el ejemplo de ubicación de las etiquetas en la parte interna de la escala, en la imagen 8(b) y 8(c) las etiquetas se ubican en la parte externa.

Para que las etiquetas de las marcas no ocupen mucho sitio en la escala, se recomienda usar el multiplicador. Es un coeficiente en el que van a dividirse todos los valores mostrados de las etiquetas. Los valores del multiplicador pueden ser de 0,0001 a 10000. En la imagen 4(c) se utiliza el multiplicador 100 lo que permite utilizar en las etiquetas de las marcas los números dígitos en vez de los números de tres cifras. En la imagen 1 para el indicador ATR se utiliza el multiplicador 0,0001 lo que permite no utilizar la coma y ceros en las etiquetas. El multiplicador se establece mediante la función GaugeSetScaleParameters().

Ubicación de las marcas y etiquetas

Fig. 8. Ubicación de las marcas y etiquetas


2.5. Leyendas

Las leyendas sirven para mostrar la información adicional y pueden ser de cuatro tipos:

  • descripción del instrumento
  • unidades de medición
  • valor actual
  • multiplicador

Usted puede ocultar cualquiera de las etiquetas. Por defecto, se muestra sólo la descripción del instrumento.

La ubicación de la la leyenda se establece mediante el ángulo y el radio. El ángulo se establece en grados y su valor es igual al ángulo entre el rayo que sale verticalmente hacia arriba del centro del instrumento y un segmento imaginario que une el centro del instrumento y el centro de la leyenda. El radio se establece en unidades condicionales. Puede tener los valores de 0 a 10, donde 0 corresponde al radio del centro de la aguja, y el valor 10 corresponde al radio exterior de la escala.

En la imagen 9 se muestra un ejemplo de la posición de las leyendas.

  • La leyenda "Profit" (descripción del instrumento) tiene las coordenadas siguientes: ángulo 0 y radio 3.
  • La leyenda "0.00" (valor actual) tiene las coordenadas siguientes: ángulo 225 y radio 4.
  • La leyenda "USD" (unidades de medición) tiene las coordenadas siguientes: ángulo 215 y radio 8.

Para la configuración de las leyendas se utiliza la función GaugeSetLegendParameters().

Coordenadas de las leyendas

Fig. 9. Coordenadas de las leyendas

Importante. Las leyendas no están fijadas en la escala y su ángulo no está conectado con el ángulo de rotación de la escala.


2.6. Rangos señalados

Los rangos destacados de los datos representan un elemento imprescindible de cualquier instrumento indicador. Ayudan a determinar que la magnitud ha obtenido un valor de emergencia o ha entrado en un rango especial. La función GaugeSetRangeParameters() permite establecer hasta cuatro rangos señalados. Para eso hay que establecer los valores extremos y el color de realce. En la imagen 1 el indicador Profit tiene resaltados dos rangos: de 200 a 400 es el color verde que señaliza que ya ha llegado la hora de fijar el beneficio, y de -200 a -400 es el color naranja que avisa sobre una reducción importante.


2.7. Aguja

La función GaugeSetNeedleParameters() se utiliza para establecer el tamaño del centro de la aguja y el tipo de relleno. El tipo de relleno influye en el consumo de recursos puesto que la capa de la aguja se redibuja completamente cada vez que se actualicen los datos. En la imagen 10 se muestran los ejemplos del relleno.

  • aguja con relleno usando el algoritmo de suavizado (a)
  • aguja con relleno sin usar el algoritmo de suavizado (b)
  • contorno de la aguja usando el algoritmo de suavizado sin relleno (c)

Métodos del relleno de la aguja

Fig. 10. Métodos del relleno de la aguja

Hablaremos sobre las ventajas y desventajas de cada método en las secciones relacionadas con la mejora de la clase CCanvas y evaluación de la intensidad del consumo de los recursos.


3. Funciones

La tabla 1 contiene la lista de funciones para el dibujo de los instrumentos indicadores y configuración de su aspecto visual.

Función
Acción
GaugeCalcLocation
Calcula las coordenadas del centro del instrumento indicador
GaugeCreate
Crea el instrumento indicador
GaugeDelete
Elimina el instrumento indicador
GaugeNewValue
Actualiza la posición de la aguja y el valor mostrado
GaugeRedraw
Redibuja el instrumento indicador
GaugeRelocation
Cambia la posición de los objetos del instrumento en el gráfico
GaugeSetCaseParameters
Establece los parámetros del cuerpo del instrumento indicador
GaugeSetLegendParameters
Establece los parámetros de la leyenda
GaugeSetMarkLabelFont
Establece la fuente para las etiquetas de las marcas de graduación de la escala
GaugeSetMarkParameters
Establece los parámetros de las marcas de graduación de la escala
GaugeSetNeedleParameters
Establece los parámetros de la aguja
GaugeSetRangeParameters
Establece los parámetros de los rangos
GaugeSetScaleParameters
Establece los parámetros de la escala

Tabla 1. Lista de funciones

Vamos a analizar cada una de las funciones más detalladamente. Están representadas en el mismo orden en el que se recomienda invocarlas durante la inicialización.


3.1. GaugeCreate

Crea el instrumento indicador.

bool GaugeCreate(
   string name,              // nombre del instrumento
   GAUGE_STR &g,             // referencia a la estructura del instrumento
   int x,                    // desplazamiento por la horizontal de la esquina de anclaje
   int y,                    // desplazamiento por la vertical de la esquina de anclaje
   int size,                 // tamaño del instrumento
   string ObjRel,            // nombre del objeto gráfico respecto al cual se establece la posición
   ENUM_REL_MODE rel_mode,   // posicionamiento relativo
   ENUM_BASE_CORNER corner,  // esquina de anclaje
   bool back,                // objetos al fondo
   uchar scale_transparency, // transparencia de la escala
   uchar needle_transparency // transparencia de la aguja 
 );

Parámetros

 name

   [in]  Nombre del instrumento indicador. Se utiliza como el prefijo para los nombres de los objetos gráficos que forman parte del instrumento indicador.

 g

   [out]  Referencia a la estructura del instrumento.

 x

   [in]  Distancia en píxeles por el eje X de la esquina de anclaje. En caso del posicionamiento relativo, es la distancia desde el principio local de las coordenadas.

 y

   [in]  Distancia en píxeles por el eje Y de la esquina de anclaje. En caso del posicionamiento relativo, es la distancia desde el principio local de las coordenadas.

 size

   [in]  Tamaño del instrumento. Se representa como el diámetro del cuerpo.

 ObjRel

   [in]  Nombre de otro instrumento respecto al cual se establece la posición. Es pertinente en el caso si se trata del posicionamiento relativo.

 rel_mode

   [in]  Modo del posicionamiento relativo. Puede ser uno de los valores de la enumeración ENUM_REL_MODE.

 corner

   [in]  Esquina del gráfico para el anclaje del objeto gráfico. Puede ser uno de los valores de la enumeración ENUM_BASE_CORNER.

 back

   [in]  Objetos al fondo.

 scale_transparency

   [in]  Grado de transparencia de la escala. Puede adquirir los valores de 0 a 255.

 needle_transparency

   [in]  Grado de transparencia de la aguja. Puede adquirir los valores de 0 a 255.

Valor devuelto

 Devolverá true si los objetos de la capa de la escala y de la aguja han sido creados, de lo contrario devolverá false.


3.2. GaugeSetCaseParameters

Establece los parámetros del cuerpo del instrumento indicador.

void GaugeSetCaseParameters(
   GAUGE_STR &g,                  // referencia a la estructura del instrumento
   ENUM_CASE_STYLE style,         // estilo del cuerpo
   color ccol,                    // color del cuerpo
   ENUM_CASE_BORDER_STYLE bstyle, // estilo del borde
   color bcol,                    // color del borde
   ENUM_SIZE border_gap_size      // tamaño del espacio entre el borde y elementos de la escala
);

Parámetros

 g

   [out]  Referencia a la estructura del instrumento.

 style

   [in]  Estilo del cuerpo. Puede ser uno de los valores de la enumeración ENUM_CASE_STYLE.

 ccol

   [in]  Color del cuerpo.

 bstyle

   [in]  Estilo del borde. Puede ser uno de los valores de la enumeración ENUM_CASE_BORDER_STYLE.

 bcol

   [in]  Color del borde.

 gap_size

   [in]  Tamaño del área entre la línea interior del borde y el elemento más cercano de la escala (en la fig. 3 el tamaño "g"). Puede ser uno de los valores de la enumeración ENUM_SIZE.


3.3. GaugeSetScaleParameters

Establece los parámetros de la escala.

void GaugeSetScaleParameters(
   GAUGE_STR &g,           // referencia a la estructura del instrumento
   int range,              // rango de la escala
   int rotation,           // ángulo de rotación
   double min,             // valor mínimo (izquierda)
   double max,             // valor máximo (derecha)
   ENUM_MUL_SCALE mul,     // multiplicador de las etiquetas de la escala
   ENUM_SCALE_STYLE style, // estilo de la escala
   color col,              // color de la escala
   bool display_arc        // mostrar la línea de la escala
);

Parámetros

 g

   [out]  Referencia a la estructura del instrumento.

 range

   [in]  Rango de la escala. Se establece como el ángulo formado por dos radio vectores de las marcas extremas de la escala. Puede adquirir los valores de 30 a 320 grados (fig. 3).

 rotation

   [in]  Ángulo de rotación de la escala (fig. 6).

 min

   [in]  Valor mínimo de la escala en caso de la enumeración directa.

 max

   [in]  Valor máximo de la escala en caso de la enumeración directa.

 mul

   [in]  Multiplicador de las etiquetas de la escala. Puede ser uno de los valores de la enumeración ENUM_MUL_SCALE.

 style

   [in]  Estilo de la escala. Puede ser uno de los valores de la enumeración ENUM_SCALE_STYLE.

 col

   [in]  Color de la escala.

 display_arc=false

   [in]  Visualización de la línea de la escala.


3.4. GaugeSetMarkParameters

Establece los parámetros de las marcas de graduación de la escala.

void GaugeSetMarkParameters(  
   GAUGE_STR &g,          // referencia a la estructura del instrumento
   ENUM_MARK_STYLE style, // estilo de las marcas del instrumento
   ENUM_SIZE size,        // tamaño de las marcas
   double major_tmi,      // paso de las marcas principales
   int middle_tmarks,     // cantidad de las marcas medianas entre las principales
   int minor_tmarks       // cantidad de las marcas pequeñas entre las medianas
);

Parámetros

 g

   [out]  Referencia a la estructura del instrumento.

 style

   [in]  Estilo de las marcas de la escala. Puede ser uno de los valores de la enumeración ENUM_MARK_STYLE.

 size

   [in]  Tamaño de las marcas. Puede ser uno de los valores de la enumeración ENUM_SIZE.

 major_tmi

   [in]  Paso de las marcas principales. Las marcas principales se acompañan con las etiquetas de los valores correspondientes.

 middle_tmarks

   [in]  Cantidad de las marcas medianas entre las marcas principales. El valor puede ser cualquier número positivo. No hay límite de la magnitud. Para el valor 0 las marcas medianas no se muestran.

 minor_tmarks

   [in]  Cantidad de las marcas pequeñas entre las marcas medianas (o las principales, si las medianas no se muestran). El valor puede ser cualquier número positivo. No hay límite de la magnitud. Para el valor 0 las marcas pequeñas no se muestran.


3.5. GaugeSetMarkLabelFont

Establece la fuente de las etiquetas de las marcas de la escala.

void GaugeSetMarkLabelFont(
   GAUGE_STR &g,        // referencia a la estructura del instrumento
   ENUM_SIZE font_size, // tamaño de la fuente 
   string font,         // la fuente
   bool italic,         // cursiva
   bool bold,           // negrita
   color col            // color
);

Parámetros

 g

   [out]  Referencia a la estructura del instrumento.

 font_size

   [in]  Tamaño de la fuente para las etiquetas de las marcas de la escala. Puede ser uno de los valores de la enumeración ENUM_SIZE.

 font

   [in]  Fuente.

 italic

   [in]  Cursiva.

 bold

   [in]  Negrita.

 col

   [in]  Color de la fuente.


3.6. GaugeSetLegendParameters

Establece los parámetros de la leyenda.

void GaugeSetLegendParameters(
   GAUGE_STR &g,         // referencia a la estructura del instrumento
   ENUM_GAUGE_LEGEND gl, // tipo de leyenda
   bool enable,          // mostrar leyenda
   string str,           // línea (o parámetro adicional)
   int radius,           // coordenadas - radio
   double angle,         // coordenadas - ángulo
   uint font_size,       // tamaño de la fuente
   string font,          // la fuente
   bool italic,          // cursiva
   bool bold,            // negrita
   color col             // color
);

Parámetros

 g

   [out]  Referencia a la estructura del instrumento

 gl

   [in]  Tipo de la leyenda. Puede ser uno de los valores de la enumeración ENUM_GAUGE_LEGEND.

 enable

   [in]  Mostrar la leyenda.

 str

   [in]  Para las leyendas del tipo LEGEND_DESCRIPTION o LEGEND_UNITS es la línea mostrada. Para la leyenda del tipo LEGEND_MUL este parámetro se ignora. Para la leyenda del tipo LEGEND_VALUE es el número de dígitos tras la coma. Puede tener los valores de 0 a 8. Cualquier otro valor se considera como 0. Por ejemplo, la línea “2” significa dos dígitos tras la coma. La línea “hello” significa 0 dígitos tras la coma.

 radius

   [in]  Radio. Distancia en unidades condicionales desde el centro del instrumento hasta el centro de la leyenda (fig. 9).

 angle

   [in]  Coordenada angular. Su valor es igual al ángulo entre el rayo que sale verticalmente hacia arriba del centro del instrumento y un segmento imaginario que une el centro del instrumento y el centro de la leyenda (fig. 9).

 font_size

   [in]  Tamaño de la fuente de la leyenda.

 font

   [in]  Fuente.

 italic

   [in]  Cursiva.

 bold

   [in]  Negrita.

 col

   [in]  Color de la fuente.


3.7. GaugeSetRangeParameters

Establece los parámetros del rango seleccionado.

void GaugeSetRangeParameters(
   GAUGE_STR &g, // referencia a la estructura del instrumento
   int index,    // índice del rango
   bool enable,  // mostrar el rango
   double start, // valor inicial
   double end,   // valor final
   color col     // color
);

Parámetros

 g

   [out]  Referencia a la estructura del instrumento.

 index

   [in]  Índice del rango. Puede tener los valores de 0 a 3.

 enable

   [in]  Mostrar la el rango.

 start

   [in]  Valor inicial.

 end

   [in]  Valor final.

 col

   [in]  Color para resaltar el rango.


3.8. GaugeSetNeedleParameters

Establece los parámetros de la aguja.

void GaugeSetNeedleParameters(
   GAUGE_STR &g,                     // referencia a la estructura del instrumento
   ENUM_NCENTER_STYLE ncenter_style, // estilo del centro de la aguja
   color ncenter_col,                // color del centro de la aguja
   color needle_col,                 // color de la aguja
   ENUM_NEEDLE_FILL needle_fill      // modo del relleno de la aguja
);

Parámetros

 g

   [out]  Referencia a la estructura del instrumento.

 ncenter_style

   [in]  Estilo del centro de la aguja. Puede ser uno de los valores de la enumeración ENUM_NCENTER_STYLE.

 ncenter_col

   [in]  Color del centro de la aguja.

 needle_col

   [in]  Color de la aguja.

 needle_fill

   [in]  Modo del relleno de la aguja. Puede ser uno de los valores de la enumeración ENUM_NEEDLE_FILL.


3.9. GaugeRedraw

Redibuja el instrumento indicador. La función debe invocarse después de alterar cualquier parámetro para que esos cambios tengan efecto.

void GaugeRedraw(
   GAUGE_STR &g       // referencia a la estructura del instrumento
); 

Parámetros

 g

   [in]  Referencia a la estructura del instrumento.


3.10. GaugeNewValue

Actualiza la posición de la aguja y el valor mostrado.

void GaugeNewValue(
   GAUGE_STR &g,     // referencia a la estructura del instrumento
   double v          // valor de la variable
);

Parámetros

 g

   [in]  Referencia a la estructura del instrumento.

 v

   [in]  Valor actual de la variable.


3.11. GaugeDelete

Elimina los objetos gráficos que forman parte del instrumento indicador. Hay que llamara a la función desde el manejador OnDeinit().

void GaugeDelete(
   GAUGE_STR &g      // referencia a la estructura del instrumento
);

Parámetros

 g

   [in]  Referencia a la estructura del instrumento.


3.12. GaugeCalcLocation

Calcula las coordenadas de los objetos del instrumento. Si el posicionamiento relativo está desactivado, siempre devolverá las mismas coordenadas. En caso contrario, las coordenadas pueden diferenciarse de los valores anteriores si el objeto de referencia ha cambiado su posición o tamaño.

bool GaugeCalcLocation( 
   GAUGE_STR& g         // referencia a la estructura del instrumento
);

Parámetros

 g

   [in]  Referencia a la estructura del instrumento.

Valor devuelto

 Devolverá true si los valores obtenidos se diferencian de los anteriores. De lo contrario, devuelve false. Si la función ha devuelto true, hay que llamar a la función GaugeRelocation() para aplicar los parámetros calculados.


3.13. GaugeRelocation

Coloca los objetos gráficos que componen el instrumento en el lugar establecido del gráfico. Es necesario llamarla si se indica el posicionamiento relativo y la función GaugeCalcLocation() ha devuelto true.

void GaugeRelocation(
   GAUGE_STR &g       // referencia a la estructura del instrumento
);

Parámetros

 g

   [in]  Referencia a la estructura del instrumento.


4. Enumeraciones

La tabla 2 contiene la lista de las enumeraciones que se utilizan como parámetros traspasados a las funciones.

Enumeración
Descripción
ENUM_CASE_BORDER_STYLEEstilo del borde
ENUM_CASE_STYLE
Estilo del cuerpo
ENUM_GAUGE_LEGEND
Tipo de la leyenda
ENUM_MARK_STYLE
Estilo de las marcas de la escala
ENUM_MUL_SCALE
Multiplicador de las etiquetas de graduaciones de la escala
ENUM_NCENTER_STYLEEstilo del centro de la aguja
ENUM_NEEDLE_FILLModo del relleno de la aguja
ENUM_REL_MODEModo del posicionamiento relativo
ENUM_SCALE_STYLEEstilo de la escala
ENUM_SIZETamaño

Tabla 2. Lista de enumeración


4.1. ENUM_CASE_BORDER_STYLE

Estilo del borde. Los valores se muestran en la tabla 3.

Identificador
Descripción
CASE_BORDER_NONE
Sin borde
CASE_BORDER_THINBorde fino
CASE_BORDER_THICK
Borde grueso

Tabla 3. Valores de ENUM_CASE_BORDER_STYLE

4.2. ENUM_CASE_STYLE

Estilo del cuerpo. Los valores se muestran en la tabla 4.

Identificador
Descripción
CASE_ROUND
Cuerpo circular
CASE_SECTOR
Cuerpo del tipo sector

Tabla 4. Valores de ENUM_CASE_STYLE

4.3. ENUM_GAUGE_LEGEND

Tipo de la leyenda. Los valores se muestran en la tabla 5.

Identificador
 Descripción
LEGEND_DESCRIPTIONDescripción del instrumento
LEGEND_UNITSUnidades de medición
LEGEND_MULMultiplicador de las etiquetas de la escala
LEGEND_VALUEValor actual de la variable

Tabla 5. Valores de ENUM_GAUGE_LEGEND

4.4. ENUM_MARK_STYLE

Estilo de las marcas de la escala. Los valores se muestran en la tabla 6.

Identificador
 Descripción
MARKS_INNERAlineación de las marcas por el borde interior
MARKS_MIDDLEAlineación de las marcas por el centro
MARKS_OUTERAlineación de las marcas por el borde exterior

Tabla 6. Valores de ENUM_MARK_STYLE

4.5. ENUM_MUL_SCALE

Multiplicador de las etiquetas de las marcas de la escala. Los valores se muestran en la tabla 7.

 IdentificadorValor
Visualización
MUL_1000010000
 х10k
MUL_10001000
 х1k
MUL_100100
 х100
MUL_1010
 х10
MUL_11
 No se muestra
MUL_010.1
 /10
MUL_0010.01
 /100
MUL_00010.001
 /1k
MUL_000010.0001
 /10k

Tabla 7. Valores de ENUM_MUL_SCALE

4.6. ENUM_NCENTER_STYLE

Estilo del centro de la aguja. Los valores se muestran en la tabla 8.

Identificador
Descripción
NDCS_NONENo se muestra el centro de la aguja
NDCS_SMALLMostrar el pequeño
NDCS_LARGEMostrar el grande

Tabla 8. Valores de ENUM_NCENTER_STYLE

4.7. ENUM_NEEDLE_FILL

Modo del relleno de la aguja. Los valores se muestran en la tabla 9.

 Identificador Descripción
NEEDLE_FILLRellenar la aguja sin suavizado de los bordes
NEEDLE_FILL_AARellenar la aguja con suavizado de los bordes
NEEDLE_NOFILL_AANo rellenar la aguja con suavizado de los bordes

Tabla 9. Valores de ENUM_NEEDLE_FILL

4.8. ENUM_REL_MODE

Modo del posicionamiento relativo. Los valores se muestran en la tabla 10.

 Identificador Descripción
RELATIVE_MODE_NONEPosicionamiento relativo desactivado
RELATIVE_MODE_HORHorizontalmente
RELATIVE_MODE_VERTVerticalmente
RELATIVE_MODE_DIAGPor la diagonal

Tab. 10. Valores de ENUM_REL_MODE

4.9. ENUM_SCALE_STYLE

Estilo de la escala. Los valores se muestran en la tabla 11.

Identificador
 Descripción
SCALE_INNEREtiquetas de las marcas en el lado interior de la escala
SCALE_OUTEREtiquetas de las marcas en el lado exterior de la escala

Tab. 11. Valores de ENUM_SCALE_STYLE

4.10. ENUM_SIZE

Tamaño. Los valores se muestran en la tabla 12.

Identificador
 Descripción
SIZE_SMALLPequeño
SIZE_MIDDLEMediano
SIZE_LARGEGrande

Tab. 12. Valores de ENUM_SIZE


5. Macro sustituciones

Coeficientes para los tamaños:

#define DIAM_TO_NDCSL_RATIO   5   //diámetro del centro de la aguja (small) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_NDCSB_RATIO   7.5 //diámetro del centro de la aguja (large) en por cientos respecto al diámetro del cuerpo
//---
#define DIAM_TO_BD_SIZE_S     2 //ancho del borde (small) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_BD_SIZE_B     5 //ancho del borde (large) en por cientos respecto al diámetro del cuerpo
//---
#define DIAM_TO_BD_GAP_S      2.0 //espacio desde el borde del cuerpo hasta los elementos internos del instrumento (small) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_BD_GAP_M      3.0 //espacio desde el borde del cuerpo hasta los elementos internos del instrumento (middle) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_BD_GAP_L      7.0 //espacio desde el borde del cuerpo hasta los elementos internos del instrumento (large) en por cientos respecto al diámetro del cuerpo
//---
#define DIAM_TO_MSZ_MJ_S      3.3 //tamaño de las marcas major de la escala (small) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_MSZ_MD_S      2.3 //tamaño de las marcas middle de la escala (small) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_MSZ_MN_S      1.3 //tamaño de las marcas minor de la escala (small) en por cientos respecto al diámetro del cuerpo
//---
#define DIAM_TO_MSZ_MJ_M      6.5 //tamaño de las marcas major de la escala (middle) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_MSZ_MD_M      4.8 //tamaño de las marcas middle de la escala (middle) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_MSZ_MN_M      3.0 //tamaño de las marcas minor de la escala (middle) en por cientos respecto al diámetro del cuerpo
//---
#define DIAM_TO_MSZ_MJ_L      10.0 //tamaño de las marcas major de la escala (large) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_MSZ_MD_L      7.5  //tamaño de las marcas middle de la escala (large) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_MSZ_MN_L      5.0  //tamaño de las marcas minor de la escala (large) en por cientos respecto al diámetro del cuerpo
//---
#define DIAM_TO_MFONT_SZ_S    4   //tamaño de la fuente de la etiquetas de las marcas (small) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_MFONT_SZ_M    6.5 //tamaño de la fuente de la etiquetas de las marcas (middle) en por cientos respecto al diámetro del cuerpo
#define DIAM_TO_MFONT_SZ_L    10  //tamaño de la fuente de la etiquetas de las marcas (large) en por cientos respecto al diámetro del cuerpo

Colores por defecto:

#define DEF_COL_SCALE      clrBlack
#define DEF_COL_MARK_FONT  clrBlack
#define DEF_COL_CASE       clrMintCream
#define DEF_COL_BORDER     clrLightSteelBlue
#define DEF_COL_LAB        clrDarkGray
#define DEF_COL_NCENTER    clrLightSteelBlue
#define DEF_COL_NEEDLE     clrDimGray


6. Últimos retoques de la clase CCanvas


6.1. Dibujo del segmento con suavizado

El método LineAA permite trazar un segmento usando el algoritmo de suavizado. Pero al dibujar las marcas de la escala ubicadas circularmente, aparece un problema. Al recalcular las coordenadas del origen y final del segmento del sistema de coordenadas polares al sistema de coordenadas rectangulares, se obtienen los números quebrados que se redondean a los números enteros, y la posición de las marcas se hace “torcida” como se ve en la imagen 11 (b).

Por eso ha sido añadido el método LineAA2 que se diferencia de LineAA sólo en que el tipo de los parámetros de entrada x1, y1, x2, y2 se cambia por double. Eso permite entregar los valores quebrados de las coordenadas y evitar el problema descrito, como se ve en la imagen 11(c).

//+------------------------------------------------------------------+
//| Draw line with antialiasing (with style) v.2                     |
//+------------------------------------------------------------------+
void CCanvas::LineAA2(const double x1,const double y1,const double x2,const double y2,const uint clr,const uint style)
  {
//--- line is out of image boundaries
   if((x1<0 && x2<0) || (y1<0 && y2<0))
      return;
   if(x1>=m_width && x2>=m_width)
      return;
   if(y1>=m_height && y2>=m_height)
      return;
//--- check
   if(x1==x2 && y1==y2)
     {
      PixelSet(int(x1),int(y1),clr);
      return;
     }
//--- set the line style
   if(style!=UINT_MAX)
      LineStyleSet(style);
//--- preliminary calculations
   double dx=x2-x1;
   double dy=y2-y1;
   double xy=sqrt(dx*dx+dy*dy);
   double xx=x1;
   double yy=y1;
   uint   mask=1<<m_style_idx;
//--- set pixels
   dx/=xy;
   dy/=xy;
   do
     {
      if((m_style&mask)==mask)
         PixelSetAA(xx,yy,clr);
      xx+=dx;
      yy+=dy;
      mask<<=1;
      if(mask==0x1000000)
         mask=1;
     }
   while(fabs(x2-xx)>=fabs(dx) && fabs(y2-yy)>=fabs(dy));
  } 

Para comparar, en la imagen 11 se muestran los ejemplos del trazado de las marcas usando diferentes métodos:

Métodos del dibujo de las marcas de la escala

Fig. 11. Ejemplos del trazado de las marcas usando diferentes métodos (zoom 200%)


6.2. Coloreado del área con bordes suavizados

El método Fill sirve para colorear el área limitada con los segmentos trazados sin usar el algoritmo de suavizado. Si intentamos colorear con él el área limitada con segmentos trazados con el método LineAA, el área se colorea de forma incompleta, como se ve en la imagen 12(a).

Coloreado del área con bordes suavizados

Fig. 12. Coloreado del área con bordes suavizados (zoom 200%)

Debido a eso, añadimos el método Fill2. La diferencia consiste en el hecho de que este método no colorea el color del fondo sino cualquier color que se diferencia del color de los segmentos que limitan el área. Eso permite colorear los semitonos que el método Fill no colorea. Puede verlo en la imagen 12(b).

//+------------------------------------------------------------------+
//| Fill closed region with color (v.2)                              |
//+------------------------------------------------------------------+
void CCanvas::Fill2(int x,int y,const uint clr)
  {
//--- check
   if(x<0 || x>=m_width || y<0 || y>=m_height)
      return;
//---
   int  index=y*m_width+x;
   uint old_clr=m_pixels[index];
//--- check if replacement is necessary
   if(old_clr==clr)
      return;
//--- use pseudo stack to emulate deeply-nested recursive calls
   int  stack[];
   uint count=1;
   int  idx;
   int  total=ArraySize(m_pixels);
//--- allocate memory for stack
   if(ArrayResize(stack,total)==-1)
      return;
   stack[0]=index;
   m_pixels[index]=clr;
   for(uint i=0;i<count;i++)
     {
      index=stack[i];
      x=index%m_width;
      //--- left adjacent point
      idx=index-1;
      if(x>0 && m_pixels[idx]!=clr)
        {
         stack[count]=idx;
         if(m_pixels[idx]==old_clr)
            count++;
         m_pixels[idx]=clr;
        }
      //--- top adjacent point
      idx=index-m_width;
      if(idx>=0 && m_pixels[idx]!=clr)
        {
         stack[count]=idx;
         if(m_pixels[idx]==old_clr)
            count++;
         m_pixels[idx]=clr;
        }
      //--- right adjacent point
      idx=index+1;
      if(x<m_width-1 && m_pixels[idx]!=clr)
        {
         stack[count]=idx;
         if(m_pixels[idx]==old_clr)
            count++;
         m_pixels[idx]=clr;
        }
      //--- bottom adjacent point
      idx=index+m_width;
      if(idx<total && m_pixels[idx]!=clr)
        {
         stack[count]=idx;
         if(m_pixels[idx]==old_clr)
            count++;
         m_pixels[idx]=clr;
        }
     }
//--- deallocate memory
   ArrayFree(stack);
  }  

A pesar de eso, este método también tiene sus defectos. Si hay un pequeño ángulo agudo, una parte se queda sin colorear, como se muestra en la imagen 12(c). Debido a eso, hemos encontrado la siguiente manera de evitar este problema.

   1)Primero, coloreamos el lienzo entero (capa de la aguja) con el color que debe usarse para colorear la aguja:

n.canvas.Fill(10, 10, ColorToARGB(n.needle.c, n.transparency));

   2) Luego dibujamos la aguja compuesta de tres segmentos usando el método LineAA2:

n.canvas.LineAA2(db_xbuf[0], db_ybuf[0], db_xbuf[1], db_ybuf[1], 0);
n.canvas.LineAA2(db_xbuf[1], db_ybuf[1], db_xbuf[2], db_ybuf[2], 0);
n.canvas.LineAA2(db_xbuf[2], db_ybuf[2], db_xbuf[0], db_ybuf[0], 0);

  3) A continuación, coloreamos el área alrededor de la aguja con el color transparente usando el método Fill2:

n.canvas.Fill2(10, 10, 0);

Este método no pretende ser el óptimo pero permite dibujar una aguja bonita.

Métodos del relleno de la aguja

Fig. 13. Agujas coloreadas con diferentes métodos

En la imagen 13 se muestran las agujas coloreadas con diferentes métodos.

  • a) Aguja compuesta de tres segmentos dibujados con el método LineAA2
    y coloreada con el método Fill2.
  • b) Aguja dibujada con el método FillTriangle.
  • c) Aguja compuesta de tres segmentos dibujados con el método LineAA2 sin relleno.

Como podemos observar, la aguja mostrada en la imagen 13(b) tiene un aspecto esquinado y pequeñas desviaciones de los ángulos múltiples de 90 grados. Además, podemos ver que la aguja se desplaza del centro. Eso se debe al redondeo de los valores de las coordenadas al recalcular del sistema polar al sistema triángular. No obstante, este método es el más económico desde el punto de vista de la intensidad del consumo de recursos (hablaremos de este asunto más tarde). La aguja de la imagen 13 (c) representa un compromiso entre dos métodos descritos anteriormente. Se compone de los segmentos dibujados con el método LineAA2 pero sin relleno.


7. Ejemplos de aplicación

Vamos a examinar la aplicación de la biblioteca de instrumentos indicadores a través de varios ejemplos.


7.1. Indicador del beneficio actual

Empezamos con lo más simple. El ejemplo de abajo demuestra el mínimo necesario para adicionar un instrumento de aguja en un EA o indicador.

//+------------------------------------------------------------------+
//|                                       profit_gauge_indicator.mq5 |
//|                                         Copyright 2015, Decanium |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Decanium"
#property version   "1.00"
#property indicator_plots 0
#property indicator_chart_window

#include <Gauge\gauge_graph.mqh>

input string inp_gauge_name="gg01";                  // Nombre del indicador
input int inp_x = 40;                                // Desplazamiento por la horizontal
input int inp_y = 40;                                // Desplazamiento por la vertical
input int inp_size=300;                              // Tamaño del indicador
input string inp_ObjRel="";                          // Nombre del indicador base en caso del posicionamiento relativo
input ENUM_REL_MODE inp_rel_mode=RELATIVE_MODE_NONE; // Modo del posicionamiento relativo
input ENUM_BASE_CORNER inp_corner=CORNER_LEFT_UPPER; // Esquina de anclaje
input bool inp_back=false;                           // Indicador al fondo
input uchar inp_scale_transparency=0;                // Grado de transparencia de la escala, 0..255
input uchar inp_needle_transparency=0;               // Grado de transparencia de la aguja, 0..255

//--- declaración de la estructura del instrumento
GAUGE_STR g0;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- creación del instrumento
   if(GaugeCreate(inp_gauge_name,g0,inp_x,inp_y,inp_size,inp_ObjRel,inp_rel_mode,
      inp_corner,inp_back,inp_scale_transparency,inp_needle_transparency)==false)
      return(INIT_FAILED);
//--- dibujo del instrumento
   GaugeRedraw(g0);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- eliminación del instrumento
   GaugeDelete(g0);
   ChartRedraw();
  }    
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//--- actualización de datos
   double profit=AccountInfoDouble(ACCOUNT_PROFIT);
   GaugeNewValue(g0,profit);
//---
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      if(GaugeCalcLocation(g0)==true)
         GaugeRelocation(g0);
     }
  }
//+------------------------------------------------------------------+

Primero, hay que declarar la estructura del instrumento indicador. Luego continuamos con la función de inicialización donde creamos el instrumento usando GaugeCreate() y llamamos a la función del dibujo GaugeRedraw(). Para la actualización de los datos se utiliza GaugeNewValue(). En este ejemplo se llama desde el manejador OnCalculate().

El instrumento indicador va a ser como se muestra en la imagen 14.

Presentación del indicador, valores de los parámetros por defecto

Fig. 14. Presentación del instrumento indicador por defecto

Ahora vamos a añadir las posibilidades de configurar el rango de la escala y ángulo de rotación. Para eso, la lista de los parámetros de entrada se completa con otros dos.

input int inp_scale_range=270;   // Rango de la escala, 30..320 grados
input int inp_rotation=45;       // Giro de la escala, 0..359 grados

Ampliamos el código de inicialización con la llamada a la función para establecer los parámetros de la escala.

//--- establecer los parámetros de la escala y las marcas en la escala
   GaugeSetScaleParameters(g0,inp_scale_range,inp_rotation,-200,400,MUL_1,SCALE_INNER,clrBlack);

Aquí, además de los parámetros nuevo, también serán establecidos los siguientes:

  • nuevos valores del mínimo y del máximo (-200 y 400, respectivamente)
  • multiplicador de las etiquetas de las marcas de la escala (MUL_1)
  • estilo de la escala (SCALE_INNER — etiquetas de las marcas están dentro)
  • color de las marcas de la escala (clrBlack)

Como hemos cambiado los valores extremos de la escala, es deseable corregir el paso de las marcas principales. Para no sobrecargar con el texto, el paso óptimo será 100. Vamos a colocar una marca mediana entre las marcas principales y 4 pequeñas entre las medianas. De esta manera, el paso mínimo de las marcas será 10.

   GaugeSetMarkParameters(g0,MARKS_INNER,SIZE_MIDDLE,100,1,4);

Resaltamos dos rangos de datos. El rango con el índice 0 que se empieza con 200 y se termina con 400 tendrá el color clrLimeGreen. El rango con el índice 1 que se empieza con -100 y se termina con -200 tendrá el color clrCoral.

//--- resalto de los rangos en la escala
   GaugeSetRangeParameters(g0,0,true,200,400,clrLimeGreen);
   GaugeSetRangeParameters(g0,1,true,-100,-200,clrCoral);

Vamos a configurar la visualización de las leyendas. Determinamos la descripción del instrumento, unidades de medición y valor actual con un dígito tras la coma. Vamos a ir paso a paso.

Descripción del instrumento:

   GaugeSetLegendParameters(g0,LEGEND_DESCRIPTION,true,"Profit",3,0,14,"Arial",false,false);

Visualización del texto "Profit", radio 3, ángulo 0, tamaño de la fuente 14 unidades condicionales.

Unidades de medición:

   GaugeSetLegendParameters(g0,LEGEND_UNITS,true,"USD",8,215,10,"Arial",true,false);

Visualización del texto "USD", radio 8, ángulo 215, tamaño de la fuente 10 unidades condicionales.

Valor actual:

   GaugeSetLegendParameters(g0,LEGEND_VALUE,true,"1",4,225,20,"Arial",true,false);

Aquí la línea “1” significa el formato de la visualización: un dígito tras la coma. Coordenadas: radio 4, ángulo 255. Tamaño de la fuente: 20 unidades condicionales.

Bien, después de los ajustes adicionales, el instrumento tendrá el siguiente aspecto (fig. 15).

Indicador del beneficio actual

Fig. 15. Presentación del instrumento indicador después de los ajustes adicionales


7.2. Indicador Dashboard

Vamos a ver un ejemplo más complicado: indicador Dashboard. Se muestra en la imagen 1. El instrumento muestra el beneficio, spread, nivel del margen libre en por cientos y los valores actuales de los indicadores técnicos ATR, Force Index y RSI.

Primero, vamos a declarar el array de las estructuras del instrumento. 

//--- declaración del array de las estructuras del instrumento
GAUGE_STR gg[6];

Luego creamos y configuramos los instrumentos.

El indicador del nivel del margen libre estará en la esquina inferior izquierda. Va a tener las coordenadas absolutas y todos los demás indicadores van a ubicarse respecto a él o respecto al indicador vecino.

//--- creación del instrumento gg00, nivel del margen
   if(GaugeCreate("gg00",gg[0],5,-90,240,"",RELATIVE_MODE_NONE,
      CORNER_LEFT_LOWER,inp_back,inp_scale_transparency,inp_needle_transparency)==false)
      return(INIT_FAILED);
//--- configuración de los parámetros del cuerpo
   GaugeSetCaseParameters(gg[0],CASE_SECTOR,DEF_COL_CASE,CASE_BORDER_THIN,DEF_COL_BORDER,SIZE_MIDDLE);
//--- configuración de los parámetros de la escala y las marcas en la escala
   GaugeSetScaleParameters(gg[0],120,35,800,2000,MUL_100,SCALE_INNER,clrBlack);
   GaugeSetMarkParameters(gg[0],MARKS_INNER,SIZE_MIDDLE,200,1,4);
   GaugeSetMarkLabelFont(gg[0],SIZE_MIDDLE,"Arial",false,false,DEF_COL_MARK_FONT);
//--- resalto de los rangos en la escala
   GaugeSetRangeParameters(gg[0],0,true,1400,2000,clrLimeGreen);
   GaugeSetRangeParameters(gg[0],1,true,1000,800,clrCoral);
//--- configuración de las marcas del texto
   GaugeSetLegendParameters(gg[0],LEGEND_DESCRIPTION,true,"Margin lvl",4,15,12,"Arial",false,false);
   GaugeSetLegendParameters(gg[0],LEGEND_VALUE,true,"0",3,80,16,"Arial",true,false);
   GaugeSetLegendParameters(gg[0],LEGEND_MUL,true,"",4,55,8,"Arial",true,false);
//--- configuración de los parámetros de la aguja
   GaugeSetNeedleParameters(gg[0],NDCS_SMALL,DEF_COL_NCENTER,DEF_COL_NEEDLE,NEEDLE_FILL_AA);

Continuamos organizando la línea de abajo. El siguiente es el indicador del beneficio actual.

//--- creación del instrumento gg01, beneficio actual
   if(GaugeCreate("gg01",gg[1],-80,20,320,"gg00",RELATIVE_MODE_HOR,
      CORNER_LEFT_LOWER,inp_back,inp_scale_transparency,inp_needle_transparency)==false)
      return(INIT_FAILED);
//--- configuración de los parámetros del cuerpo
   GaugeSetCaseParameters(gg[1],CASE_SECTOR,DEF_COL_CASE,CASE_BORDER_THIN,DEF_COL_BORDER,SIZE_MIDDLE);
//--- configuración de los parámetros de la escala y las marcas en la escala
   GaugeSetScaleParameters(gg[1],200,0,-400,400,MUL_1,SCALE_INNER,clrBlack);
   GaugeSetMarkParameters(gg[1],MARKS_INNER,SIZE_MIDDLE,100,1,4);
   GaugeSetMarkLabelFont(gg[1],SIZE_MIDDLE,"Arial",false,false,DEF_COL_MARK_FONT);
//--- resalto de los rangos en la escala
   GaugeSetRangeParameters(gg[1],0,true,200,400,clrLimeGreen);
   GaugeSetRangeParameters(gg[1],1,true,-200,-400,clrCoral);
//--- configuración de las marcas del texto
   GaugeSetLegendParameters(gg[1],LEGEND_DESCRIPTION,true,"Profit",3,0,16,"Arial",false,false);
   GaugeSetLegendParameters(gg[1],LEGEND_UNITS,true,"USD",3,-90,10,"Arial",true,false);
   GaugeSetLegendParameters(gg[1],LEGEND_VALUE,true,"1",3,90,12,"Arial",true,false);
//--- configuración de los parámetros de la aguja
   GaugeSetNeedleParameters(gg[1],NDCS_SMALL,DEF_COL_NCENTER,DEF_COL_NEEDLE,NEEDLE_FILL_AA);

El siguiente es el indicador del spread.

//--- creación del instrumento gg02, spread
   if(GaugeCreate("gg02",gg[2],-80,-20,240,"gg01",RELATIVE_MODE_HOR,
      CORNER_LEFT_LOWER,inp_back,inp_scale_transparency,inp_needle_transparency)==false)
      return(INIT_FAILED);
//--- configuración de los parámetros del cuerpo
   GaugeSetCaseParameters(gg[2],CASE_SECTOR,DEF_COL_CASE,CASE_BORDER_THIN,DEF_COL_BORDER,SIZE_MIDDLE);
//--- configuración de los parámetros de la escala y las marcas en la escala
   GaugeSetScaleParameters(gg[2],120,-35,60,0,MUL_1,SCALE_INNER,clrBlack);
   GaugeSetMarkParameters(gg[2],MARKS_INNER,SIZE_MIDDLE,10,1,4);
   GaugeSetMarkLabelFont(gg[2],SIZE_MIDDLE,"Arial",false,false,DEF_COL_MARK_FONT);
//--- resalto de los rangos en la escala
   GaugeSetRangeParameters(gg[2],0,true,35,10,clrLimeGreen);
   GaugeSetRangeParameters(gg[2],1,true,50,60,clrCoral);
//--- configuración de las marcas del texto
   GaugeSetLegendParameters(gg[2],LEGEND_DESCRIPTION,true,"Spread",4,-15,14,"Arial",false,false);
   GaugeSetLegendParameters(gg[2],LEGEND_VALUE,true,"0",3,-80,16,"Arial",true,false);
//--- configuración de los parámetros de la aguja
   GaugeSetNeedleParameters(gg[2],NDCS_SMALL,DEF_COL_NCENTER,DEF_COL_NEEDLE,NEEDLE_FILL_AA);

El indicador ATR (arriba a la izquierda) se ubica respecto al indicador del margen libre.

//--- creación del instrumento gg03, ATR
   if(GaugeCreate("gg03",gg[3],30,0,180,"gg00",RELATIVE_MODE_VERT,
      CORNER_LEFT_LOWER,inp_back,inp_scale_transparency,inp_needle_transparency)==false)
      return(INIT_FAILED);
//--- configuración de los parámetros del cuerpo
   GaugeSetCaseParameters(gg[3],CASE_ROUND,DEF_COL_CASE,CASE_BORDER_THIN,DEF_COL_BORDER,SIZE_MIDDLE);
//--- configuración de los parámetros de la escala y las marcas en la escala
   GaugeSetScaleParameters(gg[3],270,45,0.001,0.004,MUL_00001,SCALE_INNER,clrBlack);
   GaugeSetMarkParameters(gg[3],MARKS_INNER,SIZE_LARGE,0.001,9,3);
   GaugeSetMarkLabelFont(gg[3],SIZE_LARGE,"Arial",false,false,DEF_COL_MARK_FONT);
//--- resalto de los rangos en la escala
   GaugeSetRangeParameters(gg[3],0,true,0.002,0.001,clrYellow);
//--- configuración de las marcas del texto
   GaugeSetLegendParameters(gg[3],LEGEND_DESCRIPTION,true,"ATR",7,-140,26,"Arial",false,false);
//GaugeSetLegendParameters(gg[3],LEGEND_UNITS,true,"USD",8,180,5,"Arial",true,false);
   GaugeSetLegendParameters(gg[3],LEGEND_VALUE,true,"5",2,180,14,"Arial",true,false);
   GaugeSetLegendParameters(gg[3],LEGEND_MUL,true,"",2,0,20,"Arial",true,false);
//--- configuración de los parámetros de la aguja
   GaugeSetNeedleParameters(gg[3],NDCS_SMALL,DEF_COL_NCENTER,DEF_COL_NEEDLE,NEEDLE_FILL_AA);

El indicador RSI se ubica respecto al indicador del spread, encima de él.

//--- creación del instrumento gg04, RSI
   if(GaugeCreate("gg04",gg[4],-30,0,180,"gg02",RELATIVE_MODE_VERT,
      CORNER_LEFT_LOWER,inp_back,inp_scale_transparency,inp_needle_transparency)==false)
      return(INIT_FAILED);
//--- configuración de los parámetros del cuerpo
   GaugeSetCaseParameters(gg[4],CASE_ROUND,DEF_COL_CASE,CASE_BORDER_THIN,DEF_COL_BORDER,SIZE_MIDDLE);
//--- configuración de los parámetros de la escala y las marcas en la escala
   GaugeSetScaleParameters(gg[4],270,45,0,100,MUL_10,SCALE_INNER,clrBlack);
   GaugeSetMarkParameters(gg[4],MARKS_INNER,SIZE_LARGE,10,1,4);
   GaugeSetMarkLabelFont(gg[4],SIZE_LARGE,"Arial",false,false,DEF_COL_MARK_FONT);
//--- configuración de las marcas del texto
   GaugeSetLegendParameters(gg[4],LEGEND_DESCRIPTION,true,"RSI",7,-140,26,"Arial",false,false);
   GaugeSetLegendParameters(gg[4],LEGEND_VALUE,true,"2",2,180,16,"Arial",true,false);
   GaugeSetLegendParameters(gg[4],LEGEND_MUL,true,"",2,0,20,"Arial",true,false);
//--- configuración de los parámetros de la aguja
   GaugeSetNeedleParameters(gg[4],NDCS_SMALL,DEF_COL_NCENTER,DEF_COL_NEEDLE,NEEDLE_FILL_AA);

El indicador Force Index se ubica encima del indicador del beneficio actual.

//--- creación del instrumento gg05, Force
   if(GaugeCreate("gg05",gg[5],-10,60,180,"gg03",RELATIVE_MODE_HOR,
      CORNER_LEFT_LOWER,inp_back,inp_scale_transparency,inp_needle_transparency)==false)
      return(INIT_FAILED);
//--- configuración de los parámetros del cuerpo
   GaugeSetCaseParameters(gg[5],CASE_ROUND,DEF_COL_CASE,CASE_BORDER_THIN,DEF_COL_BORDER,SIZE_MIDDLE);
//--- configuración de los parámetros de la escala y las marcas en la escala
   GaugeSetScaleParameters(gg[5],270,45,-4,4,MUL_1,SCALE_INNER,clrBlack);
   GaugeSetMarkParameters(gg[5],MARKS_INNER,SIZE_LARGE,1,1,4);
   GaugeSetMarkLabelFont(gg[5],SIZE_LARGE,"Arial",false,false,DEF_COL_MARK_FONT);
//--- resalto de los rangos en la escala
   GaugeSetRangeParameters(gg[5],0,true,-1,-4,clrMediumSeaGreen);
   GaugeSetRangeParameters(gg[5],1,true,1,4,clrCrimson);
//--- configuración de las marcas del texto
   GaugeSetLegendParameters(gg[5],LEGEND_DESCRIPTION,true,"Force",7,-140,20,"Arial",false,false);
   GaugeSetLegendParameters(gg[5],LEGEND_VALUE,true,"5",2,180,14,"Arial",true,false);
   GaugeSetLegendParameters(gg[5],LEGEND_MUL,true,"",3,0,10,"Arial",true,false);
//--- configuración de los parámetros de la aguja
   GaugeSetNeedleParameters(gg[5],NDCS_SMALL,DEF_COL_NCENTER,DEF_COL_NEEDLE,NEEDLE_FILL_AA);

Los instrumentos pueden ser diseñados de manera cíclica.

//--- dibujo de instrumentos
   for(int i=0; i<6;i++)
     {
      GaugeRedraw(gg[i]);
      GaugeNewValue(gg[i],0);
     }

Cuando ocurre el evento OnCalculate(), recalculamos los valores actuales y llamamos a la función GaugeNewValue() para cada indicador.

//--- actualización de datos
//--- spread
   GaugeNewValue(gg[2],spread[rates_total-1]);
//--- beneficio actual   
   double profit=AccountInfoDouble(ACCOUNT_PROFIT);
   GaugeNewValue(gg[1],profit);
//--- nivel del margen
   double margin_level=AccountInfoDouble(ACCOUNT_MARGIN_LEVEL);
   GaugeNewValue(gg[0],margin_level);
//--- indicador ATR
   calculated=BarsCalculated(handle_ATR);
   if(calculated>0)
     {
      double ival[1];
      if(CopyBuffer(handle_ATR,0,0,1,ival)<0)
         Print("ATR CopyBuffer error");
      else
         GaugeNewValue(gg[3],ival[0]);
     }
//--- indicador RSI
   calculated=BarsCalculated(handle_RSI);
   if(calculated>0)
     {
      double ival[1];
      if(CopyBuffer(handle_RSI,0,0,1,ival)<0)
         Print("RSI CopyBuffer error");
      else
         GaugeNewValue(gg[4],ival[0]);
     }
//--- indicador Force Index
   calculated=BarsCalculated(handle_Force);
   if(calculated>0)
     {
      double ival[1];
      if(CopyBuffer(handle_Force,0,0,1,ival)<0)
         Print("Force Index CopyBuffer error");
      else
         GaugeNewValue(gg[5],ival[0]);
     }

Por favor, nótese que en este ejemplo no tiene sentido llamar GaugeRelocation() desde el evento OnChartEvent(). Aunque aquí se utiliza el posicionamiento relativo, no puede surgir la situación cuando se cambia la ubicación o el tamaño de uno de ellos y hay que recalcular las coordenadas del otro, porque los instrumentos se inicializan al mismo tiempo.


8. Evaluación del consumo de recursos

Cada vez que se actualicen los datos, la capa de la aguja se redibuja completamente. Eso puede pasar con bastante frecuencia, varias veces por segundo, en algunas ocasiones. Por eso el problema de la intensidad del consumo de recursos durante el dibujo de la aguja es bastante grave. Para evaluar el consumo de recursos del procesador relacionados con el diseño de la aguja usando diferentes métodos de relleno, escribiremos un script.

//+------------------------------------------------------------------+
//|                                                    test_fill.mq5 |
//|                                         Copyright 2015, Decanium |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Decanium"
#property version   "1.00"

#include <Canvas/Canvas2.mqh>

CCanvas canvas;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   Print("***** start test *****");
//---
   string ObjName="test";
   ObjectDelete(0,ObjName);
   canvas.CreateBitmapLabel(ObjName,10,10,400,400,COLOR_FORMAT_ARGB_NORMALIZE);
//---
   int x[3]={200,185,215};
   int y[3]={70, 250,250};
   int cycles=1000;
   uint col=ColorToARGB(clrRed,255);
   uint c1,c2;
//--- prueba del relleno con suavizado de los bordes
   canvas.Erase();
   c1=GetTickCount();
   for(int i=0; i<cycles; i++)
     {
      canvas.Fill(10, 10, col);
      canvas.LineAA2(x[0], y[0], x[1], y[1], 0);
      canvas.LineAA2(x[1], y[1], x[2], y[2], 0);
      canvas.LineAA2(x[2], y[2], x[0], y[0], 0);
      canvas.Fill2(10, 10, 0);
     }
   c2=GetTickCount();
   canvas.Update(true);
   Print("Filled AA: ",c2-c1," ms, ",cycles," cycles, ",
         DoubleToString(double(c2-c1)/double(cycles),2)," ms per cycle");
//--- prueba del contorno suavizado sin relleno
   canvas.Erase();
   c1=GetTickCount();
   for(int i=0; i<cycles; i++)
     {
      canvas.LineAA2(x[0], y[0], x[1], y[1], col);
      canvas.LineAA2(x[1], y[1], x[2], y[2], col);
      canvas.LineAA2(x[2], y[2], x[0], y[0], col);
     }
   c2=GetTickCount();
   canvas.Update(true);
   Print("Not filled AA: ",c2-c1," ms, ",cycles," cycles, ",
         DoubleToString(double(c2-c1)/double(cycles),2)," ms per cycle");
//--- prueba del relleno sin suavizado
   canvas.Erase();
   c1=GetTickCount();
   for(int i=0; i<cycles; i++)
     {
      canvas.FillTriangle(x[0],y[0],x[1],y[1],x[2],y[2],col);
      canvas.LineAA2(x[0], y[0], (x[1]+x[2])/2, y[1], col);
     }
   c2=GetTickCount();
   canvas.Update(true);
   Print("Filled: ",c2-c1," ms, ",cycles," cycles, ",
         DoubleToString(double(c2-c1)/double(cycles),2)," ms per cycle");
  }
//+------------------------------------------------------------------+

El script inicia cada uno de los modos de dibujo de la aguja 1000 veces en el ciclo y calcula el tiempo gastado para este proceso en milisegundos.

Prueba del consumo de recursos

Fig. 16. Resultados de la prueba del consumo de recursos

Como podemos ver de los resultados, el diseño de una aguja con coloreado y suavizado requiere centenas de veces más de tiempo que el diseño con coloreado y sin suavizado, y decenas de veces más de tiempo que el diseño del contorno suavizado sin colorear. En este caso, la belleza realmente tiene su precio.


Conclusión

En este artículo hemos analizado un conjunto de funciones para el diseño de los instrumentos de aguja. El principal objetivo durante la creación de la biblioteca era la sencillez de incorporación de los instrumentos en un Asesor Experto o indicador sin entrar en los detalles del dibujo y geometría. Pues, le toca a Usted decidir si hemos alcanzado este objetivo o no.

La cuestión de la intensidad del consumo de recursos requiere una atención especial. Las computaciones prolongadas en el manejador OnCalculate() pueden provocar la suspensión del terminal. Por eso como compromiso, se recomienda dibujar la aguja suavizada sin colorearla.

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

Archivos adjuntos |
dashboard.mq5 (22.69 KB)
canvas2.mqh (171.52 KB)
gauge_graph.mqh (154.69 KB)
Prueba y optimización de Asesores Expertos Prueba y optimización de Asesores Expertos
El artículo proporciona una descripción detallada del proceso de probar y optimizar los EA's en el probador de estrategias del MetaTrader 4. No se puede subestimar la importancia de dicha información y la necesidad de esta publicación. Muchos usuarios, sólo empezar a trabajar con la plataforma de trading MetaTrader 4 tienen una idea muy vaga de qué y cuales las necesidades a realizar cuando se trabaja con Asesores Expertos. El artículo propuesto da respuesta sencilla y clara a todas estas preguntas y proporciona un método un poco más profesional para manejar estas cuestiones con un ejemplo concreto.
MetaTrader 4 en Mac OS MetaTrader 4 en Mac OS
Los productos de Apple se han convertido en muy populares. MetaQuotes Software Corp. siguiendo atentamente el progreso de la industria TI ya se han publicado las aplicaciones especiales móviles para dispositivos basados en iOS - MetaTrader 4 para iPhone y MetaTrader 5 para iPhone. Hay muchos temas en el foro de MQL4.community, donde la gente está buscando una solución para el funcionamiento de MetaTrader 4 bajo sistema operativo Mac OS. En este artículo, usted encontrará la manera de trabajar en MetaTrader 4 a través del popular sistema operativo de Apple.
Gráficos sin conexión en el nuevo MQL4 Gráficos sin conexión en el nuevo MQL4
El MQL4 actualizado tiene un nuevo formato para almacenar datos históricos y proporciona la estructura adecuada de MqlRates para el almacenaje conveniente de los valores tiempo, apertura, bajo, alto, cierre y volumen. Durante muchos años, los traders han desarrollado sus aplicaciones MQL4 que recogen y almacenan sus datos en ficheros HST para generar gráficos offline. Podemos asegurar que todos los archivos EX4 previamente compilados trabajarán en la nueva terminal MetaTrader 4 del mismo modo que antes.
Kit del Trader: Librería  del trade de arraste Kit del Trader: Librería del trade de arraste
El artículo describe la librería del trade de arrastre que proporciona funcionalidad para el comercio visual. La librería puede integrarse fácilmente en prácticamente cualquier Asesor Experto. Su Asesor Experto puede transformarse de un autómata de un trading automatizado y tener a su lado un sistema de información casi sin esfuerzo agregando simplemente unas pocas líneas de código.