English Русский 中文 Deutsch 日本語 Português
Una visión de Acumulación/Distribución y donde se puede conseguir

Una visión de Acumulación/Distribución y donde se puede conseguir

MetaTrader 4Ejemplos | 29 febrero 2016, 10:09
1 611 0
Artyom Trishkin
Artyom Trishkin

Introducción

Se sabe que el indicador de Acumulación/Distribución A/D tiene una característica interesante: sugiere una ruptura de la línea de tendencia trazada en esta gráfica del indicador, con cierta probabilidad, una próxima ruptura de la línea de tendencia en el gráfico de precios:

Estaba decidido a comprobar este hecho y después de haber trazado todas las líneas de tendencia en la gráfica del A/D , rápidamente comprendí que sería inoportuno un enfoque manual para hacer frente a este problema. Es decir por qué desarrolló una función que automáticamente traza líneas de tendencia en el gráfico del A/D y establece indicadores de señal en el gráfico de precios. Me gustaría ahora mostrar un procedimiento paso a paso de cómo todo puede implementarse usando MQL4 para ser utilizados más a fondo en sus robots de trading.

Este artículo será útil e interesante para aquellos que son nuevos en la programación en MQL4. Teniendo esto en vista, he tratado de presentar la información de una forma de fácil agarre y utilizar las estructuras de código más simples.


1. Configuración de una tarea

Definamos primero la tarea a establecer.

Por lo general, la función encuentra un punto de cruce entre la línea de tendencia trazada en la gráfica A/D y la línea misma del indicador, devuelve el valor que indica la dirección del cruce — hacia abajo o hacia arriba — y ajusta las señales de los indicadores (flechas arriba/abajo dependiendo de la dirección de cruce) en el gráfico de precios con fines ilustrativos.

Permítanos ahora romper esta tarea general en objetivos más específicos:

  1. La función debe ser capaz de trabajar con cualquier símbolo y en cualquier timeframe;
  2. Puesto que esta función está diseñada para ser parte de un EA, el indicador A/D no necesita estar en la gráfica principal.
  3. Las señales de los indicadores no tampoco tienen necesariamente que mostrarse en el gráfico de precios — todos los cálculos se realizan dentro de la función y sólo se muestran para monitorear visualmente el funcionamiento de la función.
  4. Los cruces pueden ocurrir en diferentes direcciones: cruce hacia abajo de la tendencia alcista, cruce hacia arriba de la tendencia alcista, cruce hacia arriba de la tendencia bajista, cruce hacia abajo de la tendencia bajista. La función identificará a cada uno de esos cruces.

Esto es lo mas lejos en cuanto a las capacidades de la función se refiere. Veamos ahora las formas de lograr nuestra tarea.


2. Rellenado de matrices con Datos del Indicador A/D

Cuando la llamas, la función recibirá algunos valores: en este momento — la matriz de almacenamiento de datos del indicador A/D , el número de barras del historial para la identificación del extremo del gráfico A/D, el nombre del instrumento (símbolo) y el timeframe.

Les líneas de tendencia se trazan en base al extremos del gráfico A/D identificado por la conexión de una línea de tendencia alcista con el extremo inferior y una línea de tendencia bajista con el extremo superior.

Una línea de tendencia alcista requiere dos extremoa inferiores, donde será el extremo con el valor más bajo a la izquierda del extremo ubicado en inmediaciones de la barra actual (cero). Lo mismo eserá válido para una tendencia bajista: el extremo de mayor valor será a la izquierda el extremo que está junto a la barra actual.

Si no se pueden identificar extremos que cumplan estos requisitos, no se trazan líneas de tendencia en esta señal. Vamos a llamar a estas líneas de tendencia "global":

Además, agregamos dos líneas más al trazo de las líneas de tendencia "global" que requiere el uso de dos extremos lejanos por la derecha.

  • una tendencia alcista tiene un extremo inferior con un valor menor (a la izquierda el extremo inferior con un valor mayor); y
  • una tendencia bajista necesita un extremo superior con un mayor valor (a la izquierda el extremo superior con un valor menor).

Si no se pueden identificar extremos que cumplan estos requisitos, no se trazan líneas de tendencia en esta señal.

Estas líneas de tendencia se van a referir como "local":

Como resultado, lo que podemos ver es lo siguiente:

En la mayoría de los casos, no necesitamos el extremo "local" ebido a particularidades de identificación de extremo "global" y se trazan líneas de tendencia al conectarlos. La opción de buscar y trazar el extemo "local" pueden deshabilitarse.

La función operación requerirá de la disponibilidad de las variables globales del EA, especialmente una matriz para el almacenamiento de datos de A/D. Nos dejan escribir variables globales del EA:

double      TempIND[];    // Matriz de almacenamiento de datos del indicador A/D

Ahora, los datos del indicador se deben leer para llenar la matriz:

int SignalCrossIND(double &TempIND[], int nBars, string sy, int tf)
{
   if (sy=="" || sy=="0") sy = Symbol();
   ArrayResize(TempIND,nBars);       // Cambiar el tamaño de la matriz al tamaño antiguo de la función
   for (int j=0; j<=nBars-1; j++)
      {
         TempIND[j]=iAD(sy,tf,j);    // Escribe datos de indicador en el bucle de la matrizy
      }
}

Analicemos lo hemos escrito aquí:

int SignalCrossIND(double &TempIND[], int nBars, string sy, int tf)

La definición de la función como tal donde los parámetros que se pasn son [TempIND] — nombre de la matriz que contiene valores del indicador (pasados por referencia), nombre del instrumento (símbolo) nBars — número de barras del historial de la cual se obtienen los valores, sy — y el  timeframe tf.

En general, la llamada a la función puede ser como sigue:

SignalCrossIND(TempIND, 30, NULL, 5);

donde TempIND es el nombre de la matriz, 30 es el número de barras, NULL es el símbolo actual en la grafica, y 5 es М5 time frame.

La línea siguiente es:

if (sy=="" || sy=="0") sy = Symbol();

comprueba el nombre del instrumento comercial pasado a la función y si su valor es NULL o 0, el actual símbolo gráfico se utiliza.

Luego cambiar el tamaño de la matriz de acuerdo con el valor pasado a la función en la variable nBars y rellenarlo con valores del indicador desde la barra cero a la barra nBars-1 en el bucle. Puesto que las celdas de la matriz están contadas a partir de cero, el primer número será 0 en vez de 1 y el último número será, por consiguiente, 29 en vez de 30. Por lo tanto utilizamos nBars-1 (en nuestro ejemplo, 30-1 = 29).

En esta etapa, nuestra función llena la matriz con datos del indicador A/d.. Ahora necesitamos identificar el extremo en la matriz de datos de la gráfica A/D.


3. Identificación del Extremo en la matriz de datos del indicador A/D.

Comencemos. El funcionamiento de la función requiere no sólo de variables globales, sino también de variables para ser utilizadas por la misma función.

En esta etapa, tenemos que declarar dos matrices más (internas) que se utilizarán para la escritura extrema superior (picos) y extrema inferior (canales), dos matrices en las que vamos a ahorrar el tiempo del extremo y algunas de las variables a utilizar para las necesidades de la función:

// ------------------------------------------------------------------------------------------                     
// ----------------------------- Variables de la Function -----------------------------------
// ------------------------------------------------------------------------------------------                     

   double   PeakUP[], PeakDN[];     // Declarar matrices de pico/canal
   datetime TimeDN[], TimeUP[];     // Matrices para almacenar el tiempo del extremo
   int      i, k;                   // Variables internas de la función

y finalmente proceder a su identificación:

//------------------------------------------------------------------
// Rellenado de matrices con datos sobre picos y valles
//------------------------------------------------------------------         
    k=0;                                   // Inicializar el índice de la matriz
    for (i=2; i<=nBars-1; i++)             // Ejecutar a traves de los valores de la matriz
       {
          if (TempIND[i]<TempIND[i-1] && 
              TempIND[i+1]>=TempIND[i])    // Canal identificado
             {
                ArrayResize(PeakDN, k+1);  // Cambiar el tamaño de la matriz del canal según el número de canales identificados
                ArrayResize(TimeDN, k+1);  // Cambiar el tamaño de la matriz de tiempo de canal según el número de canales
                PeakDN[k]=TempIND[i];      // Escribir el valor del canal en la matriz de canal...
                TimeDN[k]=iTime(sy,tf,i);  // ...y la matriz de tiempo
                k++;                       // Incrementar el índice de la matriz de canal
             }
        } 
// -----------------------------------------------------------------------------------------------------------                       
    k=0;                                   // Inicializar el índice de la matriz de pico
    for (i=2; i<=nBars-1; i++)             // Ejecutar a traves de los valores de la matriz
       {
          if (TempIND[i]>TempIND[i-1] && 
              TempIND[i+1]<=TempIND[i])    // Pico identificado
             {
                ArrayResize(PeakUP, k+1);  // Cambiar el tamaño de la matriz de pico según el número de picos identificados
                ArrayResize(TimeUP, k+1);  // Cambiar el tamaño de la matriz de tiempo de pico según el número de picos
                PeakUP[k]=TempIND[i];      // Escriba su valor en la matriz de pico... 
                TimeUP[k]=iTime(sy,tf,i);  // ... y la matriz de tiempo
                k++;                       // Incrementar el índice de la matriz de pico
             }
       }  

La anterior aclaración de necesidades en que se hace y cómo se hace. En primer lugar, organizamos dos bucles separados — para la identificación de la parte superior e inferior extremo, respectivamente.

Vamos sobre la operación del primer bucle para la identificación de canales (extremo inferior):


Empezamos con la inicialización de la variable k a cero — apuntará al primer (cero) elemento de la matriz donde se escribirán los canales identificados. Entonces recorreremos la matriz de los valores del indicador A/D rellenado anteriormente, el punto de partida no es el primer (cero) índice de la matriz pero el tercero correspone a la barra 2 (i = 2;).

¿Por qué pasa esto? Puesto que un extremo es un punto de interrupción en la grafica del indicador, donde el valor de la primera barra es mayor que en la segunda barra y el valor en la segunda barra es menor que en la tercera (canal), fijamos el índice en el tercer elemento de la matriz (teniendo en cuenta que los elementos están numerados a partir de cero), suponiendo que puede ser el extremo. La barra cero no se utiliza en los cálculos para eliminar falsos positivos.

Entonces, empezamos nuestra primera iteración y comprobamos

  • Si el valor en la barra 2 TempIND [i] es menor que en el barra 1 TempIND [i-1] y
  • si el valor en la barra 3 TempIND [+ 1] es mayor que en la barra 2 TempIND [i].

Si esta condición es true (el extremo se identifica), primero aumentamos el canal de la matriz y tamaños de la matriz de tiempo de canal, por 1:

ArrayResize (PeakDN, k +1);     / / Cambiar el tamaño de la matriz del canal según el número de canales identificados
ArrayResize (TimeDN, k +1);     / / Cambiar el tamaño de la matriz de tiempo de canal según el número de canales

escribir los datos de la matriz de valores del indicador en estas matrices de discos y aumentar el índice de la matriz de canal por uno:

PeakDN [k] = TempIND [i];         // Escribir el valor del canal en la matriz de canal...
TimeDN[k]=iTime(sy,tf,i);     //.. .y la matriz de tiempo
k ++;                          // Incrementar el índice de la matriz de canal

Ahora el canal y la matriz de tiempo del canal, PeakDN y TimeDN respectivamente, contienen los datos requeridos en el extremo identificado y los puntos de índice de canal matriz en la siguiente celda de esta matriz. La siguiente iteración del bucle sigue el mismo patrón al identificar el extremo próximo y sus datos se escriben en la celda de la matriz del canal que señala el índice de la matriz de canal (k).

Los picos (extremo superior) se identifican de una manera muy similar, excepto que la primera, segunda y tercera barras se comparan en el sentido contrario: el signo menor — que y mayor — que debe ser intercambiado. En esta etapa, la función puede leer los datos del indicador A/D, llenar la matriz con estos datos e identificar el extremo en él, así como guardar valores y lugares extremos en las cuatro matrices designadas.

Esto es cuando podemos empezar a visualizar líneas de tendencia en el gráfico del indicador trazado basado en el extremo identificado.

Debemos primero mostrar líneas de tendencia "globales" en la gráfica del indicador. Con el fin de trazarlos conectando los extremos de la gráfica, debemos comenzar con la identificación de los dos extremos — extremo con el menor valor en la totalidad de la matriz de canal y el extremo referido a la principal. El extremo principal se ubicará en la proximidad inmediata al principio de la matriz de canal y ajustarlo estrictamente igual a 2. Así, los dos primeros extremos más cercana de todas a la barra actual en la tabla del indicador no se tendrán en cuenta (para dejar una cierta libertad para el movimiento de precio sin tener que reaccionar a un cambio más leve que ocurre en él).

