English Русский 中文 Español Deutsch 日本語
preview
Desenvolvimento de ferramentas para análise de Price Action (Parte 28): Ferramenta para operar rompimentos da faixa de abertura

Desenvolvimento de ferramentas para análise de Price Action (Parte 28): Ferramenta para operar rompimentos da faixa de abertura

MetaTrader 5 — Exemplos |
24 0
Christian Benjamin
Christian Benjamin

Sumário



Introdução

Em 6 de maio de 2010, os mercados de ações dos Estados Unidos sofreram o famoso "Flash Crash" — uma queda repentina em que uma grande ordem algorítmica de venda de contratos futuros E-Mini S&P 500 desencadeou uma onda de liquidações de alta frequência e fez o índice Dow Jones despencar quase 1.000 pontos em apenas alguns minutos, seguida por uma recuperação igualmente rápida. Esse episódio dramático revelou uma vulnerabilidade crítica: reagir a um rompimento não confirmado, por mais convincente que pareça, pode colocar o trader em uma situação difícil caso a liquidez desapareça e o mercado inverta bruscamente sua direção.

Um rompimento ocorre quando o preço ultrapassa de forma decisiva um limite claramente definido, como a máxima ou a mínima do intervalo inicial da sessão, sinalizando que a demanda ou a oferta prevaleceu sobre o lado oposto. Saber identificar rompimentos verdadeiros é fundamental, pois eles frequentemente marcam o início de tendências sustentadas, enquanto rompimentos falsos, quando acompanhados de entradas prematuras, muitas vezes resultam em perdas devido a movimentos bruscos de reversão.

A estratégia de rompimento da faixa de abertura (Opening Range Breakout, ORB) aborda esse desafio da seguinte forma: primeiro, estabelece os limites superior e inferior do intervalo inicial, que pode ter qualquer duração definida, e depois marca essa faixa no gráfico com um retângulo. Esses limites funcionam tanto como referências visuais quanto como níveis precisos de entrada. Somente quando o preço ultrapassa os limites do retângulo, retorna para testar esse limite e volta a rompê-lo, a estratégia confirma a entrada, filtrando o ruído e identificando movimentos sustentados por um impulso real do mercado.

Neste artigo, você conhecerá uma implementação profissional da estratégia ORB na forma de um EA em MQL5, que inclui:

  • um módulo encapsulado para a faixa de abertura, responsável por acompanhar e exibir a máxima e a mínima iniciais sem sobrecarregar o ciclo principal;
  • níveis de stop-loss e take-profit ajustados à volatilidade por meio de um módulo ATR reutilizável;
  • uma lógica de confirmação por reteste que distingue rompimentos verdadeiros de movimentos momentâneos;
  • visualização no gráfico com rótulos dinâmicos no painel e objetos gráficos;
  • uma máquina de estados bem definida na função OnTick(), que gerencia cada etapa e é reinicializada corretamente no encerramento da sessão.


Faixa de abertura

A faixa de abertura é definida pelos níveis de máxima e mínima registrados nos primeiros minutos de uma sessão de negociação, geralmente nos primeiros 15 ou 30 minutos. Esse período reflete a reação imediata do mercado às notícias divulgadas durante a noite, aos dados econômicos e à atuação dos participantes institucionais, sendo normalmente caracterizado por volumes elevados e maior volatilidade. Os traders utilizam os limites dessa faixa como níveis de referência, pois um rompimento para cima ou para baixo pode indicar o início de um movimento impulsivo na direção correspondente. Esses níveis permitem planejar operações com pontos de entrada, stop-loss e objetivos de lucro previamente definidos, tornando a faixa de abertura uma ferramenta prática para identificar tendências em seus estágios iniciais e desenvolver estratégias intradiárias estruturadas.

Compreender a faixa de abertura e saber utilizá-la nas operações oferece diversas vantagens no trading intradiário:

Vantagem Descrição
Identificação antecipada de tendências
O rompimento da faixa formada nos primeiros 15 a 30 minutos pode indicar o início de um movimento impulsivo, ajudando o trader a operar na direção do movimento intradiário.
Regras claras de negociação
Com limites de máxima e mínima bem definidos, é possível estabelecer pontos de entrada e níveis de stop-loss objetivos, reduzindo a necessidade de agir no improviso.
Gestão de risco integrada
Os stops podem ser posicionados um pouco além do limite oposto da faixa, permitindo definir antecipadamente a relação risco-retorno.
Economia de tempo e sistematização
Quando as operações ficam restritas à janela da manhã, o trader precisa passar menos tempo acompanhando o mercado, além de conseguir aplicar a estratégia de maneira consistente todos os dias.
Aplicabilidade em diferentes mercados
A estratégia pode ser utilizada em ações, Forex e futuros, além de diferentes períodos gráficos, oferecendo maior flexibilidade ao trader.
Aproveitamento da alta volatilidade
Permite aproveitar a liquidez e os spreads reduzidos que costumam caracterizar o início da sessão.
Flexibilidade da estratégia Permite combinar operações de rompimento, reversão e scalping dentro de uma mesma abordagem.

