- Manejadores y contadores de propietarios de indicadores
- Una forma sencilla de crear instancias de indicadores: iCustom
- Comprobación del número de barras calculadas: BarsCalculated
- Obtención de datos de series temporales a partir de un indicador: CopyBuffer
- Soporte para múltiples símbolos y marcos temporales
- Visión general de los indicadores integrados
- Utilización de los indicadores integrados
- Forma avanzada de crear indicadores: IndicatorCreate
- Creación flexible de indicadores con IndicatorCreate
- Visión general de las funciones de gestión de indicadores en el gráfico
- Combinar salida a ventanas principal y auxiliar
- Leer datos de gráficos que tienen un desplazamiento
- Borrar instancias de indicadores: IndicatorRelease
- Obtener la configuración del indicador por su manejador
- Definir la fuente de datos de un indicador
Utilización de los indicadores integrados
Como sencillo ejemplo introductorio del uso del indicador integrado, vamos a utilizar una llamada a iStochastic. El prototipo de esta función indicadora es el siguiente:
int iStochastic(const string symbol, ENUM_TIMEFRAMES timeframe,
int Kperiod, int Dperiod, int slowing,
ENUM_MA_METHOD method, ENUM_STO_PRICE price)
Como vemos, además de los parámetros estándar symbol y time frame, el estocástico tiene varios parámetros específicos:
- Kperiod : número de barras para calcular la línea %K
- Dperiod : periodo de suavizado primario para la línea %D
- slowing : periodo de suavizado secundario (deceleración)
- method : método de promediado (suavizado)
- price : método de cálculo estocástico
Vamos a intentar crear nuestro propio indicador UseStochastic.mq5, que copiará los valores del estocástico en sus búferes. Como hay dos búferes en el estocástico, reservaremos también dos: son las líneas «principal» y «señal».
#property indicator_separate_window
|
En las variables de entrada proporcionamos todos los parámetros necesarios.
input int KPeriod = 5;
|
A continuación, describimos arrays para los búferes de indicadores y una variable global para el descriptor.
double MainBuffer[];
|
Inicializaremos en OnInit.
int OnInit()
|
Ahora, en OnCalculate, necesitamos leer los datos usando la función CopyBuffer tan pronto como el manejador esté listo.
int OnCalculate(const int rates_total,
|
Tenga en cuenta que estamos llamando a CopyBuffer dos veces: para cada búfer por separado (0 y 1 en el segundo parámetro). Un intento de leer un búfer con un índice inexistente, por ejemplo, 2, generaría un error y no recibiríamos ningún dato.
Nuestro indicador no es especialmente útil, ya que no añade nada al estocástico original y no analiza sus lecturas. Por otro lado, podemos asegurarnos de que las líneas del indicador terminal estándar y las creadas en MQL5 coinciden (también se podrían añadir fácilmente niveles y ajustes de precisión, como hacíamos con los indicadores completamente personalizados, pero entonces sería difícil distinguir una copia del original).
Estocástico estándar y personalizado basado en la función iStochastic
Para demostrar el almacenamiento en caché de los indicadores por el terminal, añada a la función OnInit un par de líneas.
double array[];
|
En este caso, hemos utilizado un truco relacionado con las características conocidas: inmediatamente después de que se cree el indicador, tarda algún tiempo en calcularse, y es imposible leer datos del búfer inmediatamente después de recibir el manejador. Esto es válido para el caso del arranque «en frío», cuando el indicador con los parámetros especificados aún no existe en la caché, en la memoria del terminal. Si hay un análogo preparado, entonces podemos acceder instantáneamente al búfer.
Después de compilar un nuevo indicador, debe colocar dos copias del mismo en dos gráficos del mismo símbolo y marco temporal. La primera vez se mostrará un mensaje con la bandera true en el registro (ésta es la primera copia), y la segunda vez (y las siguientes, si hay muchos gráficos) será false. También puede añadir primero manualmente un indicador «Stochastic Oscillator» estándar al gráfico (con los ajustes predeterminados o los que se aplicarán después en Use Stochastic) y después ejecutar Use Stochastic: necesitamos obtener también false.
Ahora vamos a intentar inventar algo original basado en un indicador estándar. El siguiente indicador UseM1MA.mq5 está diseñado para calcular precios medios por barra en M5 y marcos temporales superiores (principalmente, intradía). Acumula los precios de las barras M1 que caen dentro del rango de marcas de tiempo de cada barra específica en el marco temporal de trabajo (superior). Esto le permite estimar el precio efectivo de una barra con mucha más precisión que los tipos de precio estándar (Close, Open, Median, Typical, Weighted, etc.). Además, preveremos la posibilidad de promediar dichos precios a lo largo de un período determinado, pero aquí debe estar preparado para que no funcione una línea especialmente suave.
El indicador se mostrará en la ventana principal y contendrá un único búfer. Los ajustes pueden modificarse con ayuda de 3 parámetros:
input uint _BarLimit = 100; // BarLimit
|
BarLimit establece el número de barras del historial más cercano para el cálculo. Esto es importante porque los gráficos de marco temporal alto pueden requerir un número muy grande de barras en comparación con el minuto M1 (por ejemplo, se sabe que un día D1 en el trading 24/7 contiene 1440 barras M1). Esto puede dar lugar a que se descarguen datos adicionales en espera de sincronización. Experimente con la configuración de ahorro por defecto (100 barras del marco temporal de trabajo) antes de ajustar este parámetro a 0, lo que significa procesamiento sin límite.
Sin embargo, incluso cuando se establece BarLimit en 0, es probable que el indicador no se calcule para todo el historial visible del marco temporal más antiguo: si el terminal tiene un límite en el número de barras del gráfico, entonces también afectará a las solicitudes de barras M1. En otras palabras, la profundidad del análisis está determinada por el tiempo durante el cual el número máximo permitido de barras M1 entra en la historia.
BarPeriod establece el número de barras del marco temporal superior para el que se realiza el promedio. El valor por defecto aquí es 1, lo que le permite ver el precio efectivo de cada barra por separado.
El parámetro M1Price especifica el tipo de precio utilizado para los cálculos de las barras M1.
En el contexto global, un array se describe para un búfer, un descriptor y una bandera de autoactualización, que necesitamos para esperar la construcción de una serie temporal del marco temporal M1 «ajeno».
double Buffer[];
|
Además, aquí se forman el nombre del indicador y el periodo de promediación P. La función PeriodSeconds, que devuelve el número de segundos dentro de una barra del marco temporal actual, le permite calcular el número de barras M1 dentro de una barra actual: PeriodSeconds() / 60 (60 segundos es la duración de la barra M1).
La inicialización habitual se realiza en OnInit.
int OnInit()
|
Para obtener el precio medio en una barra de marco temporal superior, aplicamos una media móvil simple, llamando a iMA con el modo MODE_SMA.
La función OnCalculate que se muestra a continuación está simplificada. En la primera ejecución o cambio de historial, borramos el búfer y rellenamos la variable BarLimit (esto es necesario porque las variables de entrada no se pueden editar, y queremos interpretar el valor 0 como el número máximo de barras disponibles para el cálculo). Durante las siguientes llamadas, los elementos del búfer se borran sólo en los últimos compases, a partir de prev_calculated y no más allá de BarLimit.
int OnCalculate(ON_CALCULATE_STD_FULL_PARAM_LIST)
|
Antes de leer los datos del indicador iMA creado, hay que esperar a que estén listos: para ello comparamos BarsCalculated con el número de barras M1.
if(BarsCalculated(Handle) != iBars(_Symbol, PERIOD_M1))
|
Si los datos no están listos, iniciamos un temporizador para intentar leerlos de nuevo en un segundo.
A continuación, entramos en la parte principal de cálculo del algoritmo y, por lo tanto, debemos detener el temporizador si todavía está en marcha. Esto puede suceder si el siguiente evento de tic llegó más rápido, antes de 1 segundo, e iMA M1 ya dio resultados. Lo lógico sería simplemente llamar a la función EventKillTimeradecuada. Sin embargo, hay un matiz en su comportamiento: no borra la cola de eventos para un programa MQL de tipo indicador, y si un evento de temporizador ya está colocado en la cola, entonces se llamará una vez al manejador OnTimer. Para evitar la actualización innecesaria del gráfico, controlamos el proceso utilizando nuestra propia variable Pending Refresh, y aquí le asignamos false.
...
|
Así es como se organiza todo en el manejador OnTimer:
void OnTimer()
|
Volvamos a OnCalculate y presentemos el flujo de trabajo principal.
for(int i = fmax(prev_calculated - 1, (int)(rates_total - BarLimit));
|
El funcionamiento del indicador se ilustra con la siguiente imagen en EURUSD,H1. La línea azul corresponde a la configuración por defecto. Cada valor se obtiene promediando PRICE_CLOSE sobre 60 barras M1. La línea naranja incluye además el suavizado en 5 barras H1, con precios M1 PRICE_TYPICAL.
Dos instancias del indicador UseM1MA en EURUSD,H1
El libro presenta una versión simplificada de UseM1MASimple.mq5. Dejamos entre bastidores las particularidades del cálculo de la media de la última barra (incompleta), el tratamiento de las barras vacías (para las que no hay datos en M1) y la configuración correcta de la propiedad PLOT_DRAW_BEGIN, así como el control de la aparición de desfases a corto plazo en el cálculo de la media cuando aparecen nuevas barras. La versión completa está disponible en el archivo UseM1MA.mq5.
Como último ejemplo de construcción de indicadores a partir de indicadores estándar, vamos a analizar la mejora del indicador IndUnityPercent.mq5, que se presentó en la sección Indicadores multidivisa y de marco temporal múltiple. La primera versión utilizaba los precios de Close para los cálculos, obteniéndolos con CopyBuffer. En la nueva versión UseUnityPercentPro.mq5, vamos a sustituir este método por la lectura de los datos del indicador iMA. Esto nos permitirá implementar nuevas funciones:
- Precios medios durante un periodo determinado
- Elija el método de cálculo de medias
- Elija el tipo de precio para el cálculo
Los cambios en el código fuente son mínimos. Añadimos 3 nuevos parámetros y un array global para los manejadores iMA:
input ENUM_APPLIED_PRICE PriceType = PRICE_CLOSE;
|
En la función de ayuda InitSymbols, que se llama desde OnInit para analizar una cadena con una lista de símbolos de trabajo, añadimos la asignación de memoria para un nuevo array (su tamaño SymbolCount se determina a partir de la lista).
string InitSymbols()
|
Al final de la misma función, crearemos los descriptores de los indicadores subordinados necesarios.
En la función Calculate, donde se realiza el cálculo principal, sustituimos las llamadas de la forma:
CopyClose(Symbols[j], _Period, time0, time1, w); |
por llamadas:
CopyBuffer(Handles[j], 0, time0, time1, w); // j-th handle, 0-th buffer |
Para mayor claridad, también hemos completado el nombre abreviado del indicador con tres nuevos parámetros:
IndicatorSetString(INDICATOR_SHORTNAME,
|
Esto es lo que ha ocurrido como resultado:
Indicador multisímbolo UseUnityPercentPro con los principales pares Forex
Aquí se muestra una cesta de las 8 principales monedas Forex (configuración por defecto) promediada sobre 11 barras y calculada en base al precio de typical. Dos líneas gruesas corresponden al valor relativo de las divisas del gráfico actual: EUR está marcado en azul y USD, en verde.