English Русский 中文 Español Deutsch 日本語
preview
Um Guia Passo a Passo sobre a Estratégia de Quebra de Estrutura (BoS)

Um Guia Passo a Passo sobre a Estratégia de Quebra de Estrutura (BoS)

MetaTrader 5Negociação |
1 183 9
Allan Munene Mutiiria
Allan Munene Mutiiria

Introdução

Neste artigo, discutiremos a Quebra de Estrutura (BoS), um termo que significa uma mudança significativa na tendência ou direção do mercado, estratégia de negociação forex, no contexto do Conceito de Smart Money (SMC), e a criação de um Expert Advisor (EA) baseado nisso.

Vamos explorar a definição, tipos, aplicações da estratégia de negociação e desenvolvimento em MetaQuotes Language 5 (MQL5) para MetaTrader 5 (MT5) enquanto mergulhamos nas nuances da Quebra de Estrutura. O conceito de Quebra de Estrutura é uma ferramenta útil para os traders aprenderem a fim de aumentar sua capacidade de prever movimentos do mercado, tomar melhores decisões e, eventualmente, se tornarem proficientes em gerenciamento de riscos. Usando os seguintes tópicos, realizaremos o acima:

  1. Definição de Quebra de Estrutura (BoS)
  2. Break of Structure (BoS) description
  3. Tipos de Quebra de Estrutura (BoS)
  4. Descrição da estratégia de negociação
  5. Esboço da estratégia de negociação
  6. Implementação em MetaQuotes Language 5 (MQL5)
  7. Resultados do Strategy Tester
  8. Conclusão

Nesta jornada, usaremos extensivamente o MetaQuotes Language 5 (MQL5) como nosso ambiente de codificação base IDE, e executaremos os arquivos no terminal de negociação MetaTrader 5 (MT5). Portanto, ter as versões mencionadas será de extrema importância. Vamos começar então.


Definição de Quebra de Estrutura (BoS)

A Quebra de Estrutura (BoS) é um conceito-chave na análise técnica que utiliza os Conceitos de Smart Money (SMCs) para identificar mudanças significativas nas tendências ou direções do mercado. Geralmente ocorre quando o preço se move decisivamente através de mínimos ou máximos que foram estabelecidos pela ação de preço anterior. Quando os preços sobem acima dos máximos ou caem abaixo dos mínimos, eles simplesmente rompem a estrutura de mercado previamente formada e, por isso, o nome “Quebra” de estrutura. Isso geralmente indica uma mudança no sentimento do mercado e na direção da tendência, sinalizando uma continuação da tendência existente ou o início de uma nova tendência.


Descrição de Quebra de Estrutura (BoS)

Para descrever efetivamente uma Quebra de Estrutura (BoS), vamos primeiro distingui-la dos outros elementos do Conceito de Smart Money, que são Mudança de Estrutura de Mercado (MSS) e Mudança de Caráter (CHoCH).

  • Mudança de Estrutura de Mercado (MSS)

Mudança de Estrutura de Mercado, que você também pode ter ouvido como Mudança de Momento de Mercado (MMS), ocorre devido a uma quebra de preço no máximo mais recente em relação a uma tendência de baixa ou inversamente o máximo mais recente sobre uma tendência de alta, sem primeiro romper o mínimo ou máximo mais recente, respectivamente. Isso significa uma reversão de tendência devido à mudança de estrutura, daí o nome “mudança” na estrutura de mercado.

Mudança de Estrutura de Mercado

  • Mudança de Caráter (CHoCH)

Por outro lado, a Mudança de Caráter ocorre devido à quebra de preço do máximo mais recente em uma tendência de baixa após romper primeiro o mínimo mais recente, ou devido à quebra de preço do mínimo mais recente em uma tendência de alta, após romper primeiro o máximo mais recente.

Mudança de Caráter

  • Quebra de Estrutura (BoS)

Agora que conhecemos as principais diferenças entre os três principais elementos da abordagem do Conceito de Smart Money baseado na estrutura de mercado, vamos nos aprofundar no tema principal do artigo, que é sua quebra. Pela definição fornecida anteriormente, você deve ter notado que uma Quebra de Estrutura significa romper máximos ou mínimos antigos para formar novos máximos ou mínimos, respectivamente. Cada ocorrência de uma Quebra de Estrutura auxilia a tendência do mercado a subir, formando um novo Máximo Maior (HH) e um novo Mínimo Maior (HL), ou a descer, formando um novo Máximo Menor (LH) e um novo Mínimo Menor (LL), geralmente descritos como os pontos de máximos e mínimos do preço.

Quebra de Estrutura

Uma regra prevalece: a quebra deve ocorrer com o fechamento da vela. Isso significa que, no caso de uma quebra em relação ao máximo, o preço de fechamento deve estar acima do ponto de oscilação, enquanto no caso de uma quebra em relação ao mínimo, o preço de fechamento também deve estar abaixo do ponto de oscilação. Simplificando, apenas quebras nos corpos das velas ou barras são consideradas quebras de estrutura válidas, o que significa que quebras em caudas, sombras ou pavios são consideradas quebras de estrutura inválidas.

  • Configurações de BoS inválidas:

BoS inválido

  • Configurações de BoS válidas:

BoS válido


Tipos de Quebra de Estrutura

Como já mencionado, as Quebras de Estrutura ocorrem em mercados de tendência, o que significa que ocorrem em tendências de alta ou de baixa. Isso já sugere que temos apenas dois tipos de Quebras de Estrutura.

  • Quebra de Estrutura Altista

Estas ocorrem em tendências de alta caracterizadas por máximos mais altos (HH) e mínimos mais altos (HL). Tecnicamente, uma Quebra de Estrutura resulta do preço rompendo o máximo mais alto recente na tendência de alta, formando um novo máximo mais alto.

Bull BoS

  • Quebra de Estrutura Baixista

Aqui, a Quebra de Estrutura Baixista ocorre em tendências de baixa, compostas por mínimos mais baixos (LL) e máximos mais baixos (LH). Uma Quebra de Estrutura resulta do preço rompendo o mínimo mais baixo recente na tendência de baixa, formando um novo mínimo mais baixo.

