English Русский 中文 Español Deutsch 日本語
preview
Automatização de estratégias de negociação em MQL5 (Parte 28): Criação do padrão harmônico "Morcego" baseado em Price Action com feedback visual

Automatização de estratégias de negociação em MQL5 (Parte 28): Criação do padrão harmônico "Morcego" baseado em Price Action com feedback visual

MetaTrader 5 — Sistemas de negociação |
18 0
Allan Munene Mutiiria
Allan Munene Mutiiria

Introdução

No artigo anterior (Parte 27), desenvolvemos um sistema baseado no padrão "Caranguejo" em MetaQuotes Language 5 (MQL5). Esse sistema utiliza padrões harmônicos e proporções precisas de Fibonacci para identificar pontos de reversão de alta probabilidade. Além disso, automatiza a execução das operações e representa os padrões no gráfico por meio de objetos gráficos. Na Parte 28, desenvolveremos um sistema baseado no padrão "Morcego", capaz de identificar configurações harmônicas de alta e de baixa utilizando pontos de pivô e níveis de retração de Fibonacci. O programa abrirá operações com níveis calculados de entrada, stop-loss e múltiplos alvos de take-profit. Também contará com triângulos, linhas de tendência e rótulos para facilitar a identificação visual dos padrões. Abordaremos os seguintes tópicos:

  1. Estudo da estrutura do padrão harmônico "Morcego"
  2. Implementação em MQL5
  3. Testes com dados históricos
  4. Conclusão

Ao final, você terá uma estratégia estável em MQL5 para negociar com base no padrão harmônico "Morcego", pronta para ser configurada. Vamos à implementação!


Estudo da estrutura do padrão harmônico "Morcego"

O padrão "Morcego" é uma formação harmônica de trading definida por cinco pontos principais de oscilação do preço, identificados pelas letras X, A, B, C e D. Ele apresenta duas configurações: uma de alta e outra de baixa. Ambas são utilizadas para identificar possíveis reversões do mercado com base nas proporções de Fibonacci. Na configuração de alta, o padrão "Morcego" apresenta uma sequência de "mínima-máxima-mínima-máxima-mínima", em que o ponto X corresponde a um swing low, o ponto A a um swing high, o ponto B a um swing low (com retração de aproximadamente 0,5 do segmento XA), o ponto C a um swing high (com extensão entre 0,382 e 0,886 do segmento AB) e o ponto D a um swing low (no nível de retração de 0,886 do segmento XA, acima do ponto X). Já na configuração de baixa, o padrão "Morcego" apresenta a sequência inversa, "máxima-mínima-máxima-mínima-máxima", em que o ponto X corresponde a um swing high, o ponto A a um swing low, o ponto B a um swing high, o ponto C a um swing low e o ponto D a um swing high situado abaixo do ponto X (com extensão de 0,886 do segmento XA). A seguir, apresentamos uma representação visual das duas configurações.

Padrão harmônico "Morcego" de alta:

BULLISH BAT PATTERN

Padrão harmônico "Morcego" de baixa:

BEARISH BAT PATTERN

Para identificar esses padrões, adotaremos a seguinte abordagem:

  • Definição da onda XA: O movimento inicial do ponto X até o ponto A estabelece a direção do padrão (ascendente na configuração de alta e descendente na de baixa) e serve como principal referência para os cálculos dos níveis de Fibonacci.
  • Formação da onda AB: O preço deve recuar até o ponto B, retraindo aproximadamente 50% do movimento XA, indicando uma correção moderada do impulso inicial.
  • Análise da onda BC: Essa onda deve corresponder a uma retração entre 38,2% e 88,6% do movimento AB, formando um movimento contrário que prepara a região da reversão final.
  • Definição da onda CD: A última onda deve alcançar o nível de retração de 88,6% do movimento XA, delimitando a possível zona de reversão no ponto D, onde o padrão se completa e gera um sinal de negociação.

Com base nesses critérios geométricos e nas proporções de Fibonacci, nosso sistema de negociação identificará de maneira sistemática os padrões "Morcego" válidos nos dados de preços. Assim que um padrão for confirmado, o EA exibirá sua estrutura no gráfico por meio de triângulos, linhas de tendência e rótulos para os pontos X, A, B, C e D, além dos níveis de entrada e take-profit das operações. Isso permitirá abrir operações automaticamente no ponto D, com stop-loss calculado e múltiplos níveis de take-profit, aproveitando a capacidade do padrão de antecipar possíveis reversões do mercado. Vamos à implementação!


Implementação em MQL5

Para criar o programa em MQL5, abra o MetaEditor, acesse o Navegador, localize a pasta "Indicadores" (Indicators), selecione a opção "Criar" (New) e siga as instruções para criar o arquivo. Depois disso, precisaremos declarar algumas variáveis globais no ambiente de desenvolvimento, que serão utilizadas em todo o programa.

//+------------------------------------------------------------------+
//|                                              Bat Pattern EA.mq5. |
//|                        Copyright 2025, Forex Algo-Trader, Allan. |
//|                                 "https://t.me/Forex_Algo_Trader" |
//+------------------------------------------------------------------+
#property copyright "Forex Algo-Trader, Allan"
#property link      "https://t.me/Forex_Algo_Trader"
#property version   "1.00"
#property description "This EA trades based on Bat Strategy"
#property strict

//--- Include the trading library for order functions  
#include <Trade\Trade.mqh>  //--- Include Trade library
CTrade obj_Trade;  //--- Instantiate a obj_Trade object

//--- Input parameters for user configuration  
input int    PivotLeft    = 5;      // Number of bars to the left for pivot check  
input int    PivotRight   = 5;      // Number of bars to the right for pivot check  
input double Tolerance    = 0.10;   // Allowed deviation (10% of XA move)  
input double LotSize      = 0.01;   // Lot size for new orders  
input bool   AllowTrading = true;   // Enable or disable trading

//---------------------------------------------------------------------------  
//--- Bat pattern definition:  
//  
//--- Bullish Bat:  
//---   Pivots (X-A-B-C-D): X swing low, A swing high, B swing low, C swing high, D swing low.  
//---   Normally XA > 0; Ideal B = A - 0.5*(A-X); Legs within specified ranges.  
//  
//--- Bearish Bat:  
//---   Pivots (X-A-B-C-D): X swing high, A swing low, B swing high, C swing low, D swing high.  
//---   Normally XA > 0; Ideal B = A + 0.5*(X-A); Legs within specified ranges.  
//---------------------------------------------------------------------------

