English Русский 中文 Español Deutsch 日本語
Uma Visão Sobre o Indicador Accumulation-Distribution e Onde Conseguilo

Uma Visão Sobre o Indicador Accumulation-Distribution e Onde Conseguilo

MetaTrader 4Exemplos | 25 setembro 2015, 09:15
1 500 0
Artyom Trishkin
Artyom Trishkin


Introdução

Sabe-se que o Indicador Accumulation/Distribution (A/D) tem uma característica interessante - um rompimento da linha de tendência traçada neste indicador gráfico sugere, com um certo grau de probabilidade, um rompimento a seguir da linha de tendência no gráfico de preços:

Eu estava determinado a verificar este fato, e tendo plotados todas as linhas de tendência no gráfico A/D, logo percebi que a abordagem manual para esta questão seria inconveniente. É por isso que eu desenvolvi uma função que desenha automaticamente as linhas de tendência A/D no gráfico e define os indicadores de sinais no gráfico de preço. Agora, gostaria de mostrar este procedimento passo a passo de como tudo pode ser implementado usando MQL4, visto que é o mais mais usado em robôs de negociação.

Este artigo vai ser útil e interessante para aqueles que são novos na programação em MQL4. Com este objetivo, tentei apresentar a informação de uma maneira fácil de entender e utilizar estruturas de código mais simples.


1. Definindo uma Tarefa

Vamos primeiro definir a tarefa a ser executada.

A função tem o objetivo geral de encontrar um ponto de cruzamento entre a linha de tendência plotada no gráfico A/D e a linha do próprio indicador, retornando um valor que indica a direção do cruzamento - a cima ou a baixo - e definir indicadores de sinal no gráfico de preços para fins ilustrativos (setas para cima/baixo, dependendo da direção do cruzamento).

Vamos agora dividir esta tarefa geral em objetivos mais específicos:

  1. A função deverá trabalhar em qualquer símbolo e em qualquer timeframe;
  2. Uma vez que esta função é concebida para ser parte de um EA, o indicador A/D não precisa estar no gráfico principal.
  3. Indicadores de sinal não têm a necessidade de serem exibidos no gráfico de preço - todos os cálculos são realizados dentro da função e somente são exibidos para monitorar visualmente a operação da função.
  4. Os cruzamento podem ocorrer em diferentes direções: cruzamento descendente da tendência de alta, cruzamento ascendente da tendência de alta, cruzamento ascendente da tendência de baixa, cruzamento descendente da tendência de baixa. A função irá identificar cada um desses cruzamentos.

Isto é, tanto quanto as possibilidades da função forem interessantes. Vamos agora considerar as formas de realizar a nossa tarefa.


2. Preencher os Arrays com os Dados do Indicador A/D

Quando chamada, a função irá receber alguns valores: o array para armazenar dados do indicador A/D, o número de barras do histórico para a identificação das extremidades A/D no gráfico, o nome e o timeframe do instrumento (símbolo).

Linhas de tendência são desenhadas com base nas extremidades do indicador A/D no gráfico, identificados por meio de uma linha de tendência de alta vinculada a extremidade inferior e uma linha de tendência de baixa vinculada a extremidade superior.

Uma linha de tendência de alta requer duas extremidades inferiores, onde a extremidade com o menor valor deve estar à esquerda da extremidade localizada na proximidade imediata da atual barra (zero). O mesmo é verdadeiro para uma tendência de baixa: a extremidade com o valor mais alto será à esquerda da extremidade próxima da barra atual.

Se nenhum extremidade satisfazer essas exigências, as linhas de tendência não são desenhadas neste tick. Vamos chamar essas linhas de tendência "global":

Além disso, nós adicionamos mais duas linhas para as linhas de tendência "globais" que requerem o uso correto de duas extremidades, em que

  • uma tendência de alta necessita de uma extremidade inferior com um valor menor (à esquerda da extremidade inferior, com um valor maior); e
  • uma tendência de baixa precisa de uma extremidade superior, com um valor maior (à esquerda da extremidade superior, com um valor menor).

Se nenhum extremidade satisfazer essas exigências, as linhas de tendência não são desenhadas neste tick.

Estas linhas de tendências serão referidas como "local":

Como resultado, podemos ver o seguinte:

Na maioria dos casos, não será necessário a extremidade"local", devido as peculiaridades de identificação da extremidade "global" e o desenho das linhas de tendência, ligando-as. A opção para procurar e chamar a extremidade "local" será definida como ativada ou desativada.

A operação da função exigirá a disponibilidade de variáveis globais do EA, em particular um array para armazenar dados do indicador A/D. Vamos escrever as variáveis globais da EA:

double      TempIND[];    // Array de armazenamento de dados do indicador A/D

Agora, os dados do indicador devem ser lidos, a fim de preencher o array:

int SignalCrossIND(double &TempIND[], int nBars, string sy, int tf)
{
   if (sy=="" || sy=="0") sy = Symbol();
   ArrayResize(TempIND,nBars);       // Redimensiona o array de acordo com o tamanho transmitido à função
   for (int j=0; j<=nBars-1; j++)
      {
         TempIND[j]=iAD(sy,tf,j);    // Escreve dados do indicador no loop ao array
      }
}

Vamos analisar o que acabamos de escrever aqui:

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

Definição da função como tal, ondes parâmetros a serem transmitidos são: TempIND[] - O nome do array contendo os valores do indicador (transmitidos por referência); nBars - O número de barras do histórico do qual são obtidos os valores; sy/tf - nome e timeframe do Instrumento (símbolo).

Geralmente, a chamada de função pode ser a seguinte:

SignalCrossIND(TempIND, 30, NULL, 5);

Onde TempIND é o nome do array, 30 é o número de barras, NULL é o símbolo atual do gráfico, e 5 é o timeframe М5.

A próxima linha é:

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

ele verifica o nome do instrumento de negociação transmitido à função e se seu valor é NULL ou 0, o símbolo do gráfico atual é usado.

Então redimensionamos o array de acordo com o valor transmitido à função na variável nBars e preenchê-lo com valores do indicador a partir da barra zero até nBars-1 no loop. Uma vez que as células do array são numeradas a partir de zero, o primeiro número será 0 em vez de 1 e o último número será, consequentemente, 29 em vez de 30. Por isto utilizamos nBars-1 (no nosso exemplo, 30-1 = 29).

Nesta fase, a função preenche o zero com dados do indicador A/D. Precisamos agora de identificar a extremidade no array de dados do indicador A/D no gráfico.


3. Identificação da Extremidade no Array de Dados do Indicador A/D

Vamos começar. Operação da função requer não apenas variáveis globais, mas também variáveis a serem utilizados pela própria função.

Nesta fase, precisamos declarar mais dois arrays (internos) que serão utilizados para escrever a extremidades superior (picos) e inferior (fundos), dois arrays em que estamos salvando o tempo da extremidade e algumas variáveis para serem utilizadas às necessidades da função:

// ------------------------------------------------------------------------------------------                     
// --------------------------------- Função variáveis ---------------------------------------
// ------------------------------------------------------------------------------------------                     

   double   PeakUP[], PeakDN[];     // Declare arrays para picos/fundos 
   datetime TimeDN[], TimeUP[];     // Arrays para armazenar o tempo da Extremidade
   int      i, k;                   // Variáveis internas da função

e, finalmente, proceder a identificação deles:

//------------------------------------------------------------------
// Preenchendo os arrays com dados sobre picos e fundos
//------------------------------------------------------------------         
    k=0;                                   // Inicializa o índice do array referente ao fundo
    for (i=2; i<=nBars-1; i++)             // Executa os valores do array referente ao fundo
       {
          if (TempIND[i]<TempIND[i-1] &&         
              TempIND[i+1]>=TempIND[i])    // Fundo identificado
             {
                ArrayResize(PeakDN, k+1);  // Redimensiona o array referente ao fundo de acordo com o número de fundos identificados
                ArrayResize(TimeDN, k+1);  // Redimensiona o array de tempo referente ao fundo de acordo com o número de fundos 
                PeakDN[k]=TempIND[i];      // Escreve o valor do fundo dentro do array referente ao fundo...
                TimeDN[k]=iTime(sy,tf,i);  // ...e o array de tempo
                k++;                       // Aumenta o índice do array referente ao fundo
             }
        } 
// -----------------------------------------------------------------------------------------------------------                       
    k=0;                                   // Inicializa o índice do array referente ao pico
    for (i=2; i<=nBars-1; i++)             // Executa os valores do array referente ao fundo
       {
          if (TempIND[i]>TempIND[i-1] && 
              TempIND[i+1]<=TempIND[i])    // Pico identificado
             {
                ArrayResize(PeakUP, k+1);  // Redimensiona o array referente ao pico de acordo com o número de picos identificados
                ArrayResize(TimeUP, k+1);  // Redimensiona o array de tempo referente ao pico de acordo com o número de picos
                PeakUP[k]=TempIND[i];      // Escreve o valor dentro do array referente ao fundo...
                TimeUP[k]=iTime(sy,tf,i);  // ...e o array de tempo
                k++;                       // Aumenta o índice do array referente ao fundo 
             }
       }  

A descrição acima precisa de esclarecimentos sobre o que é feito e como é feito. Em primeiro lugar, preparamos dois circuitos separados - para identificação dos extremos superior e inferior, respectivamente.

Passemos a operação do primeiro loop para a identificação dos fundos (extremidade inferior):