Ahora que se identifica el extremo principal, tenemos que encontrar el extremo con el menor valor en la mtriz situado a la izquierda el extremo principal. Este extremo será el más bajo en la gráfica del indicador, que sirve como punto de partida para la identificación final del segundo extremo.

Se dibuja de una línea de tendencia de tal manera que conecte el extremo más bajo y el extremo principal, y conducirá probablemente a la situación donde se cruza la línea de tendencia por el extremo más alto que el extremo menor identificado. Y significa que el principio de la línea de tendencia debe en este caso trasladarse al extremo cruzando la línea de tendencia. Los ejemplos de abajo son una muestra clara de este caso:

Puede verse que la línea que se origina en el extremo más bajo está atravesada por el máximo extremo que se extiende hacia el extremo principal. Por lo tanto es necesario, en esta situación, analizar cuidadosamente la matriz del extremo e identificar uno que, cuando se define como el punto de origen de la línea de tendencia, no de lugar a la situación donde se cruza la línea de tendencia por cualquier posterior extremo.

El extremo que sigue el extremo menor no es conveniente, — la línea de tendencia debe originarse en ese momento, todavía se cruza por máximo extremo:

He dejado fuera otros "intentos" aquí y proceder directamente al extremo «derecho» identificado:

Ahora es momento de empezar la codificación de todo. Utilizamos el extremo bajo para dibujar la línea de tendencia alcista y el extremo superior para dibujar la línea de tendencia bajista.

Revisemos un ejemplo de trazado de una línea de tendencia alcista a través del extremo bajo.


4. Identificación de dos Extremos en la matriz del indicador extremo A/D para el trazado de una línea de tendencia

Necesitaremos identificar dos extremos y requerirá la disponibilidad de variables internas de la función para almacenar y pasar valores de la inferior y superior principal y mínimo extremo, para almacenar y pasar el tiempo de una variable y al extremo mínimo y principal inferior y superior para la inexación de las matrices.

Vamos a añadir a nuestras variables de la función (no para volver a esta cuestión, más tarde añadiremos todas las variables de función necesarias para empezar a usarlas inmediatamente):

// ------------------------------------------------------------------------------------------                     
// ------------------------------- Variables de función ---------------------------
// ------------------------------------------------------------------------------------------                     

   double   PeakUP[], PeakDN[],        // declarar matrices de pico/canal
            yUP, yDN, yGUP, yGDN,      // Coordenadas del punto de cruce entre ente la linea de tendencia y el indicador UP and DN en la barra 1
            yUP2, yDN2, yGUP2, yGDN2,  // Coordenadas del punto de cruce entre ente la linea de tendencia y el indicador UP and DN en la barra 2
            CheckCross,
            PreLastVarDN,LastVarDN,    // Valores del último y el último pero extremo inferior
            PreLastVarUP,LastVarUP,    // Valores del último y el último pero extremo superior
            PivotPeakDN,PivotPeakUP,
            LowestPeakDN,HighestPeakDN,// Valores del mínimo y máximo 
            LowestPeakUP,HighestPeakUP,// Valores de la parte superior mínima y máxima

   datetime TimeDN[], TimeUP[],        // Matrices de barras de almacenamiento del extremo
            PreLastTimeDN, LastTimeDN, // Tiempo del último y el último pero el extremo inferior
            PreLastTimeUP, LastTimeUP, // Tiempo del último y el último pero el extremo superior
            PivotBarDN, PivotTimeDN,   // Barra y tiempo del extremo principal inferior
            PivotBarUP, PivotTimeUP,   // Barra y tiempo del extremo principal superior
            LowestBarDN, LowestTimeDN, // Barra y tiempo del mínimo inferior.
            HighestBarUP, HighestTimeUP;// Barra el tiempo del máximo superior
   int      i, kup, kdn, pbar=2, 
            m, l, t, asize, Index,      // Variables "Internas"
            WinID=WindowFind("A/D");    // Número Windows AD
   bool     CrossDN = false,            // Bandera que indica el cruce hacia abajo de la tendencia local
            CrossUP = false,            // Bandera que indica el cruce hacia arriba de la tendencia local
            CrossGDN = false,           // Bandera que indica el cruce hacia abajo de la tendencia mundial
            CrossGUP = false;           // Bandera que indica el cruce hacia arriba de la tendencia mundial
   
   double   pt=MarketInfo(Symbol(),MODE_POINT); // Tamaño de punto en la moneda de cotización

y agregar el código de identificación de extremo inferior:

//====================================================================================================
// --------------------------- Identificación del mínimo y máximo DN inferior -------------  
//====================================================================================================
          
  PivotTimeDN = TimeDN[pbar];                     // Tiempo del extremo principal
  PivotBarDN  = iBarShift(sy,tf,TimeDN[pbar]);    // Barra el extremo principal
  PivotPeakDN = PeakDN[pbar];                     // Valor del extremo principal
  LowestPeakDN  = ArrayMin(PeakDN);               // Obtener el valor mínimo inferior
  Index = ArraySearchDouble(PeakDN, LowestPeakDN);// Obtiene el índice del mínimo inferior de la matriz
  LowestBarDN =iBarShift(sy,tf,TimeDN[Index]);    // Obtiene la barra de la parte inferior mínimo
  LowestTimeDN = TimeDN[Index];                   // Obtener el tiempo de la baja mínima


La barra del extremo principal se encuentra estrictamente en la variable pbar y por lo tanto se obtiene el tiempo del extremo principal de la matriz de tiempo por el índice de contenidos en esta variable.

PivotTimeDN = TimeDN[pbar];     // Tiempo del extremo principal

La barra del extremo principal se obtiene de la matriz de tiempo y su valor se calcula utilizando la función estándar int iBarShift( string symbol, int timeframe, datetime time, bool exact=false).

Brevemente describiremos un poco más adelante al considerar la identificación del mínimo de la matriz del extremo.

El valor del extremo principal se obtiene de la matriz de valores especificando el valor deseado utilizando la variable pbar (que contiene el índice extremo principal):

PivotPeakDN = PeakDN [pbar];     // Valor del extremo principal

Para identificar el mínimo más bajo, usted puede utilizar la función estándar int ArrayMinimum(double array[], int count = WHOLE_ARRAY, int start=0) que es lo que vamos a utilizar, sólo organizar el cálculo a realizar mediante una llamada a una función definida por el usuario. Esta función devuelve el resultado de la identificación del extremo.

Para no reinventar la rueda, vamos a identificar el mínimo elemento de la matriz utilizando una función preparada amablemente ofrecida para el uso público por Igor Kim en su hilo del Foro. Perfectamente se adapta a nuestras necesidades y puede enviar un informe de error correspondiente en el registro, debe vaciar la matriz pasada (esto viene práctico cuando se depura):

//+----------------------------------------------------------------------------+
//|  Author    : Igor B. Kim aka KimIV,  http://www.kimiv.ru                   |
//+----------------------------------------------------------------------------+
//|  Version   : 17.05.2008                                                    |
//|  Descripción: Devuelve el valor del mínimo elemento en la matriz.      |
//+----------------------------------------------------------------------------+
//|  Parametros:                                                               |
//|    x - matriz de valores de la serie numérica |
//+----------------------------------------------------------------------------+
double ArrayMin(double& x[]) {
  if (ArraySize(x)>0) return(x[ArrayMinimum(x)]);
  else {
    Print("ArrayMin(): Array empty!");
    return(0);
  }
}

Como se puede ver, no hay nada difícil para él — es la misma función estándar ArrayMinimum() busca datos necesarios en la pasada matriz. Una función similar obtenida de la misma fuente se va a utilizar para obtener el índice del elemento mínimo de la matriz por su valor:

//+----------------------------------------------------------------------------+
//|  Author    : Igor B. Kim aka KimIV,  http://www.kimiv.ru                   |
//+----------------------------------------------------------------------------+
//|  Version   : 01.09.2005                                                    |
//|  Descripción: Encuentra un elemento de la matriz por su valor              |
//|             y devuelve el índice del elemento encontrado o -1.             |
//+----------------------------------------------------------------------------+
//|  Parametros:                                                               |
//|    m - matriz de elementos                                                 |
//|    e - el valor del elemento                                               |
//+----------------------------------------------------------------------------+
int ArraySearchDouble(double& m[], double e) {
  for (int i=0; i<ArraySize(m); i++) {
    if (m[i]==e) return(i);
  }
  return(-1);
}

Aquí, recorrer la matriz completa, busca el valor pasado a la función. Si el valor pasado de la función coincide con el valor de un elemento de la matriz, la función devuelve el valor de la variable i al juego es igual al índice del valor buscado en la matriz. Si el valor buscado no se encuentra, la función devolverá -1 que puede usarse para comprobar el error de su programa.

Ahora tenemos que encontrar la barra en el gráfico que se corresponde con el extremo identificado. Para ello, vamos a utilizar los datos de la matriz de tiempo rellenada con anterioridad [TimeDN] y el índice (Índice) del extremo requerido que jústamente hemos obtenido:

// Se hace la barra de la parte mínima inferior
LowestBarDN =iBarShift(sy,tf,TimeDN[Index]);

Para ello, utilizamos la función estándar int iBarShift( string symbol, int timeframe, datetime time, bool exact=false)

Búsqueda de la barra de tiempo. La función devuelve el desplazamiento de la barra que tiene el tiempo especificado. Si no hay ninguna barra durante el tiempo especificado (un "boquete" en el historial), la función, dependiendo del parámetro exact , devuelve -1 o un cambio de la barra más cercana.

Aquí, el primer parámetro de la función es el símbolo actual de la grafica almacenado en la variable tf y el tiempo datetime time pasado a iBarShift() que se almacena en la matriz de tiempo TimeDN[] e indexado por el valor de la variable Index obtenido en el paso anterior.

Dejamos el valor predeterminado de bool exact porque pasando a true cuando la barra es falta (una "brecha" en el historial) hará que la función devuelva -1, y luego se utilizarán en cálculos posteriores llevando a un error. El valor por defecto false , debe faltar en el historial, la barra hará que la función devuelva el valor de la barra más cercana, que no es bueno tampoco, pero es mejor que el valor esté absolutamente equivocado.

Ahora, para obtener una imagen completa de la cosa entera y más cálculos, también vamos a ahorrar en el tiempo de la barra que se encuentra como se describió anteriormente. Esto es muy simple: hemos ahorrado tiempo en la matriz TimeDN [] . Y lo vamos a obtener de esta matriz con el mismo índice:

// Obtener el tiempo de la baja mínima
LowestTimeDN = TimeDN[Index];

Por lo que hemos identificado el principal extremo y el mínimo. Ahora tenemos que ver si la línea de tendencia que conecta los dos puntos identificados va a ser atravesada por otra extremo situado entre los dos extemos identificados (como ya se mencionó anteriormente):

Tales cruces se identificarán mediante una línea virtual con el mínimo hacia el extremo principal. Se enlazan a través de la matriz de extrema, desde el mínimo hacia el extremo principal y una vez que se encuentra el punto de cruce entre el extremo y la línea, se tratará como punto de origen de la línea y otra vez enlazar a través de la matriz, esta vez a partir del extremo que sólo hemos identificado al extremo principal.

En el cruce con extrema la línea va a ser recorrida hasta que hayan más a la izquierda. Esto significa que hemos identificado el extremo requerido, y que la extrema que lo sigue hacia el extremo principal no cruza la línea de tendencia.

if (LowestBarDN>PivotBarDN)                           // Si el mínimo está a la derecha el primer extremo... 
                                                      // ... (siendo en la celda 0 de la matriz de tiempo de canal)
for (m=Index-1; m>pbar; m--)                          // bucle del extremo siguiendo el mínimo para el primer extremo
  {
//------Dibujar una línea de tendencia virtual y compruebe los cruces con el otra extremo---                                  
  CheckCross=EquationDirect(iBarShift(sy,tf,TimeDN[m+1]),
                            PeakDN[m+1],                      // Primera coordenada de la línea
                            PivotBarDN, PivotPeakDN,          // Segunda coordenada de la líne
                            iBarShift(sy,tf,TimeDN[m],false));// Punto de cruce asociado con el extremo próximo
      si (TempIND[iBarShift(sy,tf,TimeDN[m])]<CheckCross) // Si el extremo se encuentra debajo de la línea
         {
            si (PeakDN[m]<PeakDN[pbar]) // Si este extremo es más bajo que el extremo principal
               {
                  LowestBarDN = iBarShift(sy,tf,TimeDN[m]);    // Entonces este es el que necesitamos a partir de...
                  LowestPeakDN = PeakDN [m];                  // Nueva coordenadas del extremo siguiente
                  LowestTimeDN = TimeDN[m];                             
               }
         }                       
   }

Aquí, hemos dispuesto un bucle desde extremo siguiendo el mínimo hasta el primer extremo de la matriz del extrema. Esto se hace porque el mínimo será el punto de origen al dibujar la línea mientras la comprobación de cruces, comienza desde el extremo próximo.