//--- Structure for a pivot point  
struct Pivot {  
   datetime time;   //--- Bar time of the pivot  
   double   price;  //--- Pivot price (High for swing high, low for swing low)  
   bool     isHigh; //--- True if swing high; false if swing low  
};  

//--- Global dynamic array for storing pivots in chronological order  
Pivot pivots[];     //--- Declare a dynamic array to hold identified pivot points

//--- Global variables to lock in a pattern (avoid trading on repaint)  
int      g_patternFormationBar = -1;  //--- Bar index where the pattern was formed (-1 means none)  
datetime g_lockedPatternX      = 0;   //--- The key X pivot time for the locked pattern
bool     g_tradeTaken          = false; //--- Flag to indicate if a trade has been taken for the current pattern

Para estabelecer a base do sistema que automatizará as operações com o padrão harmônico "Morcego", começaremos incluindo a biblioteca "<Trade\Trade.mqh>" e criando uma instância da classe CTrade chamada "obj_Trade", responsável por gerenciar as operações de negociação, como a abertura de posições de compra e venda. Em seguida, definiremos cinco parâmetros de entrada para permitir a configuração pelo usuário. Os parâmetros "PivotLeft" e "PivotRight" terão o valor de 5 barras cada, estabelecendo uma janela de análise com cinco barras à esquerda e cinco à direita para identificar os pivôs. O parâmetro "Tolerance" será definido como 0,10, estabelecendo a margem de tolerância para desvios em relação aos níveis de Fibonacci. Já "LotSize" terá o valor de 0,01, para definir o volume das operações, enquanto "AllowTrading" será definido como true, habilitando a negociação automática.

Na sequência, definiremos a estrutura "Pivot" com os campos "time" (datetime), "price" (double) e "isHigh" (bool), para armazenar os pontos de reversão do preço. Também declararemos "pivots" como um array dinâmico para armazenar esses pontos. Inicializaremos a variável global "g_patternFormationBar" com o valor -1, para acompanhar a formação dos padrões, e "g_lockedPatternX" com 0, para registrar o horário do pivô X. Por fim, definiremos "g_tradeTaken" como false, evitando a abertura de múltiplas operações para o mesmo padrão. Com isso, teremos a estrutura básica do EA para identificar padrões "Morcego" e executar operações com base neles. Para a representação visual, poderemos utilizar funções que desenham linhas, rótulos e triângulos no gráfico.

//+------------------------------------------------------------------+  
//| Helper: Draw a filled triangle                                   |  
//+------------------------------------------------------------------+  
void DrawTriangle(string name, datetime t1, double p1, datetime t2, double p2, datetime t3, double p3, color cl, int width, bool fill, bool back) {  
   //--- Attempt to create a triangle object with three coordinate points  
   if(ObjectCreate(0, name, OBJ_TRIANGLE, 0, t1, p1, t2, p2, t3, p3)) {  
      //--- Set the triangle's color  
      ObjectSetInteger(0, name, OBJPROP_COLOR, cl);  
      //--- Set the triangle's line style to solid  
      ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);  
      //--- Set the line width of the triangle  
      ObjectSetInteger(0, name, OBJPROP_WIDTH, width);  
      //--- Determine if the triangle should be filled  
      ObjectSetInteger(0, name, OBJPROP_FILL, fill);  
      //--- Set whether the object is drawn in the background  
      ObjectSetInteger(0, name, OBJPROP_BACK, back);  
   }  
}  

//+------------------------------------------------------------------+  
//| Helper: Draw a trend line                                        |  
//+------------------------------------------------------------------+  
void DrawTrendLine(string name, datetime t1, double p1, datetime t2, double p2, color cl, int width, int style) {  
   //--- Create a trend line object connecting two points  
   if(ObjectCreate(0, name, OBJ_TREND, 0, t1, p1, t2, p2)) {  
      //--- Set the trend line's color  
      ObjectSetInteger(0, name, OBJPROP_COLOR, cl);  
      //--- Set the trend line's style (solid, dotted, etc.)  
      ObjectSetInteger(0, name, OBJPROP_STYLE, style);  
      //--- Set the width of the trend line  
      ObjectSetInteger(0, name, OBJPROP_WIDTH, width);  
   }  
}  

//+------------------------------------------------------------------+  
//| Helper: Draw a dotted trend line                                 |  
//+------------------------------------------------------------------+  
void DrawDottedLine(string name, datetime t1, double p, datetime t2, color lineColor) {  
   //--- Create a horizontal trend line at a fixed price level with dotted style  
   if(ObjectCreate(0, name, OBJ_TREND, 0, t1, p, t2, p)) {  
      //--- Set the dotted line's color  
      ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);  
      //--- Set the line style to dotted  
      ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);  
      //--- Set the line width to 1  
      ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);  
   }  
}  

//+------------------------------------------------------------------+  
//| Helper: Draw anchored text label (for pivots)                    |  
//| If isHigh is true, anchor at the bottom (label appears above);   |  
//| if false, anchor at the top (label appears below).               |  
//+------------------------------------------------------------------+  
void DrawTextEx(string name, string text, datetime t, double p, color cl, int fontsize, bool isHigh) {  
   //--- Create a text label object at the specified time and price  
   if(ObjectCreate(0, name, OBJ_TEXT, 0, t, p)) {  
      //--- Set the text of the label  
      ObjectSetString(0, name, OBJPROP_TEXT, text);  
      //--- Set the color of the text  
      ObjectSetInteger(0, name, OBJPROP_COLOR, cl);  
      //--- Set the font size for the text  
      ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontsize);  
      //--- Set the font type and style  
      ObjectSetString(0, name, OBJPROP_FONT, "Arial Bold");  
      //--- Anchor the text depending on whether it's a swing high or low  
      if(isHigh)  
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_BOTTOM);  
      else  
         ObjectSetInteger(0, name, OBJPROP_ANCHOR, ANCHOR_TOP);  
      //--- Center-align the text  
      ObjectSetInteger(0, name, OBJPROP_ALIGN, ALIGN_CENTER);  
   }  
}