Começamos com a inicialização da variável k para zero - ela vai apontar para o primeiro elemento do array (zero), onde os fundos identificados serão gravados dentro. Então é realizado um loop do array referente ao fundo dos valores do indicador A/D preenchidos anteriormente, não sendo o ponto de partida do primeiro (zero) índice do array, mas o terceiro corresponde a barra 2 (i = 2;).

Por que isso? Uma vez que uma extremidade é um ponto de ruptura no gráfico do indicador, em que o valor na primeira barra é maior do que na segunda barra e o valor na segunda barra é menor do que na terceira (fundo), definimos o índice no terceiro elemento do array (tendo em mente que os elementos são numerados começando a partir de zero), supondo que ele pode ser uma extremidade. A barra zero não é utilizada nos cálculos para eliminar falsos positivos.

Então, começamos a nossa primeira iteração e verificação

  • se o valor na barra 2 TempIND [i] é menor do que na barra 1 TempIND [i-1] e
  • se o valor na barra 3 TempIND[i+1] é maior do que na barra 2 TempIND[i].

Se esta condição for verdadeira (a extremidade é identificada), primeiro aumentamos tamanho do array referente ao fundo e o array de tempo por 1:

ArrayResize(PeakDN, k+1);     // Redimensiona o  array referente ao fundo de acordo com o número de fundos identificados
ArrayResize(TimeDN, k+1);     // Redimensiona o array de tempo referente ao fundo de acordo com o número de fundos

e então escreve os dados a partir do array dos valores do indicador para estes arrays e aumenta o índice do array por um:

PeakDN[k]=TempIND[i];         // Escreve o valor do fundo dentro do array referente ao fundo...
TimeDN[k]=iTime(sy,tf,i);     // ...e o array de tempo
k++;                          // Aumenta o índice do array referente ao fundo

Agora, os arrays referente ao fundo e tempo, PeakDN e TimeDN respectivamente, contêm os dados necessários nas extremidades identificadas e os pontos de índice do array referente ao fundo na próxima célula deste array. A próxima iteração do loop segue o mesmo padrão ao identificar a próxima extremidade e seus dados são escritos para a nova célula do array de fundo que o índice (k) indica.

Os picos (extremidade superior) são identificados de uma forma bastante semelhante, exceto que a primeira, segunda e terceira barra são comparadas em sentido oposto: sinal menor e o sinal maior devem se inverter entre si. Nesta fase, a nossa função pode ler os dados do indicador A/D, preencher a array usando esses dados e identificar a extremidade nele, bem como salvar valores e locais da extremidade nos quatro arrays designados.

Isto é, quando começamos a exibir linhas de tendência no gráfico do indicador, plotando com base nas extremidades identificadas.

Vamos primeiros exibir linhas de tendência "globais" no gráfico do indicador. A fim de desenhá-las e vinculando-as as extremidades do gráfico, devemos começar com a identificação de duas extremidades - o extremo com o menor valor em todo o array de fundo e extremidade vamos referir como principal. A principal extremidade será localizada na proximidade imediata do início do array de fundo e será definido estritamente igual a 2. Assim, não será levado em consideração as duas primeiras extremidades mais próximas da atual barra completa no gráfico de indicador (para deixar uma certa liberdade para o movimento do preço, sem a necessidade de reagir a uma menor mudança que ocorra).

Agora que a extremidade principal é identificada, é preciso encontrar a extremidade com o menor valor no array localizado à esquerda da extremidade principal. Esta extremidade será a menor no gráfico de indicador, servindo de ponto de partida para a identificação final da segunda extremidade.

Desenhando uma linha de tendência de tal forma que ela se conecta a menor extremidade, a extremidade principal provavelmente irá conduzir à situação, onde a linha de tendência é atravessada na maior extremidade do que na extremidade menor identificada. E isso significa que o início da linha de tendência deve, nesta situação, ser movida ao extremo, cruzando a linha do indicador. As figuras abaixo são uma demonstração clara de caso:

Pode ser visto que a linha de origem na extremidade inferior é atravessada pela extremidade superior, uma vez que se estende na direção da extremidade principal. Portanto nesta situação, é necessário uma análise cuidadosa do array de extremidade e identificar aquela que, quando definido o ponto de origem da linha de tendência, não vai levar a uma situação onde a linha de tendência seja atravessada por qualquer extremidade subsequente.

Neste exemplo, a extremidade que segue após a menor extremidade não é adequada (caso a linha de tendência se origine naquele ponto), pois a linha do indicador seria atravessada pelas maiores extremidades:

Deixei de fora mais "tentativas" aqui e continuei diretamente à extremidade identificada "corretamente" :

Agora é hora de começar a codificar tudo. Nós usamos a extremidade inferior para desenhar a linha tendência de alta e extremidade superior para desenhar a linha de tendência de baixa.

Vamos analisar um exemplo de plotagem de uma linha de tendência de alta através de uma extremidade inferior.


4. Identificação de Duas Extremidades no Array de Extremidade do Indicador A/D para Desenhar uma Linha de Tendência

Identificação de duas necessárias extremidades exigirá a disponibilidade de variáveis internas da função ao armazenamento e transmissão dos valores das extremidades máxima, mínima e principal; ao armazenamento e transmissão do tempo das extremidades máxima, mínima e principal e uma variável para indexação dos arrays.

Vamos adicionar as nossas variáveis de função (para não voltar a este assunto mais tarde, vamos adicionar logo todas as variáveis de função necessárias para começar a usá-las imediatamente):

// ------------------------------------------------------------------------------------------                     
// --------------------------------- Variáveis de Função ------------------------------------
// ------------------------------------------------------------------------------------------                     

   double   PeakUP[], PeakDN[],        // Declare os array referente aos picos/fundos
            yUP, yDN, yGUP, yGDN,      // As coordenadas do ponto de cruzamento entre a linha de tendência e o indicador UP e DN na 1ª barra
            yUP2, yDN2, yGUP2, yGDN2,  // As coordenadas do ponto de cruzamento entre a linha de tendência e o indicador UP e DN na 2ª barra
            CheckCross,
            PreLastVarDN,LastVarDN,    // Valores da última e penúltima extremidade inferior
            PreLastVarUP,LastVarUP,    // Valores da última e penúltima extremidade superior
            PivotPeakDN,PivotPeakUP,
            LowestPeakDN,HighestPeakDN,// Valores da Máxima e Mínima inferior
            LowestPeakUP,HighestPeakUP,// Valores da Máxima e Mínima superior

   datetime TimeDN[], TimeUP[],        //  Arrays para armazenar barras das extremidades
            PreLastTimeDN, LastTimeDN, // Tempo da última e penúltima extremidade inferior
            PreLastTimeUP, LastTimeUP, // Tempo da última e penúltima extremidade superior
            PivotBarDN, PivotTimeDN,   // Barra e tempo da extremidade principal inferior
            PivotBarUP, PivotTimeUP,   // Barra e tempo da extremidade principal superior
            LowestBarDN, LowestTimeDN, // Barra e tempo da Mínima inferior
            HighestBarUP, HighestTimeUP;// Barra e tempo da Máxima superior
   int      i, kup, kdn, pbar=2, 
            m, l, t, asize, Index,      // variáveis "internas"
            WinID=WindowFind("A/D");    // Número da janela AD
   bool     CrossDN = false,            // Flag indicando o cruzamento descendente da tendência local
            CrossUP = false,            // Flag indicando o cruzamento ascendente da tendência local
            CrossGDN = false,           // Flag indicando o cruzamento descendente da tendência global
            CrossGUP = false;           // Flag indicando o cruzamento ascendente da tendência global
   
   double   pt=MarketInfo(Symbol(),MODE_POINT); // Tamanho do ponto na cotação de moeda

e adicionar um código de identificação da extremidade inferior:

//====================================================================================================
// --------------------------- Identificação da máxima e mínima inferior (DN) ------------------------  
//====================================================================================================
          
  PivotTimeDN = TimeDN[pbar];                     // Tempo da extremidade principal
  PivotBarDN  = iBarShift(sy,tf,TimeDN[pbar]);    // Barra da extremidade principal
  PivotPeakDN = PeakDN[pbar];                     // Valor da extremidade principal
  LowestPeakDN  = ArrayMin(PeakDN);               // Obter o valor da mínima inferior
  Index = ArraySearchDouble(PeakDN, LowestPeakDN);// Obtém o índice da mínima inferior do array
  LowestBarDN =iBarShift(sy,tf,TimeDN[Index]);    // Obtém a barra da mínima inferior
  LowestTimeDN = TimeDN[Index];                   // Obter o tempo da mínima inferior 

A barra da extremidade principal é estritamente definida na variável pbar e o tempo da extremidade principal é, por conseguinte, obtido a partir do array de tempo pelo índice contido nesta variável.

PivotTimeDN = TimeDN[pbar];     // Tempo da extremidade principal

A barra da extremidade principal é obtida a partir da array de tempo e seu valor é calculado usando a função padrão int iBarShift (string symbol, int timeframe, datetime time, bool exact=false).

Será descrito mais tarde, quando se considera a identificação da mínima no array de extremidade.

O valor da extremidade principal é obtido a partir do array de valores que especificam o valor necessário, utilizando a variável pbar (que contém o índice da extremidade principal):

PivotPeakDN = PeakDN[pbar];     // Valor da extremidade principal

