English Русский 中文 Español Deutsch 日本語
preview
Introdução ao MQL5 (Parte 14): Guia para Iniciantes na Criação de Indicadores Personalizados (III)

Introdução ao MQL5 (Parte 14): Guia para Iniciantes na Criação de Indicadores Personalizados (III)

MetaTrader 5Sistemas de negociação |
27 6
ALGOYIN LTD
Israel Pelumi Abioye

Introdução

Bem-vindo de volta à nossa série MQL5! Nos artigos anteriores desta série, exploramos como construir indicadores personalizados em MQL5 usando buffers e plots. Buffers nos permitem armazenar valores do indicador, enquanto plots ajudam a visualizá-los no gráfico. Esses métodos são eficazes para muitos indicadores, mas possuem limitações quando se trata de criar representações visuais complexas.

Neste artigo, adotaremos uma nova abordagem criando indicadores usando objetos de gráfico do Meta Trader 5. Objetos de gráfico oferecem flexibilidade adicional, permitindo criar rótulos, formas e linhas de tendência diretamente no gráfico sem a necessidade de buffers de indicador. Essa técnica funciona bem para desenvolver indicadores que exigem componentes gráficos exclusivos, exibir padrões e identificar níveis importantes de preço.

Criaremos um indicador que se assemelha a Padrões Harmônicos para implementar isso. A lógica que utilizaremos pode ser modificada para identificar e representar diferentes Padrões Harmônicos, embora não nos concentraremos em nenhum específico (como Gartley, Bat ou Butterfly). Em vez de construir um detector de Padrões Harmônicos totalmente funcional, o principal objetivo é aprender como usar objetos de gráfico em MQL5 para desenvolver indicadores. Na Parte 9 desta série, analisamos como construir e trabalhar com objetos como linhas de tendência, retângulos e rótulos em MQL5, onde cobrimos pela primeira vez o uso de objetos de gráfico. Com base nesse conhecimento, este artigo o aplicará ao desenvolvimento de indicadores. Ao final, você terá uma compreensão sólida de como desenvolver indicações visuais exclusivas trabalhando dinamicamente com itens de gráfico.

Neste artigo, você aprenderá:

  • Como criar um indicador personalizado usando objetos de gráfico do MetaTrader 5 em vez de depender de buffers e plots.
  • Compreender a estrutura dos Padrões Harmônicos e como eles são identificados na ação do preço.
  • Como detectar pontos-chave de swing no mercado para formar possíveis Padrões Harmônicos.
  • Usar níveis de retração de Fibonacci para validar formações de padrão.
  • Como desenhar formas geométricas programaticamente (como triângulos e linhas) para visualizar padrões no gráfico.
  • Como filtrar padrões inválidos para melhorar a precisão nos sinais de negociação.

1. Indicador de Padrões Harmônicos

1.1. Compreendendo o Indicador de Padrões Harmônicos

Estruturas de preço conhecidas como padrões harmônicos utilizam proporções específicas de Fibonacci para identificar possíveis zonas de reversão do mercado. Os padrões Gartley, Bat e Butterfly, entre outros, dependem de flutuações de preço que criam formas geométricas que sinalizam oportunidades de negociação com alta probabilidade.

Os Padrões Harmônicos exigem a identificação de pontos críticos de preço e o uso de proporções de Fibonacci para validar sua estrutura, enquanto indicadores padrão criam sinais usando buffers e plots. Como resultado, eles são mais difíceis de identificar e exibir do que indicadores mais convencionais, como RSI ou Médias Móveis.

A lógica que utilizamos pode ser modificada para identificar e representar diferentes Padrões Harmônicos, mesmo que não estejamos nos concentrando em nenhum específico (como Gartley, Bat ou Butterfly). Em vez de construir um detector de Padrões Harmônicos totalmente eficaz, o objetivo principal é aprender como usar objetos de gráfico no MQL5 para desenvolver indicadores.

Para isso, marcaremos pontos importantes de swing (máximas e mínimas) no gráfico, utilizaremos objetos de texto (XABCD) para indicar níveis importantes, ilustraremos a estrutura do padrão com diferentes objetos e aplicaremos níveis de Fibonacci para melhorar a precisão e validação do padrão.

1.2. Configuração do Projeto

Como costumo dizer, você deve primeiro visualizar como um indicador irá aparecer antes de poder projetá-lo. Saber exatamente como o indicador deve ser configurado facilita o processo de desenvolvimento e garante que o produto final atenda aos nossos requisitos.

Neste projeto, usaremos objetos de gráfico do MetaTrader 5 para construir padrões harmônicos tanto de alta quanto de baixa. O indicador desenhará vários elementos gráficos para formar a estrutura do padrão, localizar pontos importantes de swing, marcá-los com objetos de texto (XABCD) e adicionar níveis de Fibonacci para melhorar a apresentação do padrão.

Além de criar um indicador que se assemelha de perto a padrões harmônicos, esse método nos dará experiência prática com objetos de gráfico no MQL5, o que facilitará a criação de futuros indicadores personalizados. Além de discutir como criar esses padrões com objetos de gráfico, também abordaremos possíveis erros que podem ocorrer. Problemas podem surgir, como objetos desalinhados, níveis de Fibonacci mal posicionados e detecção imprecisa de pontos de swing. Para garantir uma visualização precisa do padrão e uma operação suave do indicador, abordaremos esses problemas e ofereceremos soluções.

1.2.1. Padrão de Alta

Usaremos uma técnica metódica para identificar os pontos de swing importantes que compõem o padrão para desenvolver o Indicador de Padrão Harmônico de Alta. O processo envolve determinar pontos específicos de preço e garantir que eles sigam as diretrizes dos padrões harmônicos.

Identificar uma mínima de swing (X) como ponto inicial do padrão será nosso primeiro passo. Em seguida, identificaremos uma máxima de swing (A) e uma mínima de swing (B). B precisa retrair entre 61.8% e 78.6% da perna XA para que o padrão permaneça válido. Depois, procuraremos uma máxima de swing (C) e validaremos a mínima de swing (D). A estrutura completa do padrão de alta é formada quando o último ponto, D, é menor que X.

Quando essas condições forem satisfeitas, utilizaremos objetos de gráfico — como linhas de tendência conectando os pontos de swing, rótulos para os pontos XABCD e níveis de retração de Fibonacci para confirmar a estrutura — para representar o padrão no gráfico. Isso oferecerá uma abordagem metódica e transparente para identificar possíveis zonas de reversão de alta. Para facilitar a identificação de zonas importantes de negociação dentro do padrão, também utilizaremos objetos de gráfico para indicar possíveis posições de entrada, stop-loss (SL) e níveis de take-profit (TP). Isso ajudará na tomada de decisão de negociação ao oferecer uma abordagem metódica e transparente para identificar possíveis zonas de reversão de alta.

Figura 1.  Padrão de Alta

Pseudocódigo:

// Etapa 1: Identificar os Pontos de Swing

  • Detectar Mínima de Swing (X)
  • Identificar Máxima de Swing (A) após X
  • Detectar Mínima de Swing (B) após A

SE a retração B NÃO estiver entre 61,8% e 78,6% de XA

  • Descartar padrão e reiniciar detecção  

SE a retração B estiver entre 61,8% e 78,6% de XA

  • Identificar Máxima de Swing (C) após B
  • Detectar Mínima de Swing (D) após C

SE D NÃO estiver acima de X 

  • ENTÃO descartar o padrão e reiniciar a detecção

// Etapa 2: Desenhar objetos do gráfico

  • Desenhar objetos conectando X → A → B → C → D 
  •  Rotular pontos com objetos de texto: X, A, B, C, D
  • Desenhar retração de Fibonacci de X até A para validação 

// Etapa 3: Definir os níveis de negociação 

  • Criar objetos de gráfico para marcar Entrada, SL e TP.

1.2.2. Padrão de Baixa

Semelhante em estrutura ao padrão de alta, porém invertido, está o Indicador de Padrão Harmônico de Baixa. Para garantir que sigam as diretrizes dos padrões harmônicos, identificaremos pontos de swing importantes. O padrão será identificado inicialmente detectando uma máxima de swing (X), que será seguido por uma mínima de swing (A). A máxima de swing (B), que precisa retrair entre 61.8% e 78.6% da perna XA, será então determinado. A máxima de swing final (D) será então confirmado após detectarmos uma mínima de swing (C). D deve estar acima de X, criando uma possível zona de reversão de baixa, para validar o padrão.

Após a confirmação da estrutura, utilizaremos objetos de gráfico, como linhas de tendência, rótulos XABCD e níveis de retração de Fibonacci, para representar graficamente o padrão. Para ajudá-lo a localizar zonas importantes de negociação dentro do padrão, também indicaremos os níveis de entrada, stop-loss (SL) e take-profit (TP).

Figura 2. Padrão de Baixa

Pseudocódigo:

// Etapa 1: Identificar os Pontos de Swing

  • Detectar Máxima de Swing (X)
  • Detectar Mínima de Swing (A) após X
  • Detectar Máxima de Swing (B) após A

SE a retração B NÃO estiver entre 61,8% e 78,6% de XA

  • Descartar padrão e reiniciar detecção  

SE a retração B estiver entre 61,8% e 78,6% de XA

  • Detectar Mínima de Swing (C) após B
  • Detectar Máxima de Swing (D) após C

IF D is NOT above than X

  • Descartar padrão e reiniciar detecção

// Etapa 2: Desenhar objetos do gráfico

  • Desenhar objetos conectando X → A → B → C → D 
  • Rotular pontos com objetos de texto: X, A, B, C, D 
  • Desenhar retração de Fibonacci de X até A para validação 

// Etapa 3: Definir os níveis de negociação 

  • Criar objetos de gráfico para marcar Entrada, SL e TP.


2. Construindo Padrões Harmônicos de Alta

Começaremos a integrar o Indicador de Padrões Harmônicos no MQL5 nesta seção. Especificaremos as funções necessárias para identificar pontos de swing, confirmar níveis de retração e visualizar o padrão no gráfico usando objetos de gráfico. Além disso, personalizaremos a aparência dos objetos desenhados para melhorar a clareza e a usabilidade.

2.1. Identificando Máximas de Swing e Mínimas

Uma técnica confiável para localizar máxima de swing e mínima de swing no gráfico é necessária antes de podermos identificar um padrão harmônico. A estrutura XABCD é plotada usando pontos de swing como base. Determinamos se a máxima de um candle é a mais alta entre um intervalo especificado de candles próximos para identificar uma máxima de swing. De forma semelhante, uma mínima de swing é identificado quando a mínima de um candle é a mais baixa dentro de um determinado intervalo. O tamanho desse intervalo determina a sensibilidade da nossa detecção — valores maiores capturam swings principais, enquanto valores menores detectam pequenas flutuações. Na próxima etapa, desenvolveremos um algoritmo para varrer dados históricos de preços, localizar pontos-chave de swing e garantir que eles correspondam aos princípios de formação do padrão.

2.1.1. Funções de Máximas de Swing e Mínimas

Exemplo:

#property indicator_chart_window

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