Bear BoS


Descrição da estratégia de negociação

Para negociar efetivamente usando essa estratégia, você precisa de uma série de etapas, mas não se preocupe. Vamos cobri-las passo a passo. 

Baseie-se em timeframes mais altos (HTF): Primeiramente, para uma análise abrangente, examine timeframes mais altos para um ativo selecionado, pois isso fornece uma visão geral das tendências do mercado. Isso pode incluir um timeframe de quatro horas ou diário, pois tendem a revelar a trajetória de longo prazo do mercado. Evitamos usar timeframes mais baixos, pois contêm muitos pontos de oscilação devido às manipulações, varreduras de liquidez e ziguezagues, como um motorista embriagado, resultando em quebras menos significativas.

Identifique a tendência do mercado subjacente: Em segundo lugar, você precisa identificar a tendência atual do mercado em seu gráfico. Tendências de alta contêm padrões de máximos mais altos e mínimos mais altos na ação do preço, enquanto as tendências de baixa consistem em padrões de mínimos mais baixos e máximos mais baixos.

Identifique os pontos de entrada: Depois de identificar a tendência atual em um timeframe mais alto, você pode entrar no mercado na quebra de um máximo ou mínimo que feche com o corpo da vela de rompimento. Quanto mais forte a vela, mais segura a confirmação do sinal.

Exemplo de tendência de alta:

Exemplo de tendência de alta:

Exemplo de tendência de baixa:

Exemplo de tendência de baixa:

Em um timeframe menor, como cinco minutos, você pode usar estratégias de confirmação adicionais, como oferta e demanda, indicadores técnicos como Índice de Força Relativa (RSI) e MACD (Moving Average Convergence Divergence), ou padrões de velas japonesas como padrões de engolfo ou padrões de barra interna.

Identifique os pontos de saída: Após entrar no mercado, precisamos de uma estratégia sólida também para sair do mercado enquanto gerenciamos nossos riscos. Para o stop loss, colocamos no ponto de oscilação anterior, desde que esteja próximo ao ponto de entrada da posição, deixando uma margem de lucro significativa para nós. Se não for o caso, usamos uma relação risco-recompensa de pips fixos. Por outro lado, realizamos o lucro no próximo ponto de oscilação, mas como é difícil determinar o ponto de oscilação futuro para o nível de realização do lucro, usamos a relação risco-recompensa como um farol para a realização do lucro.

Esboço da estratégia de negociação

Para entender facilmente o conceito que transmitimos, vamos visualizá-lo em um esboço.

Quebra de Estrutura Altista:

Esboço de BoS Altista

Quebra de Estrutura Baixista:

Esboço de BoS Baixista


Implementação em MetaQuotes Language 5 (MQL5) para MetaTrader 5 (MT5)

Após aprender todas as teorias sobre a estratégia de negociação de Quebra de Estrutura, vamos automatizar a teoria e criar um Expert Advisor (EA) em MetaQuotes Language 5 (MQL5) para MetaTrader 5.

Para criar um EA, no seu terminal MetaTrader 5, clique na aba Ferramentas e selecione MetaQuotes Language Editor, ou simplesmente pressione F4 no seu teclado. Isso abrirá o ambiente MetaQuotes Language Editor, que permite escrever robôs de trading, indicadores técnicos, scripts e bibliotecas de funções.

Abrir MetaQuotes

Uma vez que o MetaEditor esteja aberto, clique em Novo, e no assistente que aparece, selecione Expert Advisor (modelo) e clique em Próximo.

Criando um novo arquivo EA

Criando um novo arquivo EA

Em seguida, forneça o nome desejado para o arquivo do expert advisor, clique em Próximo, clique em Próximo novamente e depois clique em Concluir. Após fazer tudo isso, estamos prontos para codificar e programar nossa estratégia de Quebra de Estrutura (BoS).

Primeiro, incluímos uma instância de trade usando #include no início do código-fonte. Isso nos dá acesso à classe CTrade, que usaremos para criar um objeto de trade. Isso é crucial, pois precisamos dele para abrir negociações.

#include <Trade/Trade.mqh>
CTrade obj_Trade;

A maioria de nossas atividades será executada no manipulador de eventos OnTick. Como é apenas ação de preço pura, não precisaremos usar o manipulador de eventos OnInit para inicialização do indicador. Portanto, todo o nosso código será executado apenas no manipulador de eventos OnTick. Primeiro, vamos dar uma olhada nos parâmetros que a função utiliza, além de suas funções, já que é o coração deste código:

void OnTick(){

}

Como já foi visto, esta é uma função simples, mas crucial, que não recebe argumentos nem retorna nada. É apenas uma função void, o que significa que não precisa retornar nada. Esta função é usada em Expert Advisors e é executada quando há um novo tick, ou seja, uma mudança nas cotações de preços para o ativo específico.

Agora que vimos que a função OnTick é gerada em cada mudança nas cotações de preços, precisamos definir uma lógica de controle que usaremos posteriormente para controlar a execução de trechos específicos de código, de forma que sejam executados uma vez por barra e não em cada tick, pelo menos para evitar execuções de código desnecessárias, economizando assim a memória do dispositivo. Isso será necessário ao procurar por máximos e mínimos de oscilação. Não precisamos procurar em cada tick, pois sempre obteremos os mesmos resultados, desde que estejamos na mesma vela. Aqui está a lógica:

   static bool isNewBar = false;
   int currBars = iBars(_Symbol,_Period);
   static int prevBars = currBars;
   if (prevBars == currBars){isNewBar = false;}
   else if (prevBars != currBars){isNewBar = true; prevBars = currBars;}

Primeiro, declaramos uma variável booleana static chamada "isNewBar" e a inicializamos com o valor "false". O propósito dessa variável é rastrear se uma nova barra foi formada no gráfico. Declaramos a variável local com a palavra-chave "static" para que ela possa reter seu valor durante toda a vida útil da função. Isso significa que ela não será dinâmica. Tipicamente, nossa variável será sempre igual a false, a menos que a mudemos para true posteriormente, e, quando mudada, ela manterá seu valor e não será atualizada no próximo tick, ao contrário de quando é dinâmica, onde será sempre atualizada para o valor de inicialização.

