English Русский 中文 Español Deutsch 日本語
preview
Data Science e ML (Parte 37): Utilizando padrões de Candlestick e IA para superar o mercado

Data Science e ML (Parte 37): Utilizando padrões de Candlestick e IA para superar o mercado

MetaTrader 5 — Sistemas de negociação |
54 7
Omega J Msigwa
Omega J Msigwa

Conteúdo



Introdução

A primeira estratégia que utilizei no trading era baseada em candlesticks. Hoje eu já não a chamaria de estratégia, mas minha primeira operação foi aberta em razão de alguns padrões de candlestick que aprendi ao ler o livro Candlestick Trading Bible, de Honma Munehisa, que me havia sido recomendado por um amigo.

Os padrões de candlestick presentes nos gráficos financeiros são utilizados pelos traders para identificar possíveis movimentos de preço com base em padrões anteriores. Eles são formados pelos movimentos de alta e baixa dos preços que, embora possam parecer aleatórios, são utilizados pelos traders para estimar a direção do preço no curto prazo.

Esse conceito teve origem no século XVIII com um trader chamado Honma Munehisa, considerado um dos traders mais bem-sucedidos da história. Conhecido em sua época como o Deus dos Mercados, estima-se que suas descobertas tenham lhe rendido o equivalente a mais de US$ 10 bilhões em valores atuais. 

Munehisa descobriu que, embora a oferta e a demanda determinassem o preço do arroz, os mercados também eram influenciados pelas emoções humanas.

Essas emoções humanas podem ser refletidas em um candlestick por meio da amplitude dos movimentos de preço e de diferentes cores. Tradicionalmente, um candle preto costuma representar um movimento de baixa, enquanto um candle branco representa um movimento de alta. Atualmente, porém, essas cores não são relevantes, pois podem ser personalizadas em qualquer plataforma de negociação.


Fundamentos de um Candlestick

As sombras ou pavios dos candlesticks mostram os preços máximo e mínimo do período e sua relação com os preços de abertura e fechamento. O formato do candle varia de acordo com a relação entre seus preços OHLC (Open, High, Low e Close — abertura, máxima, mínima e fechamento). Existem diversos padrões de candlestick introduzidos por Munehisa, além de outros surgidos mais recentemente entre traders.

Com base nesses padrões, vamos identificá-los, coletá-los e utilizá-los em modelos de Machine Learning para avaliar de que forma podem agregar valor aos nossos modelos de negociação baseados em IA e verificar se podem verificar se podem nos ajudar a superar o desempenho dos mercados financeiros.


Padrões de Candlestick

Como existem inúmeros padrões de candlestick, abordaremos apenas 10. O principal motivo para essa escolha é que esses padrões são simples de compreender e dependem exclusivamente de uma única barra, ou seja, podem ser detectados na barra atual.

Descartaremos todos os padrões de candlestick cuja detecção exija o processamento de múltiplos candles.

O formato de codificação da classe CTALib foi inspirado na TALib (Technical Analysis Library), uma biblioteca de análise técnica disponível para C#, C++ e Python que oferece diversas funções para detecção de padrões de candlestick.

Candle Branco

Este é um candlestick de alta, no qual o preço de fechamento é superior ao preço de abertura. Esse candlestick simples indica um movimento de alta, não oferece nenhuma previsão. Ele apenas indica a direção do candle.

Podemos implementá-lo da seguinte forma.

bool CTALib::CDLWHITECANDLE(double open, double close)
 {
   return (close > open);
 }

Candle Preto

Ao contrário do candle branco, este é um candlestick de baixa, no qual o preço de abertura é superior ao preço de fechamento. Esse candlestick simples indica um movimento de baixa.

Assim como o candle branco, ele não fornece nenhuma previsão; apenas indica a direção do candle.

bool CTALib::CDLBLACKCANDLE(double open,double close)
 {
   return (open > close);
 }

Padrão de Candlestick Doji

Um candlestick Doji é aquele em que os preços de abertura e fechamento são praticamente iguais. Visualmente, ele pode se parecer com uma cruz, uma cruz invertida ou um sinal de mais. Esse padrão de candlestick é relativamente raro e costuma aparecer em grupos. Normalmente, é interpretado como um sinal de reversão de tendência, embora também possa indicar indecisão do mercado em relação aos preços futuros.

Ele apresenta algumas variações, como mostrado na imagem abaixo.

Criar uma função para detectar um candlestick Doji pode ser desafiador, justamente por causa da própria definição desse padrão. Para que um candle seja considerado um Doji, os preços de abertura e fechamento devem ser iguais. Entretanto, é extremamente raro encontrar preços de abertura e fechamento exatamente iguais, considerando o volume e a volatilidade presentes nos mercados atuais. Mesmo que os preços estejam muito próximos — por exemplo, Open = 1.0000 e Close = 1.0001 —, para um computador esses dois valores continuam sendo diferentes.

Para contornar esse problema, podemos utilizar um valor de tolerância. Sempre que a diferença entre abertura e fechamento estiver dentro desse limite, podemos considerar que os preços estão suficientemente próximos e concluir que se trata de um padrão de candlestick Doji.

bool CTALib::CDLDOJI(double open,double close, double torrelance=3)
 {
   return (fabs(open-close)<torrelance*_Point); //A torrelance in market points
 }

Dragonfly Doji

O padrão de candlestick Dragonfly Doji sinaliza uma possível reversão no preço de um ativo. Quando um padrão Dragonfly Doji aparece durante uma tendência de baixa, ele pode indicar que os preços estão prestes a subir ou que a tendência de baixa pode estar chegando ao fim.

dragonfly doji

Como esse padrão é essencialmente um candlestick Doji com uma sombra inferior mais longa que a sombra superior, no código podemos primeiro verificar se o candle é um Doji e, em seguida, garantir explicitamente que a sombra inferior seja, por padrão, pelo menos duas vezes maior que a sombra superior.

bool CTALib::CDLDRAGONFLYDOJI(double open, 
                              double high, 
                              double low, 
                              double close, 
                              double body_torrelance = 3, 
                              double shadow_ratio = 2.0)
{
   double body_size    = MathAbs(open - close);
   double upper_shadow = upperShadowCalc(open, close, high);
   double lower_shadow = lowerShadowCalc(open, close, low);

   //--- Body is very small (like a Doji)
   if (CDLDOJI(open, close, body_torrelance))
   {
      //--- Lower shadow is significantly longer than upper shadow
      if (lower_shadow > upper_shadow * shadow_ratio)
         return true;
   }

   return false;
}

