English Русский 中文 Español Deutsch 日本語
preview
Desenvolvimento de ferramentas para análise do movimento de preços (Parte 7): Expert Advisor Signal Pulse

Desenvolvimento de ferramentas para análise do movimento de preços (Parte 7): Expert Advisor Signal Pulse

MetaTrader 5Exemplos |
86 0
Christian Benjamin
Christian Benjamin

Conteúdo



Introdução

Neste artigo, examinaremos o desenvolvimento do EA Signal Pulse em MQL5. O EA utilizará a combinação dos indicadores Bollinger Bands e Stochastic Oscillator em três timeframes distintos para detectar sinais de compra e venda. O propósito do EA é ajudar os traders a tomar decisões fundamentadas, confirmando sinais em múltiplos timeframes antes de entrar numa operação. Incluímos vários timeframes, as Bandas de Bollinger (BB) e o Oscilador Estocástico para gerar sinais. Nosso objetivo é minimizar sinais falsos que podem causar transtornos aos traders. Ao combinar esses elementos, buscamos aumentar a precisão de nossos sinais de negociação. Abaixo, elaborei uma tabela com a importância de cada componente em nossa ferramenta de geração de sinais.

  • Vários timeframes
Benefício Descrição
Gerenciamento de risco O uso de vários timeframes permite que o EA analise o mercado sob diferentes pontos de vista, reduzindo o impacto de falsos sinais e melhorando o gerenciamento de risco.
Confiança nos sinais Ao confirmar sinais em vários timeframes, o EA ganha confiança na direção da negociação, reduzindo a probabilidade de entrar em uma operação com um sinal fraco ou falso.
Diversificação A análise de múltiplos timeframes fornece uma visão de mercado mais diversificada, permitindo que o EA se adapte a condições de mercado em mudança e tome decisões de negociação mais fundamentadas.
  • Estocástico
Benefício Descrição
Condições de sobrecompra/sobrevenda
O Estocástico ajuda a identificar condições de sobrecompra e sobrevenda, indicando possíveis pontos de reversão no mercado.
Ferramenta de confirmação
O Estocástico serve como ferramenta de confirmação para as Bandas de Bollinger, garantindo que o EA não entre em uma operação baseado exclusivamente em sinais das Bollinger.
Filtragem de sinais falsos
Utilizando o Estocástico, o EA pode filtrar sinais falsos gerados pelas Bandas de Bollinger, especialmente em períodos de alta volatilidade.

  • Bandas de Bollinger
Benefício Descrição
Indicação de volatilidade
As Bandas de Bollinger mostram o nível de volatilidade do mercado, ajudando o EA a compreender o sentimento do mercado e identificar potenciais oportunidades de negociação.
Níveis de suporte/resistência
As Bandas de Bollinger atuam como níveis dinâmicos de suporte e resistência, fornecendo ao EA possíveis pontos de entrada e saída.
Confirmação de tendência 
A largura das Bandas de Bollinger pode confirmar ou refutar a presença de uma tendência, ajudando o EA a tomar decisões de negociação fundamentadas.

A interação entre múltiplos timeframes, o Estocástico e as Bandas de Bollinger (BB) aumenta significativamente a eficiência do EA na geração de sinais de negociação confiáveis e no gerenciamento de riscos. Ao analisar sinais em diferentes timeframes, o EA garante que as oportunidades de negociação sejam confirmadas por uma combinação sólida dos indicadores Stochastic e BB. Essa abordagem multidimensional reduz a probabilidade de sinais falsos, já que o EA identifica operações potenciais apenas quando existem evidências convincentes que sustentam a decisão. Como resultado, a combinação desses elementos aumenta a confiabilidade dos sinais gerados e melhora o gerenciamento geral de risco, permitindo que os traders tomem decisões mais fundamentadas. 


Estratégia

O script Signal Pulse gera sinais de negociação com base no alinhamento das Bandas de Bollinger e do Oscilador Estocástico em três timeframes (M15, M30 e H1). As condições para cada tipo de sinal são as seguintes:

Sinal de compra

  1. Condição das Bandas de Bollinger: o preço toca a banda inferior de Bollinger em todos os três timeframes.
  2. Condição do Oscilador Estocástico: O Oscilador Estocástico indica uma condição de sobrevenda em todos os três timeframes, geralmente abaixo de 20.
  3. Requisito de confirmação: Para formar um sinal de compra, ambas as condições devem ser atendidas simultaneamente nos timeframes M15, M30 e H1.