Em seguida, declaramos outra variável inteira "currBars" que armazena o número calculado de barras atuais no gráfico para o símbolo de negociação e período especificados, ou, melhor dizendo, timeframe, como você pode ter ouvido. Isso é alcançado com o uso da função iBars, que leva apenas dois argumentos, ou seja, símbolo e período.

Novamente, declaramos outra variável inteira estática "prevBars" para armazenar o número total de barras anteriores no gráfico quando uma nova barra é gerada, e ainda a inicializamos com o valor das barras atuais no gráfico para a primeira execução da função. Usaremos essa variável para comparar o número atual de barras com o número anterior de barras, para determinar a ocorrência de uma nova geração de barra no gráfico.

Finalmente, usamos uma instrução condicional para verificar se o número atual de barras é igual ao número anterior de barras. Se forem iguais, isso significa que nenhuma nova barra foi formada, então a variável "isNewBar" permanece como false. Caso contrário, se as contagens de barras atuais e anteriores não forem iguais, isso indica que uma nova barra foi formada. Nesse caso, configuramos a variável "isNewBar" para true e atualizamos o "prevBars" para corresponder ao número atual de barras. Assim, com este trecho de código, podemos acompanhar se uma nova barra foi formada e usar o resultado posteriormente para garantir que executemos uma instância apenas uma vez por barra.

Agora, podemos proceder à busca dos pontos de oscilação no nosso gráfico. Precisaremos de uma faixa de varreduras para os pontos. Planejamos conseguir isso selecionando uma barra específica e escaneando todas as barras vizinhas, à direita e à esquerda, é claro, dentro da faixa de barras pré-definida, e determinando se a barra atual é a mais alta dentro da faixa em caso de um swing high, ou a mais baixa em caso de um swing low. Então, primeiro, vamos definir as variáveis que precisaremos para armazenar essa lógica.

   const int length = 20;
   const int limit = 20;

Aqui, declaramos duas variáveis inteiras "length" e "limit". Length representa a faixa de barras a ser considerada ao identificar os swing highs e lows, enquanto limit representa o índice da barra atual que está sendo escaneada naquele instante. Por exemplo, vamos supor que selecionamos uma barra no índice 10 para escanear e identificar se é um swing high. Em seguida, percorremos todas as barras vizinhas à direita e à esquerda e verificamos se há outra barra que seja mais alta que a barra atual, que está no índice 10. Portanto, a barra à esquerda é a barra antes da barra atual e, assim, é encontrada no índice (limit, que é igual a 10, + 1) 11. O mesmo ocorre quando avançamos para a direita.

Por padrão, inicializamos as variáveis com 20. Além disso, você deve ter notado que as declaramos como "const" para torná-las constantes. Isso é feito para garantir que seu valor permaneça fixo durante a execução do programa, resultando em consistência, o que ajuda a manter a mesma faixa de análise para os pontos de oscilação em diferentes barras. Manter os valores constantes também ajuda a evitar modificações acidentais das variáveis durante a execução do programa.

Vamos, então, definir rapidamente as outras variáveis cruciais do programa. Precisamos acompanhar a barra atual que está sendo analisada e avaliar sua relação com as barras vizinhas dentro da faixa predefinida. Conseguimos isso com a declaração das seguintes variáveis.

   int right_index, left_index;
   bool isSwingHigh = true, isSwingLow = true;
   static double swing_H = -1.0, swing_L = -1.0;
   int curr_bar = limit;

Primeiro, declaramos duas variáveis inteiras "right_index" e "left_index" para rastrear os índices das barras vizinhas. O índice à direita representa o índice da barra à direita da barra atual, enquanto o índice à esquerda representa o índice da barra à esquerda da barra atual, que é a barra selecionada para análise. Além disso, declaramos duas variáveis booleanas "isSwingHigh" e "isSwingLow" que servem como sinalizadores para determinar se a barra atual é um potencial swing high ou low, respectivamente, e as inicializamos com true. Após a análise, se qualquer um dos sinalizadores permanecer true, isso indicará a presença de um ponto de oscilação. Além disso, declaramos variáveis double estáticas "swing_H" e "swing_L" que armazenarão os níveis de preço dos swing highs e lows, respectivamente. Nós as inicializamos com os valores -1 para indicar que nenhum swing high ou low foi detectado ainda. Elas são feitas estáticas para garantir que, uma vez que tenhamos os pontos de oscilação, eles permaneçam inalterados e possamos armazená-los para referência futura, para identificar mais tarde se são rompidos por uma mudança de estrutura. Nós as mudaremos para -1 se houver uma quebra de estrutura, ou elas serão substituídas por novos pontos de oscilação gerados. Finalmente, temos a variável "curr_bar" que determina o ponto de partida para a análise.

Até este ponto, declaramos perfeitamente e suficientemente todas as variáveis que são cruciais para o programa, e podemos começar nosso loop de análise. Para analisar e mapear os pontos de oscilação, só precisamos fazer isso uma vez por barra. Portanto, a análise dos pontos de oscilação será feita apenas uma vez por barra, e é aqui que nossa variável "isNewBar" é útil.

   if (isNewBar){ ... }

Em seguida, instanciamos um loop for para encontrar os swing highs e lows.

      for (int j=1; j<=length; j++){
         right_index = curr_bar - j;
         left_index = curr_bar + j;
         if ( (high(curr_bar) <= high(right_index)) || (high(curr_bar) < high(left_index)) ){
            isSwingHigh = false;
         }
         if ( (low(curr_bar) >= low(right_index)) || (low(curr_bar) > low(left_index)) ){
            isSwingLow = false;
         }
      }

Declaramos uma variável inteira de loop "j" para representar o número de barras a serem consideradas ao comparar a barra atual com suas vizinhas. Depois, calculamos o índice da barra à direita da barra atual subtraindo "j" da barra atual. Usando a mesma lógica, obtemos o índice da barra vizinha no lado esquerdo adicionando "j" à barra atual. Se fôssemos imprimir os resultados por motivos de visualização, isso é o que obteríamos:

Índice das Barras

As instruções de impressão foram alcançadas usando a seguinte função interna:

         Print("Current Bar Index = ",curr_bar," ::: Right index: ",right_index,", Left index: ",left_index);

Até aqui, é claro que, para o índice da barra selecionada, neste caso, 20, avaliamos todas as barras vizinhas à esquerda e à direita dentro do comprimento especificado. É evidente que, em cada iteração, subtraímos um à direita e adicionamos um à esquerda, o que resulta no índice direito atingindo o valor zero, geralmente significando a barra atual, e o índice esquerdo dobrando o comprimento predefinido. Agora que temos certeza de que fizemos a avaliação das barras corretamente, prosseguimos para determinar a presença dos pontos de oscilação em cada iteração. 

Para determinar se há um swing high, usamos uma instrução condicional para verificar se o preço mais alto da barra atual é menor ou igual ao preço mais alto da barra no índice à direita ou menor que o preço mais alto da barra no índice à esquerda. Se qualquer uma das condições for verdadeira, isso significa que a barra atual não tem um máximo mais alto em comparação com suas vizinhas, então "isSwingHigh" é configurado para false. Para determinar se há um swing low, a mesma lógica prevalece, mas com condições inversas.

Ao final do loop, se "isSwingHigh" ainda for true, isso sugere que a barra atual tem um máximo mais alto do que as barras circundantes dentro do intervalo de comprimento, marcando um potencial swing high. A mesma lógica ainda se aplica ao sinalizador de swing low. Se for verdadeiro, preenchemos as variáveis de ponto de oscilação com os respectivos preços e desenhamos os pontos de oscilação.

      if (isSwingHigh){
         swing_H = high(curr_bar);
         Print("UP @ BAR INDEX ",curr_bar," of High: ",high(curr_bar));
         drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),high(curr_bar),77,clrBlue,-1);
      }
      if (isSwingLow){
         swing_L = low(curr_bar);
         Print("DOWN @ BAR INDEX ",curr_bar," of Low: ",low(curr_bar));
         drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),low(curr_bar),77,clrRed,1);
      }

Funções personalizadas são usadas para obter os preços máximos dos pontos de swing high e os preços mínimos dos pontos de swing low. As funções são declaradas conforme abaixo:

double high(int index){return (iHigh(_Symbol,_Period,index));}
double low(int index){return (iLow(_Symbol,_Period,index));}
double close(int index){return (iClose(_Symbol,_Period,index));}
datetime time(int index){return (iTime(_Symbol,_Period,index));}

A função "high" recebe um único parâmetro ou argumento, que representa o índice da barra dentro da série de dados de preços, a partir do qual o preço máximo da barra especificada no índice dado deve ser recuperado. A mesma lógica se aplica às funções de low, close e time.

Para desenhar o ponto de oscilação no gráfico na respectiva barra para fins de visualização, usamos a seguinte função personalizada:

void drawSwingPoint(string objName,datetime time,double price,int arrCode,
   color clr,int direction){
   
   if (ObjectFind(0,objName) < 0){
      ObjectCreate(0,objName,OBJ_ARROW,0,time,price);
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objName,OBJPROP_FONTSIZE,10);
      if (direction > 0) ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if (direction < 0) ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
      
      string txt = " BoS";
      string objNameDescr = objName + txt;
      ObjectCreate(0,objNameDescr,OBJ_TEXT,0,time,price);
      ObjectSetInteger(0,objNameDescr,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objNameDescr,OBJPROP_FONTSIZE,10);
      if (direction > 0) {
         ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_UPPER);
         ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
      }
      if (direction < 0) {
         ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
         ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
      }
   }
   ChartRedraw(0);
}

A função personalizada "drawSwingPoint" recebe seis parâmetros para facilitar sua reutilização. As funções dos parâmetros são as seguintes:

  • objName: Uma string que representa o nome do objeto gráfico a ser criado.
  • time: Um valor datetime indicando a coordenada de tempo onde o objeto deve ser colocado.
  • price: Um valor double representando a coordenada de preço onde o objeto deve ser colocado.
  • arrCode: Um inteiro especificando o código da seta para o objeto seta.
  • clr: Um valor de cor (por exemplo, clrBlue, clrRed) para os objetos gráficos.
  • direction: Um inteiro indicando a direção (para cima ou para baixo) para posicionar o rótulo de texto.

A função primeiro verifica se um objeto com o nome objName especificado já existe no gráfico. Caso contrário, ela prossegue para criar os objetos. A criação do objeto é realizada com o uso da função interna "ObjectCreate", que requer a especificação do objeto a ser desenhado, neste caso, o objeto seta identificado como "OBJ_ARROW", bem como o tempo e o preço, que formam as coordenadas do ponto de criação do objeto. Depois, configuramos as propriedades do objeto, como código da seta, cor, tamanho da fonte e ponto de ancoragem. Para o código da seta, o MQL5 já possui alguns caracteres predefinidos da fonte wingdings que podem ser usados diretamente. Aqui está uma tabela especificando os caracteres:

Códigos das Setas

Até este ponto, apenas desenhamos a seta especificada no gráfico conforme abaixo:

Ponto de Oscilação Sem Descrição

Podemos ver que conseguimos desenhar os pontos de oscilação com o código da seta especificado, neste caso, usamos o código da seta 77, mas não há descrição deles. Portanto, para adicionar a respectiva descrição, prosseguimos para concatenar a seta com um texto. Criamos outro objeto de texto especificado como "OBJ_TEXT" e configuramos suas respectivas propriedades. O rótulo de texto serve como uma anotação descritiva associada ao ponto de oscilação, fornecendo contexto adicional ou informações sobre o ponto de oscilação, tornando-o mais informativo para traders e analistas. Escolhemos o valor do texto como "BoS", significando que é um ponto de oscilação.