Para representar visualmente o padrão e seus principais níveis no gráfico, criaremos a função "DrawTriangle", que utiliza ObjectCreate para desenhar um triângulo preenchido (OBJ_TRIANGLE) a partir de três pontos definidos pelos horários ("t1", "t2", "t3") e preços ("p1", "p2", "p3"). Com a função ObjectSetInteger, definiremos "OBJPROP_COLOR" com a cor especificada, "OBJPROP_STYLE" como "STYLE_SOLID", "OBJPROP_WIDTH" com a espessura desejada, "OBJPROP_FILL" para ativar ou desativar o preenchimento e "OBJPROP_BACK" para posicionar o objeto no fundo ou em primeiro plano. Em seguida, implementaremos a função "DrawTrendLine", que utiliza o mesmo formato para criar uma linha de tendência (OBJ_TREND) entre dois pontos.

Depois, implementaremos a função "DrawDottedLine", responsável por desenhar uma linha horizontal pontilhada e configurar suas propriedades de maneira semelhante. Por fim, desenvolveremos a função "DrawTextEx", que cria um rótulo de texto (OBJ_TEXT) nas coordenadas ("t", "p"). Utilizaremos ObjectSetString e ObjectSetInteger para definir "OBJPROP_TEXT" com o texto especificado, configurar "OBJPROP_COLOR" e "OBJPROP_FONTSIZE" e estabelecer "OBJPROP_FONT" como "Arial Bold". Com base no parâmetro "isHigh", utilizaremos "OBJPROP_ANCHOR" para posicionar o texto acima de um swing high ou abaixo de um swing low, enquanto "OBJPROP_ALIGN" permitirá centralizar o texto. Agora podemos passar ao manipulador OnTick e identificar os pivôs que serão utilizados posteriormente no reconhecimento dos padrões. Para isso, adotaremos a seguinte lógica.

//+------------------------------------------------------------------+  
//| Expert tick function                                             |  
//+------------------------------------------------------------------+  
void OnTick() {  
   //--- Declare a static variable to store the time of the last processed bar  
   static datetime lastBarTime = 0;  
   //--- Get the time of the current confirmed bar  
   datetime currentBarTime = iTime(_Symbol, _Period, 1);  
   //--- If the current bar time is the same as the last processed, exit  
   if(currentBarTime == lastBarTime)  
      return;  
   //--- Update the last processed bar time  
   lastBarTime = currentBarTime;  
   
   //--- Clear the pivot array for fresh analysis  
   ArrayResize(pivots, 0);  
   //--- Get the total number of bars available on the chart  
   int barsCount = Bars(_Symbol, _Period);  
   //--- Define the starting index for pivot detection (ensuring enough left bars)  
   int start = PivotLeft;  
   //--- Define the ending index for pivot detection (ensuring enough right bars)  
   int end = barsCount - PivotRight;  
   
   //--- Loop through bars from 'end-1' down to 'start' to find pivot points  
   for(int i = end - 1; i >= start; i--) {  
      //--- Assume current bar is both a potential swing high and swing low  
      bool isPivotHigh = true;  
      bool isPivotLow = true;  
      //--- Get the high and low of the current bar  
      double currentHigh = iHigh(_Symbol, _Period, i);  
      double currentLow = iLow(_Symbol, _Period, i);  
      //--- Loop through the window of bars around the current bar  
      for(int j = i - PivotLeft; j <= i + PivotRight; j++) {  
         //--- Skip if the index is out of bounds  
         if(j < 0 || j >= barsCount)  
            continue;  
         //--- Skip comparing the bar with itself  
         if(j == i)  
            continue;  
         //--- If any bar in the window has a higher high, it's not a swing high  
         if(iHigh(_Symbol, _Period, j) > currentHigh)  
            isPivotHigh = false;  
         //--- If any bar in the window has a lower low, it's not a swing low  
         if(iLow(_Symbol, _Period, j) < currentLow)  
            isPivotLow = false;  
      }  
      //--- If the current bar qualifies as either a swing high or swing low  
      if(isPivotHigh || isPivotLow) {  
         //--- Create a new pivot structure  
         Pivot p;  
         //--- Set the pivot's time  
         p.time = iTime(_Symbol, _Period, i);  
         //--- Set the pivot's price depending on whether it is a high or low  
         p.price = isPivotHigh ? currentHigh : currentLow;  
         //--- Set the pivot type (true for swing high, false for swing low)  
         p.isHigh = isPivotHigh;  
         //--- Get the current size of the pivots array  
         int size = ArraySize(pivots);  
         //--- Increase the size of the pivots array by one  
         ArrayResize(pivots, size + 1);  
         //--- Add the new pivot to the array  
         pivots[size] = p;  
      }  
   } 
}

Começaremos implementando a lógica inicial do manipulador OnTick para detectar os pivôs necessários à identificação do padrão harmônico "Morcego". Primeiro, declararemos a variável estática "lastBarTime", inicializada com 0, para registrar o horário da última barra processada. Esse valor será comparado com "currentBarTime", obtido por meio de iTime com deslocamento 1 para o símbolo e o período gráfico atuais. Para evitar processamento desnecessário, encerraremos a execução do manipulador caso o horário permaneça inalterado. Quando uma nova barra for detectada, atualizaremos "lastBarTime". Em seguida, limparemos o array "pivots" com ArrayResize para iniciar uma nova análise.

Depois, obteremos o número total de barras com Bars e definiremos os limites da busca por pivôs: "start" receberá o valor de "PivotLeft", enquanto "end" corresponderá ao total de barras menos "PivotRight". Percorreremos as barras de "end - 1" até "start". Para cada barra, inicialmente consideraremos verdadeiras as condições de máxima local ("isPivotHigh" = true) e mínima local ("isPivotLow" = true), obtendo seus preços máximo e mínimo com iHigh e iLow. Em seguida, verificaremos as barras vizinhas dentro dos intervalos definidos por "PivotLeft" e "PivotRight" para confirmar se a barra representa um pivô. Utilizando iHigh e iLow, descartaremos a condição de máxima local se alguma barra vizinha apresentar uma máxima superior, ou a condição de mínima local se apresentar uma mínima inferior. Por fim, se a barra atender aos critérios de pivô, criaremos uma estrutura "Pivot" e preencheremos seus campos: "time" receberá o horário obtido com iTime, "price" receberá o preço máximo ou mínimo conforme "isPivotHigh", e "isHigh" indicará se o pivô corresponde a uma máxima local. Em seguida, ampliaremos o array "pivots" com ArrayResize e armazenaremos a estrutura. Ao exibir o conteúdo do array, obteremos o seguinte resultado.

PIVOTS DATA