//--- return value of prev_calculated for next call
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false; 
     }
   return true; 
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false; 
     }
   return true; 
  }

Explicação:

A diretiva #property indicator_chart_window informa ao MetaTrader 5 que o indicador personalizado deve ser exibido no gráfico principal de preços, em vez de em uma subjanela separada. Isso é útil ao criar indicadores baseados em padrões, como Padrões Harmônicos, ou indicadores que sobrepõem a ação do preço, como linhas de tendência, níveis de suporte e resistência, etc. Na ausência dessa propriedade, o indicador pode, por padrão, ser plotado em uma janela separada, semelhante a osciladores como MACD ou RSI.

A função IsSwingLow tem como objetivo identificar a mínima de swing no gráfico de preços. Quando a mínima de um candle está abaixo das mínimas dos candles ao redor dentro de um determinado intervalo, isso é conhecido como uma mínima de swing A função recebe um valor de lookback que define quantos candles antes e depois devem ser considerados, um array de preços mínimos e o índice do candle em avaliação. Ela determina se a mínima atual é a menor iterando pelos candles próximos. Ela retorna false se encontrar um valor menor dentro do intervalo ao redor, provando que o candle atual não é uma mínima de swing. Caso contrário, retorna true, indicando que uma mínima de swing válido está presente.

De forma semelhante, as máxima de swing — pontos em que a máxima de um candle excede as máximas dos candles próximos — são encontrados usando a função IsSwingHigh. A função utiliza a mesma lógica de IsSwingLow, exceto que garante que a máxima no índice especificado seja o maior valor dentro do intervalo de lookback, em vez de procurar o menor valor. A função retorna false se qualquer um dos candles ao redor tiver um valor maior. Caso contrário, confirma uma máxima de swing e retorna true.

A detecção de pontos significativos de reversão de preço, que fornecem a base para a definição de Padrões Harmônicos, requer ambas as funcionalidades. Após identificar as máxima de swing e mínimas, a estrutura XABCD do padrão pode ser plotada conectando-os com linhas de tendência e utilizando retrações de Fibonacci para confirmação. Com esse método, garante-se que o indicador se ajuste dinamicamente a novos dados de preço e atualize os padrões identificados de forma adequada.

Analogia:

Encontrar o ponto mais baixo em um vale é como a função IsSwingLow opera. Imagine-se em uma trilha de caminhada tentando localizar a depressão mais profunda do caminho. Durante o período de lookback, você dá alguns passos para frente e alguns para trás. O ponto atual é confirmado como a depressão mais baixa (mínima de swing) se for menor que todos os outros pontos dentro desse intervalo. Sua localização atual é apenas outra parte da inclinação e não o ponto mais baixo real se qualquer ponto vizinho for mais baixo. Essa função é usada para identificar zonas potenciais de reversão onde os preços podem começar a subir.

Encontrar o ponto mais alto em uma cadeia de montanhas é semelhante ao uso da função IsSwingHigh. Considera-se uma máxima de swing se você estiver em um ponto e der alguns passos para frente e para trás para garantir que sua posição atual seja a mais alta dentro daquele intervalo. A distância que você verifica antes de declarar um topo ou uma queda depende do período de lookback; se for muito pequeno, pequenas variações podem ser confundidas com pontos importantes, e se for muito grande, você pode perder tendências menores, mas relevantes. Esse equilíbrio garante que os pontos de swing identificados sejam significativos e não apenas flutuações aleatórias no preço.

Figura 3. Máxima Swing e Mínima

2.1.2. Identificando Mínima de Swing (X)

O próximo passo é incorporar as funções IsSwingLow e IsSwingHigh na função OnCalculate após terem sido criadas. Aqui, os dados de preço em tempo real serão submetidos à lógica de detecção de pontos de swing. Encontrar mínima de swing inicial (X), que é onde o padrão harmônico começa, é o primeiro desafio. Utilizando nossa função criada, podemos examinar iterativamente cada candle no histórico de preços do OnCalculate para verificar se ele atende aos critérios de uma mínima de swing.

Exemplo:

#property indicator_chart_window

// Input parameters
input int LookbackBars = 10; // Number of bars to look back/forward for swing points
input int bars_check  = 1000; // Number of bars to check for swing points

// CHART ID
long chart_id = ChartID(); // Get the ID of the current chart to manage objects (lines, text, etc.)

//X
double X; // Price of the swing low (X).
datetime X_time; // Time of the swing low (X).
string X_line; // Unique name for the trend line object.
string X_letter; // Unique name for the text label object.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".

            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
 
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;  
     }
   return true;  
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {

   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false; 
     }
   return true; 
  }
//+------------------------------------------------------------------+

Saídas:

Figura 4. Mínima de Swing (X)

Explicação:

Começamos declarando alguns dados de entrada cruciais, já que determinar o mínima de swing (X) é o primeiro passo para encontrar um padrão harmônico de alta. O número de barras que devem ser examinadas antes e depois de um ponto específico para garantir que ele seja um ponto de swing válido é determinado pela variável LookbackBars. Isso ajuda a eliminar pequenos movimentos de preço que não resultam em mínima de swing significativas. Para garantir que o script processe apenas um número gerenciável de barras históricas e mantenha a eficiência, o argumento bars_check especifica quantas barras devem ser analisadas.

Além disso, usamos ChartID() para obter o chart_id, o que nos permite criar e gerenciar objetos de gráfico, como linhas de tendência e rótulos de texto. Declaramos variáveis "X" para armazenar o preço da mínima de swing (X) detectado, "X_time" para registrar o momento em que ocorreu, e "X_line" e "X_letter" para fornecer nomes distintos aos objetos que serão usados para identificar esse ponto no gráfico. O rótulo de texto que indica a mínima de swing será criado usando a variável X_letter, e uma linha de tendência será criada para melhor visualização usando a variável X_line.

Em seguida, utilizamos essas configurações preliminares para determinar a mínima de swing (X) na função OnCalculate. Só começamos a verificação quando há dados de preço suficientes disponíveis, graças à condição if(rates_total >= bars_check). Para evitar verificar dados de preço incompletos, o loop percorre as barras históricas, começando em rates_total - bars_check e terminando em rates_total - LookbackBars. A função IsSwingLow dentro do loop detecta se um determinado ponto é uma mínima de swing. Quando uma mínima de swing válida é encontrada, registramos seu tempo e preço, criamos nomes únicos para os objetos e, em seguida, geramos os componentes visuais no gráfico.

Um objeto de texto é criado usando ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X) para indicar a mínima de swing com a letra "X." Para ilustrar ainda mais a mínima de swing identificada, utilizamos ObjectCreate(chart_id, X_line, OBJ_TREND, 0, X_time, X, time[i+LookbackBars], X) para construir uma linha de tendência no nível X. Isso garante que o primeiro ponto importante da estrutura do nosso padrão harmônico seja identificado e exibido com precisão no gráfico, estabelecendo a base para determinar os pontos subsequentes do padrão.

2.1.3. Identificando Máxima de Swing (A)

Encontrar a máxima de swing (A) é a próxima etapa após identificar com sucesso a mínima de swing (X). Esse ponto é essencial para a formação do padrão harmônico, pois representa o primeiro movimento significativo de alta após X. Da mesma forma que identificamos X, utilizaremos a função IsSwingHigh para encontrar A, mas desta vez procuraremos um topo em vez de um fundo.

Buscaremos um ponto nos dados de preço após X onde a máxima seja superior às máximas das barras ao redor dentro do intervalo definido por LookbackBars. Após identificar uma máxima de swing válida, registraremos seu preço e tempo, atribuiremos um nome exclusivo e utilizaremos objetos de gráfico para representá-la corretamente.

Exemplo:

#property indicator_chart_window

// Input parameters
input int LookbackBars = 10; // Number of bars to look back/forward for swing points
input int bars_check  = 1000; // Number of bars to check for swing points

// CHART ID
long chart_id = ChartID(); // Get the ID of the current chart to manage objects (lines, text, etc.)

//X
double X; // Price of the swing low (X).
datetime X_time; // Time of the swing low (X).
string X_line; // Unique name for the trend line object.
string X_letter; // Unique name for the text label object.

//A
double A; // Price of the swing high (A).
datetime A_time; // Time of the swing high (A).
string A_line; // Unique name for the trend line object.
string A_letter; // Unique name for the text label object.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars)  && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                  break;
                 }
              }
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;  
     }
   return true;  
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false; 
     }
   return true; 
  }
//+------------------------------------------------------------------+

Saídas:

Figura 5. Máxima de Swing (A)

Explicação:

Primeiro, definimos as variáveis necessárias para determinar a máxima de swing (A). A_time registra o momento exato em que a máxima de swing ocorreu, enquanto A armazena o valor de preço da máxima de swing. Usamos A_line como o nome do objeto de linha de tendência e A_letter como o rótulo de texto para garantir que cada ponto A detectado tenha uma representação visual distinta. Essas variáveis auxiliam na criação de objetos de gráfico que exibem claramente o ponto A, facilitando a visualização da estrutura do padrão harmônico.

Após identificar X, o código percorre os dados de preço, começando na posição de X, para encontrar A. A função IsSwingHigh, que verifica se uma barra é um topo local dentro do intervalo LookbackBars, é usada para avaliar cada barra. A condição time[j] > X_time é utilizada para garantir que o swing high A ocorra após X. 

Isso garante que a sequência correta no padrão harmônico seja mantida ao selecionar A apenas se seu timestamp for maior que X_time. O preço e o tempo de um swing high válido são registrados, e os objetos de linha de tendência e rótulo de texto recebem identificadores únicos quando um é encontrado. Uma linha de tendência verde é construída para destacar a máxima de swing identificado, e um rótulo de texto com a letra "A" é posicionado nesse ponto. Assim que a primeira máxima de swing válida (A) é identificada, o loop é interrompido usando a expressão break;. Sem o break;, o loop continuaria procurando por mais máximas de swing, possivelmente sobrescrevendo A com uma máxima de swing posterior. Como queremos apenas a primeira ocorrência de A após X, o break; garante que o loop pare assim que uma máxima de swing é detectada, preservando a primeira A válida e evitando cálculos desnecessários. 

2.1.4. Identificando Mínima de Swing (B)

Encontrar a próxima mínima de swing, B, é o passo seguinte após determinar a máxima de swing, A. A busca por B começa imediatamente após a identificação de A, pois B deve ocorrer depois de A. Isso é feito percorrendo os dados de preço, começando na posição de A, e usando a função IsSwingLow para comparar uma barra com as barras vizinhas dentro do intervalo LookbackBars e determinar se ela é uma mínima de swing. Além disso, espera-se que B esteja dentro de um nível específico de retração de Fibonacci de XA na identificação de padrões harmônicos. No entanto, não discutiremos a validação de Fibonacci neste momento; estamos apenas focados em identificar B.

O preço e o tempo de uma mínima de swing são registrados em B e B_time, respectivamente, assim que ela é identificada. Atribuímos nomes distintos à linha de tendência (B_line) e ao rótulo de texto (B_letter) para indicar essa posição no gráfico. Uma linha de tendência é criada para conectar e destacar visualmente o objeto de texto com o rótulo "B" que é posicionado no ponto da mínima de swing. Essa etapa garante que os três pontos principais — X, A e B — que agora servem como base para a estrutura do nosso padrão harmônico estejam estabelecidos.