A variável "objNameDescr" é então criada concatenando o "objName" original com o texto descritivo. Este nome combinado garante que a seta e seu rótulo de texto associado estejam vinculados. Este trecho de código específico é usado para conseguir isso.

      string txt = " BoS";
      string objNameDescr = objName + txt;
      ObjectCreate(0,objNameDescr,OBJ_TEXT,0,time,price);
      ObjectSetInteger(0,objNameDescr,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objNameDescr,OBJPROP_FONTSIZE,10);
      if (direction > 0) {
         ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_UPPER);
         ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
      }
      if (direction < 0) {
         ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
         ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
      }

Este é o resultado da concatenação do ponto de oscilação com sua descrição.

Ponto de Oscilação Com Descrição

O código completo responsável pela análise das barras, identificação dos swing highs e lows, documentação dos dados e o respectivo mapeamento dos objetos para os pontos de oscilação no gráfico é conforme abaixo:

   if (isNewBar){
      for (int j=1; j<=length; j++){
         right_index = curr_bar - j;
         left_index = curr_bar + j;

         if ( (high(curr_bar) <= high(right_index)) || (high(curr_bar) < high(left_index)) ){
            isSwingHigh = false;
         }
         if ( (low(curr_bar) >= low(right_index)) || (low(curr_bar) > low(left_index)) ){
            isSwingLow = false;
         }
      }
      
      if (isSwingHigh){
         swing_H = high(curr_bar);
         Print("UP @ BAR INDEX ",curr_bar," of High: ",high(curr_bar));
         drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),high(curr_bar),77,clrBlue,-1);
      }
      if (isSwingLow){
         swing_L = low(curr_bar);
         Print("DOWN @ BAR INDEX ",curr_bar," of Low: ",low(curr_bar));
         drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),low(curr_bar),77,clrRed,1);
      }
   }

Em seguida, identificamos as ocorrências de quebra dos pontos de oscilação, conforme descrito na parte teórica, e, se houver uma ocorrência, visualizamos a quebra e abrimos posições no mercado, respectivamente. Isso precisa ser feito a cada tick, então o fazemos sem a restrição de novas barras. Primeiro, declaramos os preços Ask e Bid que usaremos para abrir as posições uma vez que as respectivas condições sejam atendidas. Observe que isso também precisa ser feito a cada tick para obter as cotações de preços mais recentes.

   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

Aqui, declaramos as variáveis do tipo double para armazenar os preços recentes e as normalizamos para os dígitos da moeda do símbolo, arredondando o número de ponto flutuante para manter a precisão.  

Para determinar se houve um avanço no preço e uma quebra no nível do ponto de swing high, usamos uma instrução condicional. Primeiro, verificamos se um ponto de swing high existe, com a lógica de que ele é maior que zero, simplesmente porque não podemos estar rompendo acima de um swing high que não temos. Então, se já tivermos um ponto de swing high, verificamos se o preço de bid está acima do nível do swing high, para garantir que a posição de compra seja aberta no preço de ask e que os níveis de negociação, ou seja, stop loss e take profit, associados ao preço de bid, sejam corretamente mapeados em um ponto acima do nível de rompimento. Finalmente, verificamos se o preço de fechamento da barra anterior está acima do nível do swing high, para garantir que temos uma quebra válida que atende aos requisitos. Se todas as condições forem atendidas, então temos uma Quebra de Estrutura (BoS) válida, e registramos a ocorrência no jornal.

   if (swing_H > 0 && Bid > swing_H && close(1) > swing_H){
      Print("BREAK UP NOW");
      ...
   }

Para visualizar a configuração da quebra, precisaremos desenhar uma seta que se estenda do ponto de swing high até a vela onde a quebra ocorre. Isso significa que precisaremos de duas coordenadas para os dois pontos da seta a serem criados, tipicamente o início da seta que será anexado ao ponto de oscilação e o final da seta que é a vela onde ocorre a quebra. Isso é mais facilmente representado em uma imagem conforme abaixo:

Coordenadas dos Pontos

As duas coordenadas que precisamos são o tempo, mostrado como X e representado no eixo x, e o preço, mostrado como Y e representado no eixo y. Para obter as segundas coordenadas, que são a vela onde ocorre a quebra de estrutura, usamos o índice da barra atual, que é tipicamente 0. No entanto, obter o índice da barra que contém o ponto de swing high é um pouco complicado. Lembre-se de que apenas armazenamos o preço da vela de swing high. Poderíamos também armazenar o índice da barra ao mesmo tempo em que armazenamos o preço, mas seria completamente inútil, pois novas barras são geradas posteriormente. Isso não significa que não podemos encontrar o índice da barra que contém o ponto de oscilação. Podemos percorrer os preços mais altos das barras anteriores e encontrar uma que corresponda ao nosso ponto de swing high. Abaixo está como isso é realizado.

      int swing_H_index = 0;
      for (int i=0; i<=length*2+1000; i++){
         double high_sel = high(i);
         if (high_sel == swing_H){
            swing_H_index = i;
            Print("BREAK HIGH @ BAR ",swing_H_index);
            break;
         }
      }

Primeiro, declaramos uma variável inteira "swing_H_index" que manterá nosso índice de swing high e a inicializamos com zero. Depois, usamos um loop for para percorrer o dobro das barras predefinidas mais uma faixa extra de 1000 barras, apenas um número arbitrário de barras onde o ponto de oscilação poderia ser encontrado, isso pode ser qualquer valor, e comparamos o máximo da barra selecionada com o ponto de swing high armazenado. Então, se encontrarmos uma correspondência, armazenamos o índice e saímos do loop prematuramente, pois já encontramos nosso índice de barra de swing high. 

Usando o índice da barra de swing high, podemos agora recuperar as propriedades da barra, neste caso, estamos interessados apenas no tempo para marcar as coordenadas x do ponto inicial da seta. Usamos uma função personalizada que não é muito diferente da função anterior que usamos para mapear o código da seta.