Com esses dados, podemos identificar os pontos de pivô e, quando houver uma quantidade suficiente deles, analisar os movimentos do preço para detectar os padrões. Para isso, implementaremos a seguinte lógica.

//--- Determine the total number of pivots found  
int pivotCount = ArraySize(pivots);  
//--- If fewer than five pivots are found, the pattern cannot be formed  
if(pivotCount < 5) {  
   //--- Reset pattern lock variables  
   g_patternFormationBar = -1;  
   g_lockedPatternX = 0;  
   g_tradeTaken = false;  
   //--- Exit the OnTick function  
   return;  
}  

//--- Extract the last five pivots as X, A, B, C, and D  
Pivot X = pivots[pivotCount - 5];  
Pivot A = pivots[pivotCount - 4];  
Pivot B = pivots[pivotCount - 3];  
Pivot C = pivots[pivotCount - 2];  
Pivot D = pivots[pivotCount - 1];  

//--- Initialize a flag to indicate if a valid Bat pattern is found  
bool patternFound = false;  
//--- Check for the high-low-high-low-high (Bearish reversal) structure  
if(X.isHigh && (!A.isHigh) && B.isHigh && (!C.isHigh) && D.isHigh) {  
   //--- Calculate the difference between pivot X and A  
   double diff = X.price - A.price;  
   //--- Ensure the difference is positive  
   if(diff > 0) {  
      //--- Calculate the ideal position for pivot B based on Fibonacci ratio  
      double idealB = A.price + 0.5 * diff;  
      //--- Check if actual B is within tolerance of the ideal position  
      if(MathAbs(B.price - idealB) <= Tolerance * diff) {  
         //--- Calculate the AB leg length  
         double AB = B.price - A.price;  
         //--- Calculate the BC leg length  
         double BC = B.price - C.price;  
         //--- Verify that BC is within the acceptable Fibonacci range  
         if((BC >= 0.382 * AB) && (BC <= 0.886 * AB)) {  
            //--- Calculate the extension  
            double extension = D.price - A.price;  
            //--- Verify that the extension is within tolerance of 0.886 and that D is below X  
            if(MathAbs(extension - 0.886 * diff) <= Tolerance * diff && (D.price < X.price))  
               patternFound = true;  
         }  
      }  
   }  
}  
//--- Check for the low-high-low-high-low (Bullish reversal) structure  
if((!X.isHigh) && A.isHigh && (!B.isHigh) && C.isHigh && (!D.isHigh)) {  
   //--- Calculate the difference between pivot A and X  
   double diff = A.price - X.price;  
   //--- Ensure the difference is positive  
   if(diff > 0) {  
      //--- Calculate the ideal position for pivot B based on Fibonacci ratio  
      double idealB = A.price - 0.5 * diff;  
      //--- Check if actual B is within tolerance of the ideal position  
      if(MathAbs(B.price - idealB) <= Tolerance * diff) {  
         //--- Calculate the AB leg length  
         double AB = A.price - B.price;  
         //--- Calculate the BC leg length  
         double BC = C.price - B.price;  
         //--- Verify that BC is within the acceptable Fibonacci range  
         if((BC >= 0.382 * AB) && (BC <= 0.886 * AB)) {  
            //--- Calculate the extension  
            double extension = A.price - D.price;  
            //--- Verify that the extension is within tolerance of 0.886 and that D is above X  
            if(MathAbs(extension - 0.886 * diff) <= Tolerance * diff && (D.price > X.price))  
               patternFound = true;  
         }  
      }  
   }  
}

Nesta etapa, continuaremos a identificar padrões de alta e de baixa com base em critérios precisos de Fibonacci. Primeiro, obteremos o número total de pivôs com "ArraySize(pivots)" e armazenaremos esse valor em "pivotCount". Se houver menos de cinco pivôs, encerraremos a execução, redefinindo "g_patternFormationBar", "g_lockedPatternX" e "g_tradeTaken" para -1, 0 e false, respectivamente, pois o padrão "Morcego" exige os cinco pontos X, A, B, C e D. Em seguida, recuperaremos os cinco pivôs mais recentes do array "pivots" e os atribuiremos aos pontos X (o mais antigo), A, B, C e D (o mais recente), formando a estrutura do padrão.

Depois, verificaremos se os pontos correspondem a um padrão "Morcego" de baixa, caracterizado pela sequência de máxima em X, mínima em A, máxima em B, mínima em C e máxima em D. Para isso, calcularemos a amplitude do movimento XA com "X.price - A.price" e confirmaremos que o resultado é positivo. Em seguida, calcularemos o nível ideal do ponto B pela expressão "A.price + 0.5 diff" e utilizaremos MathAbs para verificar se o desvio está dentro da tolerância definida por "Tolerance diff". Também verificaremos se o movimento BC corresponde a uma proporção entre 0,382 e 0,886 do movimento AB e se a extensão AD corresponde a 0,886 do movimento XA, com o ponto D situado abaixo de X. Se todas as condições forem atendidas, definiremos "patternFound" como true. Na sequência, verificaremos a presença de um padrão "Morcego" de alta, caracterizado pela sequência de mínima em X, máxima em A, mínima em B, máxima em C e mínima em D. Calcularemos a amplitude de XA com "A.price - X.price" e confirmaremos que o resultado é positivo. Depois, verificaremos se B corresponde ao nível de retração de 50% de XA, se BC está entre 38,2% e 88,6% de AB e se o ponto D está no nível de retração de 88,6% do movimento XA, acima do ponto X. Se o padrão atender a todos os critérios, definiremos "patternFound" como true. Dessa forma, teremos a lógica necessária para identificar os padrões "Morcego" que serão utilizados na visualização e na execução das operações. Quando um padrão for identificado, poderemos representá-lo no gráfico.

//--- If a valid Bat pattern is detected  
if(patternFound) {  
   //--- Print a message indicating the pattern type and detection time  
   Print(patternType, " Bat pattern detected at ", TimeToString(D.time, TIME_DATE|TIME_MINUTES|TIME_SECONDS));  
   
   //--- Create a unique prefix for all graphical objects related to this pattern  
   string signalPrefix = "BAT_" + IntegerToString(X.time);  
   
   //--- Choose triangle color based on the pattern type  
   color triangleColor = (patternType=="Bullish") ? clrBlue : clrRed;  
   
   //--- Draw the first triangle connecting pivots X, A, and B  
   DrawTriangle(signalPrefix+"_Triangle1", X.time, X.price, A.time, A.price, B.time, B.price,  
                triangleColor, 2, true, true);  
   //--- Draw the second triangle connecting pivots B, C, and D  
   DrawTriangle(signalPrefix+"_Triangle2", B.time, B.price, C.time, C.price, D.time, D.price,  
                triangleColor, 2, true, true);  
}