Para identificar a mínima inferior, você pode usar a função padrão int ArrayMinimum (double array[], int count=WHOLE_ARRAY, int start=0) , a qual nós estamos usando e apenas arranjando o cálculo a ser feito, chamando uma função definida pelo usuário. Esta função irá retornar o resultado de identificação da extremidade.

Não vamos reinventar a roda, vamos identificar o elemento mínimo no array usando uma função pronta, a disposição para uso público, escrita por Igor Kim, na sua discussão no fórum. Se adapta perfeitamente às nossas necessidades e pode enviar um relatório de erro relevante para ao registro (log), o array deve ser transmitido para ele estar vazio (isto vem a "calhar" quando da depuração):

//+----------------------------------------------------------------------------+
//|  Autor    : Igor B. Kim aka KimIV,  http://www.kimiv.ru                    |
//+----------------------------------------------------------------------------+
//|  Versão   :  17.05.2008                                                    |
//|  Descrição: Retorna o valor do elemento mínimo no array.                   |
//+----------------------------------------------------------------------------+
//|  Parâmetros:                                                               |
//|    x - array de valores de série numérica                                  |
//+----------------------------------------------------------------------------+
double ArrayMin(double& x[]) {
  if (ArraySize(x)>0) return(x[ArrayMinimum(x)]);
  else {
    Print("ArrayMin(): Array empty!");
    return(0);
  }
}

Como você pode ver, não há absolutamente nada difícil sobre isso - é a mesma função padrão ArrayMinimum() que verifica dados necessários no array transmitido. Uma função semelhante obtida a partir da mesma fonte que será usada para obter o índice do elemento mínimo no array pelo seu valor:

//+----------------------------------------------------------------------------+
//|  Autor    : Igor B. Kim aka KimIV,  http://www.kimiv.ru                    |
//+----------------------------------------------------------------------------+
//|  Versão   : 01.09.2005                                                     |
//|  Descrição: Localiza um elemento do array por seu valor                    |
//|             e retorna o índice do elemento encontrado ou -1                |
//+----------------------------------------------------------------------------+
//|  Parâmetros:                                                               |
//|    m - array dos elementos                                                 |
//|    e - valor do elemento                                                   |
//+----------------------------------------------------------------------------+
int ArraySearchDouble(double& m[], double e) {
  for (int i=0; i<ArraySize(m); i++) {
    if (m[i]==e) return(i);
  }
  return(-1);
}

Aqui, é feito o loop através do array completo, procurando o valor transmitido à função. Se o valor transmitido à função corresponde ao valor de um elemento array, a função retorna o valor da variável i, a qual mediante correspondência é igual ao índice do valor procurado no array. Se o valor esperado não foi encontrado, a função irá retornar -1 que pode ser usado para verificar erro no programa.

Precisamos agora encontrar a barra no gráfico que corresponde a extremidade identificada. Para isto, vamos utilizar os dados a partir do array de tempo TimeDN[] preenchido anteriormente e o índice (Index) da extremidade necessária que foi obtida:

// Obter a barra da mínima inferior
LowestBarDN =iBarShift(sy,tf,TimeDN[Index]);

Para fazer isto, usamos a função padrão int iBarShift (string symbol, int timeframe, datetime time, bool exact=false)

Encontrar a barra pelo tempo. A função retorna o deslocamento da barra que tem o tempo especificado. Se não houver nenhuma barra durante o tempo especificado (uma "lacuna" no histórico), a função retorna -1 (dependendo do parâmetro exato) ou a mudança da barra mais próxima.

Aqui, o primeiro parâmetro a ser transmitido para a função é o símbolo atual do gráfico armazenado na variável sy, o segundo parâmetro a ser transmitido é o intervalo de tempo atual armazenado na variável tf e a "datetime" transmitido para iBarShift() que é armazenado no array de tempoi TimeDN[] e indexado por o valor da variável Index obtido durante a etapa anterior.

Deixamos o valor padrão bool exato, pois colocando o valor "true" quando a barra está faltando (a "lacuna" no histórico), fará com que a função retorne -1, sendo depois utilizado em outros cálculos e levando a um erro. O valor padrão false, caso a barra não esteja no histórico, fará com que a função retorne o valor da barra mais próxima, o que não é bom, mas é melhor do que um valor absolutamente errado.

Agora, para obter uma visão completa de toda a coisa e outros cálculos, também estamos salvando o tempo da barra encontrada como descrito acima. Isto é muito simples: nós salvamos tempo no array TimeDN[]. Agora estamos indo obter o tempo a partir deste array usando o mesmo índice:

// Obter o tempo da extremidade minima inferior
LowestTimeDN = TimeDN[Index];

Então, nós identificamos a extremidade principal e a mínima. Agora precisamos ver se a linha de tendência que liga os dois pontos identificados do gráfico será atravessada por outra extremidade localizada entre as duas extremidades identificadas (como já mencionado acima):

Esses cruzamentos serão identificados utilizando uma linha virtual, plotando a mínima na direção da extremidade principal. Faremos um loop através do array de extremidade a partir da mínima na direção da extremidade principal, uma vez que o ponto de cruzamento entre a extremidade e a linha foi encontrado, será tratado como ponto de origem da linha e novamente teremos o loop através do array, desta vez começando pela extremidade principal.

A extremidade ao cruzar a linha está caminhando para ser executada até que não reste nada mais dela. Isto significa que nós identificamos a extremidade necessária e que as extremidades posteriores, no caminho da extremidade principal, não cruzem a linha de tendência.

if (LowestBarDN>PivotBarDN)                           // Se a extremidade mínima é para a direita da primeira extremidade... 
                                                      // ... estando na célula 0 do array de tempo do fundo (mínima inferior)
for (m=Index-1; m>pbar; m--)                          // Loop a partir da extremidade mínima posterior a primeira extremidade
  {
// - Desenha uma linha de tendência virtual e verifica cruzamentos com outras extremidades                                  
  CheckCross=EquationDirect(iBarShift(sy,tf,TimeDN[m+1]),
                            PeakDN[m+1],                      // Primeira coordenada da linha
                            PivotBarDN, PivotPeakDN,          // Segunda coordenada da linha
                            iBarShift(sy,tf,TimeDN[m],false));// Ponto de cruzamento associado a próxima extremidade
      if (TempIND[iBarShift(sy,tf,TimeDN[m])]<CheckCross)     // Se a extremidade encontra-se abaixo da linha
         {
            if (PeakDN[m]<PeakDN[pbar])                       // Se esta extremidade é menor do que a extremidade principal
               {
                  LowestBarDN =iBarShift(sy,tf,TimeDN[m]);    // Então esta é a que precisamos para começar a partir de ...
                  LowestPeakDN  = PeakDN[m];                  // Novas coordenadas da próxima extremidade
                  LowestTimeDN = TimeDN[m];                             
               }
         }                       
   }

Aqui, temos organizado um loop da extremidade mínima posterior a primeira extremidade no array de extremidade. Isso é feito porque a mínima será o ponto de origem quando o desenho da linha é verificado no cruzamento a partir da próxima extremidade.

A linha virtual será desenhada usando a função da equação de reta que calcula o valor de Y para X no ponto do cruzamento com a linha reta:

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);

x1 e y1 são as coordenadas do primeiro ponto; x2 e y2 são as coordenadas do segundo ponto; x é o valor para o qual y é calculado. Esta função foi idealizada por Kim -tópico do fórum.

Então:

CheckCross=EquationDirect(iBarShift(sy,tf,TimeDN[m+1]), PeakDN[m+1], // Primeiro coordenada da linha
                          PivotBarDN, PivotPeakDN,                   // Segunda coordenada da linha                                  
                          iBarShift(sy,tf,TimeDN[m],false));         // Ponto de cruzamento associado a próxima extremidade

Insira a barra da mínima como a coordenada x do primeiro ponto e o valor da mínima como a coordenada y do primeiro ponto aos parâmetros da função a ser transmitida. A barra e o valor da extremidade principal serão utilizados como a coordenada do segundo ponto da linha virtual.

O último valor a ser transmitido para a função é o número de barras que é colocado no loop para a função calcular o valor da coordenada y, comparando o valor resultante com o valor da extremidade localizada no ponto dado.

if (TempIND[iBarShift(sy,tf,TimeDN[m])]<CheckCross)  // Se a extremidade encontra-se abaixo da linha
   {
    if (PeakDN[m]<PeakDN[pbar])                      // Se esta extremidade é menor do que a extremidade principal
       {
         LowestBarDN  =iBarShift(sy,tf,TimeDN[m]);   // Então esta é a que precisa para começar a partir de...
         LowestPeakDN = PeakDN[m];                   // Novas coordenadas da próxima extremidade
         LowestTimeDN = TimeDN[m];                             
        }
   }            

Assim, se o valor de retorno pela função é maior do que o valor da extremidade localizado no ponto dado, então a extremidade cruza a linha virtual e a linha deve ser originada a partir desta extremidade. Salve os novos valores de coordenadas e avance para a próxima iteração do loop, identificando um cruzamento com a próxima extremidade

Uma vez que nós identificamos a extremidade posterior, onde a linha não é atravessada por qualquer outra extremidade, ela vai ser usada para desenhar a linha de tendência. Tudo o que precisamos saber é se o valor desta extremidade é menor do que a extremidade principal, o que significa que a linha traçada a partir dela na direção da extremidade principal estará subindo na direção certa.