void drawBreakLevel(string objName,datetime time1,double price1,
   datetime time2,double price2,color clr,int direction){
   if (ObjectFind(0,objName) < 0){
      ObjectCreate(0,objName,OBJ_ARROWED_LINE,0,time1,price1,time2,price2);
      ObjectSetInteger(0,objName,OBJPROP_TIME,0,time1);
      ObjectSetDouble(0,objName,OBJPROP_PRICE,0,price1);
      ObjectSetInteger(0,objName,OBJPROP_TIME,1,time2);
      ObjectSetDouble(0,objName,OBJPROP_PRICE,1,price2);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objName,OBJPROP_WIDTH,2);
      
      string txt = " Break   ";
      string objNameDescr = objName + txt;
      ObjectCreate(0,objNameDescr,OBJ_TEXT,0,time2,price2);
      ObjectSetInteger(0,objNameDescr,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objNameDescr,OBJPROP_FONTSIZE,10);
      if (direction > 0) {
         ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_RIGHT_UPPER);
         ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
      }
      if (direction < 0) {
         ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_RIGHT_LOWER);
         ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
      }
   }
   ChartRedraw(0);
}

Aqui estão as diferenças na função em relação à anterior.

  1. Declaramos o nome da função como "drawBreakLevel".
  2. O objeto que criamos é uma linha com seta identificada como "OBJ_ARROWED_LINE".
  3. Nossa linha com seta contém duas coordenadas com tempo 1 e preço 1 para a primeira, e tempo 2 e preço 2 para a segunda coordenada.
  4. O texto concatenado é "Break", sinalizando que ocorreu uma Quebra de Estrutura (BoS).

Usamos então a função para desenhar a linha de nível de quebra com seta no gráfico. Para o tempo 2 da segunda coordenada, apenas adicionamos 1, o que nos leva à barra antes da barra atual para precisão. Depois, redefinimos o valor da variável swing high para -1, para indicar que já rompemos a estrutura, e a configuração não existe mais. Isso ajuda a evitar a busca pela quebra do swing high nos ticks subsequentes, pois já rompemos o ponto de swing high. Portanto, apenas aguardamos a formação de outro ponto de swing high, e a variável é preenchida novamente e o loop continua.

      drawBreakLevel(TimeToString(time(0)),time(swing_H_index),high(swing_H_index),
      time(0+1),high(swing_H_index),clrBlue,-1);
      
      swing_H = -1.0;

Finalmente, abrimos uma posição de compra assim que ocorre a quebra do ponto de swing high. 

      //--- Open Buy
      obj_Trade.Buy(0.01,_Symbol,Ask,Bid-500*7*_Point,Bid+500*_Point,"BoS Break Up BUY");
      
      return;

Usamos nosso objeto "obj_Trade" e o operador ponto para acessar todos os métodos contidos na classe. Neste caso, só precisamos comprar, então usamos o método "Buy", fornecendo o volume, os níveis de negociação e o comentário da negociação. Finalmente, apenas retornamos, pois tudo está configurado e não temos mais código para executar. No entanto, se você tiver código adicional, evite usar o operador de retorno, pois ele termina a execução da função atual e retorna o controle para o programa que a chamou. O código completo que garante que encontramos as quebras de estrutura, desenhamos as linhas com seta e abrimos posições de compra é conforme abaixo:

   if (swing_H > 0 && Bid > swing_H && close(1) > swing_H){
      Print("BREAK UP NOW");
      int swing_H_index = 0;
      for (int i=0; i<=length*2+1000; i++){
         double high_sel = high(i);
         if (high_sel == swing_H){
            swing_H_index = i;
            Print("BREAK HIGH @ BAR ",swing_H_index);
            break;
         }
      }
      drawBreakLevel(TimeToString(time(0)),time(swing_H_index),high(swing_H_index),
      time(0+1),high(swing_H_index),clrBlue,-1);
      
      swing_H = -1.0;
      
      //--- Open Buy
      obj_Trade.Buy(0.01,_Symbol,Ask,Bid-500*7*_Point,Bid+500*_Point,"BoS Break Up BUY");
      
      return;
   }

Para a quebra de swing lows, o desenho simultâneo das linhas de quebra com seta e a abertura de posições de venda, a mesma lógica prevalece apenas com condições inversas. Seu código completo é conforme abaixo:

   else if (swing_L > 0 && Ask < swing_L && close(1) < swing_L){
      Print("BREAK DOWN NOW");
      int swing_L_index = 0;
      for (int i=0; i<=length*2+1000; i++){
         double low_sel = low(i);
         if (low_sel == swing_L){
            swing_L_index = i;
            Print("BREAK LOW @ BAR ",swing_L_index);
            break;
         }
      }
      drawBreakLevel(TimeToString(time(0)),time(swing_L_index),low(swing_L_index),
      time(0+1),low(swing_L_index),clrRed,1);

      swing_L = -1.0;
      
      //--- Open Sell
      obj_Trade.Sell(0.01,_Symbol,Bid,Ask+500*7*_Point,Ask-500*_Point,"BoS Break Down SELL");

      return;
   }

Aqui está a representação do marco.

Marco

A seguir está o código completo necessário para criar uma estratégia de negociação forex baseada em Quebra de Estrutura (BoS) em MQL5, que identifica as quebras e abre posições respectivamente.

//+------------------------------------------------------------------+
//|                                                          BOS.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