Utilizaremos dois métodos principais para calcular a faixa de abertura.

Método 1. Faixa baseada em dois candles

Essa abordagem utiliza apenas duas barras. Primeiro, considere o último candle da sessão anterior: sua máxima e mínima representam os extremos de preço registrados no encerramento daquela sessão. Em seguida, considere o candle de abertura da sessão atual: sua máxima e mínima refletem a movimentação inicial do mercado. A faixa de abertura corresponde à distância entre a maior máxima e a menor mínima dessas duas barras. Esse cálculo simples permite avaliar rapidamente o impulso inicial do mercado e identificar possíveis níveis de rompimento para a sessão atual.

Primeiro, determine o horário exato de início da sessão de negociação, por exemplo, 09:30 no horário local do servidor. Esse horário pode ser definido diretamente no código ou obtido por meio da função SymbolInfoSessionTrade.

// Example: use SymbolInfoSessionTrade to get today's session start
MqlDateTime nowStruct;
TimeToStruct(TimeCurrent(), nowStruct);
datetime from, to;
SymbolInfoSessionTrade(_Symbol,
                       (ENUM_DAY_OF_WEEK)nowStruct.day_of_week,
                       SessionIndex,
                       from, to);
// 'from' now holds seconds since midnight; convert to full datetime:
datetime todayStart = (TimeCurrent() - TimeCurrent()%86400) + from;

Localize o índice da primeira barra M1 correspondente ao horário todayStart ou imediatamente posterior a ele. Em seguida, utilize a barra de índice seguinte (index+1) como a última barra da sessão anterior.

// Find bar numbers
int firstBarToday = iBarShift(_Symbol, PERIOD_M1, todayStart, false);
int lastBarYesterday = firstBarToday + 1;
Utilize as funções integradas de séries temporais para obter a máxima e a mínima de cada uma dessas barras.
double highYesterday = iHigh(_Symbol, PERIOD_M1, lastBarYesterday);
double lowYesterday  = iLow (_Symbol, PERIOD_M1, lastBarYesterday);

double highToday     = iHigh(_Symbol, PERIOD_M1, firstBarToday);
double lowToday      = iLow (_Symbol, PERIOD_M1, firstBarToday);
Considere a maior das duas máximas e a menor das duas mínimas para definir os limites da faixa de abertura. Depois, calcule a amplitude dessa faixa.
double openingHigh = MathMax(highYesterday, highToday);
double openingLow  = MathMin (lowYesterday,  lowToday);
double openingSize = openingHigh - openingLow;

PrintFormat("Opening Range → High: %.5f   Low: %.5f   Size: %.5f",
            openingHigh, openingLow, openingSize);

Método 2

Em vez de utilizar candles específicos como referência, essa abordagem define a faixa de abertura com base na máxima e na mínima registradas nos primeiros minutos após a abertura do mercado. Ao acompanhar esses extremos iniciais, é possível identificar, em tempo real, o sentimento inicial do mercado e o impulso observado no início da sessão. A máxima e a mínima da faixa de abertura passam então a funcionar como níveis de rompimento. Quando o preço ultrapassa um desses limites, isso pode indicar o início de uma tendência capaz de se manter ao longo do restante da sessão.

Primeiro, determine o horário exato de início da sessão de negociação atual, por exemplo, 09:30. Utilizamos a função SymbolInfoSessionTrade para obter o horário de abertura, expresso em segundos no campo "from", e convertê-lo em um valor completo do tipo datetime.

// Calculate the session’s opening datetime
MqlDateTime nowStruct;
TimeToStruct(TimeCurrent(), nowStruct);

datetime fromSec, toSec;
SymbolInfoSessionTrade(_Symbol,
                       (ENUM_DAY_OF_WEEK)nowStruct.day_of_week,
                       SessionIndex,
                       fromSec, toSec);

// Build a full datetime from today’s midnight plus the session offset
datetime sessionStart = (TimeCurrent() - TimeCurrent() % 86400) + fromSec;