Condições para compra

Esquema 1. Condições para compra

Sinal de venda

  1. Condição das Bandas de Bollinger: o preço toca a banda superior de Bollinger em todos os três timeframes.
  2. Condição do Oscilador Estocástico: O Oscilador Estocástico indica uma condição de sobrecompra em todos os três timeframes, geralmente acima de 80.
  3. Requisito de confirmação: Para formar um sinal de venda, ambas as condições devem ser atendidas simultaneamente nos timeframes M15, M30 e H1.

Condição para venda

Esquema 2. Condições para venda

Vamos visualizar esse processo por meio do diagrama abaixo.  

Esquema de geração de sinais

Esquema. 3. Geração de sinal


Código MQL5

//+------------------------------------------------------------------+
//|                                              Signal Pulse EA.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

// Input parameters
input ENUM_TIMEFRAMES Timeframe1 = PERIOD_M15; // M15 timeframe
input ENUM_TIMEFRAMES Timeframe2 = PERIOD_M30; // M30 timeframe
input ENUM_TIMEFRAMES Timeframe3 = PERIOD_H1;  // H1 timeframe
input int BB_Period = 20;                      // Bollinger Bands period
input double BB_Deviation = 2.0;               // Bollinger Bands deviation
input int K_Period = 14;                       // Stochastic %K period
input int D_Period = 3;                        // Stochastic %D period
input int Slowing = 3;                         // Stochastic slowing
input double SignalOffset = 10.0;              // Offset in points for signal arrow
input int TestBars = 10;                       // Number of bars after signal to test win condition
input double MinArrowDistance = 5.0;          // Minimum distance in points between arrows to avoid overlapping

// Signal tracking structure
struct SignalInfo
  {
   datetime          time;
   double            price;
   bool              isBuySignal;
  };

// Arrays to store signal information
datetime signalTimes[];
double signalPrices[];
bool signalBuySignals[];