Exemplo:

#property indicator_chart_window

// Input parameters
input int LookbackBars = 10; // Number of bars to look back/forward for swing points
input int bars_check  = 1000; // Number of bars to check for swing points

// CHART ID
long chart_id = ChartID(); // Get the ID of the current chart to manage objects (lines, text, etc.)

//X
double X; // Price of the swing low (X).
datetime X_time; // Time of the swing low (X).
string X_line; // Unique name for the trend line object.
string X_letter; // Unique name for the text label object.

//A
double A; // Price of the swing high (A).
datetime A_time; // Time of the swing high (A).
string A_line; // Unique name for the trend line object.
string A_letter; // Unique name for the text label object.

//B
double B; // Price of the swing low (B).
datetime B_time; // Time of the swing low (B).
string B_line; // Unique name for the trend line object.
string B_letter; // Unique name for the text label object.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// This function is called when the indicator is removed or the chart is closed.
// Delete all objects (lines, text, etc.) from the chart to clean up.
   ObjectsDeleteAll(chart_id);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X


            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green


                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
                        ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                        ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                        ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
                        ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to green


                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING LOW                                           |
//+------------------------------------------------------------------+
bool IsSwingLow(const double &low[], int index, int lookback)
  {
   for(int i = 1; i <= lookback; i++)
     {
      if(low[index] > low[index - i] || low[index] > low[index + i])
         return false;  
     }
   return true; 
  }

//+------------------------------------------------------------------+
//| FUNCTION FOR SWING HIGH                                          |
//+------------------------------------------------------------------+
bool IsSwingHigh(const double &high[], int index, int lookback)
  {

   for(int i = 1; i <= lookback; i++)
     {
      if(high[index] < high[index - i] || high[index] < high[index + i])
         return false;  
     }
   return true;  
  }
//+------------------------------------------------------------------+

Saídas:

Figura 6.Mínima de Swing (B)

Explicação:

O preço da mínima de swing que segue A é representado pela variável B. Um loop que começa no ponto A e utiliza a função IsSwingLow para encontrar a próxima mínima de swing é usado para identificá-la. O preço, o tempo e nomes distintos para a linha de tendência e o rótulo de texto são armazenados após serem identificados. Em seguida, para indicar B no gráfico, o sistema gera uma linha de tendência na cor azul meia-noite e um rótulo de texto ("B") em verde. Para manter a sequência correta de pontos de swing para a geração do padrão, uma instrução break garante que apenas o primeiro B válido seja selecionado. Como X e B são ambos reconhecidos como mínimas de swing durante a iteração do loop, eles podem ocasionalmente se sobrepor na implementação atual. Dado que o programa avalia cada ponto de swing sequencialmente, esse comportamento é esperado. No entanto, isso pode resultar em anotações redundantes no gráfico se X e B forem iguais.

Você pode incluir uma condição para garantir que B seja uma mínima de swing separada que ocorre após A, mas que não seja igual a X, caso queira evitar a sobreposição entre X e B. Incluirei uma opção no código que permite escolher se X e B podem se sobrepor. O indicador funcionará como está atualmente, onde X e B podem ser a mesma mínima de swing se a sobreposição for permitida. No entanto, o indicador garantirá que B seja uma mínima de swing diferente de X se a sobreposição for proibida.

Como B deve ser uma mínima distinta e não possivelmente o mesmo que X, impedir a sobreposição resultará na identificação de menos padrões harmônicos. Dependendo da preferência do usuário para reconhecimento de padrões, essa opção oferece flexibilidade.

Exemplo:

input bool overlap = false; //Allow Overlaping
for(int k = j; k < rates_total - LookbackBars; k++)
  {
   if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
     {

      // If a swing low is found, store its price, time, and create a name for the object.
      B = low[k]; // Price of the swing low (B).
      B_time = time[k]; // Time of the swing low (B).
      B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
      B_letter = StringFormat("B%d", k); // Unique name for the text label object.

      ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
      ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
      ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
      ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to green

      if(overlap == false)
        {
         i = k;
        }
      if(overlap == true)
        {
         i = i;
        }

      break;

     }
  }
Saídas:


Figura 7. Sobreposição de X e B

Explicação:

Se X e B podem ter a mesma mínima de swing depende do parâmetro de entrada overlap. A linha i = k; garante que a iteração avance quando B é localizado, impedindo que B seja o mesmo que X quando overlap está definido como false. Isso reduz a quantidade de padrões harmônicos que podem ser reconhecidos, ao mesmo tempo em que minimiza redundâncias ao manter uma separação clara entre os pontos de swing.

No entanto, a linha i = i; indica que o loop continua normalmente sem necessidade de salto quando overlap é true. Isso permite descobrir mais padrões harmônicos ao possibilitar que X e B se sobreponham quando ocorrem naturalmente no mesmo nível de preço. No entanto, isso também pode gerar alguma repetição nas marcações do padrão. Ao impedir com sucesso a sobreposição entre X e B, o código garantiu que eles sejam pontos de swing distintos. Como a imagem ilustra, B agora aparece independentemente de X, preservando uma estrutura de padrão mais clara.

2.1.5. Identificando Máxima de Swing (C)

Encontrar a máxima de swing (C) ocorre após determinar a máxima de swing (X), a mínima de swing (A) e a mínima de swing subsequente (B). Esse ponto é essencial para construir a estrutura de um padrão harmônico, pois define a forma geral do padrão e a possível zona de reversão.

Tanto a linha de tendência (C_line) quanto o rótulo de texto (C_letter) recebem nomes distintos para indicar visualmente esse ponto. Uma linha de tendência é criada para conectar e destacar visualmente um objeto de texto com o rótulo "C", posicionado na máxima de swing no gráfico. Essa etapa garante que os quatro pontos principais — X, A, B e C — que compõem a estrutura do padrão harmônico estejam estabelecidos.

Exemplo:

//C
double C; // Price of the swing high (C).
datetime C_time; // Time of the swing high (C).
string C_line; // Unique name for the trend line object.
string C_letter; // Unique name for the text label object.
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
                        ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                        ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                        ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
                        ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                        for(int l = j ; l < rates_total - LookbackBars; l++)
                          {
                           if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time)
                             {
                              C = high[l]; // Price of the swing high (C).
                              C_time = time[l]; // Time of the swing high (C).
                              C_line = StringFormat("CHigh%d", l); // Unique name for the trend line object.
                              C_letter = StringFormat("C%d", l); // Unique name for the text label object.

                              ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, C_time, C); // Create text object for C
                              ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                              ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                              ObjectCreate(chart_id,C_line,OBJ_TREND,0,C_time,C,time[l+LookbackBars],C); // Create line to mark C
                              ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                              if(overlap == false)
                                {
                                 i = l;
                                }
                              if(overlap == true)
                                {
                                 i = i;
                                }

                              break;

                             }
                          }

                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }
Saídas:


Figura 8. Máxima de Swing (C)

Explicação:

Após determinar a mínima de swing (B), esta parte do código é responsável por identificar a máxima de swing (C), que é o próximo passo crucial. Ao iterar sobre os dados de preço, o loop for(int l = j; l < rates_total - LookbackBars; l++) começa no índice j, onde a máxima de swing anterior (A) foi encontrada. Para garantir que C venha após B na sequência, ele continua buscando até encontrar as barras mais recentes. Para manter a ordem correta do padrão, a condição if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time) verifica se a barra atual é uma máxima de swing dentro do intervalo de lookback especificado e garante que seu timestamp seja posterior ao de B. 

O preço e o tempo de uma máxima de swing válida são armazenados em C e C_time, respectivamente, e os objetos de linha de tendência e rótulo de texto recebem nomes distintos (C_line e C_letter). Usando ObjectCreate(chart_id, C_line, OBJ_TREND, 0, C_time, C, time[l+LookbackBars], C), uma linha de tendência é criada para destacar o rótulo de texto "C" no swing high identificado. Para diferenciar visualmente a linha de tendência de C de outros segmentos, ObjectSetInteger(chart_id, C_line, OBJPROP_COLOR, clrSaddleBrown); define a cor da linha como SaddleBrown.

O bloco condicional final garante que padrões sobrepostos sejam tratados corretamente: i = l; impede que pontos de swing anteriores sejam usados em outro padrão quando overlap está definido como false. Múltiplos padrões podem se sobrepor se overlap for true, pois i = i; mantém o valor atual. Após identificar a primeira máxima de swing válida (C), break; encerra o loop, garantindo eficiência ao evitar iterações desnecessárias.

2.1.6. Identificando Mínima de Swing (D)

A identificação da mínima de swing (D) ocorre após determinar a máxima de swing (C). Isso garante a sequência correta da ação de preço para a formação de padrões harmônicos. Para encontrar a próxima mínima de swing após C em ordem cronológica, a busca por D começa a partir da posição onde C foi identificado. Dois requisitos devem ser atendidos para validar uma mínima de swing legítima. Primeiro, dentro do período de lookback definido, o preço atual deve ser considerado uma mínima de swing. Segundo, para manter a ordem correta do padrão, seu timestamp deve ser posterior ao de C.

O preço e o tempo de uma mínima de swing válida são registrados, e identificadores distintos são criados para a linha de tendência e o rótulo de texto correspondentes. Para tornar a mínima de swing mais visível dentro do padrão, uma linha de tendência é criada para destacá-lo e um rótulo de texto é inserido em sua posição para identificá-lo visualmente.

Exemplo:

//D
double D; // Price of the swing low (D).
datetime D_time; // Time of the swing low (D).
string D_line; // Unique name for the trend line object.
string D_letter; // Unique name for the text label object.

//Trend
string XA_line; // Unique name for XA trend line object.
string AB_line; // Unique name for AB trend line object.
string BC_line; // Unique name for BC trend line object.
string CD_line; // Unique name for CD trend line object.

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, X_time, X); // Create text object for X
            ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
            ObjectCreate(chart_id,X_line,OBJ_TREND,0,X_time,X,time[i+LookbackBars],X); // Create line to mark X

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, A_time, A); // Create text object for A
                  ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                  ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                  ObjectCreate(chart_id,A_line,OBJ_TREND,0,A_time,A,time[j+LookbackBars],A); // Create line to mark A
                  ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, B_time, B); // Create text object for B
                        ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                        ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                        ObjectCreate(chart_id,B_line,OBJ_TREND,0,B_time,B,time[k+LookbackBars],B); // Create line to mark B
                        ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                        for(int l = j ; l < rates_total - LookbackBars; l++)
                          {
                           if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time)
                             {
                              C = high[l]; // Price of the swing high (C).
                              C_time = time[l]; // Time of the swing high (C).
                              C_line = StringFormat("CHigh%d", l); // Unique name for the trend line object.
                              C_letter = StringFormat("C%d", l); // Unique name for the text label object.

                              ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, C_time, C); // Create text object for C
                              ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                              ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                              ObjectCreate(chart_id,C_line,OBJ_TREND,0,C_time,C,time[l+LookbackBars],C); // Create line to mark C
                              ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                              for(int m = l; m < rates_total - (LookbackBars / 2); m++)
                                {
                                 if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
                                   {
                                    D = low[m]; // Price of the swing low (D).
                                    D_time = time[m]; // Time of the swing low (D).
                                    D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
                                    D_letter = StringFormat("D%d", m); // Unique name for the text label object.

                                    ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
                                    ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
                                    ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
                                    ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
                                    ObjectCreate(chart_id,XA_line,OBJ_TREND,0,X_time,X,A_time,A); // Create line to connect XA
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

                                    AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
                                    ObjectCreate(chart_id,AB_line,OBJ_TREND,0,A_time,A,B_time,B); // Create line to connect AB
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

                                    BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
                                    ObjectCreate(chart_id,BC_line,OBJ_TREND,0,B_time,B,C_time,C); // Create line to connect BC
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

                                    CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
                                    ObjectCreate(chart_id,CD_line,OBJ_TREND,0,C_time,C,D_time,D); // Create line to connect CD
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

                                    if(overlap == false)
                                      {
                                       i = m;
                                      }
                                    if(overlap == true)
                                      {
                                       i = i;
                                      }
                                    break;

                                   }
                                }

                              break;

                             }
                          }

                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