#include <Trade/Trade.mqh>
CTrade obj_Trade;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){return(INIT_SUCCEEDED);}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
   
   static bool isNewBar = false;
   int currBars = iBars(_Symbol,_Period);
   static int prevBars = currBars;
   if (prevBars == currBars){isNewBar = false;}
   else if (prevBars != currBars){isNewBar = true; prevBars = currBars;}
   
   const int length = 5;
   const int limit = 5;

   int right_index, left_index;
   bool isSwingHigh = true, isSwingLow = true;
   static double swing_H = -1.0, swing_L = -1.0;
   int curr_bar = limit;
   
   if (isNewBar){
      for (int j=1; j<=length; j++){
         right_index = curr_bar - j;
         left_index = curr_bar + j;
         //Print("Current Bar Index = ",curr_bar," ::: Right index: ",right_index,", Left index: ",left_index);
         //Print("curr_bar(",curr_bar,") right_index = ",right_index,", left_index = ",left_index);
         // If high of the current bar curr_bar is <= high of the bar at right_index (to the left),
         //or if it’s < high of the bar at left_index (to the right), then isSwingHigh is set to false
         //This means that the current bar curr_bar does not have a higher high compared
         //to its neighbors, and therefore, it’s not a swing high
         if ( (high(curr_bar) <= high(right_index)) || (high(curr_bar) < high(left_index)) ){
            isSwingHigh = false;
         }
         if ( (low(curr_bar) >= low(right_index)) || (low(curr_bar) > low(left_index)) ){
            isSwingLow = false;
         }
      }
      //By the end of the loop, if isSwingHigh is still true, it suggests that 
      //current bar curr_bar has a higher high than the surrounding bars within
      //length range, marking a potential swing high.
      
      if (isSwingHigh){
         swing_H = high(curr_bar);
         Print("UP @ BAR INDEX ",curr_bar," of High: ",high(curr_bar));
         drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),high(curr_bar),77,clrBlue,-1);
      }
      if (isSwingLow){
         swing_L = low(curr_bar);
         Print("DOWN @ BAR INDEX ",curr_bar," of Low: ",low(curr_bar));
         drawSwingPoint(TimeToString(time(curr_bar)),time(curr_bar),low(curr_bar),77,clrRed,1);
      }
   }
   
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);

   if (swing_H > 0 && Bid > swing_H && close(1) > swing_H){
      Print("BREAK UP NOW");
      int swing_H_index = 0;
      for (int i=0; i<=length*2+1000; i++){
         double high_sel = high(i);
         if (high_sel == swing_H){
            swing_H_index = i;
            Print("BREAK HIGH @ BAR ",swing_H_index);
            break;
         }
      }
      drawBreakLevel(TimeToString(time(0)),time(swing_H_index),high(swing_H_index),
      time(0+1),high(swing_H_index),clrBlue,-1);
      
      swing_H = -1.0;
      
      //--- Open Buy
      obj_Trade.Buy(0.01,_Symbol,Ask,Bid-500*7*_Point,Bid+500*_Point,"BoS Break Up BUY");
      
      return;
   }
   else if (swing_L > 0 && Ask < swing_L && close(1) < swing_L){
      Print("BREAK DOWN NOW");
      int swing_L_index = 0;
      for (int i=0; i<=length*2+1000; i++){
         double low_sel = low(i);
         if (low_sel == swing_L){
            swing_L_index = i;
            Print("BREAK LOW @ BAR ",swing_L_index);
            break;
         }
      }
      drawBreakLevel(TimeToString(time(0)),time(swing_L_index),low(swing_L_index),
      time(0+1),low(swing_L_index),clrRed,1);

      swing_L = -1.0;
      
      //--- Open Sell
      obj_Trade.Sell(0.01,_Symbol,Bid,Ask+500*7*_Point,Ask-500*_Point,"BoS Break Down SELL");

      return;
   }
   
}
//+------------------------------------------------------------------+

double high(int index){return (iHigh(_Symbol,_Period,index));}
double low(int index){return (iLow(_Symbol,_Period,index));}
double close(int index){return (iClose(_Symbol,_Period,index));}
datetime time(int index){return (iTime(_Symbol,_Period,index));}

void drawSwingPoint(string objName,datetime time,double price,int arrCode,
   color clr,int direction){
   
   if (ObjectFind(0,objName) < 0){
      ObjectCreate(0,objName,OBJ_ARROW,0,time,price);
      ObjectSetInteger(0,objName,OBJPROP_ARROWCODE,arrCode);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objName,OBJPROP_FONTSIZE,10);
      if (direction > 0) ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_TOP);
      if (direction < 0) ObjectSetInteger(0,objName,OBJPROP_ANCHOR,ANCHOR_BOTTOM);
      
      string txt = " BoS";
      string objNameDescr = objName + txt;
      ObjectCreate(0,objNameDescr,OBJ_TEXT,0,time,price);
      ObjectSetInteger(0,objNameDescr,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objNameDescr,OBJPROP_FONTSIZE,10);
      if (direction > 0) {
         ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_UPPER);
         ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
      }
      if (direction < 0) {
         ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
         ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
      }
   }
   ChartRedraw(0);
}

void drawBreakLevel(string objName,datetime time1,double price1,
   datetime time2,double price2,color clr,int direction){
   if (ObjectFind(0,objName) < 0){
      ObjectCreate(0,objName,OBJ_ARROWED_LINE,0,time1,price1,time2,price2);
      ObjectSetInteger(0,objName,OBJPROP_TIME,0,time1);
      ObjectSetDouble(0,objName,OBJPROP_PRICE,0,price1);
      ObjectSetInteger(0,objName,OBJPROP_TIME,1,time2);
      ObjectSetDouble(0,objName,OBJPROP_PRICE,1,price2);
      ObjectSetInteger(0,objName,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objName,OBJPROP_WIDTH,2);
      
      string txt = " Break   ";
      string objNameDescr = objName + txt;
      ObjectCreate(0,objNameDescr,OBJ_TEXT,0,time2,price2);
      ObjectSetInteger(0,objNameDescr,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,objNameDescr,OBJPROP_FONTSIZE,10);
      if (direction > 0) {
         ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_RIGHT_UPPER);
         ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
      }
      if (direction < 0) {
         ObjectSetInteger(0,objNameDescr,OBJPROP_ANCHOR,ANCHOR_RIGHT_LOWER);
         ObjectSetString(0,objNameDescr,OBJPROP_TEXT, " " + txt);
      }
   }
   ChartRedraw(0);
}

Saúde para nós! Agora, criamos um sistema de negociação baseado no conceito de smart money com a estratégia de Quebra de Estrutura (BoS), para não apenas gerar sinais de negociação, mas também abrir posições no mercado com base nos sinais gerados.


Resultados do Strategy Tester

Após testar no testador de estratégia, aqui estão os resultados.

  • Gráfico de Saldo/Equidade:

gráfico

  • esultados do backtest:

Resultado