Em seguida, percorra todas as barras de um minuto compreendidas nos primeiros RangeMinutes após sessionStart, acompanhando a maior máxima e a menor mínima registradas desde o início da sessão.

double orHigh = -DBL_MAX;
double orLow  =  DBL_MAX;

// Find the bar index at or just after sessionStart
int startIdx = iBarShift(_Symbol, TF, sessionStart, false);

// Loop through the first RangeMinutes bars (M1 timeframe)
for(int i = startIdx; i >= startIdx - (RangeMinutes - 1); i--)
{
  if(i < 0) break;  // safety check

  double h = iHigh(_Symbol, TF, i);
  double l = iLow (_Symbol, TF, i);

  orHigh = MathMax(orHigh, h);
  orLow  = MathMin(orLow, l);
}

Ao final, teremos os valores orHigh e orLow. Com eles, podemos calcular a amplitude da faixa e comparar o preço atual (Bid) com esses níveis para gerar sinais de negociação.

double openingSize = orHigh - orLow;
PrintFormat("Opening Range (Method 2): High=%.5f Low=%.5f Size=%.5f",
            orHigh, orLow, openingSize);

// Breakout detection
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(bid > orHigh)
  Alert("Breakout Long at price " + DoubleToString(bid, _Digits));
else if(bid < orLow)
  Alert("Breakout Short at price " + DoubleToString(bid, _Digits));


Visão geral da estratégia

Este EA automatiza a estratégia de rompimento da faixa de abertura, começando pela identificação dos limites superior e inferior do intervalo inicial da sessão de negociação. No início de cada sessão, ele registra o preço de abertura e, durante os RangeMinutes seguintes, por exemplo, 15 minutos, atualiza continuamente a maior máxima e a menor mínima. Ao término desse intervalo, o EA desenha linhas horizontais e um retângulo no gráfico para delimitar visualmente a faixa de preços formada durante o período inicial de volatilidade. Um filtro ATR, com período e multiplicador configuráveis, garante que os sinais de negociação sejam gerados apenas quando a volatilidade atingir um nível significativo.

Depois que a faixa é definida, o EA monitora um rompimento em duas etapas: primeiro, o preço deve fechar fora da faixa; depois, retornar ao seu limite e fechar novamente além dele (o que constitui o reteste). Quando essa confirmação ocorre, o EA desenha uma seta para cima ou para baixo na barra de entrada, calcula os níveis de stop-loss e take-profit com base no ATR e emite alertas sobre o sinal, que podem ser exibidos na tela, enviados por e-mail e/ou por notificações push. O painel no gráfico atualiza continuamente o estado atual do EA, o valor do ATR e a amplitude da faixa, e tudo é reinicializado corretamente no início da próxima sessão ou à meia-noite.

Este EA automatiza a estratégia de rompimento da faixa de abertura, começando pela identificação dos limites superior e inferior do intervalo inicial da sessão de negociação. No início de cada sessão, ele registra o preço de abertura e, durante os RangeMinutes seguintes, por exemplo, 15 minutos, atualiza continuamente a maior máxima e a menor mínima. Ao término desse intervalo, o EA desenha linhas horizontais e um retângulo no gráfico para delimitar visualmente a faixa de preços formada durante o período inicial de volatilidade. Um filtro ATR, com período e multiplicador configuráveis, garante que os sinais de negociação sejam gerados apenas quando a volatilidade atingir um nível significativo.

Depois de definir a faixa, o EA monitora um rompimento em duas etapas: primeiro, o preço precisa fechar fora dos limites da faixa; em seguida, deve retornar para testar o limite rompido e fechar novamente além dele, confirmando o reteste. Quando essa confirmação ocorre, o EA desenha uma seta para cima ou para baixo na barra de entrada, calcula os níveis de stop-loss e take-profit com base no ATR e emite alertas sobre o sinal, que podem ser exibidos na tela, enviados por e-mail e/ou por notificações push. O painel exibido no gráfico atualiza continuamente o estado atual do EA, o valor do ATR e a amplitude da faixa. No início da sessão seguinte ou à meia-noite, o EA executa corretamente a reinicialização dos componentes e estados necessários.



Análise dos componentes do EA

1. Cabeçalho do arquivo e propriedades

