
Como integrar o conceito de Smart Money (OB) em combinação com o indicador Fibonacci para entrada ideal na operação
Introdução
Os conceitos de Smart Money (Smart Money Concepts, SMC) e blocos de ordens são áreas críticas no gráfico em que os traders institucionais normalmente abrem ordens de compra ou venda em grande volume. Essas zonas frequentemente marcam o início de movimentos expressivos de preço, tornando-as essenciais para os traders que desejam alinhar suas estratégias à atividade institucional no mercado. Compreender como esses níveis-chave influenciam a movimentação de preços pode oferecer aos traders de varejo uma visão mais aprofundada da dinâmica do mercado, possibilitando prever os movimentos mais prováveis.
Ao combiná-los com ferramentas como os níveis de Fibonacci, o trader pode aprimorar ainda mais suas estratégias de entrada. A retração de Fibonacci identifica potenciais níveis de correção entre o máximo e o mínimo de oscilação mais recentes, oferecendo uma forma de medir até onde o preço pode recuar antes de retomar a tendência. Essa abordagem ajuda o trader a encontrar pontos ideais de entrada, alinhando o fluxo de ordens institucionais com áreas de interesse do mercado e, assim, aumentando a precisão das operações.
Lógica do EA
Bloco de ordens altista:
Nos gráficos, um bloco de ordens altista é identificado quando, após uma vela de baixa, surge uma vela de alta que engole totalmente a anterior, marcando o início de um impulso altista significativo. Para que a formação seja considerada um bloco de ordens altista, as velas que sucedem a vela de baixa devem consistir em pelo menos duas velas de alta ou em uma sequência delas. A forma correta de operar um bloco de ordens altista é aguardar o recuo do preço até a zona identificada do bloco e, então, abrir uma posição de compra.
Retração de Fibonacci altista:
Para encontrar o ponto de entrada ideal na operação, após a identificação do bloco de ordens altista, usa-se a ferramenta de retração de Fibonacci. Após detectar o bloco, o trader procura o ponto máximo e o ponto mínimo de oscilação relacionados. Em seguida, traça-se no gráfico a retração de Fibonacci do mínimo até o máximo de oscilação. A retração ajuda a confirmar se o bloco de ordens altista está no nível de 61,8% ou abaixo, que é uma zona-chave de correção que indica uma possível oportunidade de compra, de acordo com o fluxo de ordens institucionais.
Bloco de ordens baixista:
Um bloco de ordens baixista é identificado quando, após uma vela de alta, surge uma vela de baixa que engole totalmente a anterior, sinalizando o início de um impulso baixista significativo. Para que a formação seja considerada um bloco de ordens baixista, a vela de alta deve ser seguida por pelo menos duas velas de baixa ou uma sequência delas. A forma correta de operar um bloco de ordens baixista é aguardar o retorno do preço e o reteste da zona do bloco para, então, executar uma posição de venda.
Retração de Fibonacci baixista:
No caso de um bloco de ordens baixista, usa-se a ferramenta de retração de Fibonacci para encontrar a entrada ideal na operação. Após identificar o bloco de ordens baixista, o trader busca os máximos e mínimos de oscilação mais recentes. Nesse cenário, a retração de Fibonacci é traçada do máximo ao mínimo de oscilação, já que o foco principal está em ordens de venda. A retração confirma se o bloco de ordens baixista está no nível 61,8% ou acima, o que indica a provável zona de entrada para uma posição curta.
Começando a programar:
//+------------------------------------------------------------------+ //| FIB_OB.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 trade; #define BullOB clrLime #define BearOB clrRed
#include <Trade/Trade.mqh> — aqui, conectamos a biblioteca MQL5 Trade, que fornece funções integradas para gerenciar operações, ordens e posições. O arquivo Trade.mqh contém classes e funções pré-definidas que simplificam operações, como abrir, fechar e modificar ordens. Criamos uma instância de CTrade chamada trade. A classe CTrade encapsula as operações de negociação, como colocar ordens de compra ou venda, fechar posições e modificar operações. Ao criar esse objeto, é possível gerenciar facilmente as operações usando uma abordagem orientada a objetos no seu EA.
Em seguida, definimos duas constantes para as cores que serão usadas para visualizar os blocos de ordens altistas e baixistas. BullOB recebe a cor clrLime (verde) para os blocos de ordens altistas, indicando áreas em que os compradores provavelmente entraram no mercado. BearOB recebe a cor clrRed para os blocos de ordens baixistas, indicando áreas onde os vendedores possivelmente entraram no mercado.
//+------------------------------------------------------------------+ //| Global vars | //+------------------------------------------------------------------+ double Lots = 0.01; int takeProfit = 170; //int stopLoss = 200; int length = 100; input double stopLoss = 350; input double Mgtn = 00.85; bool isBullishOB = false; bool isBearishOB = false; input int Time1Hstrt = 3; input int Time1Hend = 4;
isBullishOB e isBearishOB são flags lógicos utilizados para rastrear a detecção de blocos de ordens (OB). Entre as variáveis globais, estão os parâmetros de entrada Time1Hstrt e Time2Hend, que são utilizados para configurar o horário. Time1Hstrt representa a hora inicial de uma janela de negociação específica; no nosso caso, a sessão de Nova York. Time1Hend representa a hora final dessa janela de tempo.
class COrderBlock : public CObject { public: int direction; datetime time;//[] double high; double low; void draw(datetime tmS, datetime tmE, color clr){ string objOB = " OB REC" + TimeToString(time); ObjectCreate( 0, objOB, OBJ_RECTANGLE, 0, time, low, tmS, high); ObjectSetInteger( 0, objOB, OBJPROP_FILL, true); ObjectSetInteger( 0, objOB, OBJPROP_COLOR, clr); string objtrade = " OB trade" + TimeToString(time); ObjectCreate( 0, objtrade, OBJ_RECTANGLE, 0, tmS, high, tmE, low); // trnary operator ObjectSetInteger( 0, objtrade, OBJPROP_FILL, true); ObjectSetInteger( 0, objtrade, OBJPROP_COLOR, clr); } };
Definimos uma classe chamada COrderBlock, que será usada para modelar um bloco de ordens (OB) no gráfico de negociação. Ela inclui propriedades para a direção do bloco de ordens, tempo, valores máximos e mínimos, além de um método (draw) para desenhar o bloco de ordens no gráfico. A classe COrderBlock herda da classe base CObject, que é uma classe genérica no MQL5 usada para criar objetos. Isso dá a COrderBlock acesso aos métodos e propriedades de CObject.
A variável-membro (propriedade) direction é do tipo int e representa a direção do bloco de ordens. Usamos esse campo para indicar se o bloco de ordens é altista (1) ou baixista (-1). time é o momento de formação ou detecção do bloco de ordens e contém o timestamp do evento. high é o preço máximo do bloco de ordens (limite superior da zona). low é o preço mínimo do bloco de ordens (limite inferior da zona). Essas quatro variáveis são atributos essenciais de um bloco de ordens (OB).
Em seguida, criamos a variável string objOB para armazenar o nome único do objeto retângulo que representará o bloco de ordens no gráfico. O nome é gerado usando o prefixo OB REC combinado com o horário do bloco de ordens (convertido em string por meio de TimeToString()). ObjectCreate() é a função que cria no gráfico um objeto retângulo (OBJ-RECTANGLE). O valor 0 representa o identificador do gráfico (0 = gráfico atual), e objOB é o nome do objeto retângulo. time e low são as coordenadas do canto inferior esquerdo do retângulo (início do bloco de ordens no eixo do tempo e nível mínimo de preço). tmS e high são as coordenadas do canto superior direito do retângulo (tempo de término e nível máximo de preço).
COrderBlock* OB; color OBClr; datetime T1; datetime T2;
- COrderBlock* OB é um ponteiro para o objeto Order Block (bloco de ordens), que será usado para exibir o bloco de ordens no gráfico e gerenciar sua exibição.
- color OBClr é a cor do bloco de ordens, dependendo se ele é altista ou baixista.
- datetime T1 é o horário de início do bloco de ordens.
- datetime T2 é o horário de término do bloco de ordens.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ trade.SetExpertMagicNumber(MagicNumber); return(INIT_SUCCEEDED); }
A função OnInit() é chamada na primeira vez em que o EA é carregado no gráfico. Aqui, simplesmente definimos o número mágico do EA, que é o identificador único das operações realizadas pelo EA.
const int len = 5; int left_bars, right_bars; int bar_Now = len; bool isSwingH = true, isSwingL = true;
- len — quantidade de barras (velas) à esquerda e à direita que serão consideradas para determinar se a barra é um ponto de oscilação.
- left-bars, right-bars — índices das barras à esquerda e à direita em relação à barra atual (bar-Now).
- bar-Now = len — a barra atualmente analisada é definida como len (neste caso, 5 barras atrás).
- isSwingH, isSwingL — essas variáveis lógicas são inicializadas com o valor true e serão usadas para verificar se a barra atual é um máximo ou mínimo de oscilação.
for(int i = 1; i <= len; i++){ right_bars = bar_Now - i; left_bars = bar_Now + i;
O laço for percorre o intervalo de barras (len = 5), analisando tanto o lado esquerdo quanto o lado direito da barra atual (bar-Now).
- right-bars = bar-Now - i — barras à direita da barra atual.
- left-bars = bar-Now + i — barras à esquerda da barra atual.
if((getHigh(bar_Now) <= getHigh(right_bars)) ||(getHigh(bar_Now) < getHigh(left_bars))){ isSwingH = false; }
Essa condição verifica se o máximo da barra atual (bar-Now) é menor ou igual ao máximo das barras vizinhas (tanto à esquerda quanto à direita). Se alguma barra de qualquer lado tiver um máximo maior ou igual, a barra atual não é um máximo de oscilação e isSwingH é definida como false.
if((getLow(bar_Now) >= getLow(right_bars)) || getLow(bar_Now) > getLow(left_bars)){ isSwingL = false; }
De forma semelhante à lógica do máximo de oscilação, essa condição verifica se o mínimo da barra atual é maior ou igual ao mínimo das barras vizinhas. Se alguma barra de qualquer lado tiver um mínimo menor ou igual, a barra atual não é um mínimo de oscilação e isSwingL é definida como false.
if(isSwingH){ Print("We have a swing high at index: ", bar_Now, "at price: ", getHigh(bar_Now)); fib_high = getHigh(bar_Now); fib_t1 = getTime(bar_Now); }
Se isSwingH for igual a true, isso significa que foi detectado um máximo de oscilação. A função exibe o índice da barra e o preço de oscilação. fib-high e fib-t1 são variáveis globais que armazenam o preço máximo de oscilação e o horário correspondente. Esses valores serão passados como parâmetros para o objeto FIBO.
if(isSwingL){ Print("We have a swing low at index: ", bar_Now," at price: ", getLow(bar_Now)); fib_low = getLow(bar_Now); fib_t2 = getTime(bar_Now); }
De forma análoga, para o processamento da detecção de um mínimo de oscilação, a variável isSwingL permanece true se for identificado um mínimo de oscilação. A função exibe o índice da barra e o preço mínimo de oscilação. fib-low e fib-t2 armazenam o preço e o horário do mínimo de oscilação. Esses valores serão passados como parâmetros para o objeto FIBO.
//+------------------------------------------------------------------+ //| Function to find OB | //+------------------------------------------------------------------+ void getOrderB(){ static int prevDay = 0; MqlDateTime structTime; TimeCurrent(structTime); structTime.min = 0; structTime.sec = 0; structTime.hour = Time1Hstrt; datetime timestrt = StructToTime(structTime); structTime.hour = Time1Hend; datetime timend = StructToTime(structTime); if(TimeCurrent() >= timestrt && TimeCurrent() < timend){ if(prevDay != structTime.day_of_year){ delete OB; for(int i = 1; i < 100; i++){ if(getOpen(i) < getClose(i)){ // index is i since the loop starts from i which is = 1 "for(int i = 1)..." if(getOpen(i + 2) < getClose(i + 2)){ if(getOpen(i + 3) > getClose(i + 3) && getOpen(i + 3) < getClose(i + 2)){ Print("Bullish Order Block confirmed at: ", TimeToString(getTime(i + 2), TIME_DATE||TIME_MINUTES)); //isBullishOB = true; OB = new COrderBlock(); OB.direction = 1; OB.time = getTime(i + 3); OB.high = getHigh(i + 3); OB.low = getLow(i + 3); isBullishOB = true; OBClr = isBullishOB ? BullOB : BearOB; // specify strt time T1 = OB.time; // reset BULL OB flag isBullishOB = false; prevDay = structTime.day_of_year; break; delete OB; } } } if(getOpen(i) > getClose(i)){ if(getOpen(i + 2) > getClose(i + 2)){ if(getOpen(i + 3) < getClose(i + 3) && getOpen(i + 3) < getClose(i + 2)){ Print("Bearish Order Block confirmed at: ", TimeToString(getTime(i + 2), TIME_DATE||TIME_MINUTES)); //isBearishOB = true; OB = new COrderBlock(); OB.direction = -1; OB.time = getTime(i + 3); OB.high = getHigh(i + 3); OB.low = getLow(i + 3); isBearishOB = true; OBClr = isBearishOB ? BearOB : BullOB; T1 = OB.time; // reset the BEAR OB flag isBearishOB = false; prevDay = structTime.day_of_year; break; delete OB; } } } } } } }
A função busca blocos de ordens altistas e baixistas nos dados de preço dentro de um intervalo de tempo específico (neste caso, de Time1Hstrt até Time1end). Após a identificação, ela cria um objeto Order Block (COrderBlock) com os atributos correspondentes, como direção, horário, preço máximo e preço mínimo. Em seguida, define cores e flags para visualização e processamento. prevDay é uma variável estática que mantém seus valores entre as chamadas da função. Isso garante que a detecção do bloco de ordens seja executada apenas uma vez por dia.
Se a função já processou o dia atual (prevDay), ela ignora a detecção para evitar o recálculo dos blocos de ordens. Esse valor é resetado quando ocorre a troca de dia. A função verifica o comportamento do preço em busca de padrões altistas e baixistas de blocos de ordens.
- Condições: Procura-se uma sequência de velas que formem um padrão altista. A primeira vela é altista (preço de abertura menor que o preço de fechamento). A segunda vela também é altista e serve como confirmação. A terceira vela é baixista, mas seu preço de abertura é menor que o preço de fechamento da segunda vela.
- Se todas as condições forem atendidas, confirma-se o bloco de ordens altista.
- É criado um novo objeto COrderBlock com propriedades como direção (altista), horário, preço máximo e preço mínimo.
- A lógica é a mesma para o bloco de ordens baixista. A primeira vela é baixista (preço de abertura maior que o preço de fechamento). A segunda vela também é baixista e serve como confirmação. A terceira vela é altista, mas seu preço de abertura é menor que o preço de fechamento da segunda vela.
- Se as condições forem atendidas, confirma-se o bloco de ordens baixista.
- Após o processamento, o objeto OB é removido para liberar memória.
- prevDay é atualizado para garantir que a função seja executada apenas uma vez por dia.
bool isNewBar() { // Memorize the time of opening of the last bar in the static variable static datetime last_time = 0; // Get current time datetime lastbar_time = (datetime)SeriesInfoInteger(Symbol(), Period(), SERIES_LASTBAR_DATE); // First call if (last_time == 0) { last_time = lastbar_time; return false; } // If the time differs (new bar) if (last_time != lastbar_time) { last_time = lastbar_time; return true; } // If no new bar, return false return false; }
A função verifica se surgiu uma nova barra no gráfico e executa algumas funções uma única vez para cada barra.
double getHigh(int index) { return iHigh(_Symbol, _Period, index); } double getLow(int index) { return iLow(_Symbol, _Period, index); } double getOpen(int index){ return iOpen(_Symbol, _Period, index); } double getClose(int index){ return iClose(_Symbol, _Period, index); } datetime getTime(int index) { return iTime(_Symbol, _Period, index); }
Nesta parte do código, há um conjunto de funções auxiliares para extrair determinados dados de preço e informações de tempo para uma barra (ou vela) específica com base no index informado. Cada função acessa o valor de preço ou tempo correspondente para o símbolo e período, utilizando funções internas do MQL5, como iHigh(), iLow(), iOpen(), iClose() e iTime().
void OnTick(){ if(isNewBar()){ getOrderB(); getSwings(); double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); if(CheckPointer(OB) != POINTER_INVALID && OB.direction > 0 && Ask < OB.high){ double entry = Ask; double tp = getHigh(iHighest(_Symbol, PERIOD_CURRENT, MODE_HIGH, iBarShift(_Symbol, PERIOD_CURRENT, OB.time))); double sl = NormalizeDouble(OB.low - Mgtn, _Digits); // double sl = getLow(iLowest(_Symbol, PERIOD_CURRENT, MODE_LOW, 2,iBarShift(_Symbol, PERIOD_CURRENT, OB.time))); ObjectCreate( 0, FIBO_OBJ, OBJ_FIBO, 0, fib_t1, fib_low, fib_t2, fib_high); double entLvl = fib_high - (fib_high - fib_low) * Fib_Trade_lvls / 100; // check this if non if(OB.high <= entLvl){ T2 = getTime(0); OB.draw(T1, T2, OBClr); trade.Buy(Lots, _Symbol, entry, sl, tp, "OB buy"); delete OB; }else{ delete OB; } } if(CheckPointer(OB) != POINTER_INVALID && OB.direction < 0 && Bid > OB.low){ double entry = Bid; double tp = getLow(iLowest(_Symbol, PERIOD_CURRENT, MODE_LOW, iBarShift(_Symbol, PERIOD_CURRENT, OB.time))); double sl = NormalizeDouble(OB.high + Mgtn, _Digits); // double sl = getHigh(iHighest(_Symbol, PERIOD_CURRENT, MODE_HIGH, iBarShift(_Symbol, PERIOD_CURRENT, OB.time))); ObjectCreate( 0, FIBO_OBJ, OBJ_FIBO, 0, fib_t2, fib_high, fib_t1, fib_low); double entLvl = fib_low + (fib_low - fib_high) * Fib_Trade_lvls / 100; if(OB.low >= entLvl){ T2 = getTime(0); OB.draw(T1, T2, OBClr); trade.Sell(Lots, _Symbol, entry, sl, tp, "OB sell"); delete OB; }else{ delete OB; } } ObjectSetInteger( 0, FIBO_OBJ, OBJPROP_COLOR, clrBlack); for(int i = 0; i < ObjectGetInteger( 0, FIBO_OBJ, OBJPROP_LEVELS); i++){ ObjectSetInteger( 0, FIBO_OBJ, OBJPROP_LEVELCOLOR, i, clrBlack); } } }
Como OnTick() é executada sempre que ocorre um novo tick (atualização de preço), usamos a função isNewBar() para verificar se uma nova barra foi formada. A função getOrderB() identifica possíveis blocos de ordens altistas ou baixistas (zonas onde traders institucionais colocam grandes ordens de compra/venda). A função getSwing() determina os pontos de oscilação (máximos e mínimos) do movimento de preço, que serão usados para traçar os níveis de retração de Fibonacci.
Quando um bloco de ordens é detectado e o preço retorna à zona desse bloco, primeiro verificamos se o preço atual está dentro dessa zona. . Se estiver, passamos para a verificação dos parâmetros, confirmando se o preço coincide com o nível de retração de Fibonacci de 61,8%. Esse nível é crucial, pois frequentemente indica um ponto relevante de reversão nas estratégias de negociação institucionais. Somente quando ambos os critérios são atendidos — preço dentro do bloco de ordens e coincidência com o nível de retração de Fibonacci de 61,8% — é que procedemos com a execução da posição (compra ou venda). Caso contrário, se pelo menos um dos critérios não for atendido, simplesmente removemos o bloco de ordens e não entramos na operação.
Confirmação do bloco de ordens altista:
Confirmação do bloco de ordens baixista:
A lógica do sistema é baseada na relação entre o bloco de ordens e os níveis de retração de Fibonacci. Quando um bloco de ordens é detectado, o sistema verifica se ele coincide com o nível de retração de Fibonacci de 61,8%. Para um bloco de ordens altista, o preço deve cair abaixo do nível de retração de 61,8%, e para um bloco de ordens baixista, ele deve estar acima desse nível. Se o bloco de ordens não atender a essas condições de Fibonacci, a posição não é executada. No entanto, o objeto de Fibonacci continua sendo exibido no gráfico para visualização do nível de retração, permitindo ao trader monitorar a situação potencial sem abrir uma posição até que as condições corretas sejam atendidas.
Considerações finais
Integramos conceitos-chave da análise técnica, como blocos de ordens, oscilações de máximos/mínimos e níveis de retração de Fibonacci, para automatizar a tomada de decisões de negociação. Criamos funções para detectar blocos de ordens altistas e baixistas, que representam áreas em que os traders institucionais normalmente posicionam grandes ordens de compra ou venda. Com os níveis de Fibonacci, o EA confirma se a retração do preço coincide com zonas de alta probabilidade antes de executar operações. A função OnTick() monitora continuamente o mercado para identificar novas barras e avaliar se as condições para abertura de posições são atendidas. Ela configura automaticamente os níveis de entrada, stop loss e take profit com base no movimento de preço em tempo real.
Em suma, o EA foi projetado para auxiliar traders varejistas a alinhar suas operações ao fluxo de ordens institucionais, proporcionando uma abordagem sistemática para executar negociações com alta probabilidade de sucesso. Ao identificar e reagir a estruturas-chave do mercado, como blocos de ordens e retrações de preço, o EA possibilita que os traders negociem conforme ações estratégicas de grandes instituições financeiras. Esse alinhamento pode melhorar a precisão das operações, reduzir o impacto emocional e, por fim, aumentar a lucratividade dos traders de varejo.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/13396
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso
Acho que seu arquivo zip não funciona como pretendido, não vejo gráficos, mas vejo algumas mensagens de depuração sobre um
swing high ou loww.
Acho que seu arquivo zip não funciona como pretendido, não vejo gráficos, mas vejo algumas mensagens de depuração sobre um
swing high ou loww.