Gravestone doji

Este é um candlestick Doji com uma longa sombra superior (pavio). Trata-se de um sinal de reversão de baixa que indica uma possível mudança na direção do mercado.

Quando esse candle aparece durante uma tendência de alta, ele pode indicar que a tendência atual está chegando ao fim e que um movimento de baixa pode estar prestes a ocorrer.

Como esse padrão é essencialmente um candlestick Doji com uma sombra superior mais longa que a inferior, no código podemos primeiro verificar se o candle é um Doji e, em seguida, garantir explicitamente que a sombra superior seja, por padrão, pelo menos duas vezes maior que a sombra inferior.

bool CTALib::CDLGRAVESTONEDOJI(double open, 
                               double high, 
                               double low, 
                               double close, 
                               double body_torrelance = 3, 
                               double shadow_ratio = 2.0)
{
   double body_size    = MathAbs(open - close);
   double upper_shadow = upperShadowCalc(open, close, high);
   double lower_shadow = lowerShadowCalc(open, close, low);

   //--- Body is very small (like a Doji)
   if (CDLDOJI(open, close, body_torrelance))
   {
      //--- Lower shadow is significantly longer than upper shadow
      if (upper_shadow > lower_shadow * shadow_ratio)
         return true;
   }

   return false;
}

Hammer

Este é um candle com corpo pequeno na parte superior e uma longa sombra inferior. Trata-se de um sinal de reversão de alta que, quando aparece durante uma tendência de baixa, sinaliza um possível movimento de alta à frente.

Padrão de Candlestick Hammer

Os padrões de candlestick podem ser abstratos e confusos. Em alguns casos, um mesmo padrão pode ser interpretado de maneiras diferentes, dependendo da forma como é analisado e do que se pretende identificar naquele momento. Um padrão Hammer pode ser confundido com um Dragonfly Doji, pois a principal diferença entre eles está no tamanho do corpo, enquanto outras características são semelhantes.

Esse é um dos problemas que encontramos com frequência ao trabalhar com padrões de candlestick.

Podemos contornar esse problema definindo regras explícitas e valores-limite que podem ser ajustados de acordo com determinado instrumento (símbolo) e outras necessidades específicas.

bool CTALib::CDLHAMMER(double open, 
                       double high, 
                       double low, 
                       double close, 
                       double min_body_percentage = 0.2,       // To avoid being a doji
                       double lower_shadow_ratio = 2.0,        // Lower shadow at least 2x the body
                       double upper_shadow_max_ratio = 0.3)    // Upper shadow must be small
{
   double body_size      = MathAbs(open - close);
   double total_range    = high - low + DBL_EPSILON;
   double upper_shadow   = upperShadowCalc(open, close, high);
   double lower_shadow   = lowerShadowCalc(open, close, low);
   double body_percentage = body_size / total_range;

   return (
      body_percentage >= min_body_percentage &&
      lower_shadow >= lower_shadow_ratio * body_size &&
      upper_shadow <= upper_shadow_max_ratio * body_size
   );
}

Como tanto o Dragonfly Doji quanto o Hammer apresentam uma sombra inferior longa, corpo pequeno e sombra superior curta, foi necessário introduzir o parâmetro min_body_percentage para determinar o tamanho mínimo que o corpo deve ter em relação à amplitude total do candle (High-Low) para que ele seja classificado como Hammer. Ao mesmo tempo, verificamos, por padrão, se a sombra inferior é pelo menos duas vezes maior que a sombra superior.

Inverted Hammer

Este padrão é semelhante ao Hammer, porém apresenta um corpo pequeno na parte inferior, uma longa sombra superior e uma pequena sombra inferior.

Esse padrão é encontrado em tendências de baixa e sinaliza a possibilidade de uma reversão de alta no mercado.

inverted hammer

Podemos implementá-lo de forma semelhante ao Hammer, realizando apenas pequenas alterações nas condições relacionadas às sombras.

bool CTALib::CDLINVERTEDHAMMER(double open, 
                               double high, 
                               double low, 
                               double close, 
                               double min_body_percentage = 0.2,        // Avoid doji
                               double upper_shadow_ratio = 2.0,         // Upper shadow must be long
                               double lower_shadow_max_ratio = 0.3)     // Lower shadow should be small
{
   double body_size        = MathAbs(open - close);
   double total_range      = high - low + DBL_EPSILON;
   double upper_shadow     = upperShadowCalc(open, close, high);
   double lower_shadow     = lowerShadowCalc(open, close, low);
   double body_percentage  = body_size / total_range;

   return (
      body_percentage >= min_body_percentage &&
      upper_shadow >= upper_shadow_ratio * body_size &&
      lower_shadow <= lower_shadow_max_ratio * body_size
   );
}

Spinning Top

Este é um candlestick com corpo pequeno localizado na região central e sombras longas em ambos os lados.

Padrão de Candlestick Spinning Top

Quando esse candle aparece, ele indica indecisão no mercado, o que muitas vezes pode significar a continuidade da tendência atual, já que nem compradores nem vendedores apresentam domínio claro.

Como esse candle é semelhante a um candlestick Doji — embora apresente um corpo maior —, precisamos garantir explicitamente que seu corpo não seja tão pequeno quanto o de um Doji e que esteja localizado aproximadamente no centro das sombras longas.

bool CTALib::CDLSPINNINGTOP(double open,
                            double high,
                            double low,
                            double close, 
                            double body_percentage_threshold = 0.3, 
                            double shadow_ratio = 2.0,
                            double shadow_symmetry_tolerance = 0.3)
{
   double body_size      = MathAbs(open - close);
   double total_range    = high - low + DBL_EPSILON;
   double upper_shadow   = upperShadowCalc(open, close, high);
   double lower_shadow   = lowerShadowCalc(open, close, low);
   double body_percentage = body_size / total_range;

   //--- Calculate shadow symmetry ratio
   double shadow_diff = MathAbs(upper_shadow - lower_shadow);
   double shadow_sum = upper_shadow + lower_shadow + DBL_EPSILON;
   double symmetry_ratio = shadow_diff / shadow_sum; // Closer to 0 = more balanced

   return (
      body_percentage < body_percentage_threshold && // Body is small compared to candle size
      upper_shadow > body_size * shadow_ratio && // Both shadows are significantly larger than the body
      lower_shadow > body_size * shadow_ratio &&
      symmetry_ratio <= shadow_symmetry_tolerance //Shadows are roughly equal (symmetrical)
   );
}