Se dibujará la línea virtual utilizando la función de ecuación de línea recta que calcula el valor de Y para X en el punto de cruce con la línea recta:

double EquationDirect(double x1, double y1, double x2, double y2, double x) {
if (x2==x1) return(y1);
return((y2-y1)/(x2-x1)*(x-x1)+y1);

x 1 y y1 son las coordenadas del primer punto; x2 y y2 son las coordenadas del segundo punto; x es el valor para el cual se calcula y . Esta función se toma de I. El hilo del Forode Kim.

Por lo tanto:

CheckCross=EquationDirect(iBarShift(sy,tf,TimeDN[m+1]), PeakDN[m+1], // Primera coordenada de la línea
                          PivotBarDN, PivotPeakDN,                   // Segunda coordenada de la línea                                  
                          iBarShift (sy,tf,TimeDN[m],false));         // Punto de cruce asociado con el extremo siguiente

Introduzca la barra del mínimo como la coordenada x-del primer punto y el valor de la mínima como la coordenada y- del primer punto en los parámetros de función al pasar. La barra y el valor del extremo principal se utilizará como la segunda coordenada del punto de línea virtual.

El último valor que pasa a la función es el número de barras que pasa del bucle a la función para el cálculo del valor de la coordenada y y la comparación del valor resultante con el valor del extremo situado en el punto dado.

si (TempIND [iBarShift(sy,tf,TimeDN[m])]<CheckCross) // Si el extremo se encuentra debajo de la línea
   {
    si (PeakDN[m]<PeakDN[pbar]) // Si este extremo es más bajo que el extremo principal
       {
         LowestBarDN =iBarShift(sy,tf,TimeDN[m]);   // Entonces este es el que necesitamos a partir de...
         LowestPeakDN = PeakDN [m];                   // Nuevas coordenadas del extremo siguiente
         LowestTimeDN = TimeDN[m];                             
        }
   }            

Así, si el valor devuelto por la función es mayor que el valor del extremo situado en el punto dado, entonces el extremo cruza la línea virtual y la línea debe originarse desde este extremo. Guardar los nuevos valores de las coordenadas y proceder a la siguiente interación del bucle para identificar un cruce con el extremo próximo.

Una vez que identificamos los siguientes extremos, la línea no se cruza por cualquier extrema mas, y va a ser utilizado para la elaboración de la línea de tendencia. Todo lo que necesitamos saber es si el valor de este extremo es menor que el extremo principal y si se encuentra a la izquierda del extremo principal, lo que significa que la línea dibujada desde ella hacia el extremo principal se va en la dirección correcta.

si (LowestBarDN>PivotBarDN && LowestPeakDN<PivotPeakDN// Si el mínimo está a la izquierda y a continuación el extremo principal

Y significa que ahora tenemos todos los datos necesarios para trazar una línea de tendencia alcista en el A/D gráfico.


5. Trazar líneas de tendencia en el gráfico del A/D

Para identificar la presencia de la ventana del indicador A/D en la ventana del gráfico principal, introducimos otra variable WinID que va a almacenar el número de la subventana del gráfico del A/D :

WinID=WindowFind("A/D");               // Número de ventana del AD

Aquí, la función estándar WindowFind("name"); devuelve el número de la subventana del gráfico que contiene el indicador con el nombre especificado name, si se encuentra; de lo contrario devolverá -1. No es básicamente necesario para dibujar la línea de tendencia en el grafico del A/D ya no es necesario en los cálculos; sin embargo vamos a dibujarlo para mayor claridad y para asegurarse de que todo es correcto:

if (WinID>0)
   {
    if (ObjectFind("Trend_GLine_DN")<0)
    ObjectCreate("Trend_GLine_DN",OBJ_TREND,WinID,LowestTimeDN,LowestPeakDN,PivotTimeDN,PivotPeakDN);
    ObjectSet("Trend_GLine_DN",OBJPROP_COLOR,Lime);
    ObjectSet("Trend_GLine_DN",OBJPROP_TIME1,LowestTimeDN);
    ObjectSet("Trend_GLine_DN",OBJPROP_PRICE1,LowestPeakDN);
    ObjectSet("Trend_GLine_DN",OBJPROP_TIME2,PivotTimeDN);
    ObjectSet("Trend_GLine_DN",OBJPROP_PRICE2,PivotPeakDN);
   }

Aquí en primer lugar comprobamos si la ventana del indicador A/D está presente en la ventana principal. Si no está allí, no hay ningún lugar para trazarlo:

if (WinID>0)

Es simple: Si el indicador no está adherido a la ventana del gráfico, la función WindowFind() devolverá -1. La ventana del gráfico principal, es decir, la tabla sí mismo, siempre tiene valor cero y por lo tanto, comprobamos si el valor es "mayor que cero". Ya que aparte de la grafica de A/D, puede haber otros indicadores en la ventana del gráfico, no podemos saber para algunos qué número se le asignará al A/D que necesitamos y en consecuencia no comprueban el número por sí mismo sino más bien si el valor es mayor que cero.

Además... Si el identificador de ventana (WinID) es mayor que cero, se considera el gráfico A/D para estar presente en la ventana y podemos proceder al trazado. Entonces comprobamos si una línea de tendencia ya se ha señalado en la gráfica con el nombre de línea de tendencia:

if (ObjectFind("Trend_GLine_DN")<0)

y si aún no está allí (la función ObjectFind() devuelve -1, de lo contrario la A/d devuelve el índice de la ventana), podemos empezar a trazar. Para ello, utilizamos la función:

ObjectCreate("Trend_GLine_DN",OBJ_TREND,WinID,LowestTimeDN,LowestPeakDN,PivotTimeDN,PivotPeakDN);

bool ObjectCreate(string name, int type, int window, datetime time1, double price1, datetime time2=0, double price2=0, datetime time3=0, double price3=0) crea un objeto con un nombre, tipo y coordenadas iniciales en una subventana del gráfico especificado. El número de coordenadas asociado al objeto puede ser 1 a 3 dependiendo del tipo. A la terminación exitosa del objeto, la función devuelve TRUE, de lo contrario FALSE.

Revisemos el detalle:

  • string name toma el valor del nombre del objeto que debe ser creado — en nuestro caso, "Trend_GLine_DN" (línea de tendencia extrema inferior de conexión); el siguiente parámetro que se pasa a la función es detipo int , es decir, el tipo de objeto — en nuestro caso, es razonable OBJ_TREND...
  • La ventana int es la ventana del ndicador A/D almacenado identificado almacenado en la variable WinIND...

Otros parámetros pasados a la función son las coordenadas de los dos puntos que se utilizan para trazar la línea de tendencia:

  • time1 DateTime es la primera coordenada de tiempo del mínimo que se guarda en la variable LowestTDN,
  • price1 doble es el primer valor del mínimo que se guarda en la variable LowestPeakDN,
  • time2 DateTime es la segunda coordenada de tiempo del mínimo que se guarda en la variable HighestTDN,
  • double price2 is the second value coordinate of the minimum saved in the variable HighestPeakDN.

Otros parámetros de la función ObjectCreate() no se utilizan en el trazado de la línea de tendencia.

Por lo tanto, en esta etapa, se ha creado el objeto de la línea de tendencia. Ahora tenemos que modificar algunos de sus parámetros. En particular, las línea color y línea de coordenadas. El color de la línea será constante, mientras que las coordenadas tendrán que modificarse cada vez que los datos sobre la nueva extrema cambian y utilizan las nuevas coordenadas para trazar la línea de tendencia:

ObjectSet("Trend_GLine_DN",OBJPROP_COLOR,Lime);

boolObjectSet( stringname, intprop_id, doublevalue) cambia el valor de la propiedad de objetos especificados. Si tiene éxito, la función devuelve TRUE, de lo contrario FALSE. Esta línea de código establece el color de la línea de tendencia alcista asignando el color estándar que la constante Lime utilizada en el conjunto de colores de la Web.

Los parámetros pasados a la función son:

  • El string name — el nombre del objeto cuyas propiedades deban modificar — en nuestro caso, "Trend_GLine_DN",
  • int prop_id — identificador de las propiedades del objeto que deben modificarse. Primero cambiamos el color, por lo tanto, el identificador será OBJPROP_COLOR,
  • doublevalue — nuevo valor de la propiedad del objeto especificado. Esto es donde se pasa la constante color Lime .

Creo que, la modificación de otras propiedades del objeto no debería plantear ninguna dificultad — es similar al ejemplo anterior que implica el cambio en el color del objeto:

ObjectSet("Trend_GLine_DN",OBJPROP_TIME1,LowestTimeDN);
ObjectSet("Trend_GLine_DN",OBJPROP_PRICE1,LowestPeakDN);
ObjectSet("Trend_GLine_DN",OBJPROP_TIME2,PivotTimeDN);
ObjectSet("Trend_GLine_DN",OBJPROP_PRICE2,PivotPeakDN);

En el primero, cambiamos la primera coordenada de tiempo extremo (OBJPROP_TIME1), seguido por el cambio del primer valor de la coordenada (OBJPROP_PRICE1), luego cambiamos la segunda coordenada de tiempo extremo (OBJPROP_TIME2) y el segundo valor de la coordenada (OBJPROP_PRICE1). Todos los valores de las coordenadas se escriben en las variables LowestTimeDN, LowestPeakDN, PivotTimeDN y PivotPeakDN.

Nuestra línea de tendencia se traza en la A/D grafico del indicador (sujeto a la presencia de la ventana indicadora en sí mismo). Ahora, tenemos que identificar el punto de cruce entre la línea en el gráfico A/D y la línea de tendencia trazada utilizando el indicador gráfico extrema. Pensando en esta tarea, llegó a la conclusión de que será más fácil (para mí) calcular el punto de cruce usando la ecuación de línea recta.


6. Identificación del punto de cruce entre la línea del gráfico de A/D y la línea de tendencia con el gráfico del indicador Extrema

Tener dos puntos a través de los cual se traza la línea de tendencia, utilizamos la ecuación de línea recta para calcular una línea imaginaria que se proyecta en la primera barra de la linea del indicador A/D. (trabajamos con la primera barra para reducir el número de falsos positivos).

El punto calculado utilizando la ecuación de la recta y proyectada sobre la primera barra del indicador será el punto donde vamos a comprobar para los cruces. Además, sólo tenemos que marcar estos puntos calculados en la gráfica del A/D y compruebe el hecho único de ellos siendo atravesada por la línea del indicador hacia arriba o hacia abajo.

Hay otro punto a tener en cuenta. Puesto que vamos a identificar el punto de cruce como tal, en lugar de ser superior/inferior, nuestros cálculos requerirán también de la segunda barra del gráfico del indicador A/D. Si la línea del indicador es más alta que el punto de cruce en la primera barra y menor o igual que el punto de cruce en la segunda barra, tenemos un cruce hacia arriba. Por lo tanto, vamos a calcular dos líneas basadas en el extrema. La primera línea se proyectará en la primera barra del indicador y la segunda línea se proyectará en la segunda barra.

Los puntos de cruce imaginarios se marcarán para mejor visualización de los resultados de cálculo.

Así que empecemos...


7. Identificación y marcado de puntos posibles

Vamos a necesitar variables adicionales para almacenar los valores de puntos posible calculados.

Ya les hemos añadido a la lista de variables de la función:

// ------------------------------------------------------------------------------------------                     
// ------------------------------- Variables de función ---------------------------
// ------------------------------------------------------------------------------------------                     
   double   PeakUP[], PeakDN[],           // declarar matrices de pico/canal
            yUP, yDN, yGUP, yGDN,         // Coordenadas del punto de cruce entre la línea de tendencia y el indicador UP and DN en la barra 1
            yUP2, yDN2, yGUP2, yGDN2,     // Coordenadas del punto de cruce entre la línea de tendencia y el indicador UP and DN en la barra 2
            LowestPeakDN,HighestPeakDN,   // Valores del mínimo y máximo inferior
            LowestPeakUP,HighestPeakUP;   // Valores del mínimo y máximo superior
   datetime TimeDN[], TimeUP[],           // Matrices de almacenamiento de las del extrema
            LowestTimeDN, HighestTimeDN,  // Barras del mínimo y máximo inferior
            LowestTimeUP, HighestTimeUP,  // Barras del mínimo y máximo superior
            LowestTDN, HighestTDN,        // Tiempo del mínimo y máximo inferior
            LowestTUP, HighestTUP;        // Tiempo del mínimo y máximo inferior
   int      i, k, Index,                  // Varialbles "Internal"
            WinID=WindowFind("A/D");      // Número de ventana AD

Adelantandose a la historia, me gustaría mencionar que en lugar de 4, hemos añadido 8 variables de otras 4 variables que serán necesarias para el cálculo de líneas de tendencia "local" y puntos de cruce. Ahora vamos a utilizar yGUP, yGDN, yGUP2 y yGDN2 para almacenar los puntos de cruce con

  • la línea de tendencia alcista "global" yGUP en la primera barra; yGUP2 - en la segunda barra y
  • la línea de tendencia bajista "global" yGDN en la primera barra; yGDN2 - en la segunda barra.

Una vez más utilicemos la función de la ecuación de la línea recta ecuación amablemente proporcionada por Igor Kim:

//+----------------------------------------------------------------------------+
//|  Author    : Igor B. Kim aka KimIV,  http://www.kimiv.ru                   |
//+----------------------------------------------------------------------------+
//|  Version   : 12.10.2007                                                    |
// |  Descripción: Ecuación de la línea recta.  Calcula el valor de Y para X  |
//|                en el punto de cruce con la línea recta.                    |
//+----------------------------------------------------------------------------+
//|  Parametros:                                                               |
//|    x1,y1 - coordenadas del primer punto,                                   |
//|    x2,y2 - coordenadas del segundo punto,                                  |
//|    x     - valor para los que Y necesita ser calculado                     |
//+----------------------------------------------------------------------------+
double EquationDirect(double x1, double y1, double x2, double y2, double x) 
{
  if (x2==x1) return(y1);
  return((y2-y1)/(x2-x1)*(x-x1)+y1);
}

5 parámetros se pasarán a la función como puntos de partida para el cálculo: dos para las coordenadas de los dos gráficos extrema y el último parámetro siendo de la barra donde debe encontrarse el punto de cruce:

yGDN =EquationDirect(LowestBarDN,LowestPeakDN,PivotBarDN,PivotPeakDN,iBarShift(sy,tf,Time[1],false));
yGDN2=EquationDirect(LowestBarDN,LowestPeakDN,PivotBarDN,PivotPeakDN,iBarShift(sy,tf,Time[2],false));

Aquí se utilizan tanto las coordenadas del mínimo como las coordenadas del primer punto: x1 = LowestTimeDN, y1 = LowestPeakDN, mientras que las coordenadas del extremo principal se utilizan tanto como las coordenadas del segundo punto: x2 = PivotBarDN, y2 = PivotPeakDN.

El cambio de la barra requerida se pasa tanto como el valor que se calcula en la ecuación: iBarShift(sy, tf, Time[1], false), wheresy es el nombre del símbolo del instrumento actual, tf es el time frame, Time[1] es la matriz de la serie de tiempo que contiene el tiempo de apertura de cada barra en el gráfico actual. Los tipos de datos datetime representan el tiempo en segundos transcurridos desde 01 de enero de 1970 a las 00:00.

Los restantes parámetros de esta función se han discutido anteriormente. Me gustaría señalar que si nuestra función va a ser utilizada en un EA de múltiples monedas, entonces en lugar de Time[1] , debemos utilizar la función estándar iTime() (que es lo que vamos a implementar en la variante final de la función) que recibe explícitamente valores del instrumento actual y el timeframe utilizado, mientras que Time[] sólo funciona con la grafica actual.

Contamos con los niveles de cruce calculados y almacenados en las variables. Para mayor claridad que ahora pueden ser marcados en el grafico del indicador A/D:

if (WinID>0)
     {
         if (ObjectFind("PointGDN"+Time[1])<0)
         ObjectCreate("PointGDN"+Time[1],OBJ_ARROW,WinID,Time[1],yGDN);
         ObjectSet("PointGDN"+Time[1],OBJPROP_ARROWCODE,4);
         ObjectSet("PointGDN"+Time[1],OBJPROP_COLOR,Lime);
         ObjectSet("PointGDN"+Time[1],OBJPROP_TIME1,Time[1]);
         ObjectSet("PointGDN"+Time[1],OBJPROP_PRICE1,yGDN);
     }

Esto es similar a lo que hemos tenido al trazar la línea de tendencia. Echemos un vistazo a algunas ligeras diferencias.

La primera diferencia es en el nombre del objeto:

ObjectCreate("PointGDN"+Time[1],OBJ_ARROW,WinID,Time[1],yGDN);

Ya que no vamos a crear un solo objeto sino más bien un conjunto de objetos en cada barra de nueva, los nombres de todos los objetos deben ser únicos. Para ello, el tiempo de la barra en la cual se crea el objeto se añade al nombre del objeto:

"PointGDN"+Time[1]

La segunda diferencia está en el identificador del tipo de objetos gráficos. Mientras que para el trazado de la línea de tendencia se utilizó OBJ_TREND, ahora vamos a utilizar OBJ_ARROW que permite para dibujar flechas (símbolos). Además, WinID es el número de la subventana donde se dibujará el objeto — en nuestro caso se trata del número de ventana A/D y existen dos coordenadas: la coordenada tiempo Time[1] siendo el tiempo de la primera barra, y la coordenadas precio yGDN siendo el punto de cruce entre la línea de tendencia y la primera barra calculada.

Las propiedades del objeto se definen como sigue:

ObjectSet("PointGDN"+Time[1],OBJPROP_ARROWCODE,4);

El identificador de las propiedades del objeto OBJPROP_ARROWCODE establece el código de objeto y puede ser uno de los símbolos wingdings o uno de los códigos de la flecha predefinidos. Para fijar el objeto exactamente en el nivel calculado, hay códigos de flecha especialesque apuntan el precio exacto y el tiempo. Vamos a usar el guión (-), siendo su código 4. Las líneas restantes establecen el color del objeto y sus coordenadas cambiantes en cada barra.

ObjectSet("PointGDN"+Time[1],OBJPROP_COLOR,Lime);
ObjectSet("PointGDN"+Time[1],OBJPROP_TIME1,Time[1]);
ObjectSet("PointGDN"+Time[1],OBJPROP_PRICE1,yGDN);

Ahora tenemos los posibles puntos de cruce entre el indicador y la línea de tendencia alcista "global" trazada basados en trazo del extrema. Son estos puntos que van a ser necesarios para detectar cruces. Si se encuentra un cruce, el indicador de señal - la flecha hacia abajo - se establecerá en el gráfico principal que es, por cierto, lo qué vamos a hacer ahora mismo.


8. Comprobación de Crossovers de la linea A/D y los puntos de cruce calculados y estableciendo indicadores de señal

Para identificar si hay un cruce de la linea del indicador A/D y los puntos de cruce, simplemente comparar sus valores tales como ser mayor que / menor que y si el valor de la línea de indicador en una barra determinada es menor que el valor del punto de cruce, mientras que el valor del indicador en la barra anterior es mayor que el valor del punto de cruce, entonces lo que tratamos es un cruce hacia abajo:

if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yGDN,8) && 
     NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yGDN2,8))
    {
        CrossGDN = true;           // Establece el flag que indica el cruce hacia abajo
        CrossGUP = false;          // Quitar el flag que indica el cruce hacia arriba
                                    
        if (ObjectFind("ArrowGDN"+Time[1])<0)
        ObjectCreate("ArrowGDN"+Time[1],OBJ_ARROW, 0 ,Time[1], iHigh(sy,tf,1)+5*pt);
        ObjectSet("ArrowGDN"+Time[1],OBJPROP_ARROWCODE,242);
        ObjectSet("ArrowGDN"+Time[1],OBJPROP_COLOR,OrangeRed);
        ObjectSet("ArrowGDN"+Time[1],OBJPROP_WIDTH,1);
        ObjectSet("ArrowGDN"+Time[1],OBJPROP_TIME1,Time[1]);
        ObjectSet("ArrowGDN"+Time[1],OBJPROP_PRICE1,iHigh(sy,tf,1)+5*pt);
    }