No início do arquivo, definimos as informações de direitos autorais, o link e a versão por meio das diretivas #property. Isso não é apenas uma formalidade: a diretiva #property strict faz com que o compilador aplique as regras modernas do MQL5, como a proibição de conversões implícitas de tipos e a exigência de protótipos de funções, ajudando a identificar erros difíceis de perceber ainda durante a compilação. Ao definir #property link, permitimos que qualquer pessoa que abra o EA no MetaEditor acesse nosso perfil na comunidade MQL5, facilitando o controle de versões e deixando clara a autoria do código. Também é possível utilizar #property description para adicionar explicações personalizadas que serão exibidas na janela de propriedades do EA. Isso facilita a inclusão de descrições personalizadas das configurações para os usuários, sem a necessidade de desenvolver código adicional para uma interface gráfica.

//+------------------------------------------------------------------+
//|                                                   ORB Breakout EA|
//|                                   Copyright 2025, MetaQuotes Ltd.|
//|                           https://www.mql5.com/ru/users/lynnchris|
//+------------------------------------------------------------------+
#property copyright   "Copyright 2025, MetaQuotes Ltd."
#property link        "https://www.mql5.com/ru/users/lynnchris"
#property version     "1.0"
#property description "Opening‑Range Breakout with ATR confirmation"
#property strict

2. Parâmetros de entrada

Organizamos os parâmetros configuráveis pelo usuário em grupos identificados por comentários claros: índice da sessão e duração da faixa, configurações do filtro ATR, códigos e cores das setas, além das opções para ativar ou desativar os alertas. No MQL5, as variáveis de entrada aparecem automaticamente na janela de propriedades do EA com os tipos de dados correspondentes. As enumerações, como ENUM_TIMEFRAMES para os períodos gráficos, são apresentadas em listas suspensas, sem a necessidade de desenvolver uma interface gráfica própria. Observe que, ao utilizar o parâmetro de entrada int ArrowUpCode, permitimos que o usuário escolha o código de qualquer símbolo da fonte Wingdings. No entanto, se precisássemos restringir as opções a uma lista fixa, poderíamos definir uma enumeração própria, como ArrowSymbol { UP=233, DOWN=234 } , limitando as opções disponíveis já na compilação. Os parâmetros de entrada também oferecem suporte a readonly, caso você queira impedir alterações durante a execução do EA.

//--- session & range
input int            SessionIndex    = 0;            // 0 = first session
input int            RangeMinutes    = 15;           // minutes to capture range
//--- ATR filter
input ENUM_TIMEFRAMES TF              = PERIOD_M1;   // ATR timeframe
input int            ATRPeriod       = 14;           // ATR look‑back
input double         ATRMultiplier   = 1.5;          // ATR * multiplier
//--- arrows & alerts
input int            ArrowUpCode     = 233;          // wingdings ↑
input int            ArrowDnCode     = 234;          // wingdings ↓
input color          ArrowUpColor    = clrLime;      // long arrow
input color          ArrowDnColor    = clrRed;       // short arrow
input bool           SendEmailAlert  = false;        // email on signal
input bool           PushNotify      = false;        // push on signal
input string         EmailSubject    = "ORB Signal"; // mail subject

3. Classe RangeCapture

Encapsular a lógica da faixa de abertura em uma classe independente, CRangeCapture, evita sobrecarregar o método principal OnTick() e reforça a estrutura orientada a objetos do código MQL5. Armazenamos o horário de início, além dos valores de máxima e mínima que são atualizados ao longo da sessão, utilizando os métodos Init(), Update() e IsDefined(). Vale lembrar que as classes em MQL5 não são inicializadas automaticamente, portanto, é necessário chamar Init() explicitamente. Além disso, ao armazenar hi e lo como double, aproveitamos a precisão de 64 bits dos números de ponto flutuante do MQL5, essencial para trabalhar com cotações no mercado Forex. Futuramente, poderíamos ampliar essa classe para registrar a máxima e a mínima de cada tick em um buffer interno. Esse exemplo mostra como é possível expandir as funcionalidades de uma classe sem alterar sua interface original.

class CRangeCapture
  {
private:
   datetime startTime;
   double   hi, lo;
public:
   void Init(datetime t, double price)
     { startTime = t; hi = lo = price; }
   void Update(double price, datetime now)
     { if(now < startTime + RangeMinutes*60)
         { hi = MathMax(hi, price); lo = MathMin(lo, price); } }
   bool IsDefined(datetime now) const
     { return(now >= startTime + RangeMinutes*60); }
   double High() const { return hi; }
   double Low()  const { return lo; }
  };
static CRangeCapture g_range;

4. Classe ATRModule

