Descargar MetaTrader 5

Como escribir Zig Zags rápido sin redibujado

20 abril 2016, 15:19
Candid
0
217

Introducción

Entre todos los algoritmos posibles para el mapeado de zig zag, podemos distinguir una clase que el autor llama "Zig zag con cambio al pasar el nivel de reducción de la velocidad". Esta clase, en su totalidad o en parte, incluye la mayoría de zig zag existentes. El propio nombre de la clase, de hecho, representa una plantilla de algoritmo. Para elaborar un indicador a partir de esta, es suficiente con solo añadir la función que detectará el nivel de ralentización. La diversidad de algoritmos de dicha función solo está limitada por la imaginación del autor del futuro zig zag.

Método general

En primer lugar, vamos a intentar formular el método general de escritura de un indicador. De este modo:

- La función start() de cualquier indicador (así como cualquier asesor experto) representa una función de retrollamada, es decir, una función que será llamada para que procese un evento concreto. Es decir, para procesar un tick.

- La finalidad de escribir un indicador es, por lo general, el cálculo de una o varias características del mercado. Junto con las cantidades accesorias necesarias para los cálculos, estas forman un conjunto de variables del indicador dado. Vamos a definir el estado del indicador como un conjunto de valores de dichas variables clave en un momento específico. En base a esta definición, podemos decir lo siguiente:

  • Al calcular los nuevos valores de las variables en un nuevo tick, la función start() calcula el nuevo estado del indicador.
  • De este modo, de hecho, la función start() es un operador que transfiere el indicador desde un estado a otro.

- En estos términos, el proceso de escritura de un indicador se reduce a determinar un conjunto de cantidades que describen su estado (variables de estado) y a escribir un operador que transfiera el indicador a un nuevo estado a la llegada de un nuevo tick. La inicialización de las variables de estado se convierte en parte esencial del algoritmo del indicador. Mostraremos cómo puede hacerse todo esto en el ejemplo del Zig Zag de un cierto tipo.

Qué Zig Zag nos interesan

Como se ha dicho anteriormente, nos interesan los Zig Zag que cambian al pasar el nivel de reducción de la velocidad. ¿Qué es un "nivel de reducción de la velocidad"? Asumimos que queremos escribir un Zig Zag para el que se fija el pico cuando el precio se desplaza de este pico en H puntos. Fijar un pico significa cambiar la dirección del segmento de un zig zag a una opuesta. Vamos solo a fijar el mínimo y ahora estaremos en un segmento más arriba. Vamos a introducir una variable para el tiempo del precio máximo de un segmento de arriba incompleto, TempMax. Fijaremos este máximo (y cambiaremos la dirección) si el precio atraviesa el nivel de:

SwitchLevel = TempMax - H *Point .

Si el máximo de tiempo se actualiza antes del cambio, tendremos que calcular el nuevo valor de SwitchLevel. De este modo, SwitchLevel seguirá el máximo del tiempo, siendo H los puntos detrás de él.

La situación será absolutamente simétrica para un segmento de abajo: SwitchLevel ahora seguirá el mínimo de tiempo (TempMin ), siendo los mismos puntos H detrás de este. Pero ahora tendremos:

SwitchLevel = TempMin + H *Point .

De hecho, hemos descrito solo el algoritmo de cálculo del nivel de ralentización para el Zig Zag que vamos a crear. Obviamente, no es el único algoritmo posible. Por ejemplo, si tenemos en cuenta el límite inferior o superior de un canal como nivel de ralentización, obtendremos exactamente tantos Zig Zag como métodos para el cálculo del canal. Además, en un análisis más detallado, la mayoría de zig zag conocidos por el autor resultan estar total o parcialmente incluidos en la clase considerada. Pero no todos ellos. Por ejemplo el zig zag calculado en los fractales de Williams no puede incluir en esta clase.

Modelo de Zig Zag

Vamos a determinar las variables del estado del Zig Zag.

En primer lugar, estará la dirección del segmento actual. Llamaremos a la variable correspondiente UpZ y le asignaremos el valor true para los segmentos de arriba y false para los segmentos de abajo.