if (LowestBarDN>PivotBarDN && LowestPeakDN<PivotPeakDN)// Se a extremidade mínima está abaixo da extremidade principal

Isto significa que temos agora todos os dados necessários para traçar uma linha de tendência de alta no gráfico A/D.


5. Plotagem de Linhas de Tendência no Gáfico A/D

Para identificar a presença da janela do indicador A/D na janela principal do gráfico, apresentamos uma outra variável, WinID, que vai armazenar o número da janela no gráfico A/D:

WinID=WindowFind("A/D");               // Número janela AD

Aqui, a função padrão WindowFind("name"); retorna o número da sub-janela do gráfico que contém o indicador com o nome especificado, caso contrário retorna -1. Basicamente não há necessidade de desenhar a linha de tendência no gráfico A/D , pois não é exigido para os cálculos; mas vamos desenhá-la para maior clareza e para nos certificar de que tudo está correto:

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);
   }

Em primeiro lugar verifica se a janela do indicador A/D está presente na janela principal. Se não estiver, não existe lugar para desenhar:

if (WinID>0)

É simples, se o indicador não está anexado à janela de gráfico, a função WindowFind() irá retornar -1. A janela principal do gráfico, ou seja, o próprio gráfico, sempre tem um valor igual a zero, portanto deve verificar se o valor é "maior do que zero". Uma vez que além do gráfico A/D, poderá haver outros indicadores no gráfico, não podemos saber ao certo que número será atribuído ao A/D, consequentemente precisamos verificar se o valor é maior do que zero.

Portanto... Se o identificador de janela (WinID) é maior do que zero, o gráfico A/D é considerado anexado na janela e podemos proceder ao desenho. Então verifica-se uma linha de tendência desenhada no gráfico, usando o nome da linha de tendência:

if (ObjectFind("Trend_GLine_DN")<0)

e se não estiver lá ainda (a função ObjectFind() retornou -1, caso contrário o índice de janela A/D é retornado), podemos começar a desenhar. Para este fim, usamos a função:

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) cria um objeto com um nome específico, tipo e coordenadas iniciais numa sub-janela específica do gráfico. O número de coordenadas associados ao objeto pode ser de 1 a 3, dependendo do tipo. Após a conclusão do objeto, a função retorna VERDADEIRA, caso contrário FALSO.

Vamos analisar isso em detalhes:

  • string name converte o valor do nome do objeto desejado a ser criado - no nosso caso, "Trend_GLine_DN"(linha de tendência global ligando uma extremidade inferior); o próximo parâmetro transmitido para a função é int type, ou seja, o tipo de objeto - no nosso caso, é razoavelmente o OBJ_TREND...
  • int janela é o identificador da janela do indicador A/D armazenado na variável WinIND...

Outros parâmetros transmitidos para a função são coordenadas dos dois pontos e são usadas para traçar a linha de tendência:

  • datetime time1 é a coordenada do primeiro tempo da mínima extremidade salva na variável LowestTDN,
  • double price1 é a coordenada do primeiro valor da mínima extremidade salva na variável LowestPeakDN,
  • datetime time2 é a coordenada do segundo tempo da mínima extremidade salva na variável HighestTDN,
  • double price2 é a coordenada do segundo valor da mínima extremidade salva na variável HighestPeakDN.

Outros parâmetros da função ObjectCreate() não são usados ao plotar a linha de tendência.

Assim, nesta fase, o objeto linha de tendência foi criado. Agora precisamos modificar alguns de seus parâmetros. Particularmente, a cor da linha e as coordenadas da linha. A cor da linha será constante, enquanto as coordenadas necessitam de modificação toda vez que alterar os dados para nova extremidade e usar as novas coordenadas para plotar a linha de tendência:

ObjectSet("Trend_GLine_DN",OBJPROP_COLOR,Lime);

bool ObjectSet ( string name, int prop_id, double value) altera o valor da propriedade de objetos específicos. Se bem sucedida, a função retorna VERDADEIRA, caso contrário FALSO. Esta linha de código define a cor da linha de tendência de alta, atribuindo a ela uma cor constante padrão Lima, utilizado no conjunto de cores Web.

Os parâmetros trasnmitidos para a função são:

  • string name - O nome do objeto cujas propriedades precisam ser modificados - no nosso caso, "Trend_GLine_DN",
  • int prop_id - Identificador das propriedades do objeto que precisam ser modificadas. Primeiro mudamos a cor, portanto o identificador será OBJPROP_COLOR,
  • double value - novo valor da propriedade do objeto especificada. Este é o lugar onde a cor constante Lima é transmitida.

Eu acredito que a modificação de outras propriedades do objeto não deve representar nenhuma dificuldade - é semelhante ao exemplo acima, envolvendo a mudança na cor 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);

Inicialmente, mudamos a coordenada do primeiro tempo da extremidade (OBJPROP_TIME1), posteriormente foi alterado (OBJPROP_PRICE1), então nós mudamos a coordenada do segundo tempo da extremidade (OBJPROP_TIME2) e a a coordenada do segundo valor (OBJPROP_PRICE1). Todos os valores das coordenadas são escritos às variáveis LowestTimeDN, LowestPeakDN, PivotTimeDN e PivotPeakDN.

Nossa linha de tendência é desenhada no gráfico do indicador A/D (sujeita à presença obrigatória da janela do indicador). Agora, precisamos identificar o ponto de cruzamento entre a linha no gráfico A/D e a linha de tendência desenhada, usando as extremidades do indicador do gráfico. Pensando sobre esta tarefa, cheguei à conclusão de que será mais fácil (para mim) calcular o ponto de cruzamento utilizando uma equação de reta.


6. Identificação do Ponto de Cruzamento Entre a Linha de Gráfico A/D e a Linha de Tendência Plotada Através da Extremidade do Indicador do Gráfico.

Tendo dois pontos através do qual a linha de tendência é plotada, usamos uma equação de reta para calcular uma linha imaginária que será projetada na primeira barra da linha do indicador A/D. (funciona com a primeira barra para reduzir o número de falsos positivos).

O ponto é calculado usando a equação de reta e projetado na primeira barra do indicador, será o ponto onde estamos indo para verificar se existem cruzamentos. Além disso, somente precisamos marcar estes pontos calculados no gráfico A/D e verificar o simples fato de haver cruzamento pela linha do indicador a baixo ou a cima.

Há outro ponto a considerar. Uma vez que estamos identificando o ponto de cruzamento, nossos cálculos também exigirão a segunda barra do gráfico do indicador A/D. Se a linha do indicador é maior do que o ponto de cruzamento na primeira barra e menor do que ou igual ao ponto de cruzamento na segunda barra, temos um cruzamento a cima. Assim, iremos calcular duas linhas com base nas extremidades. A primeira linha será projetada na primeira barra do indicador, a segunda linha será projetada na segunda barra.

Pontos de cruzamentos imaginários serão marcada para uma melhor visualização dos nossos resultados de cálculo.

Então vamos começar...


7. Identificação e Marcação de Possíveis Pontos de Cruzamento

Nós vamos precisar de variáveis adicionais para armazenar os valores calculados dos possíveis pontos de cruzamento.

Nos já adicionamos a lista das variáveis de função:

// ------------------------------------------------------------------------------------------                     
// --------------------------------- Variáveis de Função ------------------------------------
// ------------------------------------------------------------------------------------------                     
   double   PeakUP[], PeakDN[],           // Declarar arrays de picos/fundos
            yUP, yDN, yGUP, yGDN,         // As coordenadas do ponto de cruzamento entre a linha de tendência e o indicador UP e DN na 1ª barra
            yUP2, yDN2, yGUP2, yGDN2,     // As coordenadas do ponto de cruzamento entre a linha de tendência e o indicador UP e DN na 2ªº barra
            LowestPeakDN,HighestPeakDN,   // Valores da extremidade mínima e máxima inferior 
            LowestPeakUP,HighestPeakUP;   // Valores da extremidade mínima e máxima superior
   datetime TimeDN[], TimeUP[],           // Arrays para armazenar barras das Extremidades
            LowestTimeDN, HighestTimeDN,  // Barra da extremidade mínima e máxima inferior
            LowestTimeUP, HighestTimeUP,  // Barra da extremidade mínima e máxima superior
            LowestTDN, HighestTDN,        // Tempo da extremidade mínima e máxima inferior
            LowestTUP, HighestTUP;        // Tempo da extremidade mínima e máxima superior
   int      i, k, Index,                  // Variáveis "internas"
            WinID=WindowFind("A/D");      // Número da janela AD

Ficando à frente do histórico, gostaria de mencionar que em vez de quatro nós adicionamos 8 variáveis, pois mais 4 variáveis serão necessárias para o cálculo das linhas de tendência "locais" e os pontos de cruzamento. Agora usaremos yGUP, yGDN, yGUP2 e yGDN2 para armazenar os pontos de cruzamento com:

  • a linha de tendência "global" de alta yGUP na primeira barra; yGUP2 - na segunda barra e
  • a linha de tendência "global" de baixa yGDN na primeira barra; yGDN2 - na segunda barra.

Vamos mais uma vez usar a função equação de reta gentilmente cedida por Igor Kim:

//+----------------------------------------------------------------------------+
//|  Autor    : Igor B. Kim aka KimIV,  http://www.kimiv.ru                    |
//+----------------------------------------------------------------------------+
//|  Versão   : 12.10.2007                                                     |
//|  Descrição: equação de reta. Calcula o valor Y para X                      |
//|                no ponto de cruzamento com a linha reta.                    |
//+----------------------------------------------------------------------------+
//|  Parâmetros:                                                               |
//|    x1,y1 - coordenadas do primeiro ponto,                                  |
//|    x2,y2 - coordenadas do segundo ponto,                                   |
//|    x     - valor para o qual Y precisa 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 serão transmitidos para a função como pontos de partida do cálculo: duas para as coordenadas das duas extremidade do gráfico e o último parâmetro é a barra onde o ponto de cruzamento deve ser encontrado:

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

Aqui as coordenadas da extremidade mínima são utilizadas como as coordenadas do primeiro ponto: x1 = LowestTimeDN, y1 = LowestPeakDN, enquanto as coordenadas da extremidade principal são utilizadas como coordenadas do segundo ponto: x2 = PivotBarDN, y2 = PivotPeakDN.

O deslocamento da barra exigido é transmitido como o valor para o qual a equação é calculada: iBarShift(sy, tf, Tempo[1], falso), onde sy é o nome do símbolo do instrumento monetário, tf é o timeframe, Tyme[1] é o array de série temporal que contém o tempo de abertura de cada barra no gráfico atual. Os tipos de dados, datetime, representam o tempo em segundos decorridos a partir das 00:00 horas do dia 01 de janeiro de 1970.

Os parâmetros restantes desta função foram discutidos anteriormente. Gostaria de salientar que se a nossa função vai ser usado em EA de multi-moeda, então em vez de Time[1] , devemos usar a função padrão iTime() (exatamento o que nós estamos implementando na variante final da função) que recebe explicitamente os valores do instrumento monetário e do timeframe usado, enquanto que Time[] somente funciona com o gráfico atual.

Temos os níveis de cruzamentos calculados e armazenados nas variáveis. Para maior clareza, as linhas agora podem ser marcadas no gráfico do 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);
     }

Isso é semelhante a plotagem da linha de tendência. Vamos dar uma olhada em algumas pequenas diferenças.

A primeira diferença é o nome do objeto:

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

Uma vez que não estamos criando um único objeto, mas sim um conjunto de objetos a cada nova barra, os nomes de todos os objetos devem ser exclusivos. Para este efeito, o tempo da barra sobre a qual o objeto é criado será adicionado ao nome do objeto:

"PointGDN"+Time[1]

A segunda diferença está no identificador do tipo de objeto gráfico. Enquanto para traçar a linha de tendência foi utilizado OBJ_TREND, agora vamos usar OBJ_ARROW que permite desenhar setas (símbolos). Além disso, WinID é o número da sub-janela onde o objeto será desenhada - no nosso caso é o número de janela A/D, e existem duas coordenadas - coordenada de tempo Time[1] sendo o tempo da primeira barra e coordenada de preço yGDN, sendo o ponto de cruzamento entre a linha de tendência e a primeiro barra calculada.

As propriedades do objeto são definidas da seguinte forma:

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

O identificador das propriedades de objeto, OBJPROP_ARROWCODE, define o código do objeto e pode ser um dos wingdings, ou um dos símbolos dos códigos de seta predefinidos. A fim de definir o objeto precisamente no nível calculado, existem códigos especiais de setas que apontam para o preço exato e tempo. Nós estamos usando o hífen (-), sendo o seu código 4. As linhas restantes definem a cor do objeto e suas coordenadas em constante mutação a cada barra.

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

Agora temos os possíveis pontos de cruzamento entre a linha do indicador e a linha de tendência "global" de alta plotados com base nas extremidades desenhadas. Nestes pontos serão necessários as verificações se existem cruzamentos. Se um cruzamento foi encontrado, o indicador de sinal - uma seta para baixo - será definido no gráfico principal .


8. Verificando Cruzamentos da Linha A/D e os Cálculos dos Pontos de Cruzamentos e Definição dos Indicadores de Sinal

Para identificar se existe um cruzamento da linha do indicador A/D, simplesmente comparamos os valores como sendo menor/maior do que, por exemplo: se o valor da linha do indicador numa dada barra é menor do que o valor do ponto de cruzamento, enquanto o valor do indicador na barra anterior é maior do que o valor no ponto de cruzamento, temos um cruzamento para baixo:

if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yGDN,8) && 
     NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yGDN2,8))
    {
        CrossGDN = true;           // Define o flag indicando o cruzamento descendente
        CrossGUP = false;          // Remove a flag indicando o cruzamento ascendente
                                    
        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);
    }

A fim de comparação, os valores de dados do tipo double precisam ser normalizados para a precisão exigida pela função padrão double NormalizeDouble (double value,int dígits). Números de pontos flutuantes devem ser arredondados para a precisão exigida.

Os valores calculados de StopLoss e TakeProfit, bem como preços de abertura das ordens pendentes devem ser normalizados para a precisão, conforme predefinido nas variáveis Digits:

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

que é exatamente o que fizemos quando comparados os valores da linha do indicador com os valores dos ponto de cruzamentos calculados. Se esta condição for cumprida, às variáveis do tipo bool, CrossGDN e CrossGUP, são atribuídos os valores verdadeiro e falso, respectivamente.

O próximo bloco do código define a seta para baixo na janela do gráfico principal do 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);

Eu acredito que este bloco de código não exige um esclarecimento especial como já discutimos, pois as marcas e linhas podem ser definidas nas janelas do terminal. A única diferença não considerada anteriormente é a especificação da janela do gráfico principal do terminal. O número desta janela é sempre 0, portanto definindo 0 (zero) como o identificador de janela na linha abaixo,

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

nós permitimos a definição das setas na janela principal do terminal.

Existem mais algumas coisas para se prestar atenção: o valor do preço máximo da barra acima, onde a seta será definida, serve de coordenada y- da seta para baixo (o código é 242) e o travessão está definido para 5 pontos:

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

double iHigh (string symbol, int timeframe, int shift) retorna o valor máximo do preço especificado pelo parâmetro shift da barra do gráfico principal (symbol, timeframe).

O valor de pt é obtido a partir da linha imediatamente a seguir à declaração das variáveis de função:

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

Esta é uma função normal do tipo double MarketInfo (string symbol, int type). Ele retorna várias informações sobre os instrumentos financeiros listados na janela "Observação do Mercado". Função do identificador de consulta MODE_POINT retorna o tamanho do ponto na moeda de cotação ao instrumento atual que é armazenado na variável predefinida Point. A linha:

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

define o tamanho da seta mostrada = 1.


9. Verificando Cruzamento da Linha Ascendente na Direção do Movimento do Preços do Par de Moedas

Um cruzamento descendente de uma linha de tendência de alta pode sinalizar que o movimento do preço do par de moedas pode mudar em breve, ao passo que um cruzamento para cima da linha de tendência de alta pode sugerir que o preço vai continuar a se mover na mesma direção. Portanto para estar no lado seguro, também verificaremos se existe este tipo de cruzamento, esta opção de verificação pode ser desabilitada, se necessário.

Para este fim, nós mudamos a primeira linha da função, adicionando-lhe mais dois parâmetros a serem transmitidos para a função:

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

Acrescentamos duas variáveis do tipo bool: local e add. A variável local está a cargo do cálculo necessário para exibir linhas de tendência "locais", enquanto a variável add serve para verificar se existe cruzamento para cima da linha de tendência de alta ou um cruzamento para baixo da linha de tendência de baixa. Por padrão, essas variáveis ​​são definidas como falso, ou seja, se elas são omitidas na chamada a função, não serão calculadas, nem exibidas as linhas de tendência local, nem vai buscar por esses cruzamentos.

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));
           }
    }

Tudo é familiar neste bloco de código e basicamente não há necessidade de olhar para ele. O que precisamos identificar é a verificação da variável add:

if (add)

é absolutamente idêntica a esta:

if (add==true)

e verifica se esta variável é definida como "true". Se verdadeiro, todas as linhas delimitadas correspondente as chaves {} seguirão a linha dada e serão executadas. Existem apenas duas linhas sobrando a se considerar:

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

Aqui, o último parâmetro transmitido à função é o código de seta para cima - 241,

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

onde o último valor transmitido à função indica o tamanho da seta desenhada. No nosso caso, vamos exibir uma pequena seta de tamanho 0.

O código que temos no momento é funcionalmente completo: ele lê os dados do indicador A/D e utiliza-os para preencher o array, identifica a extremidade do gráfico do indicador, desenha a linha de tendência de alta no gráfico, verifica a existência de cruzamento desta linha e da linha do indicadorA/D, e ainda, se um cruzamento é identificado, coloca setas para baixo ou para cima (dependendo do sentido do cruzamento) no gráfico principal do instrumento de moeda localizado na janela do terminal.

Abaixo está o código para uma verificação semelhante, mas desta vez para a linha de tendência de baixa. Para a sua análise independente:

//====================================================================================================
// --------------------- Identificação da extremidade mínima e máxima superior (UP) ------------------            
//====================================================================================================
    PivotTimeUP = TimeUP[pbar];                           // Tempo da extremidade principal
    PivotBarUP  = iBarShift(sy,tf,TimeUP[pbar]);          // Barra da extremidade principal
    PivotPeakUP = PeakUP[pbar];                           // Valor da extremidade principal

    HighestPeakUP = ArrayMax(PeakUP);                     // Obter o valor da extremidade máxima superior
    Index = ArraySearchDouble(PeakUP, HighestPeakUP);     // Obter o índice da extremidade máxima superior no array
    HighestBarUP =iBarShift(sy,tf,TimeUP[Index]);         // Obter a barra da extremidade máxima superior
    HighestTimeUP = TimeUP[Index];                        // Obter o tempo da extremidade máxima superior

    if (HighestBarUP>PivotBarUP)                          // Se a extremidade máxima está à esquerda da primeira extremidade... 
                                                          // ... estando na célula 0 do array de tempo do pico (máxima superior)
   for (m=Index-1; m>pbar; m--)                           // Loop a partir da extremidade após a máxima para a primeira extremidade
      {
// --- Desenhar uma linha de tendência virtual e verificar cruzamentos com outras extremidades --------  
      CheckCross=EquationDirect(iBarShift(sy,tf,TimeUP[m+1]), 
                                PeakUP[m+1],                      // Primeira coordenada da linha
                                PivotBarUP, PivotPeakUP,          // Segunda coordenada da linha
                                iBarShift(sy,tf,TimeUP[m],false));// Ponto de cruzamento associado a próxima extremidade
      if (TempIND[iBarShift(sy,tf,TimeUP[m])]>CheckCross)         // Se a extremidade se encontra acima da linha
         {
            if (PeakUP[m]>PeakUP[pbar])                           // Se esta extremidade é extremidade principal superior
               {
                  HighestBarUP =iBarShift(sy,tf,TimeUP[m]);       // Então este é o que precisamos para começar a partir de ...
                  HighestPeakUP = PeakUP[m];                      // Novas coordenadas da próxima extremidade
                  HighestTimeUP = TimeUP[m];                             
               }
         }                       
   }

   if (HighestBarUP>PivotBarUP && HighestPeakUP>PivotPeakUP)      // Se a máxima está à esquerda da extremidade principal     
      {
// ------------- Desenhar uma linha de tendência de baixa (UP - extremidade) --------------------------                         
          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 dos níveis da tendência de baixa (UP - extremidade) -------------------------            
    yGUP =EquationDirect(HighestBarUP, HighestPeakUP, PivotBarUP, PivotPeakUP, iBarShift(sy,tf,Time[1],false));
    yGUP2=EquationDirect(HighestBarUP, HighestPeakUP, PivotBarUP, PivotPeakUP, iBarShift(sy,tf,Time[2],false));

 //-------------------- Desenhar níveis de tendência de baixa (UP - extremidade) ----------------------            
         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);
            }
         
// -------- Verifique se há um cruzamento para cima da tendência de baixa ------------------------------   
         if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yGUP,8) && 
             NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yGUP2,8))
               {
                  CrossGUP = true;                 // Definir o flag que indica o cruzamento para cima
                  CrossGDN = false;                // Remover o flag indicando o cruzamento para baixo
               
                  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));
               }
            
// -------- Verificar se existe cruzamento descendente da linha de tendência de baixa ---------------------   

         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. Identificação da Extremidade "Local" no Gráfico A/D, Desenhar Linhas de Tendência Através da Extremidade Identificada e Verificação de Cruzamentos

Assim, resta apenas uma pequena coisa: organizar a extremidade "local".

A única coisa que difere da extremidade "global" é o método de identificação. A extremidade local é identificada utilizando duas extremidades mais à direita e se (para uma tendência de alta) a primeira extremidade parece ser maior do que a segunda situado à esquerda, vamos assumir que uma linha de tendência local pode ser desenhada. Para uma tendência de baixa, a segunda extremidade identificada deve ser maior do que a primeira extremidade à esquerda.

O código vai ser quase idêntico ao já analisado anteriormente, exceto por alguns pontos, vou colocar na íntegra uma linha de tendência local de alta:

// -------------------------- Identificação de duas (local) extremidades inferior externas (DN) ------------           
   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];
                  }
            }
// -------------- Desenhar uma linha tendência local de alta ----------------          
         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 dos níveis de tendência local de alta  (DN - extremidade) -------------            
  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));
               
//------------ Desenha níveis de tendência local de alta (DN - extremidade) ----------          
         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);
            }
// ------- Verifique se existe um cruzamento descendente da tendência local de alta --------   
         if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yDN,8) && 
             NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yDN2,8))
               {
                  CrossDN = true;
                  CrossUP = false;
                  if (Arrow)                 // Se o uso de indicadores de sinal é permitido
                     {
                        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);
                     }
               }      
// ------- Verifique se existe um cruzamento ascendente da tendência local de alta --------   
         if (add)
            {
               if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yDN,8) && 
                   NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yDN2,8))
                  {
                     CrossUP = true;
                     CrossDN = false;
                     if (Arrow)                 // Se o uso de indicadores de sinal é permitido
                        {
                           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));
                        }
                  }                  
            }
      }            

A única diferença aqui é na identificação das extremidades por meio do qual a linha de tendência é plotada:

if (local)

Esta linha verifica se o desenho da linha de tendência e cálculo dos cruzamentos do gráfico A/D são permitidos.

Então executamos através do loop, olhando para as duas extremidades mais externas:

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];
          }
      }

e escrever seus valores às variáveis LastTimeDN, LastVarDN, PreLastTimeDN e PreLastVarDN, onde

  • LastTimeDN contém o tempo da última extremidade,
  • LastVarDN contém o valor da última extremidade,
  • PreLastTimeDN contém o tempo da penúltima extremidade e
  • PreLastVarDN contém o tempo da penúltima extremidade

Depois disso, o código é praticamente identico ao que já foi descrito, exceto pelas variáveis utilizadas para desenhar as linhas de tendência e identificação de cruzamentos com elas. E, finalmente, devemos organizar os valores da função a ser devolvida para o toque final,

podendo ser a seguinte:

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

Onde existe um cruzamento descendente da linha de tendência de alta, a função retorna -1; onde existe um cruzamento descendente da linha de tendência de baixa, a função retorna 1; em todos os outros casos, a função retorna 0 - é simples assim.

Certamente é melhor verificar todos os cruzamentos das linhas de tendência de alta e de baixa, ascendente ou descendente, atribuindo "pesos", dependendo da combinação de cruzamentos, e retorna os valores necessários à chamada da função para processamento do sinal.

Concluindo a descrição da função, vou dar o seu código completo, incluindo algumas pequenas mudanças feitas (apresentando a verificação para saber se é permitido definir indicadores de sinal quando um cruzamento da linha de tendência e a linha do gráfico A/D são identificadas, bem como a utilização da função de padrão iTime() ao invés de Time para garantir a generalização da função).

Esperamos que o código fornecido abaixo seja compreensível, após a extensiva consideração descrita no artigo acima:

//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
Identificação de um cruzamento da linha de tendência e a linha do gráfico A/D e definição dos indicadores de sinal
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
// TempIND[] - (declarado no nível global) array para armazenamento de dados do indicador A/D
// nBars - número de barras para identificação da Extremidade
// Sy - trabalhando símbolo: "" ou NULL - atual símbolo do gráfico
// Tf - trabalhando o tempo: 0 - atual, 
// local - se quiser cálculo com base nas tendências locais: por padrão - false
// add - se responder ao cruzamento da tendência na direção da tendência: por padrão - false
// Arrow - se definir indicadores de sinal no instrumento moeda no gráfico  
//         Quando um cruzamento da linha de tendência e da linha do gráfico A/D é identificado: por padrão - 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);                     // Redimensionar o array de acordo com o tamanho transmitido para a função
   for (int j=0; j<=nBars-1; j++)
      {
         TempIND[j]=iAD(sy,tf,j);                  // Escreve dados do indicador no loop dentro do array
      }
// ==========================================================================================               
// --------------------------------- Variáveis da Função -----------------------------------+
// ==========================================================================================               

   double   PeakUP[], PeakDN[],                    // Declarar arrays de picos/fundos
            yUP, yDN, yGUP, yGDN,                  // As coordenadas do ponto de cruzamento entre a linha de tendência e o indicador UP e DN na 1ª barra
            yUP2, yDN2, yGUP2, yGDN2,              // As coordenadas do ponto de  cruzamento entre a linha de tendência e o indicador UP e DN na 2ª barra
            CheckCross,
            PreLastVarDN,LastVarDN,                // Valores da última e da penúltima extremidade inferior
            PreLastVarUP,LastVarUP,                // Valores da última e da penúltima extremidade superior
            PivotPeakDN,PivotPeakUP,
            LowestPeakDN,HighestPeakDN,            // Valores da extremidade mínima e máxima inferior
            LowestPeakUP,HighestPeakUP,            // Valores da extremidade mínima e máxima superior

   datetime TimeDN[], TimeUP[],                    // Arrays para armazenar barras de Extremidade
            PreLastTimeDN, LastTimeDN,             // Tempo da última e penúltima extremidade inferior
            PreLastTimeUP, LastTimeUP,             // Time da última e penúltima extremidade superior
            PivotBarDN, PivotTimeDN,               // Barra e hora da extremidade principal inferior
            PivotBarUP, PivotTimeUP,               // Barra e hora da extremidade superior principal
            LowestBarDN, LowestTimeDN,             // Barra e o tempo da extremidade mínima inferior
            HighestBarUP, HighestTimeUP;           // Barra e tempo da extremidade máxima superior
   int      i, kup, kdn, pbar=2, 
            m, l, t, asize, Index,                 // variáveis "internas"
            WinID=WindowFind("A/D");               // Número janela AD
   bool     CrossDN = false,                       // Flag indicando o cruzamento descendente da tendência local
            CrossUP = false,                       // Flag indicando o cruzamento ascendente da tendência local
            CrossGDN = false,                      // Flag indicando o cruzamento descendente da tendência global
            CrossGUP = false;                      // Flag indicando o cruzamento ascendente da tendência global
   
   double pt=MarketInfo(Symbol(),MODE_POINT);      // Tamanho do ponto na cotação da moeda