Aqui, encapsulamos o handle do indicador ATR padrão (iATR) em uma classe chamada CATRModule. No método Init(), criamos o handle e verificamos se ele é igual a INVALID_HANDLE, evitando problemas relacionados ao símbolo ou ao período gráfico. O método Value() chama CopyBuffer apenas uma vez por tick, o que é muito mais eficiente do que chamar iATR repetidamente dentro de OnTick(). Ao armazenar o handle para reutilização, evitamos vazamentos de memória e reduzimos o consumo de recursos. Ao chamar IndicatorRelease() dentro do método Release(), liberamos o handle. Sem essa liberação, a lista exibida na aba "Indicadores" do terminal pode crescer com o tempo e comprometer seu desempenho. Essa abordagem pode ser facilmente estendida para outros indicadores, como a EMA e as Bandas de Bollinger, encapsulando cada um deles em um módulo independente.

class CATRModule
  {
private:
   int handle;
public:
   bool Init()
     {
      handle = iATR(_Symbol, TF, ATRPeriod);
      return(handle != INVALID_HANDLE);
     }
   double Value() const
     {
      double buf[];
      if(handle != INVALID_HANDLE && CopyBuffer(handle, 0, 0, 1, buf) == 1)
         return buf[0] * ATRMultiplier;
      return 0.0;
     }
   void Release()
     {
      if(handle != INVALID_HANDLE)
         IndicatorRelease(handle);
     }
  };
static CATRModule g_atr;

5. Classe de lógica de reteste

A classe CRetestSignal implementa o padrão "rompimento, reteste e novo rompimento" utilizando três flags booleanas simples. As variáveis breakLong, breakShort e retested permanecem internas à classe, enquanto apenas os métodos Reset(), OnBreak() e CheckRetest() ficam acessíveis externamente. Dessa forma, mantemos os detalhes internos da classe ocultos de OnTick(), permitindo que o leitor se concentre no que o código faz, e não nos detalhes de sua implementação. Observe que a última barra MqlRates é passada por referência, reduzindo o custo de cópia dos dados. Se futuramente precisarmos oferecer suporte a vários períodos gráficos, poderemos ampliar CheckRetest() para receber um array de MqlRates ou um parâmetro que indique o período gráfico. Esse exemplo demonstra a flexibilidade oferecida pela sobrecarga de métodos no MQL5.

class CRetestSignal
  {
private:
   bool breakLong, breakShort, retested;
public:
   void Reset()
     { breakLong = breakShort = retested = false; }
   void OnBreak(double close, double h, double l)
     { breakLong = (close > h); breakShort = (close < l); retested = false; }
   bool CheckRetest(const MqlRates &r, bool &isLong)
     {
      if(breakLong)
        {
         if(!retested && r.low <= g_range.High())
           { retested = true; isLong = true; return false; }
         if(retested && r.close > g_range.High())
           { isLong = true; return true; }
        }
      else if(breakShort)
        {
         if(!retested && r.high >= g_range.Low())
           { retested = true; isLong = false; return false; }
         if(retested && r.close < g_range.Low())
           { isLong = false; return true; }
        }
      return false;
     }
  };
static CRetestSignal g_retest;

6. Painel no gráfico

Para apresentar informações atualizadas em tempo real, a classe CDashboard cria um objeto OBJ_LABEL simples no canto superior esquerdo do gráfico. Os métodos Init(), Update() e Delete() gerenciam todo o ciclo de vida desse rótulo. A mesma abordagem pode ser utilizada com OBJ_TEXT, OBJ_RECTANGLE e outros tipos de objetos gráficos. O rótulo é atualizado a cada tick, mas, como atribuir repetidamente o mesmo texto consome poucos recursos, essa atualização não compromete o desempenho. Caso seja necessário otimizar ainda mais, podemos armazenar a última string exibida e chamar ObjectSetString() apenas quando seu conteúdo realmente mudar. Esse é um bom exemplo de como pequenos ajustes no gerenciamento de objetos podem melhorar o desempenho de EAs que processam grandes volumes de ticks.

class CDashboard
  {
private:
   string name;
public:
   void Init()
     {
      name = "ORB_Info";
      if(ObjectFind(0, name) < 0)
        {
         ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
         ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
         ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 10);
         ObjectSetInteger(0, name, OBJPROP_YDISTANCE, 30);
        }
     }
   void Update(const string &txt)
     { ObjectSetString(0, name, OBJPROP_TEXT, txt); }
   void Delete()
     { if(ObjectFind(0, name) >= 0) ObjectDelete(0, name); }
  };
static CDashboard g_dash;

7. Interface de negociação e notificações