Saídas:

Figura 9. Mínima de Swing (D)

Explicação:

O preço da mínima de swing no ponto D no padrão reconhecido é representado pela variável D. D é um ponto crucial na negociação de padrões harmônicos, onde a ação do preço pode se inverter e finalizar o padrão. D_time registra o timestamp da ocorrência dessa mínima além de D. Para identificar visualmente essa mínima de swing, a linha de tendência e o item de texto no gráfico também são criados e rotulados usando D_line e D_letter.

O programa itera pelos dados de preço para encontrar o ponto D no loop que começa com for(int m = l; m < rates_total - (LookbackBars / 2); m++).... Para verificar se o preço atual no índice m é uma mínima de swing, ele utiliza a função IsSwingLow(), garantindo que a mínima esteja após o ponto C no tempo. O preço e o tempo de uma mínima de swing válida são atribuídos a D e D_time, respectivamente.

O indicador produz elementos visuais no gráfico após o ponto D ter sido localizado. Na localização da mínima de swing, a função ObjectCreate() cria um rótulo de texto (D_letter) com a letra "D" e o colore em verde por conveniência. Para manter a representação visual consistente, uma linha de tendência (D_line) também é desenhada no ponto D, estendendo-se por períodos de LookbackBars, e recebe a cor marrom (clrSaddleBrown).

Neste ponto, o programa também cria linhas de tendência que conectam os pontos de swing que foram identificados. Para conectar visualmente os pontos correspondentes (X para A, A para B, B para C e C para D), os objetos XA_line, AB_line, BC_line e CD_line são criados. Essas linhas ajudam os traders a analisar possíveis mudanças de preço ao delinear o padrão harmônico. As configurações de largura e cor dessas linhas são ajustadas para melhorar a visibilidade no gráfico.

Após reconhecer com sucesso o padrão XABCD, é fundamental resolver algumas preocupações cruciais. A lógica do programa é que, após identificar o ponto X, ele não atualizará X até que a sequência ABCD seja finalizada. Isso implica que o programa não alterará X se uma nova mínima mais baixo do que o X originalmente determinado surgir entre X e A. Consequentemente, o padrão pode não refletir com precisão a estrutura real do mercado.

Devemos implementar um sistema que determine continuamente se X ainda é a mínima mais baixo entre X e A para garantir a validade do padrão. É necessário atualizar dinamicamente X se ocorrer uma mínima mais baixo dentro desse intervalo. Para garantir que nenhum ponto mais alto seja ignorado nesse segmento, A também deve ser a máxima mais alta entre A e B. Da mesma forma, C deve ser a máxima mais alta entre C e D, e B deve ser a mínima mais baixo entre B e C. Podemos melhorar a precisão da detecção de padrões e evitar identificações incorretas causadas pela seleção rígida de pontos seguindo esses requisitos. Esse método preserva a integridade da estrutura do padrão harmônico enquanto permite que o indicador permaneça adaptável e responsivo à nova atividade de preço.

Exemplo:

//X
int x_a_bars; // Number of bars between XA
int x_lowest_index; // Index of the lowest bar
double x_a_ll; // Price of the lowest bar
datetime x_a_ll_t; // Time of the lowest bar

//A
int a_b_bars; // Number of bars between AB
int a_highest_index; // Index of the highest bar
double a_b_hh; // Price of the highest bar
datetime a_b_hh_t; // Time of the highest bar

//B
int b_c_bars; // Number of bars between BC
int b_lowest_index; // Index of the lowest bar
double b_c_ll; // Price of the lowest bar
datetime b_c_ll_t; // Time of the lowest bar

//C
int c_d_bars; // Number of bars between CD
int c_highest_index; // Index of the highest bar
double c_d_hh; // Price of the highest bar
datetime c_d_hh_t; // Time of the highest bar

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {

//---

   if(rates_total >= bars_check)
     {

      for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
        {
         if(IsSwingLow(low, i, LookbackBars))
           {
            // If a swing low is found, store its price, time, and create a name for the objects to mark the X.
            X = low[i]; // Price of the swing low (X).
            X_time = time[i]; // Time of the swing low (X).
            X_line = StringFormat("XLow%d", i); // Unique name for the trend line object.
            X_letter = StringFormat("X%d", i); // Unique name for the text label object.

            for(int j = i; j < rates_total - LookbackBars; j++)
              {
               if(IsSwingHigh(high, j, LookbackBars) && time[j] > X_time)
                 {

                  A = high[j]; // Price of the swing high (A).
                  A_time = time[j]; // Time of the swing high (A).
                  A_line = StringFormat("AHigh%d", j); // Unique name for the trend line object.
                  A_letter = StringFormat("A%d", j); // Unique name for the text label object.

                  for(int k = j; k < rates_total - LookbackBars; k++)
                    {
                     if(IsSwingLow(low, k, LookbackBars) && time[k] > A_time)
                       {

                        // If a swing low is found, store its price, time, and create a name for the object.
                        B = low[k]; // Price of the swing low (B).
                        B_time = time[k]; // Time of the swing low (B).
                        B_line = StringFormat("BLow%d", k); // Unique name for the trend line object.
                        B_letter = StringFormat("B%d", k); // Unique name for the text label object.

                        for(int l = j ; l < rates_total - LookbackBars; l++)
                          {
                           if(IsSwingHigh(high, l, LookbackBars) && time[l] > B_time)
                             {
                              C = high[l]; // Price of the swing high (C).
                              C_time = time[l]; // Time of the swing high (C).
                              C_line = StringFormat("CHigh%d", l); // Unique name for the trend line object.
                              C_letter = StringFormat("C%d", l); // Unique name for the text label object.

                              for(int m = l; m < rates_total - (LookbackBars / 2); m++)
                                {
                                 if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
                                   {
                                    D = low[m]; // Price of the swing low (D).
                                    D_time = time[m]; // Time of the swing low (D).
                                    D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
                                    D_letter = StringFormat("D%d", m); // Unique name for the text label object.

                                    //D
                                    ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
                                    ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
                                    ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
                                    ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //C
                                    c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time, D_time);
                                    c_highest_index = ArrayMaximum(high,l, c_d_bars);

                                    c_d_hh = high[c_highest_index]; //C - D Highest High and time
                                    c_d_hh_t = time[c_highest_index];

                                    ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
                                    ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                                    ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
                                    ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //B
                                    b_c_bars = Bars(_Symbol,PERIOD_CURRENT,B_time, c_d_hh_t);
                                    b_lowest_index = ArrayMinimum(low,k, b_c_bars);

                                    b_c_ll = low[b_lowest_index]; //B - C Lowest Low and time
                                    b_c_ll_t = time[b_lowest_index];

                                    ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
                                    ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                                    ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
                                    ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                                    //A
                                    a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time, b_c_ll_t);
                                    a_highest_index = ArrayMaximum(high,j, a_b_bars);

                                    a_b_hh = high[a_highest_index]; //A - B Highest High and time
                                    a_b_hh_t = time[a_highest_index];

                                    ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
                                    ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                                    ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
                                    ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                                    //X
                                    x_a_bars = Bars(_Symbol,PERIOD_CURRENT,X_time, a_b_hh_t);
                                    x_lowest_index = ArrayMinimum(low,i, x_a_bars);

                                    x_a_ll = low[x_lowest_index]; //X - A Lowest Low and time
                                    x_a_ll_t = time[x_lowest_index];

                                    ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
                                    ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
                                    ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

                                    XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
                                    ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

                                    AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
                                    ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

                                    BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
                                    ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

                                    CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
                                    ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

                                    if(overlap == false)
                                      {
                                       i = m;
                                      }
                                    if(overlap == true)
                                      {
                                       i = i;
                                      }
                                    break;

                                   }
                                }

                              break;

                             }
                          }

                        break;

                       }
                    }

                  break;
                 }
              }
           }
        }
     }

//--- return value of prev_calculated for next call
   return(rates_total);
  }

Saídas:

Figura 10. New XABCD

Explicação:

O ponto X serve como ponto inicial de referência para identificar possíveis padrões de reversão na negociação de padrões harmônicos. Em um padrão de alta, ele representa uma grande mínima de swing; em um padrão de baixa, ele representa uma máxima de swing. Como estabelece a base para medir retrações e extensões de Fibonacci — que auxiliam na confirmação de formações harmônicas — esse ponto é essencial. O objetivo do código é reconhecer X, registrar seu tempo e preço e indicá-lo visualmente no gráfico. Para criar toda a estrutura do padrão, ele também conecta X aos outros pontos de swing (A, B, C e D).

Diversas variáveis importantes são utilizadas para armazenar dados sobre X. O número de barras entre X e A é registrado pela variável x_a_bars, o que ajuda a determinar as separações relativas entre as pernas do padrão. Para identificar a barra exata onde X ocorreu, a variável x_lowest_index acompanha o índice do array do menor preço dentro desse intervalo. O timestamp associado ao menor preço é salvo em x_a_ll_t, enquanto o próprio preço é atribuído a x_a_ll.

Encontrar o número de barras entre X e A usando a função Bars() é o primeiro passo para determinar X. O intervalo necessário para análise é fornecido por essa função, que conta o número de barras entre esses dois pontos de swing. O programa utiliza ArrayMinimum() para pesquisar nas barras designadas e retornar o índice do menor preço quando o intervalo foi determinado. Em seguida, usando os arrays low[x_lowest_index] e time[x_lowest_index], respectivamente, o preço e o tempo reais de X são obtidos.

Depois que X foi identificado, o script utiliza os objetos do MetaTrader para indicá-lo visivelmente no gráfico. Para garantir que você possa identificar rapidamente esse momento crucial, ObjectCreate() é usado para produzir um rótulo de texto (X_letter) na mínima de swing X. Para maior clareza, o texto "X" é atribuído ao rótulo de texto, que é colocado no tempo e preço de X. Para destacar adequadamente a mínima de swing, uma linha de tendência (X_line) também é formada em X usando ObjectCreate(). A linha é estendida por um número predeterminado de barras (LookbackBars).