Primeiro, se um padrão válido for encontrado ("patternFound" = true), inicializaremos "patternType" com uma string vazia e atribuiremos o valor "Bearish" quando "D.price" for menor que "X.price", indicando um sinal de venda, ou "Bullish" quando for maior, indicando um sinal de compra. Em seguida, registraremos a identificação do padrão com a função Print, exibindo "patternType" e o horário do pivô D, formatado por TimeToString para incluir a data, os minutos e os segundos. Depois, criaremos um identificador exclusivo chamado "signalPrefix", concatenando "BAT_" com o valor de "X.time", convertido em string pela função IntegerToString. Definiremos "triangleColor" como azul para os padrões de alta ou vermelho para os de baixa e chamaremos a função "DrawTriangle" duas vezes. A primeira chamada desenhará o triângulo XAB, conectando os pontos X, A e B. A segunda desenhará o triângulo BCD, conectando os pontos B, C e D. Em ambas as chamadas, utilizaremos "signalPrefix" com os sufixos "_Triangle1" e "_Triangle2", respectivamente, além dos horários e preços correspondentes aos pontos de pivô. Também passaremos "triangleColor", definiremos a espessura como 2 e ativaremos o preenchimento e a exibição dos triângulos ao fundo, utilizando true para os dois parâmetros. Essa lógica permitirá visualizar claramente a estrutura do padrão "Morcego" no gráfico, facilitando a análise e a tomada de decisões de negociação. O resultado é apresentado a seguir.

TRIANGLES SET

Na imagem, podemos observar que o padrão identificado foi representado corretamente no gráfico. Agora, precisamos adicionar as linhas de tendência para completar o contorno do padrão e adicionar rótulos que facilitem a identificação dos níveis do padrão.

//--- Draw boundary trend lines connecting the pivots for clarity  
DrawTrendLine(signalPrefix+"_TL_XA", X.time, X.price, A.time, A.price, clrBlack, 2, STYLE_SOLID);  
DrawTrendLine(signalPrefix+"_TL_AB", A.time, A.price, B.time, B.price, clrBlack, 2, STYLE_SOLID);  
DrawTrendLine(signalPrefix+"_TL_BC", B.time, B.price, C.time, C.price, clrBlack, 2, STYLE_SOLID);  
DrawTrendLine(signalPrefix+"_TL_CD", C.time, C.price, D.time, D.price, clrBlack, 2, STYLE_SOLID);  
DrawTrendLine(signalPrefix+"_TL_XB", X.time, X.price, B.time, B.price, clrBlack, 2, STYLE_SOLID);  
DrawTrendLine(signalPrefix+"_TL_BD", B.time, B.price, D.time, D.price, clrBlack, 2, STYLE_SOLID);  

//--- Retrieve the symbol's point size to calculate offsets for text positioning  
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);  
//--- Calculate an offset (15 points) for positioning text above or below pivots  
double offset = 15 * point;  

//--- Determine the Y coordinate for each pivot label based on its type  
double textY_X = (X.isHigh ? X.price + offset : X.price - offset);  
double textY_A = (A.isHigh ? A.price + offset : A.price - offset);  
double textY_B = (B.isHigh ? B.price + offset : B.price - offset);  
double textY_C = (C.isHigh ? C.price + offset : C.price - offset);  
double textY_D = (D.isHigh ? D.price + offset : D.price - offset);  

//--- Draw text labels for each pivot with appropriate anchoring  
DrawTextEx(signalPrefix+"_Text_X", "X", X.time, textY_X, clrBlack, 11, X.isHigh);  
DrawTextEx(signalPrefix+"_Text_A", "A", A.time, textY_A, clrBlack, 11, A.isHigh);  
DrawTextEx(signalPrefix+"_Text_B", "B", B.time, textY_B, clrBlack, 11, B.isHigh);  
DrawTextEx(signalPrefix+"_Text_C", "C", C.time, textY_C, clrBlack, 11, C.isHigh);  
DrawTextEx(signalPrefix+"_Text_D", "D", D.time, textY_D, clrBlack, 11, D.isHigh);  

//--- Calculate the central label's time as the midpoint between pivots X and B  
datetime centralTime = (X.time + B.time) / 2;  
//--- Set the central label's price at pivot D's price  
double centralPrice = D.price;  
//--- Create the central text label indicating the pattern type  
if(ObjectCreate(0, signalPrefix+"_Text_Center", OBJ_TEXT, 0, centralTime, centralPrice)) {  
   ObjectSetString(0, signalPrefix+"_Text_Center", OBJPROP_TEXT,  
      (patternType=="Bullish") ? "Bullish Bat" : "Bearish Bat");  
   ObjectSetInteger(0, signalPrefix+"_Text_Center", OBJPROP_COLOR, clrBlack);  
   ObjectSetInteger(0, signalPrefix+"_Text_Center", OBJPROP_FONTSIZE, 11);  
   ObjectSetString(0, signalPrefix+"_Text_Center", OBJPROP_FONT, "Arial Bold");  
   ObjectSetInteger(0, signalPrefix+"_Text_Center", OBJPROP_ALIGN, ALIGN_CENTER);  
}

Para tornar a estrutura do padrão mais clara, adicionaremos outros objetos gráficos. Primeiro, desenharemos seis linhas de tendência contínuas com a função "DrawTrendLine", utilizando "signalPrefix" para gerar nomes exclusivos. Essas linhas conectarão os pontos de pivô nos segmentos XA, AB, BC, CD, XB e BD, utilizando os respectivos horários e preços de cada ponto (por exemplo, "X.time" e "X.price"). Com ObjectSetInteger, definiremos "OBJPROP_COLOR" como "clrBlack", "OBJPROP_WIDTH" como 2 e "OBJPROP_STYLE" como "STYLE_SOLID", destacando os segmentos que compõem o padrão. Em seguida, obteremos o tamanho do ponto do símbolo com "SymbolInfoDouble(_Symbol, SYMBOL_POINT)" e calcularemos um deslocamento de 15 pontos para posicionar os rótulos. Determinaremos as coordenadas verticais ("textY_X", "textY_A", "textY_B", "textY_C" e "textY_D") somando ou subtraindo esse deslocamento conforme cada pivô represente uma máxima ("isHigh" = true) ou uma mínima local. Assim, os rótulos ficarão acima das máximas e abaixo das mínimas. Esse deslocamento pode ser ajustado de acordo com a aparência desejada e o instrumento negociado.