Embora este exemplo não envie ordens, declaramos um objeto static CTrade trade para demonstrar como poderemos integrar a execução de operações reais futuramente. Mais importante, porém, é o tratamento dos sinais confirmados: quando um sinal é confirmado, desenhamos uma seta (OBJ_ARROW) utilizando os códigos Wingdings e as cores escolhidos pelo usuário. Em seguida, chamamos Alert(), SendNotification() e SendMail(). Essas três funções demonstram os recursos de eventos e notificações integrados ao MQL5, sem a necessidade de bibliotecas externas. Se desejarmos, também podemos adicionar PlaySound() ou EventChartCustom() para integração com webhooks, mostrando ao leitor a variedade de mecanismos de comunicação disponíveis nativamente na linguagem.

static CTrade trade;

// ... inside your retest-confirmation block:
string msg = StringFormat("%s Signal @%.5f SL=%.5f TP=%.5f",
                          isLong ? "LONG" : "SHORT",
                          r[0].close, sl, tp);
Alert(msg);
if(PushNotify)    SendNotification(msg);
if(SendEmailAlert) SendMail(EmailSubject, msg);

// draw arrow on chart:
string arrowName = "ORB_Arrow_" + IntegerToString((int)r[0].time);
ObjectCreate(0, arrowName, OBJ_ARROW, 0,
             r[0].time,
             isLong ? r[0].low - 5 * _Point
                    : r[0].high + 5 * _Point);
ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, isLong ? ArrowUpCode : ArrowDnCode);
ObjectSetInteger(0, arrowName, OBJPROP_COLOR,     isLong ? ArrowUpColor : ArrowDnColor);

8. OnInit() e OnDeinit()

Em OnInit(), inicializamos o módulo ATR e o painel. Se ocorrer algum problema, a função retorna INIT_FAILED. Essa abordagem impede que o EA seja executado com apenas parte de seus componentes funcionando. Em OnDeinit(), liberamos corretamente o handle do ATR e removemos todos os objetos gráficos, evitando que indicadores e objetos sem referência permaneçam no terminal após a reinicialização ou remoção do EA. Essa prática é essencial para códigos utilizados em produção: cada handle criado por uma função iXXX deve ter uma chamada correspondente a IndicatorRelease(), enquanto cada ObjectCreate() deve ser acompanhado por ObjectDelete() em OnDeinit() ou por uma lógica condicional na rotina de reinicialização.

int OnInit()
  {
   if(!g_atr.Init())
      return INIT_FAILED;
   g_dash.Init();
   return INIT_SUCCEEDED;
  }

void OnDeinit(const int reason)
  {
   g_atr.Release();
   ObjectDelete(0, "ORB_High");
   ObjectDelete(0, "ORB_Low");
   ObjectDelete(0, "ORB_Range");
   g_dash.Delete();
  }

9. Máquina de estados em OnTick()

O núcleo do EA é a função OnTick(). Utilizamos static bool inited e static int state para preservar seus valores entre as chamadas. É assim que podemos manter o estado do EA em MQL5 sem recorrer a variáveis globais ou armazenamento externo. Primeiro, calculamos o horário de início da sessão e executamos a reinicialização uma vez por dia, uma abordagem comum em estratégias intradiárias. Em seguida, a estrutura switch(state) controla a transição entre quatro etapas: Capture ("captura"), Break ("rompimento"), Retest ("reteste") e Done ("concluído"). Como o MQL5 não oferece suporte à suspensão e retomada da execução no estilo das corrotinas (por meio de yield), a máquina de estados é a solução convencional para distribuir as etapas de uma estratégia entre sucessivos ticks. Além disso, essa estrutura mantém cada bloco de lógica pequeno e facilita os testes.

void OnTick()
  {
   static bool    inited = false;
   static int     state  = 0;
   static datetime sessionStart;

   if(!inited)
     {
      // compute sessionStart, init g_range & g_retest, Alert
      inited = true; state = 0;
     }

   // fetch latest MqlRates r[0] and bid/ask

   switch(state)
     {
      case 0: // Capture
         g_range.Update(bid, TimeCurrent());
         if(g_range.IsDefined(TimeCurrent()))
            state = 1;
         break;
      case 1: // Break
         if(r[0].close > g_range.High() || r[0].close < g_range.Low())
           { g_retest.OnBreak(r[0].close, g_range.High(), g_range.Low()); state = 2; }
         break;
      case 2: // Retest
         {
          bool isLong;
          if(g_retest.CheckRetest(r[0], isLong))
             state = 3;
         }
         break;
      case 3: // Done
         break;
     }
  }