O programa cria linhas de tendência para conectar X a outros locais importantes (A, B, C e D) após X ter sido determinado. Você pode visualizar melhor o padrão harmônico com essas linhas de tendência. A função ObjectCreate() é usada para desenhar a primeira conexão, a linha XA, que conecta X e A. Essa linha possui uma largura de três pixels e é colorida em marrom (clrSaddleBrown) para garantir visibilidade. As pernas restantes do padrão — a linha AB, que conecta A a B; a linha BC, que conecta B a C; e a linha CD, que conecta C a D — são igualmente representadas com linhas de tendência adicionais. Para produzir uma representação visual unificada, cada uma dessas linhas mantém as mesmas características de largura e cor.

2.2. Validando o Ponto B Usando Retrações de Fibonacci de XA

Verificaremos a mínima de swing B nesta seção observando se ele permanece acima do nível de 78.6% e cai abaixo do nível de retração de 61.8% de XA. Como garante que o ponto B esteja em conformidade com os índices de Fibonacci necessários, que ajudam a definir a estrutura do padrão, essa fase de validação é essencial na negociação de padrões de alta. Há uma chance maior de uma configuração harmônica legítima se B estiver nesse intervalo. Caso contrário, o padrão pode não ser genuíno ou precisar de mais confirmação se B estiver muito alto ou muito baixo.

Primeiro determinamos os níveis de retração de Fibonacci para a perna XA para realizar essa validação. A retração de Fibonacci é um método popular de análise técnica para identificar possíveis reversões da ação do preço.

Usaremos as ferramentas gráficas no MQL5 para adicionar um objeto de retração de Fibonacci à representação do gráfico além de validar B. A ferramenta de Fibonacci será plotada usando a função ObjectCreate(), com X servindo como ponto inicial e A como ponto final. Depois que o objeto tiver sido criado, nós o modificaremos incluindo níveis adicionais de Fibonacci que o MetaTrader 5 não suporta por padrão. Isso garante a exibição de todas as zonas de retração pertinentes.

Exemplo:

//Fibo
string XA_fibo; // Unique name for XA fibo
double lvl_61_8; // Level 61.8
double lvl_78_6; // Level 78.6
string fibo_618_786; // Unique name for the object that marks 61.8 and 78.6.
string fibo_78_6_txt; // Unique name for text "78.6" cause its not available by default
for(int m = l; m < rates_total - (LookbackBars / 2); m++)
  {
   if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
     {
      D = low[m]; // Price of the swing low (D).
      D_time = time[m]; // Time of the swing low (D).
      D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
      D_letter = StringFormat("D%d", m); // Unique name for the text label object.

      //D
      ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
      ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
      ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
      ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

      //C
      c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time, D_time);
      c_highest_index = ArrayMaximum(high,l, c_d_bars);

      c_d_hh = high[c_highest_index]; //C - D Highest High and time
      c_d_hh_t = time[c_highest_index];

      ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
      ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
      ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
      ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

      //B
      b_c_bars = Bars(_Symbol,PERIOD_CURRENT,B_time, c_d_hh_t);
      b_lowest_index = ArrayMinimum(low,k, b_c_bars);

      b_c_ll = low[b_lowest_index]; //B - C Lowest Low and time
      b_c_ll_t = time[b_lowest_index];

      ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
      ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
      ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
      ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

      //A
      a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time, b_c_ll_t);
      a_highest_index = ArrayMaximum(high,j, a_b_bars);

      a_b_hh = high[a_highest_index]; //A - B Highest High and time
      a_b_hh_t = time[a_highest_index];

      ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
      ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
      ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
      ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
      ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

      //X
      x_a_bars = Bars(_Symbol,PERIOD_CURRENT,X_time, a_b_hh_t);
      x_lowest_index = ArrayMinimum(low,i, x_a_bars);

      x_a_ll = low[x_lowest_index]; //X - A Lowest Low and time
      x_a_ll_t = time[x_lowest_index];

      ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
      ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
      ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

      XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
      ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
      ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

      AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
      ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
      ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

      BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
      ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
      ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

      CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
      ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
      ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
      ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

      lvl_61_8 = a_b_hh - ((61.8/100) * (a_b_hh - x_a_ll)); // Calculating level 61.8
      lvl_78_6 = a_b_hh - ((78.6/100) * (a_b_hh - x_a_ll)); // Calculating level 78.6

      //XA FIBO
      XA_fibo = StringFormat("XA FIB0 %d", i);
      ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create XA fibo
      ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
      for(int i = 1; i <= 6; i++)
        {

         ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown

        }

      fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 %d", i);
      fibo_78_6_txt = StringFormat("Fibo 78.6 Text %d", i);

      ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_ll_t, lvl_61_8,b_c_ll_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
      ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

      ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_ll_t,lvl_78_6); // Create text for level 78.6
      ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
      ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
      ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size

      if(overlap == false)
        {
         i = m;
        }
      if(overlap == true)
        {
         i = i;
        }
      break;

     }
  }
Saídas:

Figura 11. Fibo

Explicação:

Para confirmar que o ponto B está localizado dentro de um determinado intervalo, aplicamos a retração de Fibonacci para a perna XA nesta seção. Na análise técnica, a retração de Fibonacci é frequentemente utilizada para identificar possíveis zonas de reversão. Ela é essencial para verificar se o ponto B corresponde à retração esperada de XA. Em particular, B deve idealmente estar no intervalo entre os níveis de retração de 61.8% e 78.6% de XA. Será mais simples determinar se o ponto B está dentro do intervalo aceitável se construirmos um objeto de retração de Fibonacci e destacarmos essa zona no gráfico. Primeiro estabelecemos algumas variáveis importantes para realizar isso. Para garantir que cada desenho de Fibonacci seja corretamente identificado, a variável XA_fibo mantém um nome exclusivo para o objeto de retração de Fibonacci.

O objeto de retração de Fibonacci na perna XA é criado usando a função ObjectCreate() após os níveis terem sido determinados. Você pode entender como o preço interage com os níveis de Fibonacci observando esse objeto, que se estende do ponto X (mínima) até o ponto A (máxima). Definimos o número de níveis de Fibonacci como seis e alteramos sua cor para SaddleBrown para melhorar a clareza da visualização e garantir que cada nível seja facilmente observável e distinto dos outros elementos do gráfico. 

Também destacamos ainda mais a zona de retração de 61.8% a 78.6% criando um objeto retangular que chama atenção para ela, pois é uma área importante. É simples determinar se o ponto B está dentro do intervalo esperado porque o retângulo abrange os níveis de 61.8% e 78.6%. Isso facilita a validação rápida do padrão sem exigir verificações trabalhosas dos níveis de retração. Além disso, o retângulo possui a cor SaddleBrown, o que mantém o conceito visual do gráfico consistente.

Também incluímos um rótulo de texto para o nível de retração de 78.6%, que é outra alteração significativa. Geramos manualmente um objeto de texto para exibir "78.6" no nível de preço relevante porque a ferramenta de Fibonacci do MetaTrader 5 não contém esse nível por padrão. Isso aumenta a precisão da identificação de padrões harmônicos ao garantir que os traders possam observar a localização exata da retração de 78.6%. Facilitamos a verificação se o ponto B é legítimo dentro do padrão harmônico ao implementar essas alterações. Uma técnica precisa e visualmente intuitiva para validar padrões harmônicos é garantida pelo objeto de retração de Fibonacci, pela zona marcada de 61.8% – 78.6% e pelo rótulo de texto adicional. 

Devemos garantir que todos os objetos do gráfico sejam desenhados somente quando os requisitos para um padrão válido forem satisfeitos agora que temos tudo o que precisamos. Em particular, o ponto D deve estar abaixo do ponto X, e o ponto B deve estar dentro da retração de 61.8% a 78.6% de XA. Nenhum objeto deve ser adicionado ao gráfico se esses requisitos não forem atendidos.

Exemplo:

for(int m = l; m < rates_total - (LookbackBars / 2); m++)
  {
   if(IsSwingLow(low, m, LookbackBars / 2) && time[m] > C_time)
     {
      D = low[m]; // Price of the swing low (D).
      D_time = time[m]; // Time of the swing low (D).
      D_line = StringFormat("DLow%d", m); // Unique name for the trend line object.
      D_letter = StringFormat("D%d", m); // Unique name for the text label object.

      //C
      c_d_bars = Bars(_Symbol,PERIOD_CURRENT,C_time, D_time);
      c_highest_index = ArrayMaximum(high,l, c_d_bars);

      c_d_hh = high[c_highest_index]; //C - D Highest High and time
      c_d_hh_t = time[c_highest_index];

      //B
      b_c_bars = Bars(_Symbol,PERIOD_CURRENT,B_time, c_d_hh_t);
      b_lowest_index = ArrayMinimum(low,k, b_c_bars);

      b_c_ll = low[b_lowest_index]; //B - C Lowest Low and time
      b_c_ll_t = time[b_lowest_index];

      //A
      a_b_bars = Bars(_Symbol,PERIOD_CURRENT,A_time, b_c_ll_t);
      a_highest_index = ArrayMaximum(high,j, a_b_bars);

      a_b_hh = high[a_highest_index]; //A - B Highest High and time
      a_b_hh_t = time[a_highest_index];

      //X
      x_a_bars = Bars(_Symbol,PERIOD_CURRENT,X_time, a_b_hh_t);
      x_lowest_index = ArrayMinimum(low,i, x_a_bars);

      x_a_ll = low[x_lowest_index]; //X - A Lowest Low and time
      x_a_ll_t = time[x_lowest_index];

      lvl_61_8 = a_b_hh - ((61.8/100) * (a_b_hh - x_a_ll)); // Calculating level 61.8
      lvl_78_6 = a_b_hh - ((78.6/100) * (a_b_hh - x_a_ll)); // Calculating level 78.6

      if((b_c_ll <= lvl_61_8 && b_c_ll >= lvl_78_6) && (D < x_a_ll))
        {

         //D
         ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
         ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
         ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
         ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

         //C
         ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
         ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
         ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
         ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

         //B
         ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
         ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
         ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
         ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

         //A
         ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
         ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
         ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
         ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
         ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

         //X
         ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
         ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
         ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

         XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
         ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
         ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

         AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
         ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
         ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

         BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
         ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
         ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

         CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
         ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
         ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
         ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

         //XA FIBO
         XA_fibo = StringFormat("XA FIB0 %d", i);
         ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create XA fibo
         ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
         for(int i = 1; i <= 6; i++)
           {
            ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown
           }

         fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 %d", i);
         fibo_78_6_txt = StringFormat("Fibo 78.6 Text %d", i);

         ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_ll_t, lvl_61_8,b_c_ll_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
         ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

         ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_ll_t,lvl_78_6); // Create text for level 78.6
         ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
         ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
         ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size

        }

      if(overlap == false)
        {
         i = m;
        }
      if(overlap == true)
        {
         i = i;
        }
      break;
     }
  }

Saídas:

Figura 12. B e X

Explicação:

Ao ser avaliada como verdadeira, a condição if ((b_c_ll <= lvl_61_8 && b_c_ll >= lvl_78_6) && (D < x_a_ll)) garante que todos os objetos do gráfico sejam desenhados somente quando um padrão harmônico apropriado for encontrado. Isso impede que itens desnecessários sobrecarreguem o gráfico com padrões incorretos. O script então cria e exibe todos os componentes necessários, como os níveis de retração de Fibonacci, linhas de tendência conectando X, A, B, C e D, e rótulos de texto identificando cada ponto importante, quando o requisito é atendido. Ao garantir que o indicador exiba apenas padrões corretamente formados, esse método melhora a precisão e preserva uma exibição de gráfico clara e informativa.

2.3. Visualizando os Triângulos XAB e BCD

Para visualizar melhor o padrão harmônico, marcaremos as formações XAB e BCD com triângulos nesta seção. Como auxílio visual, esses triângulos facilitarão o reconhecimento e a análise da estrutura do padrão no gráfico.

Isso será realizado conectando os pontos X, A e B para o primeiro triângulo e B, C e D para o segundo triângulo usando objetos OBJ_TRIANGLE. O triângulo BCD representará a última perna do padrão, reforçando a estrutura que leva ao ponto D, a possível zona de reversão, enquanto o triângulo XAB enfatizará a primeira perna, confirmando a relação entre X, A e B.

Exemplo:

string X_A_B;
string B_C_D;
if((b_c_ll <= lvl_61_8 && b_c_ll >= lvl_78_6) && (D < x_a_ll))
  {

//D
   ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
   ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
   ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
   ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

//C
   ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_hh_t, c_d_hh); // Create text object for C
   ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
   ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_hh_t,C,time[c_highest_index+LookbackBars],c_d_hh); // Create line to mark C
   ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

//B
   ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_ll_t, b_c_ll); // Create text object for B
   ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
   ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,time[b_lowest_index+LookbackBars],b_c_ll); // Create line to mark B
   ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

//A
   ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_hh_t, a_b_hh); // Create text object for A
   ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
   ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
   ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,time[a_highest_index+LookbackBars],a_b_hh); // Create line to mark A
   ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

//X
   ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_ll_t, x_a_ll); // Create text object for X
   ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
   ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,time[x_lowest_index+LookbackBars],x_a_ll); // Create line to mark X

   XA_line = StringFormat("XA Line%d", m); // Unique name for the XA line.
   ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create line to connect XA
   ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

   AB_line = StringFormat("AB Line%d", m); // Unique name for the AB line.
   ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_hh_t,a_b_hh,b_c_ll_t,b_c_ll); // Create line to connect AB
   ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

   BC_line = StringFormat("BC Line%d", m); // Unique name for the BC line.
   ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_ll_t,b_c_ll,c_d_hh_t,c_d_hh); // Create line to connect BC
   ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

   CD_line = StringFormat("CD Line%d", m); // Unique name for the CD line.
   ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_hh_t,c_d_hh,D_time,D); // Create line to connect CD
   ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
   ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

//XA FIBO
   XA_fibo = StringFormat("XA FIB0 %d", i);
   ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_ll_t,x_a_ll,a_b_hh_t,a_b_hh); // Create XA fibo
   ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
   for(int i = 1; i <= 6; i++)
     {
      ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown
     }

   fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 %d", i);
   fibo_78_6_txt = StringFormat("Fibo 78.6 Text %d", i);

   ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_ll_t, lvl_61_8,b_c_ll_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
   ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

   ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_ll_t,lvl_78_6); // Create text for level 78.6
   ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
   ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
   ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size

   X_A_B = StringFormat("XAB %d", i);
   ObjectCreate(chart_id,X_A_B,OBJ_TRIANGLE,0,x_a_ll_t,x_a_ll, a_b_hh_t, a_b_hh, b_c_ll_t, b_c_ll);
   ObjectSetInteger(chart_id,X_A_B,OBJPROP_COLOR,clrCornflowerBlue);
   ObjectSetInteger(chart_id,X_A_B,OBJPROP_FILL,true);

   B_C_D = StringFormat("BCD %d", i);
   ObjectCreate(chart_id,B_C_D,OBJ_TRIANGLE,0,b_c_ll_t,b_c_ll, c_d_hh_t, c_d_hh, D_time, D);
   ObjectSetInteger(chart_id,B_C_D,OBJPROP_COLOR,clrCornflowerBlue);
   ObjectSetInteger(chart_id,B_C_D,OBJPROP_FILL,true);
  }

Saídas:

Figura 13. Padrão de Alta

Explicação:

Nomes exclusivos para os triângulos que constituem os segmentos XAB e BCD do padrão harmônico são armazenados nas variáveis X_A_B e B_C_D. Três pontos — X, A e B — são usados para gerar o triângulo X_A_B. Esses pontos são identificados por seus respectivos timestamps e valores de preço (x_a_ll_t, x_a_ll, a_b_hh_t, a_b_hh, b_c_ll_t, b_c_ll). O triângulo B_C_D, que utiliza (b_c_ll_t, b_c_ll, c_d_hh_t, c_d_hh, D_time, D), da mesma forma conecta B, C e D. StringFormat() é usado para fornecer a cada triângulo um nome exclusivo, permitindo o desenho de vários padrões sem problemas de nomenclatura.

ObjectSetInteger() é usado para definir as características visuais dos triângulos depois que eles foram gerados usando ObjectCreate(). O atributo OBJPROP_FILL é definido como true, garantindo que os triângulos sejam preenchidos em vez de apenas contornados, e ambos os triângulos recebem a cor Cornflower Blue (clrCornflowerBlue). Ao melhorar a clareza e facilitar a verificação de possíveis oportunidades de negociação, esses componentes visuais ajudam os traders a identificar rapidamente a estrutura do padrão.

2.4. Indicando Ponto de Entrada, Stop Loss e Take Profit

Nesta seção, definiremos o ponto de entrada, stop loss (SL) e take profit (TP) para identificar os níveis importantes de negociação para o padrão harmônico descoberto. O ponto D, o swing low mais baixo do padrão, é onde o stop loss é definido. Como os padrões harmônicos preveem reversões de preço, definir o stop loss em D minimiza possíveis perdas ao garantir que o padrão seja invalidado se o mercado subir acima desse nível.

O ponto de entrada é o índice do ponto D mais metade de LookbackBars. Isso permite um pequeno atraso após a identificação de D, possibilitando a confirmação da ação do preço antes de realizar uma transação. Como o ponto C é a máxima de swing antes do movimento de alta esperado, ele serve como nível de take profit. Rótulos e linhas horizontais para os níveis de SL, entrada e TP são criados para representar esses níveis no gráfico. Esses itens garantem clareza ao negociar com base no padrão, ajudando os traders a identificar rapidamente a configuração da operação.

Exemplo:

//Signal
string buy_txt;
string sell_txt;
string entry_line;
string tp_line;
string sl_line;
string tp_txt;
string sl_txt;
buy_txt = StringFormat("Buy %d", i);

ObjectCreate(chart_id,buy_txt,OBJ_TEXT,0,time[m + (LookbackBars / 2)],open[m  + (LookbackBars / 2)]);
ObjectSetString(chart_id,buy_txt,OBJPROP_TEXT,"BUY");
ObjectSetInteger(chart_id,buy_txt,OBJPROP_COLOR,clrCornflowerBlue);
ObjectSetInteger(chart_id,buy_txt,OBJPROP_FONTSIZE,10);

entry_line = StringFormat("Buy Entry Line %d", i);
ObjectCreate(chart_id,entry_line,OBJ_TREND,0,time[m  + (LookbackBars / 2)],open[m  + (LookbackBars / 2)], c_d_hh_t,open[m  + (LookbackBars / 2)]);
ObjectSetInteger(chart_id,entry_line,OBJPROP_WIDTH,3);
ObjectSetInteger(chart_id,entry_line,OBJPROP_COLOR,clrCornflowerBlue);

sl_txt = StringFormat("Buy SL %d", i);
ObjectCreate(chart_id,sl_txt,OBJ_TEXT,0,time[m + (LookbackBars / 2)],D);
ObjectSetString(chart_id,sl_txt,OBJPROP_TEXT,"SL");
ObjectSetInteger(chart_id,sl_txt,OBJPROP_COLOR,clrCornflowerBlue);
ObjectSetInteger(chart_id,sl_txt,OBJPROP_FONTSIZE,10);

sl_line = StringFormat("Buy SL Line %d", i);
ObjectCreate(chart_id,sl_line,OBJ_TREND,0,time[m + (LookbackBars / 2)],D,c_d_hh_t,D);
ObjectSetInteger(chart_id,sl_line,OBJPROP_WIDTH,3);
ObjectSetInteger(chart_id,sl_line,OBJPROP_COLOR,clrCornflowerBlue);

tp_txt = StringFormat("Buy TP %d", i);
ObjectCreate(chart_id,tp_txt,OBJ_TEXT,0,time[m +(LookbackBars / 2)],c_d_hh);
ObjectSetString(chart_id,tp_txt,OBJPROP_TEXT,"TP");
ObjectSetInteger(chart_id,tp_txt,OBJPROP_COLOR,clrCornflowerBlue);
ObjectSetInteger(chart_id,tp_txt,OBJPROP_FONTSIZE,10);

tp_line = StringFormat("Buy TP Line %d", i);
ObjectCreate(chart_id,tp_line,OBJ_TREND,0,time[m + (LookbackBars / 2)],c_d_hh,c_d_hh_t,c_d_hh);
ObjectSetInteger(chart_id,tp_line,OBJPROP_WIDTH,3);
ObjectSetInteger(chart_id,tp_line,OBJPROP_COLOR,clrCornflowerBlue);

Saídas:

Figura 14. Sinais

Explicação:

O sinal de compra, ponto de entrada, stop loss (SL) e níveis de take profit (TP) para o padrão harmônico são definidos e criados como objetos visuais no gráfico nesta seção. Para garantir que os itens sejam facilmente mantidos e identificados no gráfico, as variáveis buy_txt, sell_txt, entry_line, tp_line, sl_line, tp_txt e sl_txt armazenam nomes exclusivos para os objetos correspondentes. No ponto de entrada, o objeto buy_txt é um rótulo de texto que exibe "BUY" para indicar a direção da operação. A configuração da operação é claramente visualizada graças à entry_line, uma linha de tendência horizontal que indica o preço de entrada em open[m + (LookbackBars / 2)].

Da mesma forma, o rótulo de stop loss e sua linha de tendência associada são representados por sl_txt e sl_line, respectivamente, e ambos estão posicionados em D, a mínima de swing mais baixo do padrão. O stop loss garante que a operação seja anulada se o preço subir acima desse limite. Tp_txt e tp_line, que estão posicionados em c_d_hh, a máxima de swing anterior, indicam o nível de take profit. Esses elementos gráficos são definidos com uma cor distinta (clrCornflowerBlue) para que você possa reconhecer rapidamente níveis importantes de negociação no gráfico. Esses componentes apoiam o desenvolvimento de uma estratégia de negociação organizada e transparente baseada no padrão harmônico.


3. Construindo Padrões Harmônicos de Baixa

A mesma lógica que utilizamos para identificar padrões harmônicos de alta será modificada para padrões de baixa nesta parte. Não há necessidade de enfatizar excessivamente cada detalhe porque isso é apenas o oposto do padrão de alta. Uma máxima de swing agora será representada por X, uma mínima de swing por A, uma máxima de swing por B, uma mínima de swing por C e uma máxima de swing final por D. Essa é a principal diferença. Isso garante que o padrão represente com precisão um cenário de baixa, indicando um possível momento de venda.