Depois, utilizaremos "DrawTextEx" para criar os rótulos dos pontos X, A, B, C e D. Cada objeto receberá um nome formado por "signalPrefix" e um sufixo correspondente, como "_Text_X", e exibirá a letra do respectivo pivô. Os rótulos serão posicionados no horário de cada pivô, com a coordenada vertical previamente ajustada. Utilizaremos "clrBlack" como cor, tamanho de fonte 11 e o valor de "isHigh" de cada pivô para definir a ancoragem do texto. Por fim, calcularemos a posição do rótulo central, definindo "centralTime" como o ponto médio entre "X.time" e "B.time" e "centralPrice" como "D.price". Criaremos então um objeto de texto com ObjectCreate, utilizando o nome "signalPrefix + '_Text_Center'". Definiremos "OBJPROP_TEXT" como "Bullish Bat" ou "Bearish Bat", conforme o valor de "patternType". Com ObjectSetString e ObjectSetInteger, configuraremos "OBJPROP_COLOR" como "clrBlack", "OBJPROP_FONTSIZE" como 11, "OBJPROP_FONT" como "Arial Bold" e "OBJPROP_ALIGN" como "ALIGN_CENTER". Com isso, o gráfico exibirá tanto a estrutura completa quanto o tipo do padrão identificado. Ao executar o programa, obteremos o seguinte resultado.

PATTERN WITH LABELS AND EDGES

Na imagem, podemos observar que as linhas de contorno e os rótulos foram adicionados ao padrão, tornando sua estrutura mais fácil de identificar. O próximo passo será definir os níveis de negociação correspondentes a esse padrão.

//--- Define start and end times for drawing horizontal dotted lines for obj_Trade levels  
datetime lineStart = D.time;  
datetime lineEnd = D.time + PeriodSeconds(_Period)*2;  

//--- Declare variables for entry price and take profit levels  
double entryPriceLevel, TP1Level, TP2Level, TP3Level, tradeDiff;  
//--- Calculate obj_Trade levels based on whether the pattern is Bullish or Bearish  
if(patternType=="Bullish") { //--- Bullish → BUY signal  
   //--- Use the current ASK price as the entry  
   entryPriceLevel = SymbolInfoDouble(_Symbol, SYMBOL_ASK);  
   //--- Set TP3 at pivot C's price  
   TP3Level = C.price;  
   //--- Calculate the total distance to be covered by the obj_Trade  
   tradeDiff = TP3Level - entryPriceLevel;  
   //--- Set TP1 at one-third of the total move  
   TP1Level = entryPriceLevel + tradeDiff/3;  
   //--- Set TP2 at two-thirds of the total move  
   TP2Level = entryPriceLevel + 2*tradeDiff/3;  
} else { //--- Bearish → SELL signal  
   //--- Use the current BID price as the entry  
   entryPriceLevel = SymbolInfoDouble(_Symbol, SYMBOL_BID);  
   //--- Set TP3 at pivot C's price  
   TP3Level = C.price;  
   //--- Calculate the total distance to be covered by the obj_Trade  
   tradeDiff = entryPriceLevel - TP3Level;  
   //--- Set TP1 at one-third of the total move  
   TP1Level = entryPriceLevel - tradeDiff/3;  
   //--- Set TP2 at two-thirds of the total move  
   TP2Level = entryPriceLevel - 2*tradeDiff/3;  
}  

//--- Draw dotted horizontal lines to represent the entry and TP levels  
DrawDottedLine(signalPrefix+"_EntryLine", lineStart, entryPriceLevel, lineEnd, clrMagenta);  
DrawDottedLine(signalPrefix+"_TP1Line", lineStart, TP1Level, lineEnd, clrForestGreen);  
DrawDottedLine(signalPrefix+"_TP2Line", lineStart, TP2Level, lineEnd, clrGreen);  
DrawDottedLine(signalPrefix+"_TP3Line", lineStart, TP3Level, lineEnd, clrDarkGreen);  

//--- Define a label time coordinate positioned just to the right of the dotted lines  
datetime labelTime = lineEnd + PeriodSeconds(_Period)/2;  

//--- Construct the entry label text with the price  
string entryLabel = (patternType=="Bullish") ? "BUY (" : "SELL (";  
entryLabel += DoubleToString(entryPriceLevel, _Digits) + ")";  
//--- Draw the entry label on the chart  
DrawTextEx(signalPrefix+"_EntryLabel", entryLabel, labelTime, entryPriceLevel, clrMagenta, 11, true);  

//--- Construct and draw the TP1 label  
string tp1Label = "TP1 (" + DoubleToString(TP1Level, _Digits) + ")";  
DrawTextEx(signalPrefix+"_TP1Label", tp1Label, labelTime, TP1Level, clrForestGreen, 11, true);  

//--- Construct and draw the TP2 label  
string tp2Label = "TP2 (" + DoubleToString(TP2Level, _Digits) + ")";  
DrawTextEx(signalPrefix+"_TP2Label", tp2Label, labelTime, TP2Level, clrGreen, 11, true);  

//--- Construct and draw the TP3 label  
string tp3Label = "TP3 (" + DoubleToString(TP3Level, _Digits) + ")";  
DrawTextEx(signalPrefix+"_TP3Label", tp3Label, labelTime, TP3Level, clrDarkGreen, 11, true);

Para definir e representar no gráfico os níveis de negociação do padrão identificado, começaremos atribuindo a "lineStart" o horário do pivô D ("D.time") e definindo "lineEnd" como esse horário acrescido de dois períodos, utilizando "PeriodSeconds(_Period) * 2". Declararemos as variáveis "entryPriceLevel", "TP1Level", "TP2Level", "TP3Level" e "tradeDiff" para calcular os níveis das operações. Para um padrão de alta ("patternType == 'Bullish'"), definiremos "entryPriceLevel" como o preço Ask atual, obtido com SymbolInfoDouble, e "TP3Level" como o preço do pivô C. Calcularemos "tradeDiff" pela diferença "TP3Level - entryPriceLevel" e determinaremos "TP1Level" e "TP2Level" somando ao preço de entrada, respectivamente, um terço e dois terços dessa diferença. Para um padrão de baixa, utilizaremos o preço Bid como entrada e o preço do ponto C como "TP3Level". Calcularemos "tradeDiff" como "entryPriceLevel - TP3Level" e determinaremos "TP1Level" e "TP2Level" subtraindo do preço de entrada um terço e dois terços dessa diferença, respectivamente.