// ==========================================================================================               
// ---------------- Preenchimento dos arrays com dados sobre picos e fundos ----------------+
// ==========================================================================================               
         kdn=0;                                    // Inicializa o índice do array de fundo
         for (i=2; i<=nBars-1; i++)                // Executa os valores do array a partir da 2º barra na profundidade histórica
            {
               if (TempIND[i]<TempIND[i-1] &&         
                   TempIND[i+1]>=TempIND[i])       // Fundo identificado WAS THERE>=
                  {
                     ArrayResize(PeakDN, kdn+1);   // Redimensionar o array de fundo de acordo com o número de fundos identificados
                     ArrayResize(TimeDN, kdn+1);   // Redimensionar o array de tempo de fundo de acordo com o número de fundos
                     PeakDN[kdn]=TempIND[i];       // Escreve o valor de fundo dentro do array de fundo...
                     TimeDN[kdn]=iTime(sy,tf,i);   // ...e o array de tempo
                     kdn++;                        // Aumenta o índice do array de fundo
                  }
            } 
// -----------------------------------------------------------------------------------------------------------                       
         kup=0;                                    // Inicializar o índice do array de pico
         for (i=2; i<=nBars-1; i++)                // Executa os valores do array a partir da 2º barra na profundidade histórica
            {
               if (TempIND[i]>TempIND[i-1] &&      // WAS THERE >
                   TempIND[i+1]<=TempIND[i])       // Pico identificado WAS THERE>=
                  {
                     ArrayResize(PeakUP, kup+1);   // Redimensionar o array de pico de acordo com o número de picos identificados
                     ArrayResize(TimeUP, kup+1);   // Redimensionar o array de tempo de pico de acordo com o número de picos
                     PeakUP[kup]=TempIND[i];       // Escreva o valor dentro do array de pico... 
                     TimeUP[kup]=iTime(sy,tf,i);   // ...e o array de tempo
                     kup++;                        // Aumenta o índice do array de pico
                  }
            }   
//====================================================================================================
// ---------------- identificação da extremidade mínima inferior e principal (DN ) ------------------+
//====================================================================================================
         PivotTimeDN = TimeDN[pbar];                        // Tempo da extremidade principal
         PivotBarDN  = iBarShift(sy,tf,TimeDN[pbar]);       // Barra da extremidade principal
         PivotPeakDN = PeakDN[pbar];                        // Valor da extremidade principal
         LowestPeakDN  = ArrayMin(PeakDN);                  // Obter o valor da extremidade mínima inferior
         Index = ArraySearchDouble(PeakDN, LowestPeakDN);   // Obter o índice da extremidade mínima inferior no array
         LowestBarDN =iBarShift(sy,tf,TimeDN[Index]);       // Obter a barra da extremidade mínima inferior
         LowestTimeDN = TimeDN[Index];                      // Obter o tempo da extremidade mínima inferior 

   if (LowestBarDN>PivotBarDN)                              // Se a extremidade mínima é para a direita da primeira extremidade... 
                                                            // ... estando na célula 0 do array de tempo do fundo (mínima inferior)
   for (m=Index-1; m>pbar; m--)                             // Loop do extremidade seguinte a mínima da primeira extremidade
      {
// --- Desenhar uma linha de tendência virtual e verificar cruzamentos com outras extremidades --------  
                                  
         CheckCross=EquationDirect(iBarShift(sy,tf,TimeDN[m+1]),
                                   PeakDN[m+1],                      // Primeira coordenada da linha
                                   PivotBarDN, PivotPeakDN,          // Segunda coordenada da linha
                                   iBarShift(sy,tf,TimeDN[m],false));// Ponto de cruzamento associado com a próxima extremidade
         if (TempIND[iBarShift(sy,tf,TimeDN[m])]<CheckCross)         // Se a mínima inferior encontra-se abaixo da linha
            {
               if (PeakDN[m]<PeakDN[pbar])                           // Se esta extremidade é menor do que a extremidade principal
                  {
                     LowestBarDN =iBarShift(sy,tf,TimeDN[m]);        // Então este é o que precisa para começar a partir de...
                     LowestPeakDN  = PeakDN[m];                      // Novas coordenadas da próxima extremidade
                     LowestTimeDN = TimeDN[m];                             
                  }
            }                       
      }

      if (LowestBarDN>PivotBarDN && LowestPeakDN<PivotPeakDN)        // Se a extremidade mínima é para a esquerda e abaixo do extremidade principal
            {
// -------- Desenhar uma linha de tendência de alta para o ajuste (DN - extremidade) ----------                          
               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 dos níveis de tendência de alta (DN - Extremidade) -------------         
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));

//---------- Níveis de desenho da tendência de alta (DN - Extremidade) ----------            
         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);
            }
// ------- Verificar se existe um cruzamento descendente da tendência de alta --------   
         if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yGDN,8) && 
             NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yGDN2,8))
               {
                  CrossGDN = true;           // Define o flag indicando o cruzamento descendente
                  CrossGUP = false;          // Remove a flag indicando o cruzamento ascendente
                  if (Arrow)                 // Se o uso de indicadores de sinal é permitido
                     {
                        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);
                     }
               }
// ------- Verificar se existe um cruzamento ascendente da tendência de alta --------   
         
         if (add)
            {
               if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yGDN,8) && 
                   NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yGDN2,8))
                  {
                     CrossGUP = true;
                     CrossGDN = false;
                     if (Arrow)                 // Se o uso de indicadores de sinal é permitido
                        {
                           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));
                        }
                  }
             }
        }                  
//====================================================================================================
// ----------------- Identificação da extremidade máxima superior e principal (UP) ------------------+            
//====================================================================================================
         PivotTimeUP = TimeUP[pbar];                           // Tempo da extremidade principal
         PivotBarUP  = iBarShift(sy,tf,TimeUP[pbar]);          // Barra da extremidade principal
         PivotPeakUP = PeakUP[pbar];                           // Valor da extremidade principal
         
         HighestPeakUP = ArrayMax(PeakUP);                     // Obter o valor da extremidade máxima superior
         Index = ArraySearchDouble(PeakUP, HighestPeakUP);     // Obter o índice da extremidade máxima superior no array
         HighestBarUP =iBarShift(sy,tf,TimeUP[Index]);         // Obter a barra da extremidade máxima superior
         HighestTimeUP = TimeUP[Index];                        // Obter o tempo da extremidade máxima superior

         if (HighestBarUP>PivotBarUP)                          // Se a extremidade máxima está à esquerda da primeira extremidade... 
                                                               // ... estando na célula 0 do array de tempo do pico (máxima superior)
   for (m=Index-1; m>pbar; m--)                                // Loop da extremidade seguinte após a máxima para a primeira extremidade
      {
// --- Desenhar uma linha de tendência virtual e verificar cruzamentos com outras extremidades --------  
    CheckCross=EquationDirect(iBarShift(sy,tf,TimeUP[m+1]), PeakUP[m+1], // Primeira coordenada da linha
                              PivotBarUP, PivotPeakUP,                   // Segunda coordenada da linha
                              iBarShift(sy,tf,TimeUP[m],false));         // Ponto de cruzamento associado a próxima extremidade
         if (TempIND[iBarShift(sy,tf,TimeUP[m])]>CheckCross)             // Se o extremidade se encontra acima da linha
            {
               if (PeakUP[m]>PeakUP[pbar])                                // Se esta extremidade é maior do que a extremidade principal
                  {
                     HighestBarUP =iBarShift(sy,tf,TimeUP[m]);            // Então este é o que precisa para começar a partir de ...
                     HighestPeakUP = PeakUP[m];                           // Novas coordenadas da próxima extremidade
                     HighestTimeUP = TimeUP[m];                             
                  }
            }                       
      }
      if (HighestBarUP>PivotBarUP && HighestPeakUP>PivotPeakUP)           // Se a extremidade máxima está à esquerda da principal
         
            {
// ------------- Desenhar uma linha de tendência de baixa (UP - extremidade) ----------------            
               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 dos níveis da tendência de baixa (UP - extremidade) -------------------------            
         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));

 //-------------------- Desenhar níveis de tendência de baixa (UP - extremidade) ----------------------            
         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);
            }
// -------- Verifique se há um cruzamento para cima da tendência de baixa ------------------------------   
         if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yGUP,8) && 
             NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yGUP2,8))
               {
                  CrossGUP = true;                 // Definir o flag que indica o cruzamento para cima
                  CrossGDN = false;                // Remover o flag indicando o cruzamento para baixo
                  if (Arrow)                       // Se o uso de indicadores de sinal é permitido
                     {
                        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));
                     }
               }
            
// -------- Verificar se existe cruzamento descendente da linha de tendência de baixa ---------------------   
         if (add)
            {
               if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yGUP,8) && 
                   NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yGUP2,8))
                  {
                     CrossGDN = true;
                     CrossGUP = false;
                     if (Arrow)                    // Se o uso de indicadores de sinal é permitido
                        {
                           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);
                        }
                  }
            }
      }  
                                   