Bullish Marubozu

O nome "Marubozu" vem de uma palavra japonesa que significa "raspado" ou "sem cabelo", fazendo referência a um candle sem sombras.

Um candle Bullish Marubozu é um candle de alta com sombras superior e inferior muito pequenas ou inexistentes. Trata-se de um forte sinal de alta, indicando impulso comprador.

bullish marubozu

Podemos adicionar um valor de tolerância em pontos para verificar se os preços de abertura e fechamento estão suficientemente próximos dos preços mínimo e máximo.

bool CTALib::CDLBULLISHMARUBOZU(double open, double high, double low, double close, double tolerance = 2)
 {
   return (MathAbs(open - low) <= (tolerance*_Point) &&  MathAbs(close - high) <= (tolerance*_Point) && close > open);
 }

Bearish Marubozu

Um candle Bearish Marubozu é um candle de baixa com sombras superior e inferior muito pequenas ou inexistentes. Trata-se de um forte sinal de baixa, indicando impulso vendedor.

Padrão de Candlestick Bearish Marubozu

Assim como no candlestick Bullish Marubozu, utilizamos um valor de tolerância em pontos para verificar se os preços de abertura e fechamento estão suficientemente próximos dos preços máximo e mínimo.

bool CTALib::CDLBEARISHMARUBOZU(double open, double high, double low, double close, double tolerance = 2)
 {
   return (MathAbs(open - high) <= (tolerance*_Point) && MathAbs(close - low) <= (tolerance*_Point) && close < open);
 }

Até aqui, estamos considerando apenas a detecção dos padrões de candlestick e seus respectivos sinais com base em sua aparência. No entanto, segundo as minhas fontes, a forma adequada de interpretar os sinais de um candlestick também deve considerar a tendência. Por exemplo, para que um Hammer seja interpretado como um sinal de alta, ele deve aparecer durante uma tendência de baixa.

A tendência é uma parte fundamental dessa análise e deve ser considerada caso você queira aprofundar este projeto.


Indicador de Detecção de Padrões de Candlestick

Vamos visualizar os padrões de candlestick utilizando o código empregado para identificá-los. Isso é importante porque esses padrões muitas vezes podem parecer abstratos e confusos. Além disso, como pretendemos utilizar esses dados para fins de Machine Learning, sabemos que a qualidade dos dados é um dos fatores mais importantes. Ao visualizá-los, entendemos melhor como foram calculados no código e qual é o resultado visual no gráfico.

Não hesite em ajustar alguns parâmetros e modificar o código de acordo com suas necessidades.

Primeiro, precisamos garantir que o código que acabamos de desenvolver seja capaz de identificar os mesmos padrões que nós, como seres humanos, conseguimos reconhecer visualmente no mercado.

Esse indicador baseado em candlesticks terá 5 buffers e um plot no gráfico principal.

Nome do arquivo: Candlestick Identifier.mq5

#property indicator_chart_window
#property indicator_buffers 5
#property indicator_plots 1

#property indicator_type1 DRAW_COLOR_CANDLES
#property indicator_color1 clrDodgerBlue, clrOrange, clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

double OpenBuff[];
double HighBuff[];
double LowBuff[];
double CloseBuff[];
double ColorBuff[];

#include <ta-lib.mqh> //!important for candlestick patterns

Como a biblioteca ta-lib.mqh utiliza uma classe estática, não é necessário instanciar suas classes. Podemos chamar diretamente, dentro da função OnCalculate, as funções responsáveis pela detecção dos padrões de candlestick.

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<1)
     return rates_total;
   
    for(int i = prev_calculated; i < rates_total; i++)
     {
      OpenBuff[i]  = open[i];
      HighBuff[i]  = high[i];
      LowBuff[i]   = low[i];
      CloseBuff[i] = close[i];
      
      //---
      
      if (close[i]>open[i])
         ColorBuff[i] = 1.0; 
      else
         ColorBuff[i] = 0.0;
      
      //---
      
      double padding = MathAbs(high[i] - low[i]) * 0.2; // 20% padding
      
      if (CTALib::CDLDOJI(open[i], close[i]))
        {
          TextCreate(string(i)+(string)time[i], time[i]-PeriodSeconds(), high[i]+padding, "Doji", clrBlack, 90.0);
          ColorBuff[i] = 2.0;
        }
        
      if (CTALib::CDLDRAGONFLYDOJI(open[i], high[i], low[i], close[i]))
        {
          TextCreate(string(i)+(string)time[i], time[i]-PeriodSeconds(), high[i]+padding,"DragonFly Doji", clrBlack, 90.0);
          ColorBuff[i] = 2.0;
        }
        
      if (CTALib::CDLGRAVESTONEDOJI(open[i], high[i], low[i], close[i]))
        {
          TextCreate(string(i)+(string)time[i], time[i]-PeriodSeconds(), high[i]+padding,"GraveStone Doji", clrBlack, 90.0);
          ColorBuff[i] = 2.0;
        }
        
      if (CTALib::CDLHAMMER(open[i], high[i], low[i], close[i]))
        {
          TextCreate(string(i)+(string)time[i], time[i]-PeriodSeconds(), high[i]+padding,"Hammer", clrBlack, 90.0);
          ColorBuff[i] = 2.0;
        }
        
      if (CTALib::CDLINVERTEDHAMMER(open[i], high[i], low[i], close[i]))
        {
          TextCreate(string(i)+(string)time[i], time[i]-PeriodSeconds(), high[i]+padding,"Inverted Hammer", clrBlack, 90.0);
          ColorBuff[i] = 2.0;
        }
        
      if (CTALib::CDLSPINNINGTOP(open[i], high[i], low[i], close[i], 0.3, 2.0))
        {
          TextCreate(string(i)+(string)time[i], time[i]-PeriodSeconds(), high[i]+padding,"Spinning Top", clrBlack, 90.0);
          ColorBuff[i] = 2.0;
        }
        
      if (CTALib::CDLBULLISHMARUBOZU(open[i], high[i], low[i], close[i], 2))
        {
          TextCreate(string(i)+(string)time[i], time[i]-PeriodSeconds(), high[i]+padding,"Bullish Marubozu", clrBlack, 90.0);
          ColorBuff[i] = 2.0;
        }
        
      if (CTALib::CDLBEARISHMARUBOZU(open[i], high[i], low[i], close[i], 2))
        {
          TextCreate(string(i)+(string)time[i], time[i]-PeriodSeconds(), high[i]+padding,"Bearish Marubozu", clrBlack, 90.0);
          ColorBuff[i] = 2.0;
        }
     }
     