Em seguida, utilizaremos a função "DrawDottedLine" para desenhar quatro linhas horizontais pontilhadas entre "lineStart" e "lineEnd": uma linha magenta no nível de entrada "entryPriceLevel" e três linhas de take-profit, sendo "TP1Level" em verde-floresta em tom profundo, "TP2Level" em verde e "TP3Level" em verde-escuro. Por fim, definiremos "labelTime" como "lineEnd" acrescido de meio período e criaremos rótulos com os preços formatados pela função DoubleToString, como "BUY (price)" ou "SELL (price)" para a entrada e "TP1 (price)", entre outros, para os alvos de take-profit. Utilizaremos "DrawTextEx" para posicionar esses rótulos em "labelTime", com as cores correspondentes, tamanho de fonte 11 e ancoragem acima dos respectivos níveis de preço. Após compilar o programa, obteremos o seguinte resultado.

Padrão de baixa:

BEARISH PATTERN

Padrão de alta:

BULLISH PATTERN

Nas imagens, podemos observar que os níveis de negociação foram representados corretamente no gráfico. Agora, resta implementar a abertura efetiva das posições.

//--- Retrieve the index of the current bar  
int currentBarIndex = Bars(_Symbol, _Period) - 1;  
//--- If no pattern has been previously locked, lock the current pattern formation  
if(g_patternFormationBar == -1) {  
   g_patternFormationBar = currentBarIndex;  
   g_lockedPatternX = X.time;  
   //--- Print a message that the pattern is detected and waiting for confirmation  
   Print("Pattern detected on bar ", currentBarIndex, ". Waiting for confirmation on next bar.");  
   return;  
}  
//--- If still on the same formation bar, the pattern is considered to be repainting  
if(currentBarIndex == g_patternFormationBar) {  
   Print("Pattern is repainting; still on locked formation bar ", currentBarIndex, ". No obj_Trade yet.");  
   return;  
}  
//--- If we are on a new bar compared to the locked formation  
if(currentBarIndex > g_patternFormationBar) {  
   //--- Check if the locked pattern still corresponds to the same X pivot  
   if(g_lockedPatternX == X.time) {  
      Print("Confirmed pattern (locked on bar ", g_patternFormationBar, "). Opening obj_Trade on bar ", currentBarIndex, ".");  
      //--- Update the pattern formation bar to the current bar  
      g_patternFormationBar = currentBarIndex;  
      //--- Only proceed with trading if allowed and if there is no existing position  
      if(AllowTrading && !PositionSelect(_Symbol) && !g_tradeTaken) {  
         double entryPriceTrade = 0, stopLoss = 0, takeProfit = 0;  
         point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);  
         bool tradeResult = false;  
         //--- For a Bullish pattern, execute a BUY obj_Trade  
         if(patternType=="Bullish") {  //--- BUY signal  
            entryPriceTrade = SymbolInfoDouble(_Symbol, SYMBOL_ASK);  
            double diffTrade = TP2Level - entryPriceTrade;  
            stopLoss = entryPriceTrade - diffTrade * 3;  
            takeProfit = TP2Level;  
            tradeResult = obj_Trade.Buy(LotSize, _Symbol, entryPriceTrade, stopLoss, takeProfit, "Bat Signal");  
            if(tradeResult)  {
               Print("Buy order opened successfully.");  
               g_tradeTaken = true;
            } else  
               Print("Buy order failed: ", obj_Trade.ResultRetcodeDescription());  
         }  
         //--- For a Bearish pattern, execute a SELL obj_Trade  
         else if(patternType=="Bearish") {  //--- SELL signal  
            entryPriceTrade = SymbolInfoDouble(_Symbol, SYMBOL_BID);  
            double diffTrade = entryPriceTrade - TP2Level;  
            stopLoss = entryPriceTrade + diffTrade * 3;  
            takeProfit = TP2Level;  
            tradeResult = obj_Trade.Sell(LotSize, _Symbol, entryPriceTrade, stopLoss, takeProfit, "Bat Signal");  
            if(tradeResult)  {
               Print("Sell order opened successfully.");  
               g_tradeTaken = true;
            } else  
               Print("Sell order failed: ", obj_Trade.ResultRetcodeDescription());  
         }  
      }  
      else {  
         //--- If a position is already open, do not execute a new obj_Trade  
         Print("A position is already open for ", _Symbol, ". No new obj_Trade executed.");  
      }  
   }  
   else {  
      //--- If the pattern has changed, update the lock with the new formation bar and X pivot  
      g_patternFormationBar = currentBarIndex;  
      g_lockedPatternX = X.time;  
      g_tradeTaken = false;  
      Print("Pattern has changed; updating lock on bar ", currentBarIndex, ". Waiting for confirmation.");  
      return;  
   }  
}  
else {  
   //--- If no valid Bat pattern is detected, reset the pattern lock variables  
   g_patternFormationBar = -1;  
   g_lockedPatternX = 0;  
   g_tradeTaken = false;  
}

Nesta etapa, concluiremos a lógica do manipulador OnTick, incluindo o controle da abertura de operações e a confirmação do padrão. Primeiro, obteremos o índice da barra atual por meio da expressão "Bars(_Symbol, _Period) - 1" e armazenaremos o resultado em "currentBarIndex". Se nenhum padrão estiver bloqueado para confirmação ("g_patternFormationBar == -1"), atribuiremos "currentBarIndex" a "g_patternFormationBar" e armazenaremos o horário do pivô X ("X.time") em "g_lockedPatternX". Em seguida, registraremos no log que um padrão foi identificado e está aguardando confirmação, encerrando a execução do manipulador. Se o padrão ainda estiver na mesma barra em que foi detectado ("currentBarIndex == g_patternFormationBar"), registraremos a ocorrência de repintura (repainting) do padrão e encerraremos a execução para evitar a abertura prematura de operações.