//+------------------------------------------------------------------+
//| Retrieve Bollinger Band Levels                                   |
//+------------------------------------------------------------------+
bool GetBollingerBands(ENUM_TIMEFRAMES timeframe, double &upper, double &lower, double &middle)
  {
   int handle = iBands(Symbol(), timeframe, BB_Period, 0, BB_Deviation, PRICE_CLOSE);

   if(handle == INVALID_HANDLE)
     {
      Print("Error creating iBands for timeframe: ", timeframe);
      return false;
     }

   double upperBand[], middleBand[], lowerBand[];

   if(!CopyBuffer(handle, 1, 0, 1, upperBand) ||
      !CopyBuffer(handle, 0, 0, 1, middleBand) ||
      !CopyBuffer(handle, 2, 0, 1, lowerBand))
     {
      Print("Error copying iBands buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
     }

   upper = upperBand[0];
   middle = middleBand[0];
   lower = lowerBand[0];

   IndicatorRelease(handle);
   return true;
  }

//+------------------------------------------------------------------+
//| Retrieve Stochastic Levels                                       |
//+------------------------------------------------------------------+
bool GetStochastic(ENUM_TIMEFRAMES timeframe, double &k_value, double &d_value)
  {
   int handle = iStochastic(Symbol(), timeframe, K_Period, D_Period, Slowing, MODE_SMA, STO_CLOSECLOSE);

   if(handle == INVALID_HANDLE)
     {
      Print("Error creating iStochastic for timeframe: ", timeframe);
      return false;
     }

   double kBuffer[], dBuffer[];

   if(!CopyBuffer(handle, 0, 0, 1, kBuffer) ||  // %K line
      !CopyBuffer(handle, 1, 0, 1, dBuffer))   // %D line
     {
      Print("Error copying iStochastic buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
     }

   k_value = kBuffer[0];
   d_value = dBuffer[0];

   IndicatorRelease(handle);
   return true;
  }

//+------------------------------------------------------------------+
//| Check and Generate Signal                                        |
//+------------------------------------------------------------------+
void CheckAndGenerateSignal()
  {
   double upper1, lower1, middle1, close1;
   double upper2, lower2, middle2, close2;
   double upper3, lower3, middle3, close3;
   double k1, d1, k2, d2, k3, d3;

   if(!GetBollingerBands(Timeframe1, upper1, lower1, middle1) ||
      !GetBollingerBands(Timeframe2, upper2, lower2, middle2) ||
      !GetBollingerBands(Timeframe3, upper3, lower3, middle3))
     {
      Print("Error retrieving Bollinger Bands data.");
      return;
     }

   if(!GetStochastic(Timeframe1, k1, d1) ||
      !GetStochastic(Timeframe2, k2, d2) ||
      !GetStochastic(Timeframe3, k3, d3))
     {
      Print("Error retrieving Stochastic data.");
      return;
     }

// Retrieve the close prices
   close1 = iClose(Symbol(), Timeframe1, 0);
   close2 = iClose(Symbol(), Timeframe2, 0);
   close3 = iClose(Symbol(), Timeframe3, 0);

   bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                    (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition
   bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                     (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

// Check if an arrow already exists in the same region before placing a new one
   if(buySignal && !ArrowExists(close1))
     {
      Print("Buy signal detected on all timeframes with Stochastic confirmation!");

      string arrowName = "BuySignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 241);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrGreen);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = true;
     }

   if(sellSignal && !ArrowExists(close1))
     {
      Print("Sell signal detected on all timeframes with Stochastic confirmation!");

      string arrowName = "SellSignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 242);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrRed);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = false;
     }
  }

//+------------------------------------------------------------------+
//| Check if an arrow already exists within the MinArrowDistance     |
//+------------------------------------------------------------------+
bool ArrowExists(double price)
  {
   for(int i = 0; i < ArraySize(signalPrices); i++)
     {
      if(MathAbs(signalPrices[i] - price) <= MinArrowDistance)
        {
         return true; // Arrow exists in the same price region
        }
     }
   return false; // No arrow exists in the same region
  }

//+------------------------------------------------------------------+
//| OnTick Event                                                     |
//+------------------------------------------------------------------+
void OnTick()
  {
   CheckAndGenerateSignal();
  }

//+------------------------------------------------------------------+
//| OnDeinit Function                                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Clean up the objects
   long chart_id = 0;
   for(int i = ObjectsTotal(chart_id) - 1; i >= 0; i--)
     {
      string name = ObjectName(chart_id, i);
      if(StringFind(name, "Signal") != -1)
        {
         ObjectDelete(chart_id, name);
        }
     }

   Print("Multitimeframe Bollinger-Stochastic Analyzer deinitialized.");
  }
//+------------------------------------------------------------------+



Análise do código

Nesta análise do EA Signal Pulse, serão examinados passo a passo os diferentes componentes do EA, os mecanismos do seu funcionamento e a lógica básica do seu sistema.
  • Título, propriedades e parâmetros de entrada

Logo no início do nosso EA, incluímos o cabeçalho que fornece os metadados necessários. Ele é composto pelo nome do EA, informações de direitos autorais e links de referência. Mas o que realmente importa para nós, como traders, são os parâmetros de entrada. Esses parâmetros configuráveis permitem que você adapte o comportamento do EA ao seu estilo de negociação.

//+------------------------------------------------------------------+
//|                                              Signal Pulse EA.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/en/users/lynnchris"
#property version   "1.00"

// Input parameters
input ENUM_TIMEFRAMES Timeframe1 = PERIOD_M15; // M15 timeframe
input ENUM_TIMEFRAMES Timeframe2 = PERIOD_M30; // M30 timeframe
input ENUM_TIMEFRAMES Timeframe3 = PERIOD_H1;  // H1 timeframe
input int BB_Period = 20;                      // Bollinger Bands period
input double BB_Deviation = 2.0;               // Bollinger Bands deviation
input int K_Period = 14;                       // Stochastic %K period
input int D_Period = 3;                        // Stochastic %D period
input int Slowing = 3;                         // Stochastic slowing
input double SignalOffset = 10.0;              // Offset in points for signal arrow
input int TestBars = 10;                       // Number of bars after signal to test win condition
input double MinArrowDistance = 5.0;          // Minimum distance in points between arrows to avoid overlapping
Aqui especificamos diferentes timeframes (M15, M30 e H1), o que possibilita analisar a dinâmica de preços em múltiplos períodos. Também definimos os parâmetros das Bandas de Bollinger, como o período e o desvio, além das configurações do Oscilador Estocástico, incluindo os períodos %K e %D. Incluímos ainda configurações visuais para as setas que marcarão os sinais de compra e venda no gráfico, bem como parâmetros destinados a minimizar a desordem visual, evitando a sobreposição das setas.
  •  Monitoramento de sinais e estruturas

Em seguida, definimos a estrutura SignalInfo, que desempenha um papel importante na organização dos sinais de negociação. Essa estrutura reúne informações sobre o momento em que o sinal ocorreu, o preço naquele instante e se foi um sinal de compra ou de venda. Além disso, configuramos arrays para armazenar dinamicamente essas informações. 

// Signal tracking structure
struct SignalInfo {
   datetime time;
   double price;
   bool isBuySignal;
};

// Arrays to store signal information
datetime signalTimes[];
double signalPrices[];
bool signalBuySignals[];
Por meio dos arrays signalTimes, signalPrices e signalBuySignals, registramos os sinais de negociação que o EA gera ao longo do tempo, o que facilita significativamente o processamento de múltiplos sinais e ajuda a evitar confusões.
  •  Funções de busca de indicadores

Agora vamos examinar com mais detalhe as funções que utilizamos para extrair os valores dos indicadores, em especial das Bandas de Bollinger e dos indicadores Estocásticos. 

//+------------------------------------------------------------------+
//| Retrieve Bollinger Band Levels                                   |
//+------------------------------------------------------------------+
bool GetBollingerBands(ENUM_TIMEFRAMES timeframe, double &upper, double &lower, double &middle) {
   int handle = iBands(Symbol(), timeframe, BB_Period, 0, BB_Deviation, PRICE_CLOSE);

   if(handle == INVALID_HANDLE) {
      Print("Error creating iBands for timeframe: ", timeframe);
      return false;
   }

   double upperBand[], middleBand[], lowerBand[];

   if(!CopyBuffer(handle, 1, 0, 1, upperBand) ||
      !CopyBuffer(handle, 0, 0, 1, middleBand) ||
      !CopyBuffer(handle, 2, 0, 1, lowerBand)) {
      Print("Error copying iBands buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
   }

   upper = upperBand[0];
   middle = middleBand[0];
   lower = lowerBand[0];

   IndicatorRelease(handle);
   return true;
}

//+------------------------------------------------------------------+
//| Retrieve Stochastic Levels                                       |
//+------------------------------------------------------------------+
bool GetStochastic(ENUM_TIMEFRAMES timeframe, double &k_value, double &d_value) {
   int handle = iStochastic(Symbol(), timeframe, K_Period, D_Period, Slowing, MODE_SMA, STO_CLOSECLOSE);

   if(handle == INVALID_HANDLE) {
      Print("Error creating iStochastic for timeframe: ", timeframe);
      return false;
   }

   double kBuffer[], dBuffer[];

   if(!CopyBuffer(handle, 0, 0, 1, kBuffer) ||  // %K line
      !CopyBuffer(handle, 1, 0, 1, dBuffer)) { // %D line
      Print("Error copying iStochastic buffer for timeframe: ", timeframe);
      IndicatorRelease(handle);
      return false;
   }

   k_value = kBuffer[0];
   d_value = dBuffer[0];

   IndicatorRelease(handle);
   return true;
}
A primeira função, GetBollingerBands(), extrai os níveis superior, médio e inferior das Bandas de Bollinger para o timeframe especificado. Ela cria um handle para o indicador e verifica se ele foi criado com sucesso. Se tudo estiver correto, copia os valores das bandas para arrays, que posteriormente podemos usar em nossa lógica de negociação. De maneira análoga, a função GetStochastic() extrai os valores de %K e %D do Oscilador Estocástico. Ela utiliza os mesmos procedimentos de verificação de erros e cópia de dados, garantindo que sempre obtenhamos dados precisos para a tomada de decisão.

  • Verificação e geração de sinais

Agora passamos à função CheckAndGenerateSignal(), que contém a lógica principal do nosso EA. Essa função chama as funções de indicadores que definimos anteriormente para coletar dados das Bandas de Bollinger e dos indicadores Estocásticos em todos os timeframes especificados. Além disso, ela obtém os preços de fechamento mais recentes desses timeframes.

A função verifica sinais de compra e venda com base nas condições atuais do mercado. Um sinal de compra é acionado quando os preços de fechamento caem abaixo da banda inferior de Bollinger e os valores do Estocástico indicam uma condição de sobrevenda (menor que 5). De forma oposta, os sinais de venda ocorrem quando os preços ultrapassam a banda superior de Bollinger e as leituras do Estocástico excedem 95, indicando uma condição de sobrecompra.

//+------------------------------------------------------------------+
//| Check and Generate Signal                                        |
//+------------------------------------------------------------------+
void CheckAndGenerateSignal() {
   double upper1, lower1, middle1, close1;
   double upper2, lower2, middle2, close2;
   double upper3, lower3, middle3, close3;
   double k1, d1, k2, d2, k3, d3;

   if(!GetBollingerBands(Timeframe1, upper1, lower1, middle1) ||
      !GetBollingerBands(Timeframe2, upper2, lower2, middle2) ||
      !GetBollingerBands(Timeframe3, upper3, lower3, middle3)) {
      Print("Error retrieving Bollinger Bands data.");
      return;
   }

   if(!GetStochastic(Timeframe1, k1, d1) ||
      !GetStochastic(Timeframe2, k2, d2) ||
      !GetStochastic(Timeframe3, k3, d3)) {
      Print("Error retrieving Stochastic data.");
      return;
   }

   // Retrieve the close prices
   close1 = iClose(Symbol(), Timeframe1, 0);
   close2 = iClose(Symbol(), Timeframe2, 0);
   close3 = iClose(Symbol(), Timeframe3, 0);

   bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                    (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition
   bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                     (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

   // Check if an arrow already exists in the same region before placing a new one
   if(buySignal && !ArrowExists(close1)) {
      Print("Buy signal detected on all timeframes with Stochastic confirmation!");
      string arrowName = "BuySignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 241);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrGreen);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = true;
   }

   if(sellSignal && !ArrowExists(close1)) {
      Print("Sell signal detected on all timeframes with Stochastic confirmation!");
      string arrowName = "SellSignal" + IntegerToString(TimeCurrent());
      ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1);
      ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 242);
      ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrRed);
      ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2);

      // Store signal data
      ArrayResize(signalTimes, ArraySize(signalTimes) + 1);
      ArrayResize(signalPrices, ArraySize(signalPrices) + 1);
      ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1);

      signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent();
      signalPrices[ArraySize(signalPrices) - 1] = close1;
      signalBuySignals[ArraySize(signalBuySignals) - 1] = false;
   }
}

Além disso, antes de desenhar uma seta para marcar o sinal no gráfico, a função verifica se não há sobreposição com uma seta existente, por meio da chamada da função ArrowExists(). Se tudo estiver correto, ela cria a seta correspondente e salva as informações do sinal nos arrays que definimos anteriormente.

  • Verificação da existência de setas

A função ArrowExists() permite manter o gráfico limpo e organizado, verificando se existe alguma seta próxima ao preço do novo sinal. Isso evita a sobreposição de múltiplas setas, o que poderia causar confusão. Ao comparar o novo preço do sinal com os preços armazenados no array signalPrices, determinamos se já existe uma seta suficientemente próxima para que a criação de uma nova seja desnecessária.

//+------------------------------------------------------------------+
//| Check if an arrow already exists within the MinArrowDistance     |
//+------------------------------------------------------------------+
bool ArrowExists(double price) {
   for(int i = 0; i < ArraySize(signalPrices); i++) {
      if(MathAbs(signalPrices[i] - price) <= MinArrowDistance) {
         return true; // Arrow exists in the same price region
      }
   }
   return false; // No arrow exists in the same region
}

  • Funções OnTick e OnDeinit

Por fim, temos as funções OnTick() e OnDeinit(). A função OnTick() é chamada toda vez que chega um novo tick do mercado, garantindo que o nosso EA permaneça responsivo e atualizado. Ela chama a função CheckAndGenerateSignal() para reavaliar possíveis sinais de negociação com base nos dados mais recentes.

Já a função OnDeinit() é chamada quando o EA é removido do gráfico ou quando o terminal é fechado. Sua tarefa é limpar todos os objetos gráficos criados pelo EA, especialmente as setas que indicam sinais de compra e venda, mantendo assim o gráfico organizado.

//+------------------------------------------------------------------+
//| OnTick Event                                                     |
//+------------------------------------------------------------------+
void OnTick() {
   CheckAndGenerateSignal();
}

//+------------------------------------------------------------------+
//| OnDeinit Function                                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
   // Clean up the objects
   long chart_id = 0;
   for(int i = ObjectsTotal(chart_id) - 1; i >= 0; i--) {
      string name = ObjectName(chart_id, i);
      if(StringFind(name, "Signal") != -1) {
         ObjectDelete(chart_id, name);
      }
   }

   Print("Multitimeframe Bollinger-Stochastic Analyzer deinitialized.");
}