//--- return value of prev_calculated for next call
   return(rates_total);
  }

Por padrão, os candles de alta são exibidos em laranja, enquanto os candles de baixa são exibidos em azul. Qualquer candle identificado como um dos padrões abordados neste artigo será destacado em vermelho e acompanhado por um texto orientado em um ângulo de 90 graus, indicando a qual padrão de candlestick aquele candle pertence.

Exibição do indicador de padrões de Candlestick

Como podemos observar na imagem acima, nosso indicador de detecção apresenta um bom desempenho na identificação desses padrões de candlestick. Com isso, podemos ter maior confiança na lógica implementada no código. 

Agora, vamos coletar esses padrões e armazená-los em um arquivo CSV utilizando um script. Em seguida, utilizaremos essas informações no treinamento dos modelos de Machine Learning.


Coleta de Padrões de Candlestick para Machine Learning

Como alguns padrões de candlestick não aparecem com frequência no mercado, especialmente em timeframes mais altos, nos quais há menos barras disponíveis no histórico, vamos coletar nossos dados no período de 1º de janeiro de 2005 a 1º de janeiro de 2023.

Esse período de 18 anos deverá fornecer uma quantidade significativa de barras no timeframe diário e, consequentemente, diversos padrões para que nossos modelos de Machine Learning possam analisá-los.

#include <ta-lib.mqh> //Contains CTALib class for candlestick patterns detection
#include <MALE5\Pandas\pandas.mqh> //https://www.mql5.com/en/articles/17030

input datetime start_date = D'2005.01.01';
input datetime end_date = D'2023.01.01';

input string symbol = "XAUUSD";
input ENUM_TIMEFRAMES timeframe = PERIOD_D1;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   
   vector open, high, low, close;
   
   open.CopyRates(symbol, timeframe, COPY_RATES_OPEN, start_date, end_date);
   high.CopyRates(symbol, timeframe, COPY_RATES_HIGH, start_date, end_date);
   low.CopyRates(symbol, timeframe, COPY_RATES_LOW, start_date, end_date);
   close.CopyRates(symbol, timeframe, COPY_RATES_CLOSE, start_date, end_date);
   
   CDataFrame df;
   
   vector cdl_patterns = {};
   cdl_patterns = CTALib::CDLWHITECANDLE(open, close);
   df.insert("White Candle", cdl_patterns);
   
   cdl_patterns = CTALib::CDLBLACKCANDLE(open, close);
   df.insert("Black Candle", cdl_patterns);
   
   cdl_patterns = CTALib::CDLDOJI(open, close);
   df.insert("Doji Candle", cdl_patterns);
   
   cdl_patterns = CTALib::CDLDRAGONFLYDOJI(open, high, low, close);
   df.insert("Dragonflydoji Candle", cdl_patterns);
   
   cdl_patterns = CTALib::CDLGRAVESTONEDOJI(open, high, low, close);
   df.insert("Gravestonedoji Candle", cdl_patterns);
   
   cdl_patterns = CTALib::CDLHAMMER(open, high, low, close);
   df.insert("Hammer Candle", cdl_patterns);
   
   cdl_patterns = CTALib::CDLINVERTEDHAMMER(open, high, low, close);
   df.insert("Invertedhammer Candle", cdl_patterns);
   
   cdl_patterns = CTALib::CDLSPINNINGTOP(open, high, low, close);
   df.insert("Spinningtop Candle", cdl_patterns);
   
   cdl_patterns = CTALib::CDLBULLISHMARUBOZU(open, high, low, close);
   df.insert("BullishMarubozu Candle", cdl_patterns);
   
   cdl_patterns = CTALib::CDLBEARISHMARUBOZU(open, high, low, close);
   df.insert("BearishMarubozu Candle", cdl_patterns);
   
   df.insert("Open", open);
   df.insert("High", high);
   df.insert("Low", low);
   df.insert("Close", close);
   
   df.to_csv(StringFormat("CandlestickPatterns.%s.%s.csv",symbol,EnumToString(timeframe)), true);
  }

Também coletamos os valores OHLC (Open, High, Low e Close — abertura, máxima, mínima e fechamento) para preparar a variável-alvo e mantê-los disponíveis caso sejam necessários posteriormente.


Treinamento de um Modelo de IA para Realizar Previsões com Base em Padrões de Candlestick

Agora que temos um conjunto de dados, vamos carregá-lo em um script Python (Jupyter Notebook).

import pandas as pd

symbol = "XAUUSD"
df = pd.read_csv(f"/kaggle/input/forex-candlestick-patterns/CandlestickPatterns.{symbol}.PERIOD_D1.csv")

df

Outputs

White Candle Black Candle Doji Candle Dragonflydoji Candle Gravestonedoji Candle Hammer Candle Invertedhammer Candle Spinningtop Candle BullishMarubozu Candle BearishMarubozu Candle Open High Low Close
0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 438.45 438.71 426.72 429.55
1 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 429.52 430.18 423.71 427.51
2 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 427.50 428.77 425.10 426.58
3 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 426.31 427.85 420.17 421.37
4 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 421.39 425.48 416.57 419.02
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...


O maior desafio que surge ao trabalhar com esses dados de candlestick é a criação da variável-alvo.

Na maioria dos problemas de classificação relacionados aos mercados financeiros, geralmente definimos a variável-alvo com base no movimento futuro do preço, utilizando um parâmetro que normalmente chamamos de "lookahead".

Esse parâmetro especifica quantas barras (ou etapas de tempo) consideramos à frente nos dados. Por exemplo, se o lookahead for definido como 1, comparamos o preço de fechamento da barra atual com o preço de fechamento da barra seguinte:

Se Close[próxima barra] > Close[barra atual], isso indica um movimento de alta e, portanto, atribuímos à variável-alvo o rótulo 1.

Caso contrário, se essa condição não for atendida, isso indica um movimento de baixa e atribuímos o rótulo 0.