//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
// ==========================================================================================               
// ---------- Identificação de duas (local) extremidades externas inferior (DN) ------------+      
// ==========================================================================================               
   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];
                  }
            }
// -------------- Desenhar uma linha tendência de alta (DN - extremidade)--------------------            
         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 dos níveis de tendência local de alta  (DN - extremidade) -------------            
 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));
               
//------------ Níveis de desenho da tendência local de alta (DN - Extremidade) ----------            
         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);
            }
// ------- Verifique se existe um cruzamento descendente da tendência local de alta --------   
         if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yDN,8) && 
             NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yDN2,8))
               {
                  CrossDN = true;
                  CrossUP = false;
                  if (Arrow)                 // Se o uso de indicadores de sinal é permitido
                     {
                        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);
                     }
               }
// ------- Verifique se existe um cruzamento ascendente da tendência local de alta --------   
         if (add)
            {
               if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yDN,8) && 
                   NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yDN2,8))
                  {
                     CrossUP = true;
                     CrossDN = false;
                     if (Arrow)                 // Se o uso de indicadores de sinal é permitido
                        {
                           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));
                        }
                  }
            }
      }
//====================================================================================================
// ---------------- Identificação de duas (local) extremidades superior externas (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];
                  }
            }
// --------------- Desenhar uma linha de tendência local de baixa  (UP - extremidade) --------------------            
         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 dos níveis de tendência local de baixa (UP - extremidade) --------------------            
 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));

//------------------ Níveis de desenho da tendência local de baixa (UP - extremidade) ----------------------            
         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);
            }
// -------- Verificar se existe um cruzamento ascendente da tendência local de baixa ---------   
         if (NormalizeDouble(TempIND[1],8) > NormalizeDouble(yUP,8) && 
             NormalizeDouble(TempIND[2],8) <= NormalizeDouble(yUP2,8))
               {
                  CrossUP = true;
                  CrossDN = false;
                  if (Arrow)                 // Se o uso de indicadores de sinal é permitido
                     {
                        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));
                     }
               }           
// -------- Verifique se existe um cruzamento descendente da tendência local de baixa ---------   
         if (add)
            {
               if (NormalizeDouble(TempIND[1],8) < NormalizeDouble(yUP,8) && 
                   NormalizeDouble(TempIND[2],8) >= NormalizeDouble(yUP2,8))
                  {
                     CrossDN = true;
                     CrossUP = false;
                     if (Arrow)               // Se o uso de indicadores de sinal é permitido
                        {
                           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);
                        }
                  }                         
            }
      }            
// -----------------------------------------------------------------------------------------------------------            
// As condições aqui podem ser representadas por CrossGUP e CrossGDN, bem como por CrossUP e CrossDN.
// No primeiro caso, temos uma "tendência global" em todos as barras especificadas,
// no segundo caso, temos tendências locais nas últimas duas extremidades.
// Você também pode combinar sinais de cruzamentos de tendências "globais" e "locais" no gráfico A/D
/*   
   if (CrossGUP && CrossUP)   return(11);    // Um cruzamento ascendente de ambas as tendências de baixa
   else
   if (CrossGDN && CrossDN)   return(-11);   // Um cruzamento descendente de ambas as tendências de alta
   else
   if (CrossGUP)              return(10);    // Um cruzamento ascendente da tendência "global" de baixa 
   else
   if (CrossGDN)              return(-10);   // Um cruzamento descendente da tendência "global" de alta 
   else
   if (CrossUP)               return(1);     // Um cruzamento ascendente da tendência "local" de baixa 
   else
   if (CrossDN)               return(-1);    // Um cruzamento descendente da tendência "local" de alta 
*/   
   if (CrossGUP || CrossUP) return(1);
   else
   if (CrossGDN || CrossDN) return(-1); 
   else return(0);
                      
}  

O código acima é quase o mesmo que já analisamos; vou apenas comentar sobre os parâmetros de entrada da função e método de chamada.

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

Em contraste com o código que já olhamos, temos aqui acrescentado outra variável do tipo bool - Arrow que exibe indicadores de sinal na janela principal do terminal. O valor por padrão é definido como verdadeiro, ou seja, as setas devem ser exibidas no gráfico, este parâmetro pode ser deixado de fora ao chamar a função.

Em caso geral, a chamada da função pode ser a seguinte: insira a linha abaixo nas variáveis globais de um EA:

double      TempIND[];           // Array para armazenamento de dados do indicador

Em seguida, especifique o número desejado de barras do histórico, assim identificará a extremidade no gráfico do indicador A/D e receberá os sinais de negociação

int nBrs=30;

ou, por exemplo

int nBrs=200;

Aqui, tudo depende do como as linhas de tendência TF estão sendo plotadas e quantas barras do histórico nós vamos processar. Quanto maior o valor, mais "estáveis" as linhas de tendência seriam no gráfico A/D, porém mais atrasados seriam os sinais de cruzamento.

E, finalmente, a chamada da função por si só:

int sig=0;
   sig=SignalCrossIND(TempIND, nBrs, NULL, 5, false, false, true);
   
   if (sig==1)
      {Código para abertura da posição Buy}
   if (sig==-1)
      {Código para abertura da posição Sell}

Os valores dos parâmetros transmitidos aqui sugerem que os dados estão sendo obtidos a partir do atual gráfico do instrumento de moeda (NULL), o timeframe a ser utilizado é o М5 (5), linhas de tendência locais não devem ser plotadas e os cruzamentos destas linhas não devem ser procurados (falso), Além disso, nenhum cruzamento na direção da tendência é para ser procurado (falso), ao passo que os indicadores de sinal (setas a cima/a baixo) devem ser exibidas na janela do gráfico principal (verdade).

Uma vez que todos estes são valores padrão, a seguinte chamada da função é considerada absolutamente idêntica:

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


Conclusão

Para concluir, eu gostaria de dizer que esta função não é de maneira alguma uma estratégia de negociação independente. É apenas uma função para a identificação de cruzamentos de linhas de tendências plotadas no indicador A/D . Pode ser muito útil num EA, juntamente com outras funções.

Para ver as possibilidades, realizei um teste no intervalo de 01.01.2009 a 01.01.2010. O teste foi realizado utilizando apenas os valores retornados por esta função. Eu desativei o módulo de sinal do EA e o substituiu com esta função sozinha. O número de barras para a identificação da Extremidade = 250. O timeframe = 5, o símbolo selecionado foi o EURUSD, O depósito inicial foi de 10000 e o lote foi fixado em 0,1.

Também desativei o uso do SL e TP. Somente deixei o trailing stop que fecha posições parcialmente ao atingir o nível definido de lucro mais de três vezes. As posições foram abertas recebendo um sinal da função.

A posição oposta neste caso não foi fechada. Após a recepção do novo sinal na direção da posição já existente, eu determinei o tempo decorrido após a abertura da posição anterior, se fosse ao longo de 7 minutos, uma nova posição era aberta. Usei o depósito ao máximo ... :) Outra coisa, ia esquecendo de mencionar, a fim de fechar todas as posições de uma só vez, eu usei um acréscimo patrimonial por uma porcentagem definida em 5% no teste.

O gráfico resultante é o seguinte:

É claro que ele não pode ser aplicado em uma conta real, ainda creio eu.

E, finalmente, gostaria de manifestar a minha profunda e sincera gratidão a Viktor (Vinin) e Aleksey (Mathemat) pela ajuda desinteressada e um verdadeiro apoio amigável, bem como a todos aqueles que de uma forma ou de outra contribuiram para resolver diferentes problemas de programação.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/1357

MetaTrader 4 no Linux MetaTrader 4 no Linux
Este artigo explicará como instalar facilmente o MetaTrader 4 nas versões populares do Linux, Ubuntu e Debian. Esses sistemas são amplamente utilizados não apenas em hardware de servidor, mas também em computadores comuns por traders.
MetaTrader 4 no Mac OS MetaTrader 4 no Mac OS
Os produtos da Apple se tornaram muito populares. A MetaQuotes Software Corp segue atentamente o progresso da indústria TI e já lançou aplicativos especiais para dispositivos baseados em iOS - MetaTrader 4 para iPhone e MetaTrader 5 para iPhone. Há muitos temas no Fórum MQL4.community, onde as pessoas estão buscando uma solução para a execução de MetaTrader 4 no sistema operacional Mac OS. Neste artigo, você vai descobrir como trabalhar com MetaTrader 4 através do popular sistema operacional da Apple.
Uma Sandbox Aleatória Uma Sandbox Aleatória
O artigo inclui uma "sandbox" interativa como um arquivo do Excel que simula dados aleatórios para backtest de Expert Advisor. Os leitores podem usar a sandbox para ajudar a explorar e compreender mais profundamente as métricas de desempenho dos EAs oferecidos por padrão com o MetaTrader. O texto do artigo é projetado para ajudar o usuário durante esta experiência.
Uma Introdução à Lógica Fuzzy Uma Introdução à Lógica Fuzzy
A lógica fuzzy expande nossos limites da lógica matemática e da teoria dos conjuntos. Este artigo revela os princípios básicos da lógica fuzzy, bem como a descrição de dois sistemas de inferência fuzzy usando os modelos do tipo Mamdani e Sugeno. Os exemplos fornecidos descreverão a implementação de modelos difusos (fuzzy) baseados nesses dois sistemas, que utilizam a biblioteca FuzzyNet para MQL5.