O ponto B ainda será verificado usando os níveis de retração de Fibonacci para garantir que esteja dentro do intervalo apropriado em relação à perna XA. Da mesma forma, o padrão será delineado por linhas de tendência, triângulos e outros elementos do gráfico, mas suas localizações serão modificadas para se adequar à estrutura de baixa. A entrada será definida no índice de D mais metade de LookbackBars, o take-profit (TP) no ponto C e o stop-loss (SL) no ponto D. A mesma lógica continua válida porque isso é realmente o inverso do padrão de alta; portanto, não repetiremos os argumentos em grande detalhe.

Exemplo:

int x_highest_index;   // Stores the index of the highest price point (X) in the pattern
double x_a_hh;         // Holds the price value of the swing high at point X
datetime x_a_hh_t;     // Stores the timestamp of when the swing high at X occurred

int a_lowest_index;   // Stores the index of the lowest price point (A) in the pattern
double a_b_ll;        // Holds the price value of the swing low at point A
datetime a_b_ll_t;    // Stores the timestamp of when the swing low at A occurred

int b_highest_index;   // Stores the index of the highest price point (B) in the pattern
double b_c_hh;         // Holds the price value of the swing high at point B
datetime b_c_hh_t;     // Stores the timestamp of when the swing high at B occurred
int c_lowest_index;   // Stores the index of the lowest price point (C) in the pattern
double c_d_ll;        // Holds the price value of the swing low at point C
datetime c_d_ll_t;    // Stores the timestamp of when the swing low at C occurred
if(rates_total >= bars_check)
  {
   for(int i = rates_total - bars_check; i < rates_total - LookbackBars; i++)
     {
      if(IsSwingHigh(high, i, LookbackBars))
        {

         X = high[i];                   // Assign the highest price at index 'i' to X
         X_time = time[i];              // Assign the corresponding time value to X_time
         X_line = StringFormat("XHigh%d", i);  // Create a unique string identifier for the X-high trendline
         X_letter = StringFormat("XB%d", i);   // Create a unique string identifier for the X-high label

         for(int j = i; j < rates_total - LookbackBars; j++)
           {
            if(IsSwingLow(low, j, LookbackBars) && time[j] > X_time)
              {
               A = low[j];                    // Assign the lowest price at index 'j' to A
               A_time = time[j];               // Assign the corresponding time value to A_time
               A_line = StringFormat("ALow%d", j);  // Create a unique string identifier for the A-low trendline
               A_letter = StringFormat("AB%d", j);  // Create a unique string identifier for the A-low label

               for(int k = j; k < rates_total - LookbackBars; k++)
                 {
                  if(IsSwingHigh(high, k, LookbackBars) && time[k] > A_time)
                    {

                     B = high[k];                    // Assign the highest price at index 'k' to B
                     B_time = time[k];                // Assign the corresponding time value to B_time
                     B_line = StringFormat("BHigh%d", k);  // Create a unique string identifier for the B-high trendline
                     B_letter = StringFormat("BB%d", k);   // Create a unique string identifier for the B-high label

                     for(int l = k; l < rates_total - LookbackBars; l++)
                       {
                        if(IsSwingLow(low, l, LookbackBars) && time[l] > B_time)
                          {

                           C = low[l];                      // Assign the lowest price at index 'l' to C
                           C_time = time[l];                // Assign the corresponding time value to C_time
                           C_line = StringFormat("CLow%d", l);  // Create a unique string identifier for the C-low trendline
                           C_letter = StringFormat("CB%d", l);   // Create a unique string identifier for the C-low label

                           for(int m = l; m < rates_total - (LookbackBars / 2); m++)
                             {
                              if(IsSwingHigh(high, m, LookbackBars / 2) && time[m] > C_time)
                                {
                                 D = high[m];                      // Assign the highest price at index 'm' to D
                                 D_time = time[m];                 // Assign the corresponding time value to D_time
                                 D_line = StringFormat("DHigh%d", m);  // Create a unique string identifier for the D-high trendline
                                 D_letter = StringFormat("DB%d", m);   // Create a unique string identifier for the D-high label

                                 // C - D Segment: Find the lowest low between C and D
                                 c_d_bars = Bars(_Symbol, PERIOD_CURRENT, C_time, D_time); // Count the number of bars between C and D
                                 c_lowest_index = ArrayMinimum(low, l, c_d_bars); // Find the index of the lowest low in the range

                                 c_d_ll = low[c_lowest_index]; // Store the lowest low (C - D lowest point)
                                 c_d_ll_t = time[c_lowest_index]; // Store the corresponding time for C - D

                                 // B - C Segment: Find the highest high between B and C
                                 b_c_bars = Bars(_Symbol, PERIOD_CURRENT, B_time, c_d_ll_t); // Count the number of bars between B and C
                                 b_highest_index = ArrayMaximum(high, k, b_c_bars); // Find the index of the highest high in the range

                                 b_c_hh = high[b_highest_index]; // Store the highest high (B - C highest point)
                                 b_c_hh_t = time[b_highest_index]; // Store the corresponding time for B - C

                                 // A - B Segment: Find the lowest low between A and B
                                 a_b_bars = Bars(_Symbol, PERIOD_CURRENT, A_time, b_c_hh_t); // Count the number of bars between A and B
                                 a_lowest_index = ArrayMinimum(low, j, a_b_bars); // Find the index of the lowest low in the range

                                 a_b_ll = low[a_lowest_index]; // Store the lowest low (A - B lowest point)
                                 a_b_ll_t = time[a_lowest_index]; // Store the corresponding time for A - B

                                 // X - A Segment: Find the highest high between X and A
                                 x_a_bars = Bars(_Symbol, PERIOD_CURRENT, X_time, a_b_ll_t); // Count the number of bars between X and A
                                 x_highest_index = ArrayMaximum(high, i, x_a_bars); // Find the index of the highest high in the range

                                 x_a_hh = high[x_highest_index]; // Store the highest high (X - A highest point)
                                 x_a_hh_t = time[x_highest_index]; // Store the corresponding time for X - A

                                 // Fibonacci Retracement Levels: Calculate 61.8% and 78.6% retracement levels from X to A
                                 lvl_61_8 = a_b_ll + ((61.8 / 100) * (x_a_hh - a_b_ll)); // 61.8% retracement level
                                 lvl_78_6 = a_b_ll + ((78.6 / 100) * (x_a_hh - a_b_ll)); // 78.6% retracement level

                                 if((b_c_hh >= lvl_61_8 && b_c_hh <= lvl_78_6) && (D > x_a_hh))
                                   {
                                    //D
                                    ObjectCreate(chart_id, D_letter, OBJ_TEXT, 0, D_time, D); // Create text object for D
                                    ObjectSetString(chart_id, D_letter, OBJPROP_TEXT, "D"); // Set the text to "D".
                                    ObjectSetInteger(chart_id,D_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,D_line,OBJ_TREND,0,D_time,D,time[m+LookbackBars],D); // Create line to mark D
                                    ObjectSetInteger(chart_id,D_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //C
                                    ObjectCreate(chart_id, C_letter, OBJ_TEXT, 0, c_d_ll_t, c_d_ll); // Create text object for C
                                    ObjectSetString(chart_id, C_letter, OBJPROP_TEXT, "C"); // Set the text to "C".
                                    ObjectSetInteger(chart_id,C_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,C_line,OBJ_TREND,0,c_d_ll_t,C,time[c_lowest_index+LookbackBars],c_d_ll); // Create line to mark C
                                    ObjectSetInteger(chart_id,C_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown

                                    //B
                                    ObjectCreate(chart_id, B_letter, OBJ_TEXT, 0, b_c_hh_t, b_c_hh); // Create text object for B
                                    ObjectSetString(chart_id, B_letter, OBJPROP_TEXT, "B"); // Set the text to "B".
                                    ObjectSetInteger(chart_id,B_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,B_line,OBJ_TREND,0,b_c_hh_t,b_c_hh,time[b_highest_index+LookbackBars],b_c_hh); // Create line to mark B
                                    ObjectSetInteger(chart_id,B_line,OBJPROP_COLOR,clrMidnightBlue); // Set line color to MidnightBlue

                                    //A
                                    ObjectCreate(chart_id, A_letter, OBJ_TEXT, 0, a_b_ll_t, a_b_ll); // Create text object for A
                                    ObjectSetString(chart_id, A_letter, OBJPROP_TEXT, "A"); // Set the text to "A".
                                    ObjectSetInteger(chart_id,A_letter,OBJPROP_COLOR,clrGreen); // Set text color to green
                                    ObjectCreate(chart_id,A_line,OBJ_TREND,0,a_b_ll_t,a_b_ll,time[a_lowest_index+LookbackBars],a_b_ll); // Create line to mark A
                                    ObjectSetInteger(chart_id,A_line,OBJPROP_COLOR,clrGreen); // Set line color to green

                                    //X
                                    ObjectCreate(chart_id, X_letter, OBJ_TEXT, 0, x_a_hh_t, x_a_hh); // Create text object for X
                                    ObjectSetString(chart_id, X_letter, OBJPROP_TEXT, "X"); // Set the text to "X".
                                    ObjectCreate(chart_id,X_line,OBJ_TREND,0,x_a_hh_t,x_a_hh,time[x_highest_index+LookbackBars],x_a_hh); // Create line to mark X

                                    XA_line = StringFormat("XA LineB%d", m); // Unique name for the XA line.
                                    ObjectCreate(chart_id,XA_line,OBJ_TREND,0,x_a_hh_t,x_a_hh,a_b_ll_t,a_b_ll); // Create line to connect XA
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,XA_line,OBJPROP_WIDTH,3); // Line width

                                    AB_line = StringFormat("AB LineB%d", m); // Unique name for the AB line.
                                    ObjectCreate(chart_id,AB_line,OBJ_TREND,0,a_b_ll_t,a_b_ll,b_c_hh_t,b_c_hh); // Create line to connect AB
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,AB_line,OBJPROP_WIDTH,3); // Line width

                                    BC_line = StringFormat("BC LineB%d", m); // Unique name for the BC line.
                                    ObjectCreate(chart_id,BC_line,OBJ_TREND,0,b_c_hh_t,b_c_hh,c_d_ll_t,c_d_ll); // Create line to connect BC
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,BC_line,OBJPROP_WIDTH,3); // Line width

                                    CD_line = StringFormat("CD LineB%d", m); // Unique name for the CD line.
                                    ObjectCreate(chart_id,CD_line,OBJ_TREND,0,c_d_ll_t,c_d_ll,D_time,D); // Create line to connect CD
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_COLOR,clrSaddleBrown); // Set line color to SaddleBrown
                                    ObjectSetInteger(chart_id,CD_line,OBJPROP_WIDTH,3); // Line width

                                    //XA FIBO
                                    XA_fibo = StringFormat("XA FIB0 B%d", i);
                                    ObjectCreate(chart_id,XA_fibo,OBJ_FIBO,0,x_a_hh_t,x_a_hh,a_b_ll_t,a_b_ll); // Create XA fibo
                                    ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELS,6); // Number of default levels
                                    for(int i = 1; i <= 6; i++)
                                      {
                                       ObjectSetInteger(chart_id,XA_fibo,OBJPROP_LEVELCOLOR,i,clrSaddleBrown); // Set each level color to SaddleBrown
                                      }

                                    fibo_618_786 = StringFormat("Fibo 78.6 - 61.8 B%d", i);
                                    fibo_78_6_txt = StringFormat("Fibo 78.6 Text B%d", i);

                                    ObjectCreate(chart_id,fibo_618_786,OBJ_RECTANGLE,0,x_a_hh_t, lvl_61_8,b_c_hh_t,lvl_78_6); // Create rectangle object marking 61.8 and 78.6
                                    ObjectSetInteger(chart_id,fibo_618_786,OBJPROP_COLOR,clrSaddleBrown); // Set color to clrSaddleBrown

                                    ObjectCreate(chart_id,fibo_78_6_txt,OBJ_TEXT,0,b_c_hh_t,lvl_78_6); // Create text for level 78.6
                                    ObjectSetString(chart_id,fibo_78_6_txt,OBJPROP_TEXT,"78.6"); // Text to be displayed
                                    ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_COLOR,clrSaddleBrown); // Set text color
                                    ObjectSetInteger(chart_id,fibo_78_6_txt,OBJPROP_FONTSIZE,8); // Set text size
                                    // Create and format the first bearish harmonic pattern (XAB)
                                    X_A_B = StringFormat("XAB B%d", i);
                                    ObjectCreate(chart_id, X_A_B, OBJ_TRIANGLE, 0, x_a_hh_t, x_a_hh, a_b_ll_t, a_b_ll, b_c_hh_t, b_c_hh);
                                    ObjectSetInteger(chart_id, X_A_B, OBJPROP_COLOR, clrMistyRose); // Set color for the pattern
                                    ObjectSetInteger(chart_id, X_A_B, OBJPROP_FILL, true); // Fill the triangle shape

                                    // Create and format the second bearish harmonic pattern (BCD)
                                    B_C_D = StringFormat("BCD B%d", i);
                                    ObjectCreate(chart_id, B_C_D, OBJ_TRIANGLE, 0, b_c_hh_t, b_c_hh, c_d_ll_t, c_d_ll, D_time, D);
                                    ObjectSetInteger(chart_id, B_C_D, OBJPROP_COLOR, clrMistyRose);
                                    ObjectSetInteger(chart_id, B_C_D, OBJPROP_FILL, true);

                                    // Create and format the SELL text at the entry position
                                    sell_txt = StringFormat("Sell %d", i);
                                    ObjectCreate(chart_id, sell_txt, OBJ_TEXT, 0, time[m + (LookbackBars / 2)], open[m + (LookbackBars / 2)]);
                                    ObjectSetString(chart_id, sell_txt, OBJPROP_TEXT, "SELL");
                                    ObjectSetInteger(chart_id, sell_txt, OBJPROP_COLOR, clrMagenta); // Set text color
                                    ObjectSetInteger(chart_id, sell_txt, OBJPROP_FONTSIZE, 10); // Set font size

                                    // Create and format the SELL entry line
                                    entry_line = StringFormat("Sell Entry Line %d", i);
                                    ObjectCreate(chart_id, entry_line, OBJ_TREND, 0, time[m + (LookbackBars / 2)], open[m + (LookbackBars / 2)], c_d_ll_t, open[m + (LookbackBars / 2)]);
                                    ObjectSetInteger(chart_id, entry_line, OBJPROP_WIDTH, 3); // Set line thickness
                                    ObjectSetInteger(chart_id, entry_line, OBJPROP_COLOR, clrMagenta); // Set line color

                                    // Create and format the Stop Loss (SL) text
                                    sl_txt = StringFormat("Sell SL %d", i);
                                    ObjectCreate(chart_id, sl_txt, OBJ_TEXT, 0, time[m + (LookbackBars / 2)], D);
                                    ObjectSetString(chart_id, sl_txt, OBJPROP_TEXT, "SL");
                                    ObjectSetInteger(chart_id, sl_txt, OBJPROP_COLOR, clrMagenta);
                                    ObjectSetInteger(chart_id, sl_txt, OBJPROP_FONTSIZE, 10);

                                    // Create and format the Stop Loss (SL) line
                                    sl_line = StringFormat("Sell SL Line %d", i);
                                    ObjectCreate(chart_id, sl_line, OBJ_TREND, 0, time[m + (LookbackBars / 2)], D, c_d_ll_t, D);
                                    ObjectSetInteger(chart_id, sl_line, OBJPROP_WIDTH, 3);
                                    ObjectSetInteger(chart_id, sl_line, OBJPROP_COLOR, clrMagenta);

                                    // Create and format the Take Profit (TP) text
                                    tp_txt = StringFormat("Sell TP %d", i);
                                    ObjectCreate(chart_id, tp_txt, OBJ_TEXT, 0, time[m + (LookbackBars / 2)], c_d_ll);
                                    ObjectSetString(chart_id, tp_txt, OBJPROP_TEXT, "TP");
                                    ObjectSetInteger(chart_id, tp_txt, OBJPROP_COLOR, clrMagenta);
                                    ObjectSetInteger(chart_id, tp_txt, OBJPROP_FONTSIZE, 10);

                                    // Create and format the Take Profit (TP) line
                                    tp_line = StringFormat("Sell TP Line %d", i);
                                    ObjectCreate(chart_id, tp_line, OBJ_TREND, 0, time[m + (LookbackBars / 2)], c_d_ll, c_d_ll_t, c_d_ll);
                                    ObjectSetInteger(chart_id, tp_line, OBJPROP_WIDTH, 3);
                                    ObjectSetInteger(chart_id, tp_line, OBJPROP_COLOR, clrMagenta);

                                    if(overlap == false)
                                      {
                                       i = m;
                                      }
                                    if(overlap == true)
                                      {
                                       i = i;
                                      }
                                    break;

                                   }

                                 break;

                                }
                             }

                           break;

                          }
                       }

                     break;

                    }
                 }

               break;

              }
           }

        }
     }
  }