Podemos aplicar a mesma abordagem aqui para garantir que nossas feature sejam utilizadas para prever informações futuras. No entanto, como mostrado na tabela acima, há muitos valores zero nesses dados, pois frequentemente nenhuma barra apresenta um padrão específico detectado. As exceções são os candles White e Black, que não são padrões especiais e, portanto, não os consideramos padrões de candlestick propriamente ditos.

Isso significa que, na maior parte do tempo, forneceremos valores zero aos nossos modelos de Machine Learning e os forçaremos a tentar compreender relações e prever a variável-alvo praticamente sem informações relevantes. Como consequência, os modelos poderão passar a depender excessivamente dos candles White e Black, algo que não queremos.

Podemos contornar esse problema removendo todas as linhas em que os valores de todos os padrões de candlestick sejam zero e treinando o modelo apenas com dados que contenham padrões de candlestick. Essa abordagem também exigiria que evitássemos a mesma situação durante a execução do modelo.

Outra forma de lidar com esse problema seria introduzir um sinal da classe hold, representado por -1, em todas as linhas nas quais todos os padrões de candlestick fossem 0 (false), com exceção das colunas White e Black. No entanto, isso criaria um grave problema de desbalanceamento entre as classes, questão que abordamos no artigo anterior. Ainda assim, mesmo essa abordagem não foi capaz de resolver o problema.

Por enquanto, vamos prosseguir com a preparação da variável-alvo independentemente dessa limitação.

lookahead = 1

new_df = df.copy()
new_df["future_close"] = new_df["Close"].shift(-lookahead)
new_df.dropna(inplace=True)  # Drop NaNs caused by the shift operation

signal = []
for i in range(len(new_df)):  # Iterate over rows, not columns
    if new_df["future_close"].iloc[i] > new_df["Close"].iloc[i]:
        signal.append(1)
    else:
        signal.append(0)

new_df["Signal"] = signal

Em seguida, organizamos os preditores em um array bidimensional chamado X, removendo as feature que não desejamos utilizar, como os valores OHLC, a coluna que queremos prever (target) e a feature de fechamento future_close, que utilizamos para criar a coluna target. Também atribuímos a coluna target, denominada Signal, ao array y.

X = new_df.drop(columns=[
    "Signal",
    "Open",
    "High",
    "Low",
    "Close",
    "future_close"
])

y = new_df["Signal"]

# Split data into train and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, shuffle=False)

Escolhi trabalhar com um modelo CatBoost para esse problema, pois temos várias colunas categóricas que, em teoria, devem funcionar bem com o classificador CatBoost.

from catboost import CatBoostClassifier
from sklearn.utils.class_weight import compute_class_weight

# Automatically calculate class weights
classes = np.unique(y)
weights = compute_class_weight(class_weight='balanced', classes=classes, y=y)
class_weights = dict(zip(classes, weights))

# Define the base model
model = CatBoostClassifier(
    iterations=1000,
    learning_rate=0.01,
    depth=5,
    loss_function='Logloss',
    class_weights=class_weights,
    verbose=100
)

model.fit(X_train, y_train) # Training the classifier

Saídas.

0:      learn: 0.6930586        total: 3.64ms   remaining: 3.64s
100:    learn: 0.6897625        total: 136ms    remaining: 1.21s
200:    learn: 0.6888030        total: 269ms    remaining: 1.07s
300:    learn: 0.6883559        total: 401ms    remaining: 931ms
400:    learn: 0.6881469        total: 532ms    remaining: 795ms
500:    learn: 0.6879966        total: 661ms    remaining: 658ms
600:    learn: 0.6879013        total: 789ms    remaining: 524ms
700:    learn: 0.6878311        total: 916ms    remaining: 391ms
800:    learn: 0.6877729        total: 1.04s    remaining: 260ms
900:    learn: 0.6877273        total: 1.17s    remaining: 129ms
999:    learn: 0.6876900        total: 1.3s     remaining: 0us
<catboost.core.CatBoostClassifier at 0x798cc6d08dd0>

Vamos avaliar esse modelo utilizando dados que ele ainda não viu anteriormente (a amostra de teste).

y_pred = model.predict(X_test)

print("\nClassification Report:\n", classification_report(y_test, y_pred))

Saídas.

Classification Report:
               precision    recall  f1-score   support

           0       0.49      0.55      0.52       429
           1       0.58      0.52      0.55       511

    accuracy                           0.53       940
   macro avg       0.53      0.53      0.53       940
weighted avg       0.54      0.53      0.53       940

Os resultados indicam um desempenho mediano do modelo, com precision de 0,58 para a classe 1 e 0,49 para a classe 0. Embora possamos ter alguma confiança no modelo ao prever a classe 1, para a qual apresenta precision de 58%, não podemos confiar da mesma forma em suas previsões para a classe 0; nesse caso, praticamente seria melhor tentar adivinhar.

A accuracy geral é de 53%, um resultado plausível no contexto de trading. Ainda assim, é superior ao resultado esperado de uma escolha aleatória entre duas possibilidades, que seria de aproximadamente 50%.

Vamos verificar o gráfico de importância das feature para identificar quais delas tiveram maior impacto sobre o modelo.

import matplotlib.pyplot as plt

# Get feature importances
importances = model.get_feature_importance()
feature_names = X_train.columns if hasattr(X_train, 'columns') else [f'feature_{i}' for i in range(X_train.shape[1])]

# Create DataFrame for plotting
feat_imp_df = pd.DataFrame({
    'Feature': feature_names,
    'Importance': importances
}).sort_values(by='Importance', ascending=False)

# Plot
plt.figure(figsize=(7, 3))
plt.barh(feat_imp_df['Feature'], feat_imp_df['Importance'])
plt.gca().invert_yaxis()  # Highest importance on top
plt.title('Feature Importances')
plt.xlabel('Importance')
plt.ylabel('Feature')
plt.tight_layout()
plt.show()

Saídas.

O padrão de candlestick Spinning Top foi a feature de maior impacto no modelo, seguido pelo candlestick Doji. Já o candle Bearish Marubozu foi o que apresentou menor impacto.

De acordo com o que li sobre esses padrões de candlestick, alguns deles são utilizados para indicar uma tendência ou sugerir o que poderá acontecer no mercado ao longo de um horizonte de tempo mais amplo. Por exemplo, o aparecimento de um candle Doji no topo de uma tendência de alta pode indicar que uma tendência de baixa está prestes a começar e poderá se prolongar por algum tempo.