Por fim, quando uma nova barra se formar ("currentBarIndex > g_patternFormationBar") e o horário do pivô X corresponder ao valor armazenado em "g_lockedPatternX", confirmaremos o padrão, registraremos a confirmação no log e atualizaremos "g_patternFormationBar". Antes de abrir uma operação, verificaremos se a negociação automática está habilitada por "AllowTrading", se não há posições abertas para o símbolo, utilizando PositionSelect, e se nenhuma operação já foi executada para o padrão ("g_tradeTaken" = false). Para um padrão de alta, definiremos "entryPriceTrade" como o preço Ask e calcularemos "diffTrade" pela expressão "TP2Level - entryPriceTrade". Posicionaremos "stopLoss" abaixo do preço de entrada, a uma distância equivalente a três vezes "diffTrade", e definiremos "takeProfit" como "TP2Level". Em seguida, abriremos uma posição de compra com "obj_Trade.Buy", utilizando o volume especificado em "LotSize" e a identificação "Bat Signal". Registraremos no log se a execução foi bem-sucedida ou falhou e definiremos "g_tradeTaken" como true. Para um padrão de baixa, utilizaremos o preço Bid, posicionaremos "stopLoss" acima do preço de entrada, a uma distância equivalente a três vezes a diferença calculada, e abriremos uma posição de venda com "obj_Trade.Sell". Se a negociação automática estiver desabilitada, já houver uma posição aberta ou uma operação tiver sido executada para o padrão, registraremos no log que nenhuma nova operação será realizada. Caso o padrão identificado mude, atualizaremos os valores armazenados e aguardaremos uma nova confirmação. Se nenhum padrão for encontrado, redefiniremos as variáveis globais de controle. Após compilar o programa, obteremos o seguinte resultado.

Sinal de baixa:

BEARISH SIGNAL

Sinal de alta:

BULLISH SIGNAL

Na imagem, podemos observar que o padrão harmônico foi representado no gráfico e que o sistema está preparado para executar as operações correspondentes assim que o padrão for confirmado. Com isso, atingimos nosso objetivo de identificar, visualizar e negociar com base nesse padrão. Resta apenas testar o programa com dados históricos, o que faremos na próxima seção.


Testes com dados históricos

Após realizar testes detalhados com dados históricos, obtivemos os seguintes resultados.

Gráfico do teste com dados históricos:

Gráfico

Relatório do teste com dados históricos:

REPORT


Conclusão

Neste artigo, desenvolvemos um sistema baseado no padrão harmônico "Morcego" em MQL5. O sistema utiliza Price Action e proporções precisas de Fibonacci para identificar padrões de alta e de baixa, automatiza a abertura de operações com níveis calculados de entrada, stop-loss e múltiplos alvos de take-profit e representa os padrões no gráfico por meio de objetos gráficos, como triângulos e linhas de tendência.

Aviso de responsabilidade: O conteúdo deste artigo tem finalidade exclusivamente educacional. A negociação nos mercados financeiros envolve riscos significativos, e a volatilidade pode resultar em perdas. Antes de utilizar este programa em condições reais de mercado, é fundamental realizar testes históricos rigorosos e adotar práticas adequadas de gestão de risco.

Com os conceitos e métodos de implementação apresentados, você poderá adaptar o sistema baseado no padrão "Morcego" ao seu estilo de negociação e aprimorar suas estratégias algorítmicas. Boas negociações!

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

Arquivos anexados |
Bat_Pattern_EA.mq5 (50.85 KB)
Simplificando o uso de bancos de dados em MQL5 (Parte 1): Introdução aos bancos de dados e ao SQL Simplificando o uso de bancos de dados em MQL5 (Parte 1): Introdução aos bancos de dados e ao SQL
Neste artigo, veremos como utilizar bancos de dados em MQL5 por meio das funções nativas da linguagem. Abordaremos desde a criação de tabelas e a inserção, atualização e exclusão de registros até a importação e exportação de dados, sempre com exemplos de código. Este conteúdo oferece uma base sólida para compreender os mecanismos internos de acesso aos dados e prepara o terreno para abordarmos o ORM (Object-Relational Mapping, mapeamento objeto-relacional), que implementaremos em MQL5.
Sincronização de gráficos para facilitar a análise técnica Sincronização de gráficos para facilitar a análise técnica
A sincronização de gráficos facilita a análise técnica ao permitir que objetos gráficos, como linhas de tendência, retângulos e indicadores, sejam exibidos de maneira uniforme em todos os timeframes de um mesmo símbolo. Ações como rolagem, zoom ou mudança de instrumento são reproduzidas em todos os gráficos sincronizados, facilitando a visualização e a comparação do mesmo contexto em diferentes timeframes.
Desenvolvimento de um sistema de trading (Parte 3): Determinação do nível mínimo de risco para atingir metas de lucro realistas Desenvolvimento de um sistema de trading (Parte 3): Determinação do nível mínimo de risco para atingir metas de lucro realistas
O objetivo final de todo trader é operar de forma lucrativa. Por isso, muitos estabelecem metas específicas de lucro a serem alcançadas em determinado período de operação. Neste artigo, utilizaremos simulações de Monte Carlo para determinar o percentual ideal de risco por operação necessário para atingir essas metas. Os resultados ajudarão os traders a avaliar se suas metas de lucro são realistas ou ambiciosas demais. Por fim, discutiremos quais parâmetros podem ser ajustados para definir um nível de risco por operação compatível com as metas de trading.
Desenvolvimento de EAs auto-otimizáveis em MQL5 (Parte 13): Introdução à teoria de controle com fatoração de matrizes Desenvolvimento de EAs auto-otimizáveis em MQL5 (Parte 13): Introdução à teoria de controle com fatoração de matrizes
Os mercados financeiros são imprevisíveis, e estratégias de negociação que pareciam lucrativas no passado muitas vezes fracassam em condições reais de mercado. Isso ocorre porque a maioria das estratégias permanece inalterada após entrar em operação, sem capacidade de adaptação ou de aprendizado com os próprios erros. Com base em conceitos da teoria de controle, podemos utilizar controladores com realimentação para monitorar a interação das nossas estratégias com o mercado e ajustar seu comportamento com o objetivo de torná-las lucrativas. Nossos resultados mostram que a inclusão de um controlador com realimentação em uma estratégia simples baseada em média móvel permitiu aumentar o lucro, reduzir o risco e melhorar a eficiência, demonstrando o grande potencial dessa abordagem para aplicações em trading.