Além disso, no EA Signal Pulse ajustamos os níveis de limite do Oscilador Estocástico para garantir a geração apenas dos sinais mais confiáveis. Essas modificações têm como objetivo confirmar que o mercado se encontra em condições extremas — ou seja, em sobrevenda para sinais de compra, ou em sobrecompra para sinais de venda — antes de executar qualquer ação.

  • Condição de sobrevenda: sinal de compra
bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) &&
                 (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition

Para um sinal de compra, o preço deve estar no nível ou abaixo da banda inferior de Bollinger em todos os três timeframes (M15, M30, H1), o que indica uma forte pressão de baixa. Além disso, o valor de %K do Oscilador Estocástico deve ser menor que 5 em todos os três timeframes. Esse valor representa uma condição de sobrevenda extrema, na qual o mercado tem alta probabilidade de reverter para cima. O limite mais rigoroso de < 5 garante que o EA considere apenas sinais em que a probabilidade de reversão seja suficientemente alta.

  • Condição de sobrecompra: sinal de venda

bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) &&
                  (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition

Para um sinal de venda, o preço deve estar no nível ou acima da banda superior de Bollinger em todos os três timeframes, o que indica um forte impulso de alta que pode se reverter em breve. O valor de %K do Oscilador Estocástico deve exceder 95 em todos os timeframes, sinalizando uma condição de sobrecompra extrema, na qual o mercado provavelmente se tornará baixista. Essa condição rigorosa garante que o EA evite sinais falsos de venda durante movimentos de preço moderados ou períodos de consolidação.


Testes e resultados

  • Testes em dados históricos
O teste em histórico é um componente essencial no desenvolvimento de EAs, pois permite que os traders analisem a eficácia de seu robô utilizando dados de preços passados. Esse processo ajuda a determinar a lucratividade, precisão e confiabilidade do EA, permitindo que o trader aperfeiçoe sua estratégia e otimize o desempenho geral.
1. Carregamento dos dados históricos

Para iniciar o teste em histórico, é necessário carregar dados históricos de alta qualidade, preferencialmente no nível de ticks, para o instrumento e timeframes escolhidos. Esses dados servirão como base para a avaliação do desempenho do EA. É fundamental garantir a precisão e a confiabilidade das informações, pois qualquer inconsistência pode levar a conclusões incorretas sobre o funcionamento do EA.

2. Configuração dos parâmetros de teste

Após o carregamento dos dados, é hora de configurar o testador de estratégias no MetaTrader, definindo os parâmetros necessários. Eles incluem:
  • Símbolo – selecionar o par de moedas ou ativo para negociação.
  • Período – utilizar os mesmos timeframes definidos nas configurações do EA (por exemplo, M15, M30, H1).
  • Spread – definir um spread realista ou fixo, a fim de simular custos de negociação e garantir que os resultados reflitam condições reais de mercado.
  • Otimização – testar os parâmetros de entrada (por exemplo, o período das Bandas de Bollinger e os limites do Estocástico) para alcançar o melhor desempenho possível.
3. Avaliação dos resultados
Após a configuração dos parâmetros de teste, chega o momento de analisar os resultados obtidos:
  • Lucratividade: avaliar o lucro líquido do EA e o fator de lucro para determinar sua rentabilidade geral.
  • Risco: avaliar o rebaixamento máximo (drawdown) para estimar a resistência do EA ao risco.
  • Taxa de operações lucrativas e frequência de operações: analisar o número de operações bem-sucedidas e a frequência com que elas ocorrem, a fim de compreender a eficiência do EA em diferentes condições de mercado.

Vamos observar os resultados dos testes apresentados a seguir.

Resultado do teste 1

Fig. 4. Resultado do teste 1

Resultado 2

Esquema. 5. Resultado do teste 2

Os gráficos acima ilustram o teste de desempenho do EA. Na animação GIF, podemos observar o registro de cada sinal detectado. Você pode continuar os testes ajustando os parâmetros de entrada, os timeframes e os níveis do Estocástico até alcançar resultados que atendam às suas exigências.


Conclusão

Neste artigo, desenvolvemos o EA Signal Pulse, que combina as Bandas de Bollinger e o Oscilador Estocástico para gerar sinais de negociação nos timeframes M15, M30 e H1. O sistema identifica condições de sobrecompra/sobrevenda apenas quando há coincidência entre múltiplos timeframes, o que aumenta a probabilidade de sucesso. É fundamental realizar testes detalhados em diferentes condições de mercado. Melhorias futuras podem incluir a adição de filtros de direção de tendência, aprimoramento do gerenciamento de risco e refinamento da lógica de sinais para diferentes tipos de mercado. Incentivamos os traders a utilizarem o Signal Pulse junto de suas próprias estratégias e metodologias, adotando uma abordagem abrangente para a negociação.

Data Nome da ferramenta  Descrição Versão  Atualizações  Observações
01/10/24 Chart Projector Script que sobrepõe o efeito “fantasma” ao movimento do preço do dia anterior. 1.0 Versão inicial Primeira ferramenta do Lynnchris Tools Chest
18/11/24 Analytical Comment Fornece informações do dia anterior em formato de tabela e também prevê a direção futura do mercado. 1.0 Versão inicial Segunda ferramenta do Lynnchris Tools Chest
27/11/24 Analytics Master Atualiza regularmente os indicadores de mercado a cada duas horas.  1.01 Segunda versão Terceira ferramenta do Lynnchris Tools Chest
02/12/24 Analytics Forecaster  Atualiza regularmente os indicadores de mercado a cada duas horas, com integração ao Telegram. 1.1 Terceira versão Ferramenta número 4
09/12/24 Volatility Navigator EA que analisa as condições de mercado usando Bandas de Bollinger, RSI e ATR. 1.0 Versão inicial Ferramenta número 5
19/12/24 Mean Reversion Signal Reaper Analisa o mercado e gera sinais utilizando a estratégia de retorno à média  1.0  Versão inicial  Ferramenta número 6 
09/01/2025  Signal Pulse  Analisa múltiplos timeframes. 1.0  Versão inicial  Ferramenta número 7 

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

Arquivos anexados |
Modelos ocultos de Markov para previsão de volatilidade com consideração de tendência Modelos ocultos de Markov para previsão de volatilidade com consideração de tendência
Os modelos ocultos de Markov (HMM) são uma poderosa ferramenta estatística que permite identificar estados ocultos do mercado com base na análise de movimentos observáveis dos preços. No trading, os HMM permitem melhorar a previsão da volatilidade e são aplicados no desenvolvimento de estratégias de tendência, modelando as mudanças nos regimes de mercado. Neste artigo, apresentaremos um processo passo a passo para o desenvolvimento de uma estratégia de seguimento de tendência que utiliza HMM como filtro para previsão de volatilidade.
MQL5 Trading Toolkit (Parte 5): Expansão da biblioteca EX5 para gerenciamento do histórico com funções do último ordem pendente executada MQL5 Trading Toolkit (Parte 5): Expansão da biblioteca EX5 para gerenciamento do histórico com funções do último ordem pendente executada
Aprenda a criar um módulo EX5 com funções exportáveis que permite consultar e armazenar facilmente os dados da última ordem pendente executada. Neste guia passo a passo, aprimoraremos a biblioteca EX5 de gerenciamento de histórico (History Management) desenvolvendo funções especializadas e independentes para extrair as principais propriedades da última ordem pendente executada. Entre essas propriedades estão o tipo de ordem, o horário de colocação, o horário de execução, o tipo de execução e outros dados importantes necessários para o gerenciamento e análise eficaz do histórico de operações com ordens pendentes.
Integrando MQL5 com pacotes de processamento de dados (Parte 4): Manipulação de Big Data Integrando MQL5 com pacotes de processamento de dados (Parte 4): Manipulação de Big Data
Explorando técnicas avançadas para integrar o MQL5 com ferramentas poderosas de processamento de dados, esta parte se concentra no tratamento eficiente de big data para aprimorar a análise de negociação e a tomada de decisões.
Recursos do Assistente MQL5 que você precisa conhecer (Parte 52): Oscilador Accelerator Recursos do Assistente MQL5 que você precisa conhecer (Parte 52): Oscilador Accelerator
O Oscilador de Aceleração (Accelerator Oscillator) é mais um dos indicadores de Bill Williams, que monitora a aceleração do impulso de preço, e não apenas sua velocidade. Embora seja em muitos aspectos semelhante ao oscilador Awesome, que analisamos em um artigo recente, ele busca evitar os efeitos de defasagem, concentrando-se na aceleração e não apenas na taxa de variação. Como de costume, vamos examinar os padrões do indicador e também seu significado no trading com o uso de um EA criado no Assistente.