Criamos a variável-alvo utilizando um valor de lookahead igual a 1. Portanto, estamos utilizando esses padrões de candlestick para prever apenas uma barra à frente, em vez de várias barras futuras.

Sinta-se à vontade para experimentar diferentes valores de lookahead superiores a 1 e observar o impacto desses padrões de candlestick em períodos mais longos ou em diferentes horizontes de previsão. Nos testes que realizei até agora, constatei que o modelo treinado com lookahead igual a 1 apresentou a maior accuracy.

Por enquanto, manteremos o valor de lookahead igual a 1, pois acredito que podemos lidar com essa questão do horizonte de previsão diretamente em nosso robô de negociação final, utilizando valores de Stop Loss e Take Profit ou encerrando as operações após a passagem de determinado número de barras.


Finalizando a Implementação em um Robô de Negociação

Agora que treinamos um modelo baseado em padrões de candlestick, vamos testá-lo em um ambiente real de negociação para verificar se esses padrões podem ser úteis no contexto da Inteligência Artificial (IA).

Primeiramente, precisamos salvar nosso modelo no formato ONNX, compatível com MQL5 e MetaTrader 5.

model_onnx = convert_sklearn(
    model,
    "catboost",
    [("input", FloatTensorType([None, X_train.shape[1]]))],
    target_opset={"": 12, "ai.onnx.ml": 2},
)

# And save.
with open(f"CatBoost.CDLPatterns.{symbol}.onnx", "wb") as f:
    f.write(model_onnx.SerializeToString())

Mais informações sobre como salvar esse modelo CatBoost podem ser encontradas aqui.

Nosso Expert Advisor (EA) é relativamente simples.

#include <Trade\Trade.mqh> //The trading module
#include <Trade\PositionInfo.mqh> //Position handling module
#include <ta-lib.mqh> //For candlestick patterns
#include <Catboost.mqh> //Has a class for deploying a catboost model

CTrade m_trade;
CPositionInfo m_position;

CCatboostClassifier catboost;

input int magic_number = 21042025;
input int slippage = 100;
input string symbol_ = "XAUUSD";
input ENUM_TIMEFRAMES timeframe_ = PERIOD_D1;
input int lookahead = 1;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
      
   if (!MQLInfoInteger(MQL_TESTER))
     if (!ChartSetSymbolPeriod(0, symbol_, timeframe_))
       {
         printf("%s failed to set symbol %s and timeframe %s, Check these values. Err = %d",__FUNCTION__,symbol_,EnumToString(timeframe_),GetLastError());
         return INIT_FAILED;
       }
  
//---
   
   if (!catboost.Init(StringFormat("CatBoost.CDLPatterns.%s.onnx",symbol_), ONNX_COMMON_FOLDER)) //Initialize the catboost model
      return INIT_FAILED;
   
//---

   m_trade.SetExpertMagicNumber(magic_number);
   m_trade.SetDeviationInPoints(slippage);
   m_trade.SetMarginMode();
   m_trade.SetTypeFillingBySymbol(Symbol());
           
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   
   double open = iOpen(Symbol(), Period(), 1),
          high = iHigh(Symbol(), Period(), 1),
          low  = iLow(Symbol(), Period(), 1), 
          close = iClose(Symbol(), Period(), 1);   
   
   vector x = {
               CTALib::CDLWHITECANDLE(open, close),
               CTALib::CDLBLACKCANDLE(open, close),
               CTALib::CDLDOJI(open, close),
               CTALib::CDLDRAGONFLYDOJI(open, high, low, close),
               CTALib::CDLGRAVESTONEDOJI(open, high, low, close),
               CTALib::CDLHAMMER(open, high, low, close),
               CTALib::CDLINVERTEDHAMMER(open, high, low, close),
               CTALib::CDLSPINNINGTOP(open, high, low, close),
               CTALib::CDLBULLISHMARUBOZU(open, high, low, close),
               CTALib::CDLBEARISHMARUBOZU(open, high, low, close)
              };
       
   long signal = catboost.predict(x).cls; //Predicted class

   MqlTick ticks;
   if (!SymbolInfoTick(Symbol(), ticks))
      {
         printf("Failed to obtain ticks information, Error = %d",GetLastError());
         return;
      }
      
   double volume_ = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);   
   
   if (signal == 1) 
     {        
        if (!PosExists(POSITION_TYPE_BUY) && !PosExists(POSITION_TYPE_SELL))  
            m_trade.Buy(volume_, Symbol(), ticks.ask,0,0);
     }
     
   if (signal == 0)
     {        
        if (!PosExists(POSITION_TYPE_SELL) && !PosExists(POSITION_TYPE_BUY))  
            m_trade.Sell(volume_, Symbol(), ticks.bid,0,0);
     } 
    
    CloseTradeAfterTime((Timeframe2Minutes(Period())*lookahead)*60); //Close the trade after a certain lookahead and according the the trained timeframe
  }

Após inicializarmos o modelo CatBoost no formato ONNX, que foi salvo na pasta Common, podemos prosseguir com a lógica do EA.

Dentro da função OnTick, obtemos os valores Open, High, Low e Close da barra anteriormente fechada e os passamos para as funções da CTALib responsáveis pela detecção dos padrões de candlestick. Em seguida, utilizamos os resultados dessas funções para realizar previsões a partir de um vetor denominado x. 

Precisamos ter atenção às feature e à ordem em que são fornecidas, pois elas devem seguir exatamente a mesma organização utilizada durante o treinamento do modelo CatBoost final no script Python.

X_train.columns

Em nosso modelo final, tínhamos:

Index(['White Candle', 'Black Candle', 'Doji Candle', 'Dragonflydoji Candle',
       'Gravestonedoji Candle', 'Hammer Candle', 'Invertedhammer Candle',
       'Spinningtop Candle', 'BullishMarubozu Candle',
       'BearishMarubozu Candle'],
      dtype='object')

Essa mesma ordem foi preservada dentro do Expert Advisor.

No momento, não temos valores definidos para Stop Loss e Take Profit. Por isso, encerramos as operações (posições) abertas depois que transcorre o número de barras correspondente ao valor de lookahead no timeframe utilizado.

Configurações do Strategy Tester.

Resultados.

 

O que me chama a atenção é a semelhança entre os resultados das operações de compra e de venda. Durante esse período de dois anos, foram abertas 257 operações de venda. Isso representa apenas 2 operações a menos que as 259 operações de compra.