Conclusão

Em conclusão, podemos dizer com confiança que a automação da estratégia de Quebra de Estrutura (BoS) não é tão complexa quanto parece, uma vez que se tenha o pensamento necessário. Tecnicamente, você pode ver que sua criação exigiu apenas uma compreensão clara da estratégia e dos requisitos reais, ou seja, os objetivos que devem ser atendidos para criar uma configuração de estratégia válida. 

No geral, o artigo enfatiza a parte teórica que deve ser levada em consideração e ser claramente compreendida para criar uma estratégia de negociação forex de BoS. Isso envolve sua definição, descrição e tipos, além do esboço. Além disso, a parte de codificação da estratégia destaca as etapas que são realizadas para analisar os candlesticks, identificar os pontos de oscilação, rastrear suas quebras, visualizar seus resultados e abrir posições de negociação com base nos sinais gerados. A longo prazo, isso permite a automação da estratégia de BoS, facilitando a execução mais rápida e a escalabilidade da estratégia.

Aviso legal: As informações ilustradas neste artigo são apenas para fins educacionais. O objetivo é apenas mostrar insights sobre como criar um Expert Advisor (EA) de Quebra de Estrutura (BoS) com base na abordagem do Conceito de Smart Money e, portanto, deve ser usado como base para criar um expert advisor melhor com mais otimização e extração de dados considerada. As informações apresentadas não garantem quaisquer resultados de negociação.

Esperamos que você tenha achado o artigo útil, divertido e fácil de entender, de uma forma que possa usar o conhecimento apresentado no desenvolvimento de futuros expert advisors. Tecnicamente, isso facilita sua forma de analisar o mercado com base na abordagem do Conceito de Smart Money (SMC) e, particularmente, na estratégia de Quebra de Estrutura (BoS).


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

Últimos Comentários | Ir para discussão (9)
Allan Munene Mutiiria
Allan Munene Mutiiria | 8 out. 2024 em 21:18
Dragosh Zavadschi #:

Obrigado pela base de código fornecida, ela é realmente muito boa.

Com alterações mínimas, adaptei/mudei.

O resultado inicial sem nenhum filtro adicionado é realmente impressionante.


@Dragosh Zavadschi, obrigado pelo feedback e pela avaliação. Isso é muito bom. Muito obrigado.
Maxim Kuznetsov
Maxim Kuznetsov | 8 nov. 2024 em 20:08

Eu o li na diagonal.

No código, isso me chamou a atenção:

void function() {

const int localConst = 5; // 

        // some code follows

}

você não pode fazer isso. Isso é um disfarce para constantes "mágicas"

Vitaly Murlenko
Vitaly Murlenko | 8 nov. 2024 em 22:03

Autor, não estou entendendo. Sua captura de tela, que mostra a tendência de alta, tem níveis HH e HL. Mas a captura de tela que vem a seguir cria confusão. Veja:

Então, como escolher o nível certo para romper?

Maxim Kuznetsov
Maxim Kuznetsov | 8 nov. 2024 em 22:43
Vitaly Murlenko #:

Autor, não estou entendendo. Sua captura de tela, que mostra a tendência de alta, tem níveis HH e HL. Mas a captura de tela que vem a seguir cria confusão. Veja:

Então, como escolher o nível certo para romper?

Todas essas estratégias funcionam (e isso não é um fato) somente em dias.

Durante o dia, com suas explosões de volatilidade regulares e acentuadas, NÃO FUNCIONAM.

Mas é conveniente selecionar capturas de tela no intraday.

Vitaly Murlenko
Vitaly Murlenko | 8 nov. 2024 em 22:44
Maxim Kuznetsov #:

Todas essas estratégias só funcionam (e isso não é um fato) em viagens de um dia.

Durante o dia, com suas explosões regulares e acentuadas de volatilidade, NÃO FUNCIONAM.

Mas é conveniente selecionar capturas de tela no intraday.

A pergunta não era sobre isso

Construindo um Modelo de Restrição de Tendência de Candlestick (Parte 4): Personalizando o Estilo de Exibição para Cada Onda de Tendência Construindo um Modelo de Restrição de Tendência de Candlestick (Parte 4): Personalizando o Estilo de Exibição para Cada Onda de Tendência
Neste artigo, exploraremos as capacidades da poderosa linguagem MQL5 na criação de vários estilos de indicadores no MetaTrader 5. Também analisaremos os scripts e como eles podem ser utilizados em nosso modelo.
Redes neurais de maneira fácil (Parte 93): Previsão adaptativa nas áreas de frequência e tempo (Conclusão) Redes neurais de maneira fácil (Parte 93): Previsão adaptativa nas áreas de frequência e tempo (Conclusão)
Neste artigo, continuamos a implementação das abordagens do ATFNet — um modelo que adapta e combina os resultados de 2 blocos (frequencial e temporal) de previsão de séries temporais.
MQL5 Trading Toolkit (Parte 1): Desenvolvendo uma Biblioteca EX5 para Gerenciamento de Posições MQL5 Trading Toolkit (Parte 1): Desenvolvendo uma Biblioteca EX5 para Gerenciamento de Posições
Aprenda a criar um kit de ferramentas para desenvolvedores para gerenciar várias operações de posição com MQL5. Neste artigo, vou demonstrar como criar uma biblioteca de funções (ex5) que realizará operações de gerenciamento de posições, de simples a avançadas, incluindo o tratamento automático e a geração de relatórios dos diferentes erros que surgem ao lidar com tarefas de gerenciamento de posições com MQL5.
Algoritmo de Busca Cooperativa Artificial (Artificial Cooperative Search, ACS) Algoritmo de Busca Cooperativa Artificial (Artificial Cooperative Search, ACS)
Apresentamos o algoritmo Artificial Cooperative Search (ACS). Este método inovador utiliza uma matriz binária e várias populações dinâmicas, baseadas em relações mutualísticas e cooperação, para encontrar rapidamente e com precisão soluções ótimas. A abordagem única do ACS em relação a "predadores" e "presas" permite alcançar excelentes resultados em problemas de otimização numérica.