10. Reinicialização à meia-noite

Por fim, comparamos today = now - now%86400 com a variável estática datetime lastDay. Assim que a data muda, removemos os objetos antigos e restauramos as flags ao estado inicial, sem recorrer a soluções improvisadas, como "if hour==0". Essa abordagem é útil para qualquer EA que execute rotinas diárias, como o processamento das barras de índice zero, o cálculo de pontos de pivô diários e a geração de relatórios no encerramento do dia. Ao adotar essa prática, o leitor pode evitar erros sutis de deslocamento de índice por uma unidade, especialmente nas transições entre dias e durante as mudanças de horário de verão.

// at the end of OnTick():
static datetime lastDay = 0;
datetime        today   = TimeCurrent() - TimeCurrent() % 86400;
if(today != lastDay)
  {
   lastDay = today;
   inited  = false;
   state   = 0;
   ObjectDelete(0, "ORB_High");
   ObjectDelete(0, "ORB_Low");
   ObjectDelete(0, "ORB_Range");
  }



Testes com dados históricos e resultados

O teste com dados históricos consiste em executar a estratégia de negociação implementada no EA utilizando dados históricos de mercado para avaliar como a estratégia teria se comportado no passado. Isso permite:

  1. verificar se as regras de negociação produzem resultados coerentes;
  2. medir métricas importantes, como a taxa de operações vencedoras, o drawdown e o fator de lucro;
  3. otimizar parâmetros de entrada, como a duração da faixa e o multiplicador ATR, para identificar as combinações que apresentaram os melhores resultados históricos.

No MetaTrader 5, o Testador de Estratégias fornece cada tick histórico à função OnTick(). Dessa forma:

  • OnInit() inicializa todos os componentes necessários, incluindo o handle do ATR, os objetos gráficos e o estado inicial;
  • OnTick() gerencia a formação da faixa, a lógica de rompimento e reteste, o desenho das setas, os alertas e a atualização do painel a cada tick simulado;
  • OnDeinit() executa as rotinas de limpeza após o término do teste.

Em outras palavras, o Testador de Estratégias executa o mesmo fluxo de código utilizado pelo EA em um gráfico real.

O GIF animado acima mostra o funcionamento do EA Opening Range Breakout no gráfico EURUSD M15 durante um backtest. Na área principal do gráfico, podemos observar um retângulo sombreado que representa a faixa de abertura, delimitada por duas linhas horizontais posicionadas na máxima e na mínima desse intervalo inicial. Essa representação visual permite identificar imediatamente os níveis em que o EA espera movimentos significativos do preço.

Cada seta verde no gráfico representa um sinal confirmado de entrada em posição comprada. A lógica "rompimento → reteste → novo rompimento" implementada no EA exige que o preço primeiro ultrapasse o limite superior da faixa, retorne para testá-lo e, somente depois, volte a fechar acima desse nível para que a seta seja exibida. Essa confirmação em duas etapas ajuda a filtrar falsos rompimentos e gera sinais apenas quando há um impulso genuíno do mercado.

A aba Journal, abaixo do gráfico, registra todos os eventos importantes: início da sessão, definição da faixa, identificação do rompimento e sinal final, incluindo os valores exatos de entrada, stop-loss e take-profit. Esses registros refletem as transições internas de estado do EA e permitem acompanhar com clareza como e quando cada decisão é tomada.

Esse exemplo demonstra como a estratégia ORB aproveita a volatilidade do início da sessão, confirma rompimentos genuínos e gera sinais reproduzíveis no gráfico EURUSD M15.


Também testei esse EA no par AUD/USD, utilizando o período gráfico M5, para observar com mais detalhes os movimentos intradiários do preço. Veja o gráfico acima.

Conclusão

O EA Opening Range Breakout que desenvolvemos em MQL5 transforma a ideia simples de uma faixa de preços formada no início da sessão em uma estratégia automatizada com regras bem definidas. Ao separar seus componentes em módulos independentes, responsáveis pela identificação da faixa, pelo cálculo dos stops com base na volatilidade, pela confirmação dos retestes e pela apresentação de informações no gráfico, obtivemos um código fácil de manter e com desempenho adequado para uso em condições reais de mercado.

Essa abordagem atende a duas necessidades fundamentais do trading intradiário: distinguir impulsos genuínos de picos de preço de curta duração e dimensionar o risco de acordo com as condições do mercado em tempo real. A sequência de confirmação "rompimento → reteste → novo rompimento" ajuda a eliminar sinais de falsos rompimentos, enquanto os níveis de stop-loss e take-profit calculados com base no ATR se adaptam dinamicamente às mudanças de volatilidade. Com isso, o EA gera sinais mais consistentes e confiáveis, favorecendo entradas que tendem a suportar melhor as oscilações bruscas do mercado e permitem aproveitar movimentos genuínos do preço.