Esse resultado não é adequado e podemos concluir que, embora o modelo considere todos os padrões de candlestick, os candles White e Black acabam exercendo uma influência significativa, pois são os únicos presentes em todas as barras. Além disso, estamos encerrando cada operação após apenas uma barra (lookahead = 1).Esse problema está relacionado à forma como preparamos a variável-alvo e treinamos o modelo com dados que continham valores zero (false) em muitas das feature. 

Para garantir que os padrões específicos de candlestick sejam efetivamente considerados, precisamos verificar quando todos os padrões especiais de candlestick forem iguais a 0 (false) — ou seja, quando nenhum deles tiver sido detectado — e impedir a abertura de uma operação nessa situação.

Queremos abrir uma operação somente quando algum padrão específico de candlestick for detectado, além dos candles White e Black.

void OnTick()
  {
//---
   
   double open = iOpen(Symbol(), Period(), 1),
          high = iHigh(Symbol(), Period(), 1),
          low  = iLow(Symbol(), Period(), 1), 
          close = iClose(Symbol(), Period(), 1);
   
   
   vector x = {
               CTALib::CDLWHITECANDLE(open, close),
               CTALib::CDLBLACKCANDLE(open, close),
               CTALib::CDLDOJI(open, close),
               CTALib::CDLDRAGONFLYDOJI(open, high, low, close),
               CTALib::CDLGRAVESTONEDOJI(open, high, low, close),
               CTALib::CDLHAMMER(open, high, low, close),
               CTALib::CDLINVERTEDHAMMER(open, high, low, close),
               CTALib::CDLSPINNINGTOP(open, high, low, close),
               CTALib::CDLBULLISHMARUBOZU(open, high, low, close),
               CTALib::CDLBEARISHMARUBOZU(open, high, low, close)
              };
   
   vector patterns = {
                        CTALib::CDLDOJI(open, close),
                        CTALib::CDLDRAGONFLYDOJI(open, high, low, close),
                        CTALib::CDLGRAVESTONEDOJI(open, high, low, close),
                        CTALib::CDLHAMMER(open, high, low, close),
                        CTALib::CDLINVERTEDHAMMER(open, high, low, close),
                        CTALib::CDLSPINNINGTOP(open, high, low, close),
                        CTALib::CDLBULLISHMARUBOZU(open, high, low, close),
                        CTALib::CDLBEARISHMARUBOZU(open, high, low, close)
                     }; //Store all the special patterns 
    
   long signal = catboost.predict(x).cls; //Predicted class

   MqlTick ticks;
   if (!SymbolInfoTick(Symbol(), ticks))
      {
         printf("Failed to obtain ticks information, Error = %d",GetLastError());
         return;
      }
      
   double volume_ = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);   
   
   if (signal == 1 && patterns.Sum()>0) //Check if there are is atleast a special pattern before opening a trade
     {        
        if (!PosExists(POSITION_TYPE_BUY) && !PosExists(POSITION_TYPE_SELL))  
            m_trade.Buy(volume_, Symbol(), ticks.ask,0,0);
     }
     
   if (signal == 0 && patterns.Sum()>0) //Check if there are is atleast a special pattern before opening a trade
     {        
        if (!PosExists(POSITION_TYPE_SELL) && !PosExists(POSITION_TYPE_BUY))  
            m_trade.Sell(volume_, Symbol(), ticks.bid,0,0);
     } 
    
    CloseTradeAfterTime((Timeframe2Minutes(Period())*lookahead)*60); //Close the trade after a certain lookahead and according the the trained timeframe
  }

Resultados do Strategy Tester.

Agora o resultado parece muito melhor. Foram abertas poucas operações, o que é compatível com a baixa frequência com que esses padrões de candlestick aparecem em timeframes mais altos, considerando que nosso modelo foi treinado no timeframe diário.

O percentual de operações lucrativas foi de 54,55%, valor bastante próximo da accuracy geral de 0,53 (53%) obtida no classification report. Essa proximidade entre os resultados indica que estamos seguindo na direção correta.


Conclusão

Portanto, é possível utilizar padrões de candlestick em conjunto com modelos de Inteligência Artificial (IA) e empregar o resultado final para realizar previsões de mercado. No entanto, diferentemente do uso de indicadores, cálculos matemáticos e outros tipos de dados normalmente empregados na previsão dos mercados, os padrões de candlestick exigem uma série de cuidados e atenção aos mínimos detalhes durante a coleta dos dados e a criação das feature derivadas dos candles observados no mercado. Uma pequena interpretação incorreta de um candle pode levar a um resultado completamente diferente.

Costuma-se dizer que nossos desejos e crenças influenciam a maneira como percebemos e interpretamos as informações. Em outras palavras, vemos aquilo que queremos ver.

Acredito que isso aconteça com frequência ao trabalhar com padrões de candlestick. Se você estiver procurando por um Hammer, um Dragonfly Doji poderá parecer um Hammer, e vice-versa.

Acredito que sejam necessárias muitas tentativas, ajustes e correções durante a preparação de dados baseados em candlesticks para alcançar um desempenho satisfatório ao utilizá-los em Machine Learning.

Atenciosamente. 

Continue acompanhando e contribua para o desenvolvimento de algoritmos de Machine Learning para a linguagem MQL5 neste repositório do GitHub.


Fontes e Referências


Tabela de Anexos

Nome do arquivo Descrição/Uso
Experts\CandlestickPatterns AI-EA.mq5 Um Expert Advisor (EA) que utiliza um modelo CatBoost para realizar previsões com base em padrões de Candlestick.
Indicators\Candlestick Identifier.mq5 Um indicador para exibir padrões de Candlestick no gráfico.
Scripts\Candlestick Patterns Collect.mq5 Um script para coletar padrões de Candlestick e armazenar essas informações em um arquivo CSV.
Include\Catboost.mqh Uma biblioteca que contém classes para carregar, inicializar e utilizar o classificador CatBoost na realização de previsões de mercado.
Include\pandas.mqh Módulo Pandas semelhante ao Python para armazenamento e manipulação de dados.
Include\ta-lib.mqh Biblioteca de análise técnica que contém uma classe para detectar padrões de Candlestick.
Common\Files\*.csv Arquivos CSV contendo dados de Candlestick para utilização em Machine Learning.
Common\Files\*.onnx Modelos de Machine Learning no formato ONNX.
CandlestickMarket Prediction.ipynb Um script Python (Jupyter Notebook) para treinamento do modelo CatBoost.


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

