- Descripción de recursos mediante la directiva #resource
- Uso compartido de recursos de distintos programas MQL
- Variables de recursos
- Conectar indicadores personalizados como recursos
- Creación de recursos dinámicos: ResourceCreate
- Eliminar recursos dinámicos: ResourceFree
- Leer y modificar datos de recursos: RecursoReadImage
- Guardar imágenes en un archivo: ResourceSave
- Fuentes y salida de texto a recursos gráficos
- Aplicación de recursos gráficos en trading
Conectar indicadores personalizados como recursos
Para su funcionamiento, los programas MQL pueden requerir uno o varios indicadores personalizados. Todos ellos pueden incluirse como recursos en el ejecutable ex5, lo que facilita su distribución e instalación.
La directiva #resource con la descripción del indicador anidado tiene el siguiente formato:
#resource "path_indicator_name.ex5" |
Las reglas de configuración y búsqueda del archivo especificado son las mismas que para todos los recursos en general.
Ya hemos utilizado esta función en el ejemplo de Asesor Experto, en la versión final de UnityMartingale.mq5.
#resource "\\Indicators\\MQL5Book\\p6\\UnityPercentEvent.ex5" |
En ese Asesor Experto, en lugar del nombre del indicador, este recurso se pasó a la función iCustom: «::Indicators\\MQL5Book\\p6\\UnityPercentEvent.ex5».
El caso en que un indicador personalizado en la función OnInit crea una o más instancias de sí mismo requiere una consideración aparte (si esta solución técnica en sí parece extraña, daremos un ejemplo práctico después de los ejemplos introductorios).
Como sabemos, para utilizar un recurso desde un programa MQL, debe especificarse de la siguiente forma: ruta_nombre_archivo.ex5::nombre_del_recurso. Por ejemplo, si el indicador EmbeddedIndicator.ex5 se incluye como recurso en otro indicador MainIndicator.mq5 (más concretamente, en su imagen binaria MainIndicator.ex5), entonces el nombre especificado al llamarse a sí mismo a través de iCustom ya no puede ser corto, sin una ruta, y la ruta debe incluir la ubicación del indicador «padre» dentro de la carpeta MQL5. De lo contrario, el sistema no podrá encontrar el indicador anidado.
De hecho, en circunstancias normales, un indicador puede llamarse a sí mismo utilizando, por ejemplo, el operador iCustom(_Symbol, _Period, myself,...), donde myself es una cadena igual a MQLInfoString(MQL_PROGRAM_NAME) o al nombre que se asignó previamente a la propiedad INDICATOR_SHORTNAME en el código. Pero cuando el indicador se encuentra dentro de otro programa MQL como recurso, el nombre ya no hace referencia al archivo correspondiente porque el archivo que servía de prototipo para el recurso se quedó en el ordenador donde se realizó la compilación, y en el ordenador del usuario sólo existe el archivo MainIndicator.ex5. Esto requerirá un cierto análisis del entorno del programa al iniciar el programa.
Veámoslo en la práctica.
Para empezar, vamos a crear un indicador NonEmbeddedIndicator.mq5. Es importante señalar que se encuentra en la carpeta MQL5/Indicators/MQL5Book/p7/SubFolder/, es decir, en una SubFolder relativa a la carpeta p7 asignada para todos los indicadores de esta parte del libro. Esto se hace intencionadamente para emular una situación en la que el archivo compilado no está presente en el ordenador del usuario. Ahora veremos cómo funciona (o mejor dicho, demuestra el problema).
El indicador tiene un único parámetro de entrada Reference. Su propósito es contar el número de copias de sí mismo: cuando se crea por primera vez, el parámetro es igual a 0, y el indicador creará su propia copia con el valor de parámetro de 1. La segunda copia, después de «ver» el valor 1, ya no creará otra copia (de lo contrario nos quedaríamos rápidamente sin recursos sin la condición límite para detener la reproducción).
input int Reference = 0; |
La variable handle está reservada para el manejador del indicador de copia.
int handle = 0; |
En el manejador OnInit, para mayor claridad, primero mostramos el nombre y la ruta del programa MQL.
int OnInit()
|
A continuación viene el código adecuado para el auto-lanzamiento de un indicador independiente (existente en forma del conocido archivo NonEmbeddedIndicator.ex5).
if(Reference == 0)
|
Podríamos colocar con éxito un indicador de este tipo en el gráfico y recibir entradas del tipo siguiente en el registro (usted tendrá sus propias rutas del sistema de archivos):
0 Name: NonEmbeddedIndicator Full path: C:\Program Files\MT5East\MQL5\Indicators\MQL5Book\p7\SubFolder\NonEmbeddedIndicator.ex5 Success 1 Name: NonEmbeddedIndicator Full path: C:\Program Files\MT5East\MQL5\Indicators\MQL5Book\p7\SubFolder\NonEmbeddedIndicator.ex5 Success |
La copia se ha iniciado correctamente con sólo utilizar el nombre «NonEmbeddedIndicator».
Dejemos este indicador por ahora y creemos un segundo, FaultyIndicator.mq5, en el que incluiremos el primer indicador como recurso (preste atención a la especificación de subfolder en la ruta relativa del recurso; esto es necesario porque el indicador FaultyIndicator.mq5 se encuentra en la carpeta de un nivel superior: MQL5/Indicators/MQL5Book/p7/).
// FaultyIndicator.mq5
|
Si intenta ejecutar el archivo compilado FaultyIndicator.ex5 se producirá un error:
0 Name: NonEmbeddedIndicator Full path: C:\Program Files\MT5East\MQL5\Indicators\MQL5Book\p7\FaultyIndicator.ex5 » » ::SubFolder\NonEmbeddedIndicator.ex5 cannot load custom indicator 'NonEmbeddedIndicator' [4802] |
Cuando se lanza una copia de un indicador anidado, se busca en la carpeta del indicador principal, en la que se describe el recurso. Pero no hay ningún archivo NonEmbeddedIndicator.ex5 porque el recurso requerido está dentro de FaultyIndicator.ex5.
Para resolver el problema, modificamos NonEmbeddedIndicator.mq5. En primer lugar, démosle otro nombre más apropiado, EmbeddedIndicator.mq5. En el código fuente tenemos que añadir una función de ayuda GetMQL5Path, que puede aislar la parte relativa dentro de la carpeta MQL5 de la ruta general del programa MQL lanzado (esta parte también contendrá el nombre del recurso si el indicador se lanza desde un recurso).
// EmbeddedIndicator.mq5
|
Teniendo en cuenta la nueva función, cambiaremos la llamada a iCustom en el manejador OnInit.
int OnInit()
|
Asegurémonos de que esta edición no rompe el lanzamiento del indicador. La superposición en un gráfico hace que aparezcan las líneas esperadas en el registro:
0 Name: EmbeddedIndicator Full path: C:\Program Files\MT5East\MQL5\Indicators\MQL5Book\p7\SubFolder\EmbeddedIndicator.ex5 Location in MQL5:\Indicators\MQL5Book\p7\SubFolder\EmbeddedIndicator.ex5 Success 1 Name: EmbeddedIndicator Full path: C:\Program Files\MT5East\MQL5\Indicators\MQL5Book\p7\SubFolder\EmbeddedIndicator.ex5 Location in MQL5:\Indicators\MQL5Book\p7\SubFolder\EmbeddedIndicator.ex5 Success |
Aquí añadimos la salida de depuración de la ruta relativa que recibió la función GetMQL5Path. Esta línea se utiliza ahora en iCustom, y funciona de este modo: se ha creado una copia.
Ahora vamos a incrustar este indicador como un recurso en otro indicador en la carpeta MQL5Book/p7 con el nombre MainIndicator.mq5. MainIndicator.mq5 es completamente idéntico a FaultyIndicator.mq5 excepto por el recurso conectado.
// MainIndicator.mq5
|
Vamos a compilarlo y ejecutarlo. Las entradas aparecen en el registro con una nueva ruta relativa que incluye el recurso anidado.
0 Name: EmbeddedIndicator Full path: C:\Program Files\MT5East\MQL5\Indicators\MQL5Book\p7\MainIndicator.ex5 » » ::SubFolder\EmbeddedIndicator.ex5 Location in MQL5:\Indicators\MQL5Book\p7\MainIndicator.ex5::SubFolder\EmbeddedIndicator.ex5 Success 1 Name: EmbeddedIndicator Full path: C:\Program Files\MT5East\MQL5\Indicators\MQL5Book\p7\MainIndicator.ex5 » » ::SubFolder\EmbeddedIndicator.ex5 Location in MQL5:\Indicators\MQL5Book\p7\MainIndicator.ex5::SubFolder\EmbeddedIndicator.ex5 Success |
Como podemos ver, esta vez el indicador anidado ha creado correctamente una copia de sí mismo, ya que ha utilizado un nombre cualificado con una ruta relativa y un nombre de recurso «\Indicators\MQL5Book\p7\MainIndicator.ex5::SubFolder\EmbeddedIndicator.ex5».
Durante múltiples experimentos con el lanzamiento de este indicador, tenga en cuenta que las copias anidadas no se descargan inmediatamente del gráfico después de que se elimine el indicador principal. Por lo tanto, los reinicios deben realizarse sólo después de haber esperado a que se produzca la descarga: de lo contrario, se reutilizarán las copias que aún se estén ejecutando, y las líneas de inicialización anteriores no aparecerán en el registro. Para controlar la descarga, se ha añadido una impresión del valor Reference al manejador OnDeinit.
Prometimos demostrar que crear una copia del indicador no es algo extraordinario. Como demostración aplicada de esta técnica, utilizamos el indicador DeltaPrice.mq5, que calcula la diferencia en incrementos de precio de una orden determinada. Orden 0 significa sin diferenciación (solo para comprobar la serie temporal original), 1 significa diferenciación simple, 2 significa diferenciación doble, y así sucesivamente.
El orden se especifica en el parámetro de entrada Differentiating.
input int Differencing = 1; |
Las series de diferencias se mostrarán en un único búfer en la subventana.
#property indicator_separate_window
|
En el manejador OnInit, configuramos el búfer y creamos el mismo indicador, pasando el valor reducido en 1 en el parámetro de entrada.
#include <MQL5Book/AppliedTo.mqh> // APPLIED_TO_STR macro
|
Para evitar posibles problemas con la incrustación del indicador como recurso, utilizamos la función ya probada GetMQL5Path.
En la función OnCalculate realizamos la operación de restar valores vecinos de la serie temporal. Cuando Differentiating es igual a 1, los operandos son elementos del array price. Con un valor mayor de Differentiating, leemos el búfer de la copia del indicador creada para la orden anterior.
int OnCalculate(const int rates_total,
|
El tipo inicial de precio diferenciado se establece en el cuadro de diálogo de configuración del indicador, en la lista desplegable Apply to. De manera predeterminada, se trata del precio Close.
Así es como se ven varias copias del indicador en el gráfico con diferentes órdenes de diferenciación.
Diferencia en los precios de cierre de distintas órdenes