Agora é hora de adaptar o EA às suas necessidades. Compile o código no MetaEditor, teste-o com diferentes símbolos e sessões de negociação e experimente ajustar parâmetros como a duração da faixa de abertura e o multiplicador ATR. Observe como o retângulo, as linhas e as setas aparecem dinamicamente no gráfico e acompanhe os registros na aba Journal para entender cada etapa da tomada de decisão. Com essa estrutura ORB, você terá uma base para transformar as oscilações do início de cada sessão em oportunidades de negociação reproduzíveis, com maior consistência e confiança na execução das operações. Desejo a você entradas cada vez mais precisas e uma gestão de risco cada vez mais criteriosa.





   
Chart Projector
Analytical Comment
Analytics Master
Analytics Forecaster
Volatility Navigator
Mean Reversion Signal Reaper
Signal Pulse
Metrics Board
External Flow
VWAP
Heikin Ashi FibVWAP
RSI DIVERGENCE
Parabolic Stop and Reverse (PSAR)
Script Quarters Drawer
Intrusion Detector
TrendLoom Tool Quarters Board
ZigZag Analyzer Correlation Pathfinder Market Structure Flip Detector Tool
Correlation Dashboard Currency Strength Meter
PAQ Analysis Tool
Dual EMA Fractal Breaker
Pin bar, Engulfing and RSI divergence
Liquidity Sweep Opening Range Breakout Tool    

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

Arquivos anexados |
ORB.mq5 (21.49 KB)
Criação de EAs auto-otimizáveis em MQL5 (Parte 8): Análise de múltiplas estratégias (2) Criação de EAs auto-otimizáveis em MQL5 (Parte 8): Análise de múltiplas estratégias (2)
Dando continuidade à nossa discussão, vamos combinar nossas duas primeiras estratégias de trading em uma estratégia de conjunto (ensemble). Apresentaremos diferentes formas de combinar várias estratégias e de gerenciar o espaço de parâmetros, permitindo uma otimização eficiente mesmo com o aumento do número de parâmetros.
Aprendizado de Máquina e Data Science (Parte 43): Identificação de padrões ocultos em indicadores com modelos de misturas gaussianas latentes (LGMM) Aprendizado de Máquina e Data Science (Parte 43): Identificação de padrões ocultos em indicadores com modelos de misturas gaussianas latentes (LGMM)
Você já teve a sensação de que existe algo mais por trás de um gráfico, algum padrão que ainda não conseguiu identificar? Como se houvesse um código secreto que, uma vez decifrado, permitiria saber exatamente para onde os preços estão indo? Apresento o LGMM, uma ferramenta capaz de detectar padrões ocultos no mercado. Esse modelo de aprendizado de máquina ajuda a identificar regularidades que normalmente passam despercebidas.
Está chegando o novo MetaTrader 5 e MQL5 Está chegando o novo MetaTrader 5 e MQL5
Esta é apenas uma breve resenha do MetaTrader 5. Eu não posso descrever todos os novos recursos do sistema por um período tão curto de tempo - os testes começaram em 09.09.2009. Esta é uma data simbólica, e tenho certeza que será um número de sorte. Alguns dias passaram-se desde que eu obtive a versão beta do terminal MetaTrader 5 e MQL5. Eu ainda não consegui testar todos os seus recursos, mas já estou impressionado.
Desenvolvimento de um Kit de Ferramentas para Análise da Ação do Preço (Parte 25): Rompimento de Fractais com EMA Dupla Desenvolvimento de um Kit de Ferramentas para Análise da Ação do Preço (Parte 25): Rompimento de Fractais com EMA Dupla
A análise da ação do preço é uma abordagem fundamental para identificar oportunidades de negociação lucrativas. No entanto, monitorar manualmente os movimentos e padrões de preços pode ser uma tarefa desafiadora e demorada. Para resolver esse problema, estamos desenvolvendo ferramentas que analisam automaticamente a ação do preço, fornecendo sinais oportunos sempre que possíveis oportunidades são identificadas. Este artigo apresenta uma ferramenta robusta que combina rompimentos de fractais com as EMAs de 14 e 200 períodos para gerar sinais de negociação confiáveis, ajudando os traders a tomar decisões fundamentadas com maior confiança.