Arquivos anexados |
Attachments.zip (183.92 KB)
Últimos Comentários | Ir para discussão (7)
Stanislav Korotky
Stanislav Korotky | 1 mai. 2025 em 10:17
Usar a configuração das velas em vez da ação do preço subjacente é semelhante a usar uma imagem indexada de 256 cores em vez de uma imagem em cores reais — você perde muitas nuances que podem ser importantes. Além disso, dependendo do deslocamento temporal da corretora, os padrões das velas podem mudar completamente no mesmo histórico de cotações. E mesmo que você não utilize um intervalo de tempo amplo (como D1 [no seu caso] ou H4), um simples deslocamento artificial do tempo (em minutos) dentro de uma hora produzirá formações de velas completamente diferentes. Isso não é confiável e não agrega nenhum valor.
Omega J Msigwa
Omega J Msigwa | 1 mai. 2025 em 13:08
Stanislav Korotky os padrões das velas podem mudar completamente no mesmo histórico de cotações. E mesmo que você não utilize um intervalo de tempo amplo (como D1 [no seu caso] ou H4), um simples deslocamento artificial do tempo (minutos) dentro de uma hora produzirá formações de velas completamente diferentes. Isso não é confiável e não agrega nenhum valor.

Já expliquei isso no artigo.

No momento, estamos considerando apenas a detecção de padrões de velas e seus sinais com base na aparência deles, mas a maneira correta de extrair os sinais de uma vela, de acordo com minhas fontes, deve incluir a detecção de tendência; por exemplo, para que um martelo seja considerado um sinal de alta, ele precisa aparecer em uma tendência de baixa.

A tendência é uma parte crucial da equação que você talvez queira levar em conta se quiser levar este projeto adiante.

A ação do preço é importante, não há como negar isso.

Stanislav Korotky
Stanislav Korotky | 1 mai. 2025 em 13:35
Omega J Msigwa #:

Já expliquei isso no artigo.

No momento, estamos considerando apenas a detecção de padrões de velas e seus sinais com base na aparência deles, mas, segundo minhas fontes, a maneira correta de extrair os sinais de uma vela deve incluir a detecção de tendência; por exemplo, para que um martelo seja considerado um sinal de alta, ele precisa aparecer em uma tendência de baixa.

A tendência é uma parte crucial da equação que você talvez queira levar em conta se quiser levar este projeto adiante.

A ação do preço é importante, não há como negar isso.

Sua citação não está relacionada à ideia principal do meu argumento.

Anil Varma
Anil Varma | 23 dez. 2025 em 10:58

Oi, projeto de aprendizado de máquina seguirá essa linha.

Desejo a você um Feliz Natal...

Wen Rui Yi
Wen Rui Yi | 16 mar. 2026 em 09:28
Recentemente, também tenho pensado nisso: usar o aprendizado por reforço para treinar os gráficos de velas. No entanto, venho refletindo sobre qual é a base lógica subjacente do modelo treinado com dados discretos da forma das velas. A propósito, como está indo sua pesquisa atualmente?
Automatizando Estratégias de Trading em MQL5 (Parte 16): Rompimento da Faixa da Meia-Noite com Break of Structure (BoS) e Price Action Automatizando Estratégias de Trading em MQL5 (Parte 16): Rompimento da Faixa da Meia-Noite com Break of Structure (BoS) e Price Action
Neste artigo, automatizamos em MQL5 a estratégia de rompimento da faixa da meia-noite com Break of Structure, detalhando o código utilizado para detectar rompimentos e executar operações. Definimos parâmetros precisos de risco para entradas, Stop Loss e Take Profit. Também abordamos o backtesting e a otimização da estratégia para sua aplicação prática no trading.
Automatizando Estratégias de Trading em MQL5 (Parte 15): Padrão Harmônico Cypher Baseado em Price Action com Visualização Automatizando Estratégias de Trading em MQL5 (Parte 15): Padrão Harmônico Cypher Baseado em Price Action com Visualização
Neste artigo, exploramos a automatização do padrão harmônico Cypher em MQL5, detalhando sua detecção e visualização nos gráficos do MetaTrader 5. Implementamos um Expert Advisor que identifica pontos de oscilação, valida padrões com base em Fibonacci e executa operações com anotações gráficas claras. O artigo termina com orientações sobre backtesting e otimização do programa para tornar a negociação mais eficiente.
Desenvolvimento do Kit de Ferramentas de Análise de Price Action (Parte 21): Detector de Inversão da Estrutura de Mercado Desenvolvimento do Kit de Ferramentas de Análise de Price Action (Parte 21): Detector de Inversão da Estrutura de Mercado
O Expert Advisor (EA) Market Structure Flip Detector atua como um parceiro atento, monitorando continuamente as mudanças no sentimento do mercado. Utilizando limites baseados no Average True Range (ATR), ele detecta com eficiência as mudanças na estrutura do mercado e identifica cada higher low (HL) e lower high (LH) com marcadores claros. Graças à rápida execução do MQL5 e à flexibilidade de sua API, essa ferramenta realiza análises em tempo real, ajusta a exibição para proporcionar melhor legibilidade e disponibiliza um painel dinâmico para acompanhar a quantidade de flips e os horários/intervalos dos flips. Além disso, notificações sonoras e push personalizáveis garantem que você seja informado sobre sinais importantes, demonstrando como parâmetros simples e funções auxiliares podem transformar movimentos de preço em estratégias acionáveis.
Técnicas do MQL5 Wizard que você deve conhecer (Parte 60): Aprendizado por Inferência (Wasserstein-VAE) com Padrões da Média Móvel e do Oscilador Estocástico Técnicas do MQL5 Wizard que você deve conhecer (Parte 60): Aprendizado por Inferência (Wasserstein-VAE) com Padrões da Média Móvel e do Oscilador Estocástico
Concluímos nossa análise sobre o uso complementar da Média Móvel (MA) e do Oscilador Estocástico examinando o papel que o aprendizado por inferência pode desempenhar após as etapas de aprendizado supervisionado e aprendizado por reforço. Existem diversas maneiras de abordar o aprendizado por inferência nesse contexto. No entanto, nossa abordagem consiste em utilizar Variational Autoencoders (VAEs). Primeiro, exploraremos essa abordagem em Python e, em seguida, exportaremos nosso modelo treinado no formato ONNX para utilizá-lo em um Expert Advisor desenvolvido com o MQL5 Wizard no MetaTrader.