Obviamente, debemos añadir a la lis TempMax y TempMin presentados anteriormente. También añadiremos sus coordenadas temporales. Aquí, no obstante, tenemos algún grado de libertad a la hora de definir las unidades de medida. Como coordenada temporal usaremos el número de barra comenzando desde el principio del gráfico, es decir, usaremos el sistema de numeración inverso al aceptado en MT4. Esto simplificará el código y mejorará su velocidad de ejecución. De este modo, la lista será completada con las variables TempMaxBar y TempMinBar.

Tenemos pensado dibujar el zig zag en un gráfico y usarlo de alguna forma. Por tanto, lo añadiremos a la lista de coordenadas de los últimos picos Zig Zag fijados: CurMax, CurMaxBar, CurMin, CurMinBar.

Y eso es todo respecto a la lista. Un autor de un zig zag concreto puede libremente completar la lista con aquello que vaya a hacer con este zig zag. Por ejemplo, puede ser razonable añadir las coordenadas de los picos anteriores: PreMax, PreMaxBar, PreMin, PreMinBar. O puede que necesitemos añadir las coordenadas de un número predefinido de picos precedentes, usando matrices en tal caso.

Operador de transición

En el método propuesto, escribir un operador de transición para un zig zag es una tarea bastante simple. Tan solo tenemos que traducir la definición de la clase del zig zag que nos interesa a MQL4. Así es como aparece:

// First, process the case of an up-segment
    if (UpZ) {
// Check whether the current maximum has changed
      if (High[pos]>TempMax) {
// If yes, then correct the corresponding variables
        TempMax = High[pos];
        TempMaxBar = Bars-pos;  // Here switching to direct numbering
      } else {
// If not, then check whether the slowing level has been broken through
        if (Low[pos]<SwitchLevel()) {
// If yes, then fix the maximum
          CurMax = TempMax;
          CurMaxBar = TempMaxBar;
// And draw a peak
          ZZ[Bars-CurMaxBar]=CurMax;  // Here switching to reverse numbering
// Correct the corresponding variables
          UpZ = false;
          TempMin = Low[pos];
          TempMinBar = Bars-pos;  // Here switching to direct numbering
        }
      }
    }  else {
// Now processing the case of down-segment
// Check whether the current minimum has changed
      if (Low[pos]<TempMin) {
// If yes, then correct the corresponding variables
        TempMin = Low[pos];
        TempMinBar = Bars-pos;  // Here switching to direct numbering
      } else {
// If not, then check whether the slowing level has been broken through
        if (High[pos]>SwitchLevel()) {
// If yes, then fix the minimum
          CurMin = TempMin;
          CurMinBar = TempMinBar;
// And draw a peak
          ZZ[Bars-CurMinBar]=CurMin;  // Here switching to reverse numbering
// Correct the corresponding variables
          UpZ = true;
          TempMax = High[pos];
          TempMaxBar = Bars-pos;  // Here switching to direct numbering
       }
      }
    }

El operador de transición está listo. Ahora podemos referirnos a las variables de estado del indicador en cualquier momento.

No obstante, dicho operador tiene una característica especial que puede percibirse como un error al escribir el zig zag. Vamos a considerar el fragmento siguiente con mayor detalle:

      if (High[pos]>TempMax) {
// If yes, then correct the corresponding variables
        TempMax = High[pos];
        TempMaxBar = Bars-pos;  // Here switching to direct numbering
      } else {
// If not, then check whether the slowing level has been broken through
        if (Low[pos]<SwitchLevel()) {
// If yes, then fix the maximum
          CurMax = TempMax;
          CurMaxBar = TempMaxBar;

El uso del par if - else significa que el Low de la barra que contiene TempMax no sea considerado. Las situaciones en que este precio es inferior al siguiente mínimo fijado pueden percibirse como errores al dibujar el zig zag. ¿Se trata de un error?

Teniendo en cuenta que el trabajo sobre el historial y en tiempo real deben ser idénticos, el autor es de la opinión de que esto no es un error. De hecho, dentro de un periodo de tiempo nunca sabremos qué ocurrió antes en el historial, el máximo o el mínimo de la barra. El uso aquí de la construcción if-else significa tomar una decisión consciente: Preferimos el momento. Significa que sacrificamos el mínimo para un segmento de arriba y el máximo para un segmento de abajo. Es razonable pensar que cuanto más pequeño es el periodo de tiempo con menor frecuencia aparecerá este dilema.

Otro fragmento necesita algunos comentarios:

// Correct the corresponding variables
          UpZ = false;
          TempMin = Low[pos];
          TempMinBar = Bars-pos;  // Here switching to direct numbering
        }
      }

Aquí, de hecho, se establece el punto de inicio de la comprobación del mínimo de tiempo para el momento de cambiar entre segmentos. Es justificable para el ejemplo considerado, pero, en general, no debemos hacerlo. Sería más razonable establecer el mínimo temporal para el intervalo mínimo desde el máximo fijo hasta la posición actual (es decir, el momento del cambio). El código puede ser el siguiente:

   // Correct the corresponding variables
          UpZ = false;
          TempMinBar = CurMaxBar+1;
          TempExtPos = Bars - TempMinBar;  // Here switching to reverse numbering
          TempMin = Low[TempExtPos];
          for (i=TempExtPos-1;i>=pos;i--) {
            if (Low[i]<TempMin) {
              TempMin = Low[i];
              TempMinBar = Bars-i;  // Here switching to direct numbering
            }
          }

Aquí, el Low de la barre donde se ha fijado el mínimo se excluye de nuevo de la consideración.

Estas dos notas también tienen que ver con el procesamiento de los segmentos de abajo.

Indicador

Solo queda completar el indicador para que funcione. No es necesario comentar en init() y deinit(), todo está bastante claro y estándar aquí. No obstante, tomaremos una importante decisión sobre la función start(). Trabajaremos solo con barras completas. La razón principal de ello es que nos permite lograr una estructura del código sencilla y compacta.

Hay otra importante consideración sobre ello. Un trabajo serio en un sistema de trading implica recopilar las estadísticas del historial. Estas estadísticas serán válidas (correctas) solo si las características obtenidas en tiempo real se corresponden por completo con las obtenidas en el historial. No tenemos un historial de los ticks reales, por lo que solo podemos lograr esa correspondencia completa trabajando en tiempo real solo con barras completas. Lo máximo que podemos hacer para reducir el retraso es usar periodos de tiempo más pequeños, hasta M1.

Otra característica esencial es no usar la función IndicatorCounted(). La razón principal para ello es que el código usado necesita otra acción importante: la inicialización de las variables de estado del indicador. Esto no puede hacerse en la función init() ya que usar una numeración directa requiere recalcular el indicador en el llenado del historial, por tanto, reinicializar las variables de estado. La función init() no se ejecuta en el llenado del historial.

De este modo, tenemos que añadir una función "estándar" más, Reset(). Finalmente, el deseo de no usar IndicatorCounted() demasiado ayuda e impide organizar la comprobación del recálculo necesaria para un indicador de este tipo. Esta comprobación se realiza de la forma siguiente:

int start() {
//  Work with completed bars only
  if (Bars == PreBars) return(0);  
//  Check whether there are enough bars on the chart
  if (Bars < MinBars) {
    Alert(": Not enough bars on the chart");
    return(0);
  }  
//  If the history was not pumped, make calculations for the bar just completed
  if (Bars-PreBars == 1 && BarTime==Time[1]) StartPos = 1;
//  Otherwise, count the number of bars specified in function Reset() 
  else StartPos = Reset();
// Modify check variables
  PreBars = Bars;  
  BarTime=Time[0];
// Cycle on history
  for (pos=StartPos;pos>0;pos--) {

La función Reset() es la siguiente:

int Reset() {
  if (MinBars == 0) MinBars = Bars-1;
  StartPos = MinBars;
  PreBars = 0;
  BarTime = 0;
  dH = H*Point;
  UpZ = true;
  TempMaxBar = Bars-StartPos;
  TempMinBar = Bars-StartPos;
  TempMax = High[StartPos];
  TempMin = Low[StartPos];
  StartPos++;
  return(StartPos);
}

Aquí podríamos prestar especial atención a la variable adicional, dH, a la que de una vez por todas asignamos el valor umbral de cambio del ZigZag (H ) transformado en la escala del precio. Puede surgir una pregunta: ¿Por qué es UpZ = truey no false ? La respuesta es simple: Después de un pequeño número de segmentos, el indicador dará como resultado el mismo gráfico, con independencia del valor inicial de UpZ.

Bueno, por último, los cálculos del nivel de ralentización:

double SwitchLevel() {
  double SwLvl;
  if (UpZ) SwLvl = TempMax - dH;
  else SwLvl = TempMin + dH;
  return(SwLvl);
}

Aquí debe quedar todo claro.

Conclusión

Se adjunta al artículo una plantilla para escribir ZigZags, ZZTemplate. Todo lo que tenemos que hacer es añadir el código necesario a la función SwitchLevel(). Para convertir la plantilla en el zig zag usado aquí como ejemplo, solo tenemos que encontrar las líneas siguientes y comentar en ellas:

//extern int H = 33;
//double dH;
//  dH = H*Point;

//  if (UpZ) SwLvl = TempMax - dH;
//  else SwLvl = TempMin + dH;


El código final se refiere a la velocidad del zig zag. La plantilla implica generalización. Además, queremos tener una estructura lo más transparente posible. Creo que pueden optimizarse construcciones más específicas para mejorar su funcionamiento.

La recomendación general es la siguiente: Cuando sea posible, colocamos las operaciones en operadores if. Como ejemplo (pero no como modelo ideal) de optimización, adjunto encontrará el indicador HZZ, una alternativa al zig zag usado en este artículo. La simplicidad del problema nos permite abandonar la función SwitchLevel() y algunas variables de estado. Como pequeño regalo, he añadido a HZZ picos de ZigZag al archivo y una comprobación "sobre la marcha" de algunas características estadísticas del ZigZag.

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

Archivos adjuntos |
HZZ.mq4 (4.22 KB)
ZZTemplate.mq4 (5.67 KB)
MetaTrader 5 - ¡Más de lo que puedas imaginar! MetaTrader 5 - ¡Más de lo que puedas imaginar!

El terminal de cliente de MetaTrader 5 ha sido desarrollado desde cero y mejora con creces a su predecesor. La nueva plataforma ofrece oportunidades ilimitadas para operar en cualquier mercado financiero. Además, se ha ampliado su funcionalidad para ofrecer aún más características y facilidad de uso. Todo ello hace que sea muy difícil la enumeración de todas las ventajas de MetaTrader 5. Hemos intentado describir brevemente todas estas ventajas en un único artículo y nos ha sorprendido ver que el resultado ¡no ha sido nada breve!

Aumente la velocidad de los cálculos con la red en la nube de MQL5 Aumente la velocidad de los cálculos con la red en la nube de MQL5

¿Cuántos procesadores tiene tu ordenador? ¿Cuántos ordenadores puedes usar para optimizar una estrategia de trading? Aquí mostraremos cómo usar la red en la nube de MQL5 para acelerar los cálculos recibiendo la capacidad de procesamiento a través de la red mundial con solo el clic de un ratón. La frase "el tiempo es dinero" se hace más evidente aun con el paso de los años, y no podemos permitirnos esperar para realisar cálculos importantes durante decenas de horas o incluso días.

Trabajando con cestas de parejas de divisas en el mercado fórex Trabajando con cestas de parejas de divisas en el mercado fórex

En el artículo se analizan cuestiones relacionadas con la división en grupos de las parejas de divisas, las cestas; también sobre cómo obtener datos sobre el estado de estas cestas (por ejemplo, sobrecompra o sobreventa); qué indicadores pueden proporcionar estos datos; y al fin, sobre cómo se puede aplicar la información obtenida en el trading práctico.

Red neuronal profunda con Stacked RBM. Auto-aprendizaje, auto-control Red neuronal profunda con Stacked RBM. Auto-aprendizaje, auto-control

El artículo es la continuación de artículos anteriores sobre neuroredes profundas y elección de predictores. En este veremos las particularidades de una neurored iniciada con Stacked RBM, así como su implementación en el paquete "darch".