Para comparar, los valores de datos de tipo doble que se normalizó con la precisión requerida por la función estándar double NormalizeDouble(double value, int digits). Los números de coma flotante se deben redondear con la precisión requerida.

Los valores calculados de StopLoss y TakeProfit, así como los precios de apertura de órdenes pendientes deben normalizarse a la exactitud así como el conjunto de dígitos variables predefinidos:

if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yGDN,8) && 
    NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yGDN2,8))

que es exactamente lo que hicimos cuando se comparan los valores de indicador con los valores del punto de paso calculado. Si se cumple esta condición, las variables del tipo bool CrossGDN y CrossGUP se asignan los valores true y false , respectivamente.

El siguiente bloque del código establece la flecha hacia abajo en la ventana del gráfico principal del terminal:

if (ObjectFind("ArrowGDN"+Time[1])<0)
  ObjectCreate("ArrowGDN"+Time[1],OBJ_ARROW, 0 ,Time[1], iHigh(sy,tf,1)+5*pt);
  ObjectSet("ArrowGDN"+Time[1],OBJPROP_ARROWCODE,242);
  ObjectSet("ArrowGDN"+Time[1],OBJPROP_COLOR,OrangeRed);
  ObjectSet("ArrowGDN"+Time[1],OBJPROP_WIDTH,1);
  ObjectSet("ArrowGDN"+Time[1],OBJPROP_TIME1,Time[1]);
  ObjectSet("ArrowGDN"+Time[1],OBJPROP_PRICE1,iHigh(sy,tf,1)+5*pt);

Creo que este bloque de código no requiere una aclaración especial, como ya hemos comentado las marcas y líneas se pueden establecer en las ventanas del terminal. La única diferencia no considerada anteriormente es la especificación de la ventana del gráfico principal del terminal. El número de esta ventana es siempre 0, por lo tanto ajustando a 0 el identificador de ventana en el umbral

ObjectCreate("ArrowGDN"+Time[1],OBJ_ARROW, 0 ,Time[1], iHigh(sy,tf,1)+5*pt);

nos permiten establecer las flechas en la ventana principal del terminal.

Hay que prestar atención a unas cuantas cosas más: el valor del precio máximo de la barra por encima del cual se establecerá la flecha sirve como la coordenada de la flecha hacia abajo y- y (su código es 242) y el guión se establece en 5 puntos:

iHigh(sy,tf,1)+5*pt

double iHigh( string symbol, int timeframe, int shift) devuelve el valor del precio máximo especificado por el parámetro shift e la barra del grafico correspondiente (symbol, timeframe).

Se obtiene el valor de pt de la línea inmediatamente después de la declaración de las variables de la función:

double pt=MarketInfo(Symbol(),MODE_POINT);

Esta es una función estándar double MarketInfo( string symbol, int type). Devuelve información de varios instrumentos financieros enumerados en la ventana "Market Watch". Identificador de la consulta de la función MODE_POINT devuelve el tamaño en la moneda de cotización. Para el instrumento actual, se almacena en la variable predefinida Pointo. La línea:

ObjectSet("ArrowGDN"+Time[1],OBJPROP_WIDTH,1);

establece el tamaño de la flecha aparecida = 1.


9. Control para el cruce de la línea de tendencia alcista en la dirección del movimiento de precio del par de divisas

Un cruce hacia abajo de una línea de tendencia alcista puede indicar que el movimiento del precio del par de divisas puede cambiar dentro de poco, mientras que un cruce hacia arriba de la misma línea de tendencia alcista puede sugerir que el precio continuará en la misma dirección. Por lo tanto, para estar en el lado seguro, también vamos a comprobar este tipo de cruce, mientras que en el mismo teniendo en cuenta que el check esté desactivado, si es necesario.

Para ello, cambiar la primera línea de la función agregando otros dos parámetros para ser pasados a la función:

int SignalCrossIND(double &TempIND[], int nBars, string sy, int tf, bool local=false, bool add=false)

Aquí hemos añadido dos variables del tipo bool : local and add. La variable local está a cargo de cálculo necesario para mostrar las líneas de tendencia "local", mientras que la variable add sirve para comprobar un cruce hacia arriba de la línea de tendencia alcista y un cruce hacia abajo de la línea de tendencia bajista. Por defecto, estas variables se establecen en false que significa que se omiten cuando se llama a la función, la función no calcula, ni mostrar las líneas de tendencia local, ni comprobará los cruces.

if (add)
    {
       if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yGDN,8) && 
           NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yGDN2,8))
           {
              CrossGUP = true;
              CrossGDN = false;        
              if (ObjectFind("ArrowGUP"+Time[1])<0)
              ObjectCreate("ArrowGUP"+Time[1],OBJ_ARROW, 0 ,Time[1], iLow(sy,tf,1));
              ObjectSet("ArrowGUP"+Time[1],OBJPROP_ARROWCODE,241);
              ObjectSet("ArrowGUP"+Time[1],OBJPROP_COLOR,Lime);
              ObjectSet("ArrowGUP"+Time[1],OBJPROP_WIDTH,0);
              ObjectSet("ArrowGUP"+Time[1],OBJPROP_TIME1,Time[1]);
              ObjectSet("ArrowGUP"+Time[1],OBJPROP_PRICE1,iLow(sy,tf,1));
           }
    }

Todo es familiar en este bloque de código y no es básicamente necesario buscarlo en él. Lo que tenemos que identificar es el check de la variable add:

if (add)

es absolutamente idéntico a este:

if (add==true)