Saídas:

Figura 15. Padrão de Baixa

Explicação:

Encontrar uma máxima de swing em X, que representa o início do padrão, é o primeiro passo no procedimento de detecção. Em seguida, ele procura por uma mínima de swing (A), uma máxima (B), uma mínima (C) e uma máxima (D). Uma estrutura de padrão legítima é garantida verificando cada ponto de acordo com sua posição relativa em relação ao ponto anterior. A validação do padrão depende principalmente dos níveis de retração, especialmente das retrações de Fibonacci de 61.8% e 78.6% de X até A. Uma possível configuração de SELL é encontrada se esses requisitos forem atendidos e D for maior que X.

Explicações detalhadas não serão repetidas porque os padrões harmônicos de baixa e de alta são semelhantes. A principal distinção é que a forma de alta desse padrão prevê um aumento de preço, enquanto esse padrão prevê uma queda de preço. A orientação do padrão e a direção de negociação associada são as únicas diferenças. Fora isso, as ideias fundamentais são as mesmas.


Conclusão

Neste artigo, exploramos como construir um indicador semelhante a Harmonic Patterns usando objetos de gráfico do MetaTrader 5. Abordamos a lógica por trás da detecção dos principais pontos de swing, a estruturação do padrão e sua validação usando níveis de retração de Fibonacci. Ao implementar padrões de alta e de baixa, demonstramos como identificar possíveis oportunidades de negociação com base na ação do preço. Com essa abordagem, você pode visualizar formações harmônicas diretamente em seus gráficos, permitindo uma melhor tomada de decisão sem depender dos buffers tradicionais de indicadores. Esse método aumenta a flexibilidade e fornece uma base sólida para personalização e refinamento adicionais de estratégias de negociação baseadas em padrões.

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/17574

Últimos Comentários | Ir para discussão (6)
ALGOYIN LTD
Israel Pelumi Abioye | 1 abr. 2025 em 12:03
Simon Simson #:
Muito obrigado por seu bom trabalho com essas séries MQL5 .
Olá, Simon.
Obrigado por suas palavras gentis.
Oluwatosin Mary Babalola
Oluwatosin Mary Babalola | 1 abr. 2025 em 12:15
Uau, este é o melhor até agora desde que comecei a acompanhar seus artigos. Continue com o bom trabalho
ALGOYIN LTD
Israel Pelumi Abioye | 1 abr. 2025 em 13:02
Oluwatosin Mary Babalola #:
Uau, este é o melhor até agora desde que comecei a acompanhar seus artigos. Continuem com o bom trabalho
Obrigado.
Louai Habiche
Louai Habiche | 19 abr. 2025 em 17:03

é incrível que você esteja se saindo muito bem com seus artigos, muito obrigado

podemos colocar um alerta quando o show do sihnal for exibido!

ALGOYIN LTD
Israel Pelumi Abioye | 20 abr. 2025 em 10:37
Louai Habiche #:

É incrível que você esteja se saindo muito bem com seus artigos.

podemos colocar um alerta quando o show do sihnal for exibido!

Olá, obrigado por suas palavras gentis. É possível fazer isso usando a função "PlaySound()".

Caminhe em novos trilhos: Personalize indicadores no MQL5 Caminhe em novos trilhos: Personalize indicadores no MQL5
Vou agora listar todas as possibilidades novas e recursos do novo terminal e linguagem. Elas são várias, e algumas novidades valem a discussão em um artigo separado. Além disso, não há códigos aqui escritos com programação orientada ao objeto, é um tópico muito importante para ser simplesmente mencionado em um contexto como vantagens adicionais para os desenvolvedores. Neste artigo vamos considerar os indicadores, sua estrutura, desenho, tipos e seus detalhes de programação em comparação com o MQL4. Espero que este artigo seja útil tanto para desenvolvedores iniciantes quanto para experientes, talvez alguns deles encontrem algo novo.
Estratégias de Reversão à Média com RSI2 de Larry Connors para Day Trading Estratégias de Reversão à Média com RSI2 de Larry Connors para Day Trading
Larry Connors é um trader e autor renomado, mais conhecido por seu trabalho em trading quantitativo e estratégias como o RSI de 2 períodos (RSI2), que ajuda a identificar condições de sobrecompra e sobrevenda de curto prazo no mercado. Neste artigo, primeiro explicaremos a motivação por trás de nossa pesquisa, depois recriaremos três das estratégias mais famosas de Connors em MQL5 e as aplicaremos ao trading intradiário do CFD do índice S&P 500.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Do básico ao intermediário: Arquivo template (II) Do básico ao intermediário: Arquivo template (II)
O artigo mostra como aplicar indicadores a gráficos criados por OBJ_CHART usando templates, quando ChartIndicatorAdd não funciona nesse contexto. Explicamos como salvar um template com o indicador, recuperar o ID do gráfico e aplicar ChartApplyTemplate ao destino correto. Você aprenderá a integrar indicadores como recurso, automatizar a configuração do gráfico embutido e entender limitações práticas, como a não listagem de indicadores na janela padrão.