y comprueba si esta variable está establecida en "true". Si es así, se ejecutan todas las líneas incluidas entre paréntesis {} siguiendo la línea dada. Hay solamente dos líneas en la izquierda a considerar:

ObjectSet("ArrowGUP"+Time[1],OBJPROP_ARROWCODE,241);

Aquí, el último parámetro que se pasa a la función es el código de la flecha hacia arriba — 241, y

ObjectSet("ArrowGUP"+Time[1],OBJPROP_WIDTH,0);

donde el último valor pasado a la función indica el tamaño de la flecha dibujada. En nuestro caso, vamos a mostrar una pequeña flecha de tamaño 0.

El código que tenemos en este momento es funcionalmente completo: Lee los datos del indicador A/D y lo utiliza para rellenar la matriz, identifica el indicador gráfico extrema, traza la línea de tendencia alcista en el gráfico, comprueba los cruces entre esta línea y la línea del indicador A/D y debe identificarse tal cruce, coloca arriba o abajo las flechas (dependiendo de la dirección de cruce) en el gráfico principal del instrumento moneda situado en la ventana del terminal.

Abajo está el código para un control similar pero esta vez para la línea de tendencia bajista. Es dado para su análisis independiente:

//====================================================================================================
// -------------------- Identificación del UP superior mínimo y máximo --------------------            
//====================================================================================================
    PivotTimeUP = TimeUP[pbar];                           // Tiempo del extremo principal
    PivotBarUP  = iBarShift(sy,tf,TimeUP[pbar]);          // Barra del extremo principal
    PivotPeakUP = PeakUP[pbar];                           // Valor del extremo principal

    HighestPeakUP = ArrayMax(PeakUP);                     // Obtiene el máximo valor superior
    Index = ArraySearchDouble(PeakUP, HighestPeakUP);     // Obtiene el índice de la parte superior máximo de la matriz
    HighestBarUP =iBarShift(sy,tf,TimeUP[Index]);         // Obtiene la barra de la parte superior máxima
    HighestTimeUP = TimeUP[Index];                        // Obtiene el tiempo de la parte superior máxima

    if (HighestBarUP>PivotBarUP)                          // Si el máximo está por la izquierda del primer extremo... 
                                                          // ... (siendo en la celda 0 de la matriz de tiempo de pico)
   for (m=Index-1; m>pbar; m--)                           // Bucle del extremo siguiendo el máximo del primer extremo
      {
// ------- Dibuja una línea de tendencia virtual y comprueba lo cruces con otra extrema --------  
      CheckCross=EquationDirect(iBarShift(sy,tf,TimeUP[m+1]), 
                                PeakUP[m+1],                      // Primera coordinada de la línea
                                PivotBarUP, PivotPeakUP,          // Segunda coordenada de la linea
                                iBarShift(sy,tf,TimeUP[m],false));// Punto de crfuce asociado con el siguiente extremo
      if (TempIND[iBarShift(sy,tf,TimeUP[m])]>CheckCross)         // Si el extremo está por encima de la línea
         {
            if (PeakUP[m]>PeakUP[pbar])                           // i este extremo es más alto que el extremo principal
               {
                  HighestBarUP =iBarShift(sy,tf,TimeUP[m]);       // Entonces este es el que necesitamos a partir de...
                  HighestPeakUP = PeakUP[m];                      // Nuevas coordenadas del extremo siguiente
                  HighestTimeUP = TimeUP[m];                             
               }
         }                       
   }

   if (HighestBarUP>PivotBarUP && HighestPeakUP>PivotPeakUP)      // Si el máximo está a la izquierda del extremo principal     
      {
// ------------- Dibujar una línea de tendencia bajista (UP - extrema)--------                         
          if (WinID>0)
             {
                if (ObjectFind("Trend_Line_GUP")<0)
                ObjectCreate("Trend_Line_GUP",OBJ_TREND,WinID,HighestTimeUP,HighestPeakUP,PivotTimeUP,PivotPeakUP);
                ObjectSet("Trend_Line_GUP",OBJPROP_COLOR,OrangeRed);
                ObjectSet("Trend_Line_GUP",OBJPROP_TIME1,HighestTimeUP);
                ObjectSet("Trend_Line_GUP",OBJPROP_PRICE1,HighestPeakUP);
                ObjectSet("Trend_Line_GUP",OBJPROP_TIME2,PivotTimeUP);
                ObjectSet("Trend_Line_GUP",OBJPROP_PRICE2,PivotPeakUP);
             }        
//-------------- Cálculo de niveles de la tendencia bajista (UP - extrema) ----------------            
    yGUP =EquationDirect(HighestBarUP, HighestPeakUP, PivotBarUP, PivotPeakUP, iBarShift(sy,tf,Time[1],false));
    yGUP2=EquationDirect(HighestBarUP, HighestPeakUP, PivotBarUP, PivotPeakUP, iBarShift(sy,tf,Time[2],false));

//---------- Dibuja los niveles de la tendencia bajista (UP - extrema) ----------            
         if (WinID>0)
            {
               if (ObjectFind("PointGUP"+Time[1])<0)
               ObjectCreate("PointGUP"+Time[1],OBJ_ARROW,WinID,Time[1],yGUP);
               ObjectSet("PointGUP"+Time[1],OBJPROP_ARROWCODE,4);
               ObjectSet("PointGUP"+Time[1],OBJPROP_COLOR,OrangeRed);
               ObjectSet("PointGUP"+Time[1],OBJPROP_TIME1,Time[1]);
               ObjectSet("PointGUP"+Time[1],OBJPROP_PRICE1,yGUP);
            }
         
// --------------- Check un cruce alcista de la tendencia bajista -----------------   
         if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yGUP,8) && 
             NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yGUP2,8))
               {
                  CrossGUP = true;                 // Establece el flag que indica el cruce hacia arriba
                  CrossGDN = false;                // Quitar el flag que indica el cruce hacia abajo
               
                  if (ObjectFind("ArrowGUP"+Time[1])<0)
                  ObjectCreate("ArrowGUP"+Time[1],OBJ_ARROW, 0 ,Time[1], iLow(sy,tf,1));
                  ObjectSet("ArrowGUP"+Time[1],OBJPROP_ARROWCODE,241);
                  ObjectSet("ArrowGUP"+Time[1],OBJPROP_COLOR,Lime);
                  ObjectSet("ArrowGUP"+Time[1],OBJPROP_WIDTH,1);
                  ObjectSet("ArrowGUP"+Time[1],OBJPROP_TIME1,Time[1]);
                  ObjectSet("ArrowGUP"+Time[1],OBJPROP_PRICE1,iLow(sy,tf,1));
               }
            
// ------------- Busque un cruce hacia abajo de la tendencia bajista ---------------   

         if (add)
            {
               if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yGUP,8) && 
                   NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yGUP2,8))
                  {
                     CrossGDN = true;
                     CrossGUP = false;
                              
                     if (ObjectFind("ArrowGDN"+Time[1])<0)
                     ObjectCreate("ArrowGDN"+Time[1],OBJ_ARROW, 0 ,Time[1], iHigh(sy,tf,1)+15*pt);
                     ObjectSet("ArrowGDN"+Time[1],OBJPROP_ARROWCODE,242);
                     ObjectSet("ArrowGDN"+Time[1],OBJPROP_COLOR,OrangeRed);
                     ObjectSet("ArrowGDN"+Time[1],OBJPROP_WIDTH,0);
                     ObjectSet("ArrowGDN"+Time[1],OBJPROP_TIME1,Time[1]);
                     ObjectSet("ArrowGDN"+Time[1],OBJPROP_PRICE1,iHigh(sy,tf,1)+15*pt);
                  }
            }
      }  
                                  


10. Identificación del Extrema "Local" en la tabla A/D, trazado de líneas de tendencia a través del Extrema identificados y comprobación de cruces

Por lo tanto, hay sólo una cosa pequeña en la izquierda: para solicitar el mismo que el anterior extrema "local".

En lo único que se diferencian de la extrema "global" es el método de su identificación. Se identificarán utilizando dos del extrema derecha y si el primer extremo (para una tendencia alcista) parece mayor que el segundo que se encuentra a la izquierda del primer extremo, se asume que puede establecerse una línea de tendencia local. Para una tendencia bajista, el segundo extremo identificado debe ser superior y a la izquierda del primer extremo.

Desde el código va a ser absolutamente idéntico al ya revisado por encima (en realidad será casi idéntica, excepto en algunos puntos), proporcionará en su totalidad para una línea de tendencia alcista local:

// ------------------------ Identificación de dos (locales) DN extrema más externa inferior --------           
   if (local)
      {     
         asize=ArraySize(PeakDN);
         for (l=asize-1; l>=1; l--)
            {
               if (PeakDN[l]<PeakDN[l-1])
                  {
                     LastTimeDN     =TimeDN[l-1];
                     LastVarDN      =PeakDN[l-1];
                     PreLastTimeDN  =TimeDN[l];
                     PreLastVarDN   =PeakDN[l];
                  }
            }
//-------- Dibuja una línea de tendencia alcista local (DN - extrema) -------          
         if (WinID>0)
            {
               if (ObjectFind("Trend_Line_DN")<0)
               ObjectCreate("Trend_Line_DN",OBJ_TREND,WinID,TimeDN[1],PeakDN[1],TimeDN[0],PeakDN[0]);
               ObjectSet("Trend_Line_DN",OBJPROP_COLOR,MediumSeaGreen);
               ObjectSet("Trend_Line_DN",OBJPROP_TIME1,PreLastTimeDN);
               ObjectSet("Trend_Line_DN",OBJPROP_PRICE1,PreLastVarDN);
               ObjectSet("Trend_Line_DN",OBJPROP_TIME2,LastTimeDN);
               ObjectSet("Trend_Line_DN",OBJPROP_PRICE2,LastVarDN);
            }
//------------- Cálculo de niveles de la tendencia alcista local (DN - extrema) -------------            
  yDN =EquationDirect(iBarShift(sy,tf,PreLastTimeDN,false), PreLastVarDN, 
                      iBarShift(sy,tf,LastTimeDN,false), LastVarDN, iBarShift(sy,tf,Time[1],false));
  yDN2=EquationDirect(iBarShift(sy,tf,PreLastTimeDN,false), PreLastVarDN, 
                      iBarShift(sy,tf,LastTimeDN,false), LastVarDN, iBarShift(sy,tf,Time[2],false));
               
//------- Dibuja los niveles de la tendencia alcista local (DN - extrema) ---------          
         if (WinID>0)
            {
               if (ObjectFind("PointDN"+Time[1])<0)
               ObjectCreate("PointDN"+Time[1],OBJ_ARROW,WinID,Time[1],yDN);
               ObjectSet("PointDN"+Time[1],OBJPROP_ARROWCODE,4);
               ObjectSet("PointDN"+Time[1],OBJPROP_COLOR,MediumSeaGreen);
               ObjectSet("PointDN"+Time[1],OBJPROP_TIME1,Time[1]);
               ObjectSet("PointDN"+Time[1],OBJPROP_PRICE1,yDN);
            }
// ------------- Check un cruce hacia abajo de la tendencia alcista local --------------   
         if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yDN,8) && 
             NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yDN2,8))
               {
                  CrossDN = true;
                  CrossUP = false;
                  if (Arrow)                 // Si se permite el uso de indicadores de señal
                     {
                        if (ObjectFind("ArrowDN"+Time[1])<0)
                        ObjectCreate("ArrowDN"+Time[1],OBJ_ARROW, 0 ,Time[1], iHigh(sy,tf,1)+15*pt);
                        ObjectSet("ArrowDN"+Time[1],OBJPROP_ARROWCODE,242);
                        ObjectSet("ArrowDN"+Time[1],OBJPROP_COLOR,Chocolate);
                        ObjectSet("ArrowDN"+Time[1],OBJPROP_WIDTH,1);
                        ObjectSet("ArrowDN"+Time[1],OBJPROP_TIME1,Time[1]);
                        ObjectSet("ArrowDN"+Time[1],OBJPROP_PRICE1,iHigh(sy,tf,1)+15*pt);
                     }
               }      
// ------------ Check un cruce hacia arriba de la tendencia alcista local -------------   
         if (add)
            {
               if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yDN,8) && 
                   NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yDN2,8))
                  {
                     CrossUP = true;
                     CrossDN = false;
                     if (Arrow)                 // Si se permite el uso de indicadores de señal
                        {
                           if (ObjectFind("ArrowUP"+Time[1])<0)
                           ObjectCreate("ArrowUP"+Time[1],OBJ_ARROW, 0 ,Time[1], iLow(sy,tf,1));
                           ObjectSet("ArrowUP"+Time[1],OBJPROP_ARROWCODE,241);
                           ObjectSet("ArrowUP"+Time[1],OBJPROP_COLOR,MediumSeaGreen);
                           ObjectSet("ArrowUP"+Time[1],OBJPROP_WIDTH,0);
                           ObjectSet("ArrowUP"+Time[1],OBJPROP_TIME1,Time[1]);
                           ObjectSet("ArrowUP"+Time[1],OBJPROP_PRICE1,iLow(sy,tf,1));
                        }
                  }                  
            }
      }            

La única diferencia aquí es la identificación del extrema a través del cual se traza la línea de tendencia:

if (local)

Esta línea comprueba si el dibujo de la línea de tendencia y el cálculo de cruces de la gráfica A/D se permiten.

Entonces corremos a través del bucle en busca de dos extrema exterior:

asize=ArraySize(PeakDN);
  for (l=asize-1; l>=1; l--)
      {
       if (PeakDN[l]<PeakDN[l-1])
          {
            LastTimeDN     =TimeDN[l-1];
            LastVarDN      =PeakDN[l-1];
            PreLastTimeDN  =TimeDN[l];
            PreLastVarDN   =PeakDN[l];
          }
      }

y escriba sus valores a las variables LastTimeDN, LastVarDN, PreLastTimeDN y PreLastVarDN, donde

  • LastTimeDN contiene el tiempo de último extremo,
  • LastVarDN contiene el valor del último extremo,
  • PreLastTimeDN contiene la hora del penúltimo extremum y
  • PreLastVarDN contiene el valor del penúltima extremum.

Después de eso, el código es prácticamente idéntico a la ya considerada anteriormente, a excepción de las variables utilizadas para la elaboración de la líneas de tendencia e identificación de cruces con ellos. Y por último, debemos prever los valores de la función a ser devuelto por este broche de oro,

que en el caso general puede ser como sigue:

if (CrossGUP || CrossUP) return(1);
   else
   if (CrossGDN || CrossDN) return(-1); 
   else return(0);

Donde hay un cruce hacia abajo de la línea de tendencia alcista, la función devuelve -1; donde hay un cruce hacia abajo de la línea de tendencia bajista, la función devuelve 1; en los demás casos la función devuelve 0 — es simple como eso.

Es sin duda mejor verificar los cruces de las líneas de tendencia alcista y bajista, ya sea hacia arriba o hacia abajo, asignar "pesos", dependiendo de la combinación de cruces y retomar los valores necesarios de la función de llamada para su posterior procesamiento de la señal.

En conclusión de la descripción de la función, voy a dar su código completo, incluyendo algunas modificaciones menores (con la comprobación de si se permite establecer indicadores de señal cuando un cruce de la línea de tendencia y la linea de la grafica A/D esta identificada, así como el uso de la función estándar iTime() en lugar de Time para asegurar la generalidad de la función).

El código proporcionado a continuación se espera que sea comprensible, después de la extensa consideración dada arriba:

//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
// Identificación de un cruce de la línea de tendencia y la línea del gráfico de A/D y ajuste de los indicadores de señal
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
TempIND [] - (declarada a nivel global) matriz de almacenamiento de datos indicador A/D
// nBars - número de barras para identificación del extrema
// sy - símbolo del trabajo: "" o NULL - símbolo actual de la tabla
// tf - marco de tiempo de trabajo: 0 - actual, 
// local - ya sea calcular la base sobre las tendencias locales: predeterminado: false
// add - ya sea reaccionar a la cruce de la tendencia en la dirección de la tendencia: de forma predeterminada - false
// Arrow - ya sea establecer indicadores de señal en el grafico del instrumento de la moneda 
//         Cuando se identifica un cruce de la línea de tendencia y la línea gráfico del A/D: por defecto - true
//==========================================================================================
int SignalCrossIND(double &TempIND[], int nBars, string sy, int tf, 
                   bool local=false, bool add=false, bool Arrow=true)
{
   if (sy=="" || sy=="0") sy = Symbol();
   ArrayResize(TempIND,nBars);                     // Cambiar el tamaño de la matriz según el tamaño pasado a la función
   for (int j=0; j<=nBars-1; j++)
      {
         TempIND[j]=iAD(sy,tf,j);                  // Escribir los datos del indicador en el bucle de la matriz
      }
// ==========================================================================================               
// ------------------------------------ Function variables ---------------------------------+
// ==========================================================================================               

   double   PeakUP[], PeakDN[],                    // Declarar matrices de pico/canal
            yUP, yDN, yGUP, yGDN,                  // Coordenadas del punto de cruce entre la línea de tendencia y el indicador Up and DN en la barra 1
            yUP2, yDN2, yGUP2, yGDN2,              // Coordenadas del punto de cruce entre la línea de tendencia y el indicador Up and DN en la barra 2
            CheckCross,
            PreLastVarDN,LastVarDN,                // Valores de la última y penúltima extrema inferior inferior
            PreLastVarUP,LastVarUP,                // Valores de la última y penúltima extrema superior
            PivotPeakDN,PivotPeakUP,
            LowestPeakDN,HighestPeakDN,            // Valores de la mínima y máxima
            LowestPeakUP,HighestPeakUP,            // Valores de la parte superior mínima y máxima

   datetime TimeDN[], TimeUP[],                    // Matrices para almacenar barras del extrema
            PreLastTimeDN, LastTimeDN,             // Tiempo de la última y penúltima extrema inferior
            PreLastTimeUP, LastTimeUP,             // Tiempo de la última y penúltima extrema superior
            PivotBarDN, PivotTimeDN,               // Barra y tiempo del extremo principal inferior
            PivotBarUP, PivotTimeUP,               // Barra y tiempo del extremo principal superior
            LowestBarDN, LowestTimeDN,             // Barra y tiempo del mínimo inferior
            HighestBarUP, HighestTimeUP;           // Barra y tiempo del máximo superior
   int      i, kup, kdn, pbar=2, 
            m, l, t, asize, Index,                 // variables "Internal"
            WinID=WindowFind("A/D");               // Número de ventana del AD
   bool     CrossDN = false,                       // Flag que indica el cruce hacia abajo de la tendencia local
            CrossUP = false,                       // Flag que indica el cruce hacia arriba de la tendencia local
            CrossGDN = false,                      // Flag que indica el cruce hacia abajo de la tendencia mundial
            CrossGUP = false;                      // Flag que indica el cruce hacia arriba de la tendencia mundial
   
   double pt=MarketInfo(Symbol(),MODE_POINT);      // Tamaño de punto en la moneda de cotización

// ==========================================================================================               
// ------------- Llenade de matrices de discos de datos en picos y valles ----------------+
// ==========================================================================================               
         kdn=0;                                    // Inicializar el índice de la matriz de canal
         for (i=2; i<=nBars-1; i++)                // Ejecutar a través de la matriz de valores de la 2ª barra profunda en el historial
            {
               if (TempIND[i]<TempIND[i-1] && 
                   TempIND[i+1]>=TempIND[i])       // canal identificado FUE ALLÍ >=
                  {
                     ArrayResize(PeakDN, kdn+1);   // Cambiar el tamaño de la matriz del canal según el número de canales identificados
                     ArrayResize(TimeDN, kdn+1);   // Cambiar el tamaño de la matriz de tiempo de canal según el número de canales
                     PeakDN[kdn]=TempIND[i];       //Escribir el valor del canal en la matriz de canal...
                     TimeDN[kdn]=iTime(sy,tf,i);   // ...y la matriz de tiempo
                     kdn++;                        // Incrementar el índice de la matriz de canal
                  }
            } 
// -----------------------------------------------------------------------------------------------------------                       
         kup=0;                                    // Inicializar el índice de la matriz de pico
         for (i=2; i<=nBars-1; i++)                // Ejecutar a través de la matriz de valores de la 2ª barra profunda en el historial
            {
               if (TempIND[i]>TempIND[i-1] &&      // ESTABA ALLÍ >
                   TempIND[i+1]<=TempIND[i])       // peL ico identificado FUE ALLÍ <=
                  {
                     ArrayResize(PeakUP, kup+1);   // Cambiar el tamaño de la matriz de pico según el número de picos identificados
                     ArrayResize(TimeUP, kup+1);   // Cambiar el tamaño de la matriz de tiempo de pico según el número de picos
                     PeakUP[kup]=TempIND[i];       // EscribE su valor en la matriz de pico... 
                     TimeUP[kup]=iTime(sy,tf,i);   // ...y la matriz de tiempo
                     kup++;                        // Incrementar el índice de la matriz de pico
                  }
            }   
//====================================================================================================
// ------------------------- Identificación del mínimo inferior y EL DN principal extremo ---------------+
//====================================================================================================
         PivotTimeDN = TimeDN[pbar];                        // Tiempo el extremo principal
         PivotBarDN  = iBarShift(sy,tf,TimeDN[pbar]);       // Barra el extremo principal
         PivotPeakDN = PeakDN[pbar];                        // Valor del extremo principal
         LowestPeakDN  = ArrayMin(PeakDN);                  // Obtiene el valor mínimo inferior value
         Index = ArraySearchDouble(PeakDN, LowestPeakDN);   // Obtener el índice de la baja mínima de la matriz
         LowestBarDN =iBarShift(sy,tf,TimeDN[Index]);       // Obtener la barra de la parte inferior mínima
         LowestTimeDN = TimeDN[Index];                      // Obtener el momento del bajo mínima

   if (LowestBarDN>PivotBarDN)                              // Si el mínimo está a la izquierda del primer extremo... 
                                                            // ... (siendo en la celda 0 de la matriz de tiempo de canal)
   for (m=Index-1; m>pbar; m--)                             // Bucle de la extremo siguiendo el mínimo para el primer extremo
      {
// ------- Dibuja una línea de tendencia virtual y comprueba lo cruces con otra extrema --------  
                                  
         CheckCross=EquationDirect(iBarShift(sy,tf,TimeDN[m+1]),
                                   PeakDN[m+1],                      // primero coordenada de la línea
                                   PivotBarDN, PivotPeakDN,          // Segunda coordenada de la líne
                                   iBarShift(sy,tf,TimeDN[m],false));// Punto de cruce asociado con el extremo próximo de paso
         if (TempIND[iBarShift(sy,tf,TimeDN[m])]<CheckCross)         // Si el extremo se encuentra debajo de la línea
            {
               if (PeakDN[m]<PeakDN[pbar])                           // si este extremo es más bajo que el extremo principal
                  {
                     LowestBarDN =iBarShift(sy,tf,TimeDN[m]);        // Entonces este es el que necesitamos a partir de...
                     LowestPeakDN  = PeakDN[m];                      // Nueva coordenadas extremo siguiente
                     LowestTimeDN = TimeDN[m];                             
                  }
            }                       
      }

      if (LowestBarDN>PivotBarDN && LowestPeakDN<PivotPeakDN)        // Si el mínimo está a la izquierda y a continuación el extremo principal
            {
// ------- Dibujar una línea de tendencia alcista para el ajuste (DN - extrema)---------                          
               if (WinID>0)
                  {
                     if (ObjectFind("Trend_GLine_DN")<0)
                     ObjectCreate("Trend_GLine_DN",OBJ_TREND,WinID,LowestTimeDN,LowestPeakDN,PivotTimeDN,PivotPeakDN);
                     ObjectSet("Trend_GLine_DN",OBJPROP_COLOR,Lime);
                     ObjectSet("Trend_GLine_DN",OBJPROP_TIME1,LowestTimeDN);
                     ObjectSet("Trend_GLine_DN",OBJPROP_PRICE1,LowestPeakDN);
                     ObjectSet("Trend_GLine_DN",OBJPROP_TIME2,PivotTimeDN);
                     ObjectSet("Trend_GLine_DN",OBJPROP_PRICE2,PivotPeakDN);
                  }
//------------- Cálculo de niveles de la tendencia alcista (DN - extrema) -------------         
yGDN =EquationDirect(LowestBarDN, LowestPeakDN,PivotBarDN, PivotPeakDN, iBarShift(sy,tf,iTime(sy,tf,1),false));
yGDN2=EquationDirect(LowestBarDN, LowestPeakDN,PivotBarDN, PivotPeakDN, iBarShift(sy,tf,iTime(sy,tf,2),false));

//---------- Dibuja los niveles de la tendencia alcista (DN - extrema) --------            
         if (WinID>0)
            {
               if (ObjectFind("PointGDN"+iTime(sy,tf,1))<0)
               ObjectCreate("PointGDN"+iTime(sy,tf,1),OBJ_ARROW,WinID,iTime(sy,tf,1),yGDN);
               ObjectSet("PointGDN"+iTime(sy,tf,1),OBJPROP_ARROWCODE,4);
               ObjectSet("PointGDN"+iTime(sy,tf,1),OBJPROP_COLOR,Lime);
               ObjectSet("PointGDN"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
               ObjectSet("PointGDN"+iTime(sy,tf,1),OBJPROP_PRICE1,yGDN);
            }
// ----------- Chequea un cruce hacia abajo de la tendencia alcista --------------   
         if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yGDN,8) && 
             NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yGDN2,8))
               {
                  CrossGDN = true;           // Establece el flag que indica el cruce hacia abajo
                  CrossGUP = false;          // Quitar el flag que indica el cruce hacia arriba
                  if (Arrow)                 // Si se permite el uso de indicadores de señal
                     {
                        if (ObjectFind("ArrowGDN"+iTime(sy,tf,1))<0)
                        ObjectCreate("ArrowGDN"+iTime(sy,tf,1),OBJ_ARROW, 0 ,iTime(sy,tf,1), iHigh(sy,tf,1)+5*pt);
                        ObjectSet("ArrowGDN"+iTime(sy,tf,1),OBJPROP_ARROWCODE,242);
                        ObjectSet("ArrowGDN"+iTime(sy,tf,1),OBJPROP_COLOR,OrangeRed);
                        ObjectSet("ArrowGDN"+iTime(sy,tf,1),OBJPROP_WIDTH,1);
                        ObjectSet("ArrowGDN"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
                        ObjectSet("ArrowGDN"+iTime(sy,tf,1),OBJPROP_PRICE1,iHigh(sy,tf,1)+5*pt);
                     }
               }
// ------------- Chequea un cruce alcista de la tendencia alcista ---------------   
         
         if (add)
            {
               if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yGDN,8) && 
                   NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yGDN2,8))
                  {
                     CrossGUP = true;
                     CrossGDN = false;
                     if (Arrow)                 // Si se permite el uso de indicadores de señal
                        {
                           if (ObjectFind("ArrowGUP"+iTime(sy,tf,1))<0)
                           ObjectCreate("ArrowGUP"+iTime(sy,tf,1),OBJ_ARROW, 0 ,iTime(sy,tf,1), iLow(sy,tf,1));
                           ObjectSet("ArrowGUP"+iTime(sy,tf,1),OBJPROP_ARROWCODE,241);
                           ObjectSet("ArrowGUP"+iTime(sy,tf,1),OBJPROP_COLOR,Lime);
                           ObjectSet("ArrowGUP"+iTime(sy,tf,1),OBJPROP_WIDTH,0);
                           ObjectSet("ArrowGUP"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
                           ObjectSet("ArrowGUP"+iTime(sy,tf,1),OBJPROP_PRICE1,iLow(sy,tf,1));
                        }
                  }
             }
        }                  
//====================================================================================================
// -------------- Identificación de la parte superior máxima y principal hasta el extremo -------------+            
//====================================================================================================
         PivotTimeUP = TimeUP[pbar];                           // Tiempo del extremo principal
         PivotBarUP  = iBarShift(sy,tf,TimeUP[pbar]);          // Barra el extremo principal
         PivotPeakUP = PeakUP[pbar];                           // Valor del extremo principal
         
         HighestPeakUP = ArrayMax(PeakUP);                     // Obtiene el valor de la parte superior máxima
         Index = ArraySearchDouble(PeakUP, HighestPeakUP);     // Obtener el índice de la parte superior máximo de la matriz
         HighestBarUP =iBarShift(sy,tf,TimeUP[Index]);         // Obtener la barra de la parte superior máxima
         HighestTimeUP = TimeUP[Index];                        // Obtiene el tiempo de la parte superior máxima

         if (HighestBarUP>PivotBarUP)                          // Si el máximo está por la izquierda del primer extremo... 
                                                               // ... (siendo en la celda 0 de la matriz de tiempo de pico)
   for (m=Index-1; m>pbar; m--)                                // Loop from the extremum following the maximum to the first extremum
      {
// ------- Dibuja una línea de tendencia virtual y comprueba lo cruces con otra extrema --------  
    CheckCross=EquationDirect(iBarShift(sy,tf,TimeUP[m+1]), PeakUP[m+1], // First coordinate of the line
                              PivotBarUP, PivotPeakUP,                   // Segunda coordenada de la línea
                              iBarShift(sy,tf,TimeUP[m],false));         // Punto asociado con el extremo próximo de paso
         if (TempIND[iBarShift(sy,tf,TimeUP[m])]>CheckCross)             // Si el extremo está por encima de la línea
            {
               if (PeakUP[m]>PeakUP[pbar])                                // if this extremum is higher than the main extremum
                  {
                     HighestBarUP =iBarShift(sy,tf,TimeUP[m]);            // Entonces este es el que necesitamos a partir de...
                     HighestPeakUP = PeakUP[m];                           // Nuevas coordenadas extremo siguiente
                     HighestTimeUP = TimeUP[m];                             
                  }
            }                       
      }
      if (HighestBarUP>PivotBarUP && HighestPeakUP>PivotPeakUP)           // Si el máximo está a la izquierda el extremo principal
         
            {
// --------- Dibuja una línea de tendencia bajista (UP - extrema)            
               if (WinID>0)
                  {
                     if (ObjectFind("Trend_Line_GUP")<0)
                     ObjectCreate("Trend_Line_GUP",OBJ_TREND,WinID,HighestTimeUP,HighestPeakUP,PivotTimeUP,PivotPeakUP);
                     ObjectSet("Trend_Line_GUP",OBJPROP_COLOR,OrangeRed);
                     ObjectSet("Trend_Line_GUP",OBJPROP_TIME1,HighestTimeUP);
                     ObjectSet("Trend_Line_GUP",OBJPROP_PRICE1,HighestPeakUP);
                     ObjectSet("Trend_Line_GUP",OBJPROP_TIME2,PivotTimeUP);
                     ObjectSet("Trend_Line_GUP",OBJPROP_PRICE2,PivotPeakUP);
                  }
//-------------- Cálculo de niveles de la tendencia bajista (UP - extrema) ----------------            
         yGUP =EquationDirect(HighestBarUP, HighestPeakUP, PivotBarUP, PivotPeakUP, iBarShift(sy,tf,iTime(sy,tf,1),false));
         yGUP2=EquationDirect(HighestBarUP, HighestPeakUP, PivotBarUP, PivotPeakUP, iBarShift(sy,tf,iTime(sy,tf,2),false));

//---------- Dibuja los niveles de la tendencia bajista (UP - extrema) ----------            
         if (WinID>0)
            {
               if (ObjectFind("PointGUP"+iTime(sy,tf,1))<0)
               ObjectCreate("PointGUP"+iTime(sy,tf,1),OBJ_ARROW,WinID,iTime(sy,tf,1),yGUP);
               ObjectSet("PointGUP"+iTime(sy,tf,1),OBJPROP_ARROWCODE,4);
               ObjectSet("PointGUP"+iTime(sy,tf,1),OBJPROP_COLOR,OrangeRed);
               ObjectSet("PointGUP"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
               ObjectSet("PointGUP"+iTime(sy,tf,1),OBJPROP_PRICE1,yGUP);
            }
// --------------- Check un cruce alcista de la tendencia bajista -----------------   
         if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yGUP,8) && 
             NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yGUP2,8))
               {
                  CrossGUP = true;                 // Establece el flag que indica el cruce hacia arriba
                  CrossGDN = false;                // Quitar el flag que indica el cruce hacia abajo
                  if (Arrow)                       // Si se permite el uso de indicadores de señal
                     {
                        if (ObjectFind("ArrowGUP"+iTime(sy,tf,1))<0)
                        ObjectCreate("ArrowGUP"+iTime(sy,tf,1),OBJ_ARROW, 0 ,iTime(sy,tf,1), iLow(sy,tf,1));
                        ObjectSet("ArrowGUP"+iTime(sy,tf,1),OBJPROP_ARROWCODE,241);
                        ObjectSet("ArrowGUP"+iTime(sy,tf,1),OBJPROP_COLOR,Lime);
                        ObjectSet("ArrowGUP"+iTime(sy,tf,1),OBJPROP_WIDTH,1);
                        ObjectSet("ArrowGUP"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
                        ObjectSet("ArrowGUP"+iTime(sy,tf,1),OBJPROP_PRICE1,iLow(sy,tf,1));
                     }
               }
            
// ------------- Busque un cruce hacia abajo de la tendencia bajista ---------------   
         if (add)
            {
               if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yGUP,8) && 
                   NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yGUP2,8))
                  {
                     CrossGDN = true;
                     CrossGUP = false;
                     if (Arrow)                    // Si se permite el uso de indicadores de señal
                        {
                           if (ObjectFind("ArrowGDN"+iTime(sy,tf,1))<0)
                           ObjectCreate("ArrowGDN"+iTime(sy,tf,1),OBJ_ARROW, 0 ,iTime(sy,tf,1), iHigh(sy,tf,1)+15*pt);
                           ObjectSet("ArrowGDN"+iTime(sy,tf,1),OBJPROP_ARROWCODE,242);
                           ObjectSet("ArrowGDN"+iTime(sy,tf,1),OBJPROP_COLOR,OrangeRed);
                           ObjectSet("ArrowGDN"+iTime(sy,tf,1),OBJPROP_WIDTH,0);
                           ObjectSet("ArrowGDN"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
                           ObjectSet("ArrowGDN"+iTime(sy,tf,1),OBJPROP_PRICE1,iHigh(sy,tf,1)+15*pt);
                        }
                  }
            }
      }  
                                   
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
// ==========================================================================================               
// ------------------ Identificación de dos (locales) más inferior DN extrema ------------------+      
// ==========================================================================================               
   if (local)
      {     
         asize=ArraySize(PeakDN);
         for (l=asize-1; l>=1; l--)
            {
               if (PeakDN[l]<PeakDN[l-1])
                  {
                     LastTimeDN     =TimeDN[l-1];
                     LastVarDN      =PeakDN[l-1];
                     PreLastTimeDN  =TimeDN[l];
                     PreLastVarDN   =PeakDN[l];
                  }
            }
// -------- Dibuja una línea de tendencia alcista local (DN - extrema) ----------            
         if (WinID>0)
            {
               if (ObjectFind("Trend_Line_DN")<0)
               ObjectCreate("Trend_Line_DN",OBJ_TREND,WinID,TimeDN[1],PeakDN[1],TimeDN[0],PeakDN[0]);
               ObjectSet("Trend_Line_DN",OBJPROP_COLOR,MediumSeaGreen);
               ObjectSet("Trend_Line_DN",OBJPROP_TIME1,PreLastTimeDN);
               ObjectSet("Trend_Line_DN",OBJPROP_PRICE1,PreLastVarDN);
               ObjectSet("Trend_Line_DN",OBJPROP_TIME2,LastTimeDN);
               ObjectSet("Trend_Line_DN",OBJPROP_PRICE2,LastVarDN);
            }
//------------- Cálculo de niveles de la tendencia alcista local (DN - extrema) -------------            
 yDN =EquationDirect(iBarShift(sy,tf,PreLastTimeDN,false), PreLastVarDN, 
                     iBarShift(sy,tf,LastTimeDN,false), LastVarDN, iBarShift(sy,tf,iTime(sy,tf,1),false));
 yDN2=EquationDirect(iBarShift(sy,tf,PreLastTimeDN,false), PreLastVarDN, 
                     iBarShift(sy,tf,LastTimeDN,false), LastVarDN, iBarShift(sy,tf,iTime(sy,tf,2),false));
               
//--------- Dibuja los niveles de la tendencia alcista local (DN - extrema) ---------            
         if (WinID>0)
            {
               if (ObjectFind("PointDN"+iTime(sy,tf,1))<0)
               ObjectCreate("PointDN"+iTime(sy,tf,1),OBJ_ARROW,WinID,iTime(sy,tf,1),yDN);
               ObjectSet("PointDN"+iTime(sy,tf,1),OBJPROP_ARROWCODE,4);
               ObjectSet("PointDN"+iTime(sy,tf,1),OBJPROP_COLOR,MediumSeaGreen);
               ObjectSet("PointDN"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
               ObjectSet("PointDN"+iTime(sy,tf,1),OBJPROP_PRICE1,yDN);
            }
// ------------- Check un cruce hacia abajo de la tendencia alcista local --------------   
         if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yDN,8) && 
             NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yDN2,8))
               {
                  CrossDN = true;
                  CrossUP = false;
                  if (Arrow)                 // Si se permite el uso de indicadores de señal
                     {
                        if (ObjectFind("ArrowDN"+iTime(sy,tf,1))<0)
                        ObjectCreate("ArrowDN"+iTime(sy,tf,1),OBJ_ARROW, 0 ,iTime(sy,tf,1), iHigh(sy,tf,1)+15*pt);
                        ObjectSet("ArrowDN"+iTime(sy,tf,1),OBJPROP_ARROWCODE,242);
                        ObjectSet("ArrowDN"+iTime(sy,tf,1),OBJPROP_COLOR,Chocolate);
                        ObjectSet("ArrowDN"+iTime(sy,tf,1),OBJPROP_WIDTH,1);
                        ObjectSet("ArrowDN"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
                        ObjectSet("ArrowDN"+iTime(sy,tf,1),OBJPROP_PRICE1,iHigh(sy,tf,1)+15*pt);
                     }
               }
// ------------ Check un cruce hacia arriba de la tendencia alcista local -------------   
         if (add)
            {
               if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yDN,8) && 
                   NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yDN2,8))
                  {
                     CrossUP = true;
                     CrossDN = false;
                     if (Arrow)                 // Si se permite el uso de indicadores de señal
                        {
                           if (ObjectFind("ArrowUP"+iTime(sy,tf,1))<0)
                           ObjectCreate("ArrowUP"+iTime(sy,tf,1),OBJ_ARROW, 0 ,iTime(sy,tf,1), iLow(sy,tf,1));
                           ObjectSet("ArrowUP"+iTime(sy,tf,1),OBJPROP_ARROWCODE,241);
                           ObjectSet("ArrowUP"+iTime(sy,tf,1),OBJPROP_COLOR,MediumSeaGreen);
                           ObjectSet("ArrowUP"+iTime(sy,tf,1),OBJPROP_WIDTH,0);
                           ObjectSet("ArrowUP"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
                           ObjectSet("ArrowUP"+iTime(sy,tf,1),OBJPROP_PRICE1,iLow(sy,tf,1));
                        }
                  }
            }
      }
//====================================================================================================
// ---------------------- Identificación de los dos mas superior externos (local) del UP ---------------+       
//====================================================================================================
   if (local)
      {
         asize=ArraySize(PeakUP);
         for (l=asize-1; l>=1; l--)
            {
               if (PeakUP[l]>PeakUP[l-1])
                  {
                     LastTimeUP     =TimeUP[l-1];
                     LastVarUP      =PeakUP[l-1];
                     PreLastTimeUP  =TimeUP[l];
                     PreLastVarUP   =PeakUP[l];
                  }
            }
// -------- Dibuja una línea de tendencia bajista local (UP - extrema) -------------            
         if (WinID>0)
            {
               if (ObjectFind("Trend_Line_UP")<0)
               ObjectCreate("Trend_Line_UP",OBJ_TREND,WinID,TimeUP[1],PeakUP[1],TimeUP[0],PeakUP[0]);
               ObjectSet("Trend_Line_UP",OBJPROP_COLOR,Chocolate);
               ObjectSet("Trend_Line_UP",OBJPROP_TIME1,PreLastTimeUP);
               ObjectSet("Trend_Line_UP",OBJPROP_PRICE1,PreLastVarUP);
               ObjectSet("Trend_Line_UP",OBJPROP_TIME2,LastTimeUP);
               ObjectSet("Trend_Line_UP",OBJPROP_PRICE2,LastVarUP);
            }
//-------------- Cálculo de niveles de la tendencia bajista local (UP - extrema) ----------------            
 yUP =EquationDirect(iBarShift(sy,tf,PreLastTimeUP,false), PreLastVarUP, 
                     iBarShift(sy,tf,LastTimeUP,false), LastVarUP, iBarShift(sy,tf,iTime(sy,tf,1),false));
 yUP2=EquationDirect(iBarShift(sy,tf,PreLastTimeUP,false), PreLastVarUP, 
                     iBarShift(sy,tf,LastTimeUP,false), LastVarUP, iBarShift(sy,tf,iTime(sy,tf,2),false));

//---------- Dibuja los niveles de la tendencia bajista local (UP - extrema) ----------            
         if (WinID>0)
            {
               if (ObjectFind("PointUP"+iTimeiTimesy,tf,1))<0)
               ObjectCreate("PointUP"+iTime(sy,tf,1),OBJ_ARROW,WinID,iTime(sy,tf,1),yUP);
               ObjectSet("PointUP"+iTime(sy,tf,1),OBJPROP_ARROWCODE,4);
               ObjectSet("PointUP"+iTime(sy,tf,1),OBJPROP_COLOR,Chocolate);
               ObjectSet("PointUP"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
               ObjectSet("PointUP"+iTime(sy,tf,1),OBJPROP_PRICE1,yUP);
            }
// -------------- Chequea un cruce alcista de la tendencia bajista local ----------------   
         if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yUP,8) && 
             NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yUP2,8))
               {
                  CrossUP = true;
                  CrossDN = false;
                  if (Arrow)                 // Si se permite el uso de indicadores de señal
                     {
                        if (ObjectFind("ArrowUP"+iTime(sy,tf,1))<0)
                        ObjectCreate("ArrowUP"+iTime(sy,tf,1),OBJ_ARROW, 0 ,iTime(sy,tf,1), iLow(sy,tf,1));
                        ObjectSet("ArrowUP"+iTime(sy,tf,1),OBJPROP_ARROWCODE,241);
                        ObjectSet("ArrowUP"+iTime(sy,tf,1),OBJPROP_COLOR,MediumSeaGreen);
                        ObjectSet("ArrowUP"+iTime(sy,tf,1),OBJPROP_WIDTH,1);
                        ObjectSet("ArrowUP"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
                        ObjectSet("ArrowUP"+iTime(sy,tf,1),OBJPROP_PRICE1,iLow(sy,tf,1));
                     }
               }           
// ------------- Chequea un cruce hacia abajo de la tendencia bajista local --------------   
         if (add)
            {
               if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yUP,8) && 
                   NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yUP2,8))
                  {
                     CrossDN = true;
                     CrossUP = false;
                     if (Arrow)               // Si se permite el uso de indicadores de señal
                        {
                           if (ObjectFind("ArrowDN"+iTime(sy,tf,1))<0)
                           ObjectCreate("ArrowDN"+iTime(sy,tf,1),OBJ_ARROW, 0 ,iTime(sy,tf,1), iHigh(sy,tf,1)+15*pt);
                           ObjectSet("ArrowDN"+iTime(sy,tf,1),OBJPROP_ARROWCODE,242);
                           ObjectSet("ArrowDN"+iTime(sy,tf,1),OBJPROP_COLOR,Chocolate);
                           ObjectSet("ArrowDN"+iTime(sy,tf,1),OBJPROP_WIDTH,0);
                           ObjectSet("ArrowDN"+iTime(sy,tf,1),OBJPROP_TIME1,iTime(sy,tf,1));
                           ObjectSet("ArrowDN"+iTime(sy,tf,1),OBJPROP_PRICE1,iHigh(sy,tf,1)+15*pt);
                        }
                  }                         
            }
      }            
// -----------------------------------------------------------------------------------------------------------            
// Las condiciones aquí pueden ser representadas por CrossGUP y CrossGDN, así como por CrossUP y CrossDN.
// En el primer caso, tenemos una "tendencia global" en todas las barras especificadas,
// en el segundo caso, tenemos las tendencias locales en los dos últimos extrema.
// También puede combinar señales de cruces de la tendencia "global" y "local" en la gráfica A/D
/*   
   if (CrossGUP && CrossUP)   return(11);    // Un cruce hacia arriba de ambas tendencias bajistas
   else
   if (CrossGDN && CrossDN)   return(-11);   // Un cruce hacia abajo de ambos uptrends
   else
   if (CrossGUP)              return(10);    // Un cruce hacia arriba de la tendencia bajista "global"
   else
   if (CrossGDN)              return(-10);   // Un cruce hacia abajo de la tendencia alcista "global"
   else
   if (CrossUP)               return(1);     // Un cruce hacia arriba de la tendencia bajista "local"
   else
   if (CrossDN)               return(-1);    // Un cruce hacia abajo de la tendencia alcista "local"
*/   
   if (CrossGUP || CrossUP) return(1);
   else
   if (CrossGDN || CrossDN) return(-1); 
   else return(0);
                      
}  

El código anterior es casi igual al que ya hemos analizado; Por lo tanto comentaré solamente sobre los parámetros de entrada de la función y el método para llamarla.

int   SignalCrossIND(double &TempIND[], int nBars, string sy, int tf, bool local=false, bool add=false, bool Arrow=true)

En contraste con el anterior código comentado, aquí hemos añadido otra variable de tipo bool - Arrow que muestra señal de indicadores en la ventana principal del terminal. El valor por defecto se establece en true, es decir, si son las flechas que se muestran en la grafica, este parámetro puede omitirse cuando se llama a la función.

Por lo general, la funcion de llamada puede ser como sigue. Inserte el umbral en las variables globales de un EA:

double      TempIND[];           // Matriz de almacenamiento de datos del indicador

A continuación, especificar el número de barras del historial para la identificación del extrema en la grafica del indicador A/D en la función de recepción de las señales de trading

int nBrs=30;

o, por ejemplo

int nBrs=200;

Aquí, todo depende de lo va a ser trazado en líneas de tendencia TF y cuántas barras del historial vayamos a procesar. Cuanto mayor sea el valor, la más "estable" las líneas de tendencia estaría en la grafica del A/D, pero la más retrasada del cruce se convertiría en señal.

Y por último la función de llamada propiamente:

int sig=0;
   sig=SignalCrossIND(TempIND, nBrs, NULL, 5, false, false, true);
   
   if (sig==1)
      {Código para la apertura de una posición de compra}
   if (sig==-1)
      {Código para la apertura de una posición de venta}

Los valores de parámetros pasados aquí sugieren que los datos son obtenidos de la grafica actual del instrumento de la moneda (NULL), el time frame para ser utilizado es М5 (5), líneas de tendencia local no se pueden trazar y los cruces de estas líneas no deben ser buscados (false), además, no hay cruce en la dirección de la tendencia debe ser buscado (false), mientras que los indicadores de señal (flechas arriba/abajo) que se mostrarán en la ventana del gráfico principal (verdadero).

Puesto que todos estos son valores por defecto, la siguiente función de llamada se considerará absolutamente idéntica:

sig=SignalCrossIND(TempIND, nBrs, NULL, 5);


Conclusión

Para concluir lo anterior, me gustaría decir que esta función no es una estrategia comercial independiente. Es simplemente una función de identificación de cruces de líneas de tendencia trazadas en indicador grafico A/D y la línea del indicador. Bien puede ser utilizado en un EA junto con otras funciones.

Para ver sus capacidades, se realiza una prueba sobre el intervalo desde el 01.01.2009 al 01.01.2010. La prueba se llevó a cabo usando sólo los valores devueltos por esta función. Había desactivado el módulo de señal del EA y solo lo reemplazó con esta función. El número de barras para la identificación de extrema = 250. El time frame = 5, el símbolo seleccionado fue el EURUSD, el depósito inicial fue de 10000, el lote fijo fue 0.1.

También se desactiva el uso de SL y TP. Sólo salí a la parada final que cierra posiciones parcialmente sobre tres veces al llegar al nivel de beneficio conjunto (que, naturalmente, es diferente para cada uno de las tres etapas). Las posiciones se abrieron a recibir una señal de la función.

La posición contraria era en este caso not consigue cerrado. Al recibir la nueva señal en la dirección de la posición ya existente, tenía que determinar el tiempo transcurrido después de la posición anterior había abierto, y si es más de 7 minutos, que abrió una nueva posición. Poner poco, utilicé el depósito al máximo... :) Otra cosa que casi se me olvida mencionar es que para cerrar todas las posiciones a la vez, un aumento de capital por un porcentaje determinado. Me puse al 5% en esta prueba.

La grafica resultante que representa datos de más de un año es como sigue:

Está claro que no se puede aplicar en una cuenta real, sin embargo, creo que hay un núcleo de sentido en ella (más aún ya que es sólo una función de la señal).

Y por último, me gustaría expresar mi agradecimiento profundo y sincero de Viktor (Vinin) y Aleksey (Mathemat) por su ayuda desinteresada y un verdadero apoyo amistoso, así como a todos aquellos que de una forma u otra contribuyen a resolver diferentes problemas de programación.

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

FANN2MQL Neural Network Tutorial FANN2MQL Neural Network Tutorial
Este artículo trata de mostrar cómo utilizar las redes neuronales, a través de FANN2MQL, utilizando un ejemplo fácil: enseñando un patrón simple para la neuralnetwork y pruebar para ver si puede reconocer patrones que nunca ha visto.
Cómo añadir rápidamente un panel de control a un indicador o asesor Cómo añadir rápidamente un panel de control a un indicador o asesor
¿Quiere añadir a su indicador o asesor un panel gráfico de control rápido y cómodo, pero no sabe como hacerlo? En este artículo le enseñaré paso a paso cómo "atornillar" un panel de diálogo con parámetros de entrada a su programa MQL4/MQL5.
Comprobar el mito: todo el día de trading depende de cómo se cotiza la sesión asiática Comprobar el mito: todo el día de trading depende de cómo se cotiza la sesión asiática
En este artículo revisaremos la declaración bien conocida que "El trading de todo el día depende de cómo se cotiza la sesión de Asia".
Interfaces gráficas II: Control "Elemento del menú" (Capítulo 1) Interfaces gráficas II: Control "Elemento del menú" (Capítulo 1)
En la segunda parte de la serie demostraremos el proceso del desarrollo de los controles como el menú principal y el menú contextual. Además, trataremos la cuestión del dibujo de los controles, y para ello vamos a crear una clase especial. También aclararemos detalladamente la cuestión de la gestión de los eventos del programa, inclusive los eventos del usuario.