Introdução ao MQL5 (Parte 11): Um guia para iniciantes sobre como trabalhar com indicadores incorporados no MQL5 (II)
Introdução
Bem-vindo de volta à nossa série sobre MQL5! Neste capítulo, abordaremos um tema fascinante que acredito que você achará muito útil e interessante. No capítulo anterior, vimos como usar os indicadores integrados do MQL5, com especial atenção ao RSI. Além disso, desenvolvemos um projeto prático que demonstra como incorporar o RSI à sua estratégia de negociação com facilidade. Desta vez, vamos um passo além, incluindo não um, mas três indicadores importantes em nosso projeto (RSI, Oscilador Estocástico e Média Móvel). Isso não é tudo; você também aprenderá sobre a ideia intrigante de detecção de divergência oculta por meio do nosso projeto. Discutiremos especificamente como identificar divergências ocultas de alta e de baixa.
É crucial lembrar que o único objetivo deste projeto é educacional. Construir sua confiança no uso do MQL5 e aprender a reconhecer esses padrões de forma programática são seus principais objetivos. Assim, vamos começar este projeto prático que aumentará sua compreensão do MQL5 e permitirá que você avance suas habilidades de negociação.
Neste artigo, você aprenderá:
- Como examinar mínimas e máximas do RSI em relação ao movimento de preço correspondente para descobrir divergências ocultas de alta e de baixa.
- Desenvolver Expert Advisors usando múltiplos indicadores (RSI, MA e Oscilador Estocástico).
- Identificar e visualizar divergências ocultas de alta e de baixa no gráfico.
- Implementar gerenciamento de risco calculando tamanhos de lote com base no risco em dólares e na distância do stop-loss para tamanhos de candle inconsistentes ao usar indicadores incorporados.
- Automatizar negociações com uma Relação Risco-Recompensa (RRR) predefinida usando sinais de divergência.
1. Configuração do Projeto
1.1. Como o EA Funciona
Os indicadores Média Móvel e RSI são usados neste projeto para encontrar divergências ocultas de alta e de baixa. Enquanto o RSI encontra diferenças entre os níveis do RSI e os preços correspondentes, a MA auxilia na identificação da tendência. O oscilador estocástico é usado apenas para validar os sinais de negociação no final e não para identificar divergência.
1.1.1. Divergência Oculta de Alta
Neste ponto, o RSI forma uma mínima mais baixa (LL), enquanto o preço forma uma mínima mais alta (HL). Essa divergência implica que o RSI está fraco, sugerindo possível impulso de alta no futuro, mesmo que o preço correspondente (C-Price) tenha feito um fundo mais alto.

1.1.2. Divergência de baixa oculta
Nesse ponto, o RSI forma uma máxima mais alta enquanto o preço forma uma máxima mais baixa. Isso sugere uma possível tendência de queda no futuro.

1.1.3. Lógica para Venda
Filtro de Tendência:
- Certifique-se de que o preço atual esteja abaixo da EMA 200 para confirmar uma tendência de baixa.
Marcar o Último Máximo Significativo do RSI:
- Identifique o máximo mais recente do RSI formado após um candle de alta, seguido então por 3 candles consecutivos de baixa.
- Coloque uma linha horizontal no gráfico do RSI nesse nível.
Marcar o Preço Correspondente:
- No gráfico de preços (mude para gráfico de linha), coloque uma linha horizontal no nível de preço correspondente (C-PRICE) do máximo do RSI.
Divergência Oculta de Baixa:
- Procure um novo máximo do RSI acima da linha horizontal do RSI.
- Certifique-se de que o máximo de preço correspondente esteja abaixo da linha horizontal de preço no gráfico.
Confirmação pelo Estocástico:
- Após todas as condições serem atendidas, aguarde o Estocástico cruzar acima do nível de sobrecompra (por exemplo, 80) e depois cruzar abaixo dele novamente dentro de 11 barras.
- Se a confirmação não ocorrer dentro de 11 barras, nenhuma negociação é realizada.
Definir SL e TP:
- SL: Último topo de oscilação.
- TP: Definido por um parâmetro de entrada para a Relação Risco-Recompensa (RRR).
1.1.4. Lógica para Compra
Filtro de Tendência:
- Certifique-se de que o preço atual esteja acima da EMA 200.
Marcar a Última Mínima Significativa do RSI:
- Identifique a mínima mais recente do RSI formada após um candle de baixa, entãoseguido por 3 candles consecutivos de alta.
- Coloque uma linha horizontal no gráfico do RSI nesse nível.
Marcar o Preço Correspondente:
- No gráfico de preços (mude para gráfico de linha), coloque uma linha horizontal no nível de preço correspondente (C-PRICE) da mínima do RSI.
Divergência Oculta de Alta:
- Procure uma nova mínima do RSI abaixo da linha horizontal do RSI.
- Certifique-se de que a mínima de preço correspondente esteja acima da linha horizontal de preço (C-PRICE) no gráfico.
Confirmação pelo Estocástico:
- Após todas as condições serem atendidas, aguarde o Estocástico cruzar abaixo do nível de sobrevenda (por exemplo, 20) e depois cruzar acima dele novamente dentro de 11 barras.
- Se a confirmação não ocorrer dentro de 11 barras, nenhuma negociação é realizada.
Definir SL e TP:
- SL: Último fundo de oscilação.
- TP: Definido por um parâmetro de entrada para a Relação Risco-Recompensa (RRR).
2. Adicionando Propriedades dos Indicadores e Recuperando Dados
2.1. Configurando as Propriedades dos Indicadores
Vamos configurar as propriedades dos indicadores que utilizaremos em nosso projeto: o Oscilador Estocástico, o RSI e a Média Móvel. Essas propriedades oferecem flexibilidade ao projetar o EA e especificam como os indicadores irão se comportar.
Analogia
Considere que você está montando um kit de ferramentas para uma tarefa específica. Semelhante a uma fita métrica, a média móvel garante que você compreenda as dimensões gerais da tarefa (direção da tendência). Agindo como uma lupa, o RSI ajuda você a identificar as menores nuances ou divergências ocultas. Antes de prosseguir para a etapa seguinte (confirmação final), o Oscilador Estocástico atua como uma ferramenta de nivelamento para garantir que tudo esteja em perfeito alinhamento.
Considere o computador como seu ajudante nesse empreendimento. Você precisa explicar exatamente a ele o que essas ferramentas são e como elas devem funcionar antes de pedir que ele as utilize. Uma ferramenta genérica não pode ser entregue e esperar que saiba o que fazer. Em vez disso, você deve especificar as características de cada ferramenta, como o tipo de fita métrica, o nível de ampliação da lupa ou a sensibilidade da ferramenta de nivelamento. Ao configurar esses recursos, o computador tem a garantia de entender exatamente quais indicadores usar e como utilizá-los de forma eficiente.
Exemplos://DECLEAR INDICATOR HANDLES int ma_handle; int rsi_handle; int stoch_handle; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //INDICATOR PROPERTIES ma_handle = iMA(_Symbol,PERIOD_CURRENT,200,0,MODE_EMA,PRICE_CLOSE); rsi_handle = iRSI(_Symbol,PERIOD_CURRENT,14,PRICE_CLOSE); stoch_handle = iStochastic(_Symbol,PERIOD_CURRENT,5,3,3,MODE_SMA,STO_LOWHIGH); return(INIT_SUCCEEDED); }
Explicação:
Imagine-se em uma oficina com três equipamentos especializados para o seu projeto: uma fita métrica (MA), uma lupa (RSI) e um nível de bolha (Oscilador Estocástico). Certifique-se de que cada ferramenta esteja pronta para uso e configurada corretamente antes de começar. Você não simplesmente as tiraria da caixa de ferramentas e as usaria imediatamente!
Declarando Handles dos Indicadores (Preparando as Ferramentas)
int ma_handle; int rsi_handle; int stoch_handle;
É semelhante a nomear os armários em sua oficina onde suas ferramentas serão guardadas. Cada ferramenta deve ter seu próprio local para que você possa encontrá-la quando precisar.
- ma_handle é para a fita métrica (Média Móvel).
- rsi_handle é para a lupa (RSI).
- stoch_handle é para o nível de bolha (Oscilador Estocástico).
Configurando as Ferramentas (Inicializando os Indicadores)
Configuração do iMA (Média Móvel)ma_handle = iMA(_Symbol,PERIOD_CURRENT,200,0,MODE_EMA,PRICE_CLOSE);
Isso é como dizer ao seu assistente: “Preciso configurar a fita métrica para um projeto.” Você está especificando exatamente como utilizá-la:
- _Symbol: Isso permite que o assistente saiba o que você está medindo, como o ativo, ação ou par de moedas com o qual está lidando. Isso descreve o ativo que você está estudando (por exemplo, EUR/USD), assim como você identificaria o que está medindo com sua fita métrica.
- PERIOD_CURRENT: Isso se refere ao período de tempo com o qual você está trabalhando. Pense nisso como o comprimento da fita métrica — você está medindo o último dia, semana ou mês? PERIOD_CURRENT significa que você está trabalhando com o período do gráfico atual.
- 200: Este é o comprimento da fita métrica (o número de candles que a Média Móvel irá abranger). Assim, você está pedindo ao seu assistente para usar uma fita métrica que observa os últimos 200 períodos para medir a tendência geral.
- 0: Este é o deslocamento. Ele indica quanto você deseja deslocar a medição para a direita ou para a esquerda. Aqui, 0 significa nenhum deslocamento — você está medindo diretamente o preço atual e os últimos 200 períodos.
- MODE_EMA: Isso especifica o tipo de fita métrica que você está usando: Média Móvel Exponencial (EMA). A EMA é mais sensível e reage mais rapidamente às mudanças de preço do que uma média móvel simples. Assim, você está escolhendo uma fita métrica que se adapta rapidamente a novos dados.
- PRICE_CLOSE: Este é o ponto de referência para sua fita métrica. Neste caso, você está medindo com base no preço de fechamento de cada período. Assim como uma fita métrica pode ser calibrada para medir distâncias específicas, você está dizendo ao seu assistente para medir especificamente os preços de fechamento.

Configuração do iRSI (Índice de Força Relativa)
rsi_handle = iRSI(_Symbol,PERIOD_CURRENT,14,PRICE_CLOSE);
Agora, você está configurando a lupa (RSI). Você diz ao seu assistente exatamente como utilizá-la:
- _Symbol: Isso funciona da mesma forma que antes, especificando o ativo que você está analisando.
- PERIOD_CURRENT: Assim como na Média Móvel, você está trabalhando com o período do gráfico atual.
- 14: Este é o período do RSI. Pense nisso como definir o poder de ampliação da sua lupa. Você está dizendo ao seu assistente para focar em 14 períodos (ou candles), ajudando a analisar a força relativa e detectar divergências.
- PRICE_CLOSE: Assim como na Média Móvel, você está focando nos preços de fechamento para calcular o RSI. Isso garante que você esteja observando o ponto final de cada período para obter uma leitura precisa.

Configuração do iStochastic (Oscilador Estocástico)
stoch_handle = iStochastic(_Symbol,PERIOD_CURRENT,5,3,3,MODE_SMA,STO_LOWHIGH);
- _Symbol: Novamente, isso especifica qual ativo você está analisando, assim como nos indicadores anteriores.
- PERIOD_CURRENT: Você está trabalhando com o período do gráfico atual.
- 5, 3 e 3: Estes são os parâmetros do Oscilador Estocástico:
- 5 é o período %K: Isso é como definir o quão sensível o nível de bolha (Oscilador Estocástico) é aos movimentos de preço. Ele verifica os últimos 5 períodos para ver onde o preço está em relação ao seu intervalo.
- 3 é o período %D: Esta é a versão suavizada do %K, frequentemente usada para obter um sinal mais claro.
- 3 é o período de Slowing: Isso suaviza ainda mais o indicador para garantir que ele não reaja excessivamente a pequenas mudanças, ajudando a evitar sinais falsos.
- MODE_SMA: Você está pedindo ao nível de bolha que utilize o método de Média Móvel Simples (SMA) para suavizar os valores %K e %D, que é uma forma básica, porém confiável, de calcular médias de dados.
- STO_LOWHIGH: Isso informa ao assistente para usar o método Low/High para calcular o Oscilador Estocástico. Isso significa que você está focando no intervalo de preços (menor mínima e maior máxima) durante cada período, em vez de usar os preços de fechamento.

Ao informar esses parâmetros ao computador, você garante que cada um dos seus indicadores (ferramentas) esteja devidamente calibrado para executar sua função de forma eficaz e precisa no projeto.
3. Recuperando Dados dos Indicadores e dos Candles
3.1. Recuperando Dados dos Indicadores
A extração dos dados dos indicadores que estabelecemos na seção anterior será o foco principal desta seção. Podemos utilizar os dados dos indicadores para orientar as recomendações de negociação do nosso Expert Advisor ao recuperá-los. Também examinaremos como extrair informações do Oscilador Estocástico, do RSI e da Média Móvel (MA). Esses fatores são cruciais porque fornecem ao nosso EA os sinais de que ele precisa para realizar negociações. Assim como um construtor precisa de medições precisas de seus equipamentos para garantir que um projeto esteja avançando bem, nosso EA precisa obter os dados relevantes desses indicadores para determinar se as condições de negociação são atendidas. Examinaremos como chamar e armazenar essas variáveis de forma eficaz nas próximas etapas, para que o EA possa usar dados de mercado em tempo real para orientar suas decisões.
Exemplo:
//DECLEAR INDICATOR HANDLES int ma_handle; int rsi_handle; int stoch_handle; //DECLEAR DOUBLE VARIABLES THAT STORES INDICATORS DATA double ma_buffer[]; double rsi_buffer[]; double stoch_buffer_k[], stoch_buffer_d[]; //DECLEAR VARIABLES TO STORE CANDLE DATA double open[]; double close[]; double high[]; double low[]; datetime time[]; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //INDICATOR PROPERTIES ma_handle = iMA(_Symbol,PERIOD_CURRENT,200,0,MODE_EMA,PRICE_CLOSE); rsi_handle = iRSI(_Symbol,PERIOD_CURRENT,14,PRICE_CLOSE); stoch_handle = iStochastic(_Symbol,PERIOD_CURRENT,5,3,3,MODE_SMA,STO_LOWHIGH); //START FROM THE LATEST CANDLE ON THE CHART ArraySetAsSeries(ma_buffer,true); ArraySetAsSeries(rsi_buffer,true); ArraySetAsSeries(stoch_buffer_k,true); ArraySetAsSeries(stoch_buffer_d,true); //START FROM THE LATEST CANDLE ON THE CHART ArraySetAsSeries(open,true); ArraySetAsSeries(close,true); ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArraySetAsSeries(time,true); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //COPY INDICATOR'S DATA FROM THE SECOND BAR ON THE CHART TO THE LAST 31st BAR ON THE CHART CopyBuffer(ma_handle,0,1,30,ma_buffer); CopyBuffer(stoch_handle,0,1,30,stoch_buffer_k); CopyBuffer(stoch_handle,1,1,30,stoch_buffer_d); CopyBuffer(rsi_handle,0,1,30,rsi_buffer); //COPY CANDLE'S DATA FROM THE SECOND BAR ON THE CHART TO THE LAST 31st BAR ON THE CHART CopyOpen(_Symbol,PERIOD_CURRENT,1,30,open); CopyClose(_Symbol,PERIOD_CURRENT,1,30,close); CopyHigh(_Symbol,PERIOD_CURRENT,1,30,high); CopyLow(_Symbol,PERIOD_CURRENT,1,30,low); CopyTime(_Symbol,PERIOD_CURRENT,1,30,time); }
Explicação:
Declarar Variáveis do Tipo Double para Armazenar Dados dos Indicadores
Os arrays devem ser declarados antes que os dados dos indicadores possam ser armazenados. Como os valores numéricos dos indicadores — que incluem o Oscilador Estocástico, o RSI e a Média Móvel — serão armazenados nesses arrays, eles são do tipo double. O ma_buffer[] armazenará os valores da Média Móvel (MA), enquanto o rsi_buffer[] retém os valores do RSI. Os arrays stoch_buffer_k[] e stoch_buffer_d[] armazenam especificamente as linhas K e D do oscilador estocástico. Esses arrays estão inicialmente vazios e rapidamente serão preenchidos com os dados dos indicadores que obtemos do gráfico.
Iniciando a partir do Candle Mais Recente no Gráfico
Nesta etapa, usamos a função ArraySetAsSeries() para organizar os arrays de forma que os dados mais recentes fiquem no primeiro índice de cada array. Ao passar true como argumento, estamos dizendo ao programa para começar a preencher os arrays a partir dos valores mais recentes. Isso é importante porque, por padrão, os arrays são preenchidos a partir dos dados mais antigos (o primeiro elemento), mas, neste caso, precisamos garantir que os valores mais recentes dos indicadores estejam acessíveis primeiro. Essa organização facilita o trabalho com os dados mais recentes ao tomar decisões de negociação.
Copiando os Dados dos Indicadores para os Arrays
Depois que os arrays estão configurados, usamos a função CopyBuffer() para recuperar os dados reais dos indicadores a partir do gráfico. A função CopyBuffer() copia os dados do buffer do indicador para os arrays previamente declarados. Cada chamada de CopyBuffer() é específica para um indicador:
- Para a Média Móvel, copiamos os dados de ma_handle e os colocamos em ma_buffer[].
- Recuperamos os valores %K e %D do Oscilador Estocástico, armazenando-os em stoch_buffer_k[] e stoch_buffer_d[], respectivamente.
- Copiamos os dados do RSI para rsi_buffer[].
A função é instruída a transferir dados das últimas 30 barras pelo quarto parâmetro, 30, e a começar pela segunda barra mais recente pelo terceiro parâmetro, o que nos permite extrair dos indicadores os dados históricos necessários para a análise e a tomada de decisão do nosso Expert Advisor.
Em resumo, essas etapas garantem que possamos coletar, armazenar e acessar os dados de nossos indicadores. Ao declarar os arrays, definir corretamente a ordem dos dados e usar CopyBuffer() para recuperar as informações, temos tudo pronto para começar a analisar os valores dos indicadores e tomar decisões de negociação com base nesses valores.
3.2. Dados de Candles
Agora precisamos coletar os dados de candles correspondentes para combinar com os valores dos indicadores após recuperar com sucesso os dados dos indicadores. Como fornecem o contexto no qual aplicamos nossos indicadores, os dados de candles são cruciais para a tomada de decisões de negociação. Os candles nos mostram a atividade real de preços do mercado, assim como os indicadores nos informam sobre tendências e momentum. Podemos identificar possíveis sinais de negociação, incluindo o desenvolvimento de divergências de alta ou de baixa ou outros padrões que possam indicar uma mudança no sentimento do mercado, ao integrar dados de indicadores e de candles.
Exemplos:
double open[]; double close[]; double high[]; double low[]; datetime time[];
Declaramos arrays (open[], close[], high[], low[] e time[]) para armazenar informações essenciais dos candles, como preços de abertura, fechamento, máxima e mínima, bem como seus respectivos registros de tempo. Essas variáveis nos ajudam a analisar os movimentos de preço e a correlacioná-los com os dados dos indicadores recuperados anteriormente.
ArraySetAsSeries(open,true); ArraySetAsSeries(close,true); ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArraySetAsSeries(time,true);Para garantir que o candle mais recente esteja no início de cada array, usamos a função ArraySetAsSeries. Isso reorganiza os dados, de modo que o candle mais recente fique no índice 0, com os candles mais antigos seguindo em sequência. Esse alinhamento simplifica a análise e garante consistência com a estrutura de dados dos indicadores.
CopyOpen(_Symbol,PERIOD_CURRENT,1,30,open); CopyClose(_Symbol,PERIOD_CURRENT,1,30,close); CopyHigh(_Symbol,PERIOD_CURRENT,1,30,high); CopyLow(_Symbol,PERIOD_CURRENT,1,30,low); CopyTime(_Symbol,PERIOD_CURRENT,1,30,time);
Usando funções como CopyOpen, CopyClose, CopyHigh, CopyLow e CopyTime, preenchemos os arrays com dados reais do mercado. Recuperamos os dados dos últimos 30 candles a partir do segundo candle no gráfico, alinhando os dados de preço com os valores correspondentes dos indicadores para uma tomada de decisão precisa.
4. Identificando as Últimas Máximas e Mínimas do RSI com Dados Correspondentes
Como critério para comparar o comportamento do indicador com a ação do preço, é crucial localizar as máximas e mínimas mais recentes do RSI. O mercado pode continuar subindo quando há uma divergência oculta de alta, que ocorre quando o preço faz uma mínima mais alta e o RSI faz uma mínima mais baixa. No entanto, existe uma divergência oculta de baixa que aponta para uma possível continuação de queda quando o preço atinge uma máxima mais baixa e o RSI atinge uma máxima mais alta.
Para determinar se a máxima estava abaixo da MA naquele momento ou se a mínima estava acima dela, também obteremos o valor correspondente da Média Móvel. Essa validação adicional garante que a tendência esteja alinhada com o movimento esperado e ajuda a confirmar os sinais de divergência.
4.1. Encontrando Divergência Oculta de Alta
Identificar a mínima mais recente do RSI é uma etapa crítica na detecção de divergências ocultas de alta. A mínima do RSI representa um ponto em que o momentum enfraquece durante um recuo de preço, e analisá-la juntamente com o preço correspondente e os valores da Média Móvel (MA) fornece insights valiosos. Uma divergência oculta de alta ocorre quando o RSI forma uma mínima mais baixa enquanto o preço cria uma mínima mais alta, indicando um possível impulso de alta apesar do recuo.
Para detectar a mínima do RSI, definiremos uma lógica específica: a mínima deve ser formada após pelo menos um movimento de baixa seguido por três movimentos consecutivos de alta. Essa condição garante que a mínima reflita uma mudança significativa no momentum. Uma vez identificada a mínima do RSI, recuperaremos sua posição, anotaremos o preço correspondente no gráfico naquele ponto e extrairemos o valor da Média Móvel para determinar se a mínima do preço estava acima da MA. Essa validação ajuda a confirmar o alinhamento do sinal de divergência com a tendência predominante, aumentando sua confiabilidade.
Após identificar a mínima do RSI, também definiremos uma lógica para procurar uma mínima mais baixa que possa se formar após a mínima do RSI. Essa nova mínima deve ter um valor de RSI abaixo da mínima do RSI identificada, com o preço naquele ponto permanecendo acima da mínima de preço anterior. Isso garante que a divergência permaneça intacta e sustente os critérios de divergência oculta de alta. Ao integrar essas etapas, estabelecemos uma abordagem abrangente e estruturada para identificar de forma confiável oportunidades de divergência oculta de alta.
Exemplo://DECLEAR INDICATOR HANDLES int ma_handle; int rsi_handle; int stoch_handle; //DECLEAR DOUBLE VARIABLES THAT STORES INDICATORS DATA double ma_buffer[]; double rsi_buffer[]; double stoch_buffer_k[], stoch_buffer_d[]; //DECLEAR VARIABLES TO STORE CANDLE DATA double open[]; double close[]; double high[]; double low[]; datetime time[]; //DECLEAR VARIBLE ROR RSI LOW AND CORESPONDING CANDLE double rsi_low_value; // Stores the RSI value at the identified low point. double corresponding_low_value; // Stores the price (closing value) corresponding to the RSI low. double corresponding_low_ma; // Stores the Moving Average value at the same point. datetime rsi_low_time; // Stores the timestamp of the RSI low. //DECLEAR VARIABLE FOR THE MINIMUM CORRESPONDING PRICE VALUE int minimum_value_low; //DECLEAR VARIBLE ROR NEW RSI LOW AND CORESPONDING CANDLE double new_rsi_low_value; datetime new_rsi_low_time; double new_corresponding_low_value; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //INDICATOR PROPERTIES ma_handle = iMA(_Symbol,PERIOD_CURRENT,200,0,MODE_EMA,PRICE_CLOSE); rsi_handle = iRSI(_Symbol,PERIOD_CURRENT,14,PRICE_CLOSE); stoch_handle = iStochastic(_Symbol,PERIOD_CURRENT,5,3,3,MODE_SMA,STO_LOWHIGH); //START FROM THE LATEST CANDLE ON THE CHART ArraySetAsSeries(ma_buffer,true); ArraySetAsSeries(rsi_buffer,true); ArraySetAsSeries(stoch_buffer_k,true); ArraySetAsSeries(stoch_buffer_d,true); //START FROM THE LATEST CANDLE ON THE CHART ArraySetAsSeries(open,true); ArraySetAsSeries(close,true); ArraySetAsSeries(high,true); ArraySetAsSeries(low,true); ArraySetAsSeries(time,true); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //COPY INDICATOR'S DATA FROM THE SECOND BAR ON THE CHART TO THE LAST 31st BAR ON THE CHART CopyBuffer(ma_handle,0,1,30,ma_buffer); CopyBuffer(stoch_handle,0,1,30,stoch_buffer_k); CopyBuffer(stoch_handle,1,1,30,stoch_buffer_d); CopyBuffer(rsi_handle,0,1,30,rsi_buffer); //COPY CANDLE'S DATA FROM THE SECOND BAR ON THE CHART TO THE LAST 31st BAR ON THE CHART CopyOpen(_Symbol,PERIOD_CURRENT,1,30,open); CopyClose(_Symbol,PERIOD_CURRENT,1,30,close); CopyHigh(_Symbol,PERIOD_CURRENT,1,30,high); CopyLow(_Symbol,PERIOD_CURRENT,1,30,low); CopyTime(_Symbol,PERIOD_CURRENT,1,30,time); //LOOP THROUGH THE LAST 30 BARS ON THE CHART for(int i = 0; i < 30; i++) { //PREVENT ARRAY OUT OF RANGE ERROR if((i+1 < 30) && (i+2 < 30) && (i < 30) && (i+3 < 30) && (i+4 < 30)) { //LOGIC TO IDENTIFY THE LATEST RSI LOW if(rsi_buffer[i+4] > rsi_buffer[i+3] && rsi_buffer[i+2] > rsi_buffer[i+3] && rsi_buffer[i+1] > rsi_buffer[i+2] && rsi_buffer[i] > rsi_buffer[i+1]) { //GETTING LATEST RSI LOW, CORRESPONDING CANDLE LOW, CORRESPONDING MA VALUE, and RSI TIME rsi_low_value = rsi_buffer[i+3]; corresponding_low_value = close[i+3]; corresponding_low_ma = ma_buffer[i+3]; rsi_low_time = time[i+3]; break; } } } //TOTAL NUMBERS OF BARS FROM THE LAST SIGNIFICANT RSI LOW int total_bars_2 = 0; total_bars_2 = Bars(_Symbol,PERIOD_CURRENT,rsi_low_time, time[0]); //MINIMUM CLOSE PRICE FROM THE LAST SIGNIFICANT RSI LOW minimum_value_low = ArrayMinimum(close,0,total_bars_2); if(corresponding_low_value > corresponding_low_ma && close[0] > ma_buffer[0] && close[minimum_value_low] >= corresponding_low_value) { //CREATE LINES TO MARK RSI AND CORRESPONDING CANDLE LOW ObjectCreate(ChartID(),"RSI LOW VALUE",OBJ_TREND,1,rsi_low_time,rsi_low_value,TimeCurrent(),rsi_low_value); ObjectCreate(ChartID(),"C-CANDLE",OBJ_TREND,0,rsi_low_time,corresponding_low_value,TimeCurrent(),corresponding_low_value); //SETTING OBJECTS COLOUR ObjectSetInteger(ChartID(),"RSI LOW VALUE",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"C-CANDLE",OBJPROP_COLOR,clrBlack); //CREATE TWO LINES TO CONNECT RSI LOW AND THE CORRESPONDING PRICE ON THE CHART ObjectCreate(ChartID(),"C-CANDLE LINE",OBJ_TREND,0,rsi_low_time,corresponding_low_value,rsi_low_time,0); ObjectCreate(ChartID(),"RSI LOW LINE",OBJ_TREND,1,rsi_low_time,rsi_low_value,rsi_low_time,100); //SETTING OBJECTS COLOUR ObjectSetInteger(ChartID(),"C-CANDLE LINE",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"RSI LOW LINE",OBJPROP_COLOR,clrBlack); //CREATE TEXTS TO MART RSI LOW AND CORRESPONDING PRICE (C-PRICE) ObjectCreate(ChartID(),"C-CANDLE TEXT",OBJ_TEXT,0,TimeCurrent(),corresponding_low_value); ObjectSetString(ChartID(),"C-CANDLE TEXT",OBJPROP_TEXT,"C-PRICE"); ObjectCreate(ChartID(),"RSI LOW TEXT",OBJ_TEXT,1,TimeCurrent(),rsi_low_value); ObjectSetString(ChartID(),"RSI LOW TEXT",OBJPROP_TEXT,"RSI LOW"); //SETTING TEXT COLOUR ObjectSetInteger(ChartID(),"C-CANDLE TEXT",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"RSI LOW TEXT",OBJPROP_COLOR,clrBlack); //19 LOGIC TO GET THE NEW RSI LOW if(rsi_buffer[0] > rsi_buffer[1] && rsi_buffer[1] < rsi_buffer[2] && rsi_buffer[1] < rsi_low_value && close[1] > corresponding_low_value) { new_rsi_low_value = rsi_buffer[1]; new_rsi_low_time = time[1]; new_corresponding_low_value = close[1]; } //CONDITION FOR HIDDEN BULLISH DIVERGENCE if(rsi_low_value > new_rsi_low_value && corresponding_low_value < new_corresponding_low_value) { ObjectCreate(ChartID(),"RSI LOW TREND LINE",OBJ_TREND,1,rsi_low_time,rsi_low_value,new_rsi_low_time,new_rsi_low_value); ObjectCreate(ChartID(),"L",OBJ_TEXT,1,rsi_low_time,rsi_low_value); ObjectSetString(ChartID(),"L",OBJPROP_TEXT,"L"); ObjectSetInteger(ChartID(),"L",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"RSI LOW TREND LINE",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"L",OBJPROP_COLOR,clrBlack); ObjectCreate(ChartID(),"LL",OBJ_TEXT,1,new_rsi_low_time,new_rsi_low_value); ObjectSetString(ChartID(),"LL",OBJPROP_TEXT,"LL"); ObjectSetInteger(ChartID(),"LL",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"LL",OBJPROP_COLOR,clrBlack); //for candle ObjectCreate(ChartID(),"C-CANDLE TREND LINE",OBJ_TREND,0,rsi_low_time,corresponding_low_value,new_rsi_low_time,new_corresponding_low_value); ObjectCreate(ChartID(),"CL",OBJ_TEXT,0,rsi_low_time,corresponding_low_value); ObjectSetString(ChartID(),"CL",OBJPROP_TEXT,"L"); ObjectSetInteger(ChartID(),"CL",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"C-CANDLE TREND LINE",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"CL",OBJPROP_COLOR,clrBlack); ObjectCreate(ChartID(),"CLL",OBJ_TEXT,0,new_rsi_low_time,new_corresponding_low_value); ObjectSetString(ChartID(),"CLL",OBJPROP_TEXT,"HL"); ObjectSetInteger(ChartID(),"CLL",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"CLL",OBJPROP_COLOR,clrBlack); } } //LOGIC TO DELETE THE OBJECTS WHEN ITS NO LONGER RELEVEANT else if((close[0] < ma_buffer[0]) || (close[minimum_value_low] < corresponding_low_value)) { ObjectDelete(ChartID(),"RSI LOW VALUE"); ObjectDelete(ChartID(),"C-CANDLE"); ObjectDelete(ChartID(),"C-CANDLE LINE"); ObjectDelete(ChartID(),"RSI LOW LINE"); ObjectDelete(ChartID(),"C-CANDLE TEXT"); ObjectDelete(ChartID(),"RSI LOW TEXT"); ObjectDelete(ChartID(),"RSI LOW TREND LINE"); ObjectDelete(ChartID(),"L"); ObjectDelete(ChartID(),"LL"); ObjectDelete(ChartID(),"C-CANDLE TREND LINE"); ObjectDelete(ChartID(),"CL"); ObjectDelete(ChartID(),"RSI LOW TEXT"); ObjectDelete(ChartID(),"CLL"); } }
Explicação:
Divergências potenciais podem ser encontradas usando o rsi_low_value, que registra o menor valor do RSI dentro de um determinado intervalo. Como os gráficos de linha são baseados em preços de fechamento, a compatibilidade com eles é garantida pelo corresponding_low_value, que é o preço de fechamento do candle onde ocorre a mínima do RSI. Ao converter para um gráfico de linha, esse alinhamento faz com que as mínimas do RSI e os pontos de preço associados pareçam lógicos. Para determinar se o preço está acima ou abaixo da Média Móvel (MA), que frequentemente valida tendências, o corresponding_low_ma mantém o valor da MA no mesmo ponto. Por fim, a função rsi_low_time permite a construção de objetos como linhas de tendência ou rótulos associados a candles específicos, registrando o horário exato da mínima do RSI.
O próximo passo é identificar a última mínima significativa do RSI. Isso envolve verificar padrões específicos nos valores do RSI, nos quais há pelo menos um movimento de baixa seguido por três movimentos consecutivos de alta.
- Isso envolve verificar padrões específicos nos valores do RSI, nos quais há pelo menos um movimento de baixa seguido por três movimentos consecutivos de alta.
- Condição Principal:
- O valor do RSI em i+3 deve primeiro cair (movimento de baixa de i+4 para i+3).
- Depois disso, ele deve mostrar três aumentos consecutivos (i+3 → i+2 → i+1 → i).
- Uma vez detectado esse padrão, a mínima do RSI, o preço de fechamento correspondente, o valor da Média Móvel e o registro de tempo são salvos.
Essa lógica garante que a mínima faça parte de um comportamento significativo do RSI, em que uma queda no RSI é seguida por recuperação, tornando-a um ponto de reversão relevante.
Por que usar close[i+3]?
Se você usar um gráfico de linha, a linha é traçada usando preços de fechamento. Ao associar as mínimas do RSI ao preço de fechamento, os marcadores que você cria (por exemplo, linhas de tendência) se alinharão corretamente com o gráfico de linha. Isso garante clareza e consistência visual.
if(corresponding_low_value > corresponding_low_ma && close[0] > ma_buffer[0] && close[minimum_value_low] >= corresponding_low_value)
Essa condição verifica vários fatores para confirmar se a situação atual está alinhada com os critérios para detectar uma divergência oculta de alta:
- corresponding_low_value > corresponding_low_ma: Isso verifica se o preço na mínima do RSI identificada está acima da Média Móvel (MA). Isso sugere que o preço está acima de sua média móvel, o que indica que a tendência ainda é relativamente forte ou de alta.
- close[0] > ma_buffer[0]: Isso verifica se o preço de fechamento mais recente (candle atual) está acima do valor da média móvel, reforçando que o preço ainda está acima da MA e em tendência de alta.
- close[minimum_value_low] >= corresponding_low_value: Isso confirma que o preço na mínima significativa mais recente (a encontrada anteriormente) ainda está igual ou acima da mínima significativa anterior. Isso ajuda a garantir que o preço não esteja caindo abaixo da mínima anterior, indicando mínimas mais altas no preço e sustentando a interpretação de alta.
Quando todas essas condições são verdadeiras, isso sugere que o preço está acima de sua média móvel e formou uma mínima mais alta, que é uma característica fundamental de uma possível divergência oculta de alta, na qual a ação do preço não confirma o momentum de baixa mais profundo sugerido pelo RSI.
//CREATE LINES TO MARK RSI AND CORRESPONDING PRICE ObjectCreate(ChartID(),"RSI LOW VALUE",OBJ_TREND,1,rsi_low_time,rsi_low_value,TimeCurrent(),rsi_low_value); ObjectCreate(ChartID(),"C-CANDLE",OBJ_TREND,0,rsi_low_time,corresponding_low_value,TimeCurrent(),corresponding_low_value); //SETTING OBJECTS COLOUR ObjectSetInteger(ChartID(),"RSI LOW VALUE",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"C-CANDLE",OBJPROP_COLOR,clrBlack); //CREATE TWO LINES TO CONNECT RSI LOW AND THE CORRESPONDING PRICE ON THE CHART ObjectCreate(ChartID(),"C-CANDLE LINE",OBJ_TREND,0,rsi_low_time,corresponding_low_value,rsi_low_time,0); ObjectCreate(ChartID(),"RSI LOW LINE",OBJ_TREND,1,rsi_low_time,rsi_low_value,rsi_low_time,100); //SETTING OBJECTS COLOUR ObjectSetInteger(ChartID(),"C-CANDLE LINE",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"RSI LOW LINE",OBJPROP_COLOR,clrBlack); //CREATE TEXTS TO MART RSI LOW AND CORRESPONDING PRICE (C-PRICE) ObjectCreate(ChartID(),"C-CANDLE TEXT",OBJ_TEXT,0,TimeCurrent(),corresponding_low_value); ObjectSetString(ChartID(),"C-CANDLE TEXT",OBJPROP_TEXT,"C-PRICE"); ObjectCreate(ChartID(),"RSI LOW TEXT",OBJ_TEXT,1,TimeCurrent(),rsi_low_value); ObjectSetString(ChartID(),"RSI LOW TEXT",OBJPROP_TEXT,"RSI LOW"); //SETTING TEXT COLOUR ObjectSetInteger(ChartID(),"C-CANDLE TEXT",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"RSI LOW TEXT",OBJPROP_COLOR,clrBlack);
Este código cria elementos visuais no gráfico para destacar a mínima do RSI e o preço correspondente, que são pontos-chave para identificar possíveis padrões de divergência. Primeiro, linhas de tendência são desenhadas para marcar tanto o valor da mínima do RSI quanto o preço correspondente (C-PRICE) no mesmo ponto. Essas linhas, rotuladas como “RSI LOW VALUE” e “C-CANDLE”, são desenhadas na cor preta para manter a clareza visual. O objetivo dessas linhas de tendência é conectar visualmente a mínima do RSI com o preço correspondente, ajudando a identificar facilmente a relação entre a ação do preço e o comportamento do RSI.
Em seguida, linhas de tendência adicionais são criadas para conectar a mínima do RSI ao preço correspondente no gráfico. A “C-CANDLE LINE” conecta o preço na mínima do RSI ao tempo atual, enquanto a “RSI LOW LINE” estende a mínima do RSI verticalmente no gráfico. Essas linhas servem como marcadores visuais que ajudam a analisar o movimento tanto do RSI quanto do preço, especialmente ao procurar possíveis divergências de alta ou de baixa. Todas essas linhas de tendência são definidas na cor preta para manter a consistência e garantir que sejam claramente visíveis contra o fundo do gráfico.
Por fim, o código cria rótulos de texto para anotar o gráfico com os valores da mínima do RSI e do preço correspondente (mínima do candle). Os rótulos “RSI LOW” e “C-PRICE” são posicionados nos respectivos níveis do RSI e do preço, facilitando a identificação desses pontos-chave diretamente no gráfico Esses rótulos de texto também são definidos na cor preta, garantindo que se destaquem e sejam legíveis. Ao criar esses objetos, o código ajuda os traders a visualizar rapidamente níveis importantes de preço e pontos do RSI, auxiliando na análise técnica e na identificação de divergências ocultas.
SAÍDA:

Depois que a primeira mínima significativa do RSI é identificada, o próximo passo é encontrar uma nova mínima mais baixa do RSI. A lógica aqui é mais simples do que para a primeira mínima.
Lógica para a Nova Mínima do RSI:
Para a nova mínima do RSI:
- Deve haver apenas um movimento de baixa, no qual o RSI diminui por uma barra.
- Isso deve ser seguido por um movimento de alta, no qual o RSI começa a subir imediatamente após a mínima.
if(rsi_buffer[0] > rsi_buffer[1] && rsi_buffer[1] < rsi_buffer[2] && rsi_buffer[1] < rsi_low_value && close[1] > corresponding_low_value) { new_rsi_low_value = rsi_buffer[1]; new_rsi_low_time = time[1]; new_corresponding_low_value = close[1]; }
A primeira parte do código declara variáveis para armazenar informações sobre a nova mínima do RSI e seu nível de preço correspondente. A variável new_rsi_low_value mantém o valor da nova mínima do RSI, o que é necessário para comparação e análise da divergência. O new_rsi_low_time armazena o momento em que ocorre a nova mínima do RSI, e esse registro de tempo é importante para marcar esse ponto no gráfico. Por fim, new_corresponding_low_value armazena o preço associado à nova mínima do RSI, normalmente o preço de fechamento, o que ajuda a conectar os movimentos do RSI com a ação real do preço no mercado.
O requisito para determinar a nova mínima do RSI é definido na segunda seção do código. O raciocínio garante que a nova mínima atenda a dois requisitos: um movimento de baixa (em que o RSI cai) e um movimento de alta (em que o RSI começa a subir). Além disso, o preço correspondente deve produzir uma mínima mais alta, sugerindo uma possível divergência oculta de alta, enquanto a nova mínima do RSI deve ser mais baixa do que a mínima principal anterior do RSI. Para destacar posteriormente a divergência no gráfico, o algoritmo atribui os novos valores para a mínima do RSI, seu registro de tempo e o preço associado se esses critérios forem atendidos.
if(rsi_low_value > new_rsi_low_value && corresponding_low_value < new_corresponding_low_value) Essa condição procura uma divergência oculta de alta entre o gráfico de preços e o RSI. Quando o preço faz uma mínima mais alta e o RSI faz uma mínima mais baixa, isso é conhecido como divergência oculta de alta.
//FOR RSI ObjectCreate(ChartID(),"RSI LOW TREND LINE",OBJ_TREND,1,rsi_low_time,rsi_low_value,new_rsi_low_time,new_rsi_low_value); ObjectCreate(ChartID(),"L",OBJ_TEXT,1,rsi_low_time,rsi_low_value); ObjectSetString(ChartID(),"L",OBJPROP_TEXT,"L"); ObjectSetInteger(ChartID(),"L",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"RSI LOW TREND LINE",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"L",OBJPROP_COLOR,clrBlack); ObjectCreate(ChartID(),"LL",OBJ_TEXT,1,new_rsi_low_time,new_rsi_low_value); ObjectSetString(ChartID(),"LL",OBJPROP_TEXT,"LL"); ObjectSetInteger(ChartID(),"LL",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"LL",OBJPROP_COLOR,clrBlack); //FOR CORRESPONDING PRICE ObjectCreate(ChartID(),"C-CANDLE TREND LINE",OBJ_TREND,0,rsi_low_time,corresponding_low_value,new_rsi_low_time,new_corresponding_low_value); ObjectCreate(ChartID(),"CL",OBJ_TEXT,0,rsi_low_time,corresponding_low_value); ObjectSetString(ChartID(),"CL",OBJPROP_TEXT,"L"); ObjectSetInteger(ChartID(),"CL",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"C-CANDLE TREND LINE",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"CL",OBJPROP_COLOR,clrBlack); ObjectCreate(ChartID(),"CLL",OBJ_TEXT,0,new_rsi_low_time,new_corresponding_low_value); ObjectSetString(ChartID(),"CLL",OBJPROP_TEXT,"HL"); ObjectSetInteger(ChartID(),"CLL",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"CLL",OBJPROP_COLOR,clrBlack);
Uma vez que uma divergência oculta de alta é identificada, este bloco de código tem como objetivo marcar graficamente aspectos importantes do gráfico. No primeiro conjunto de ações, o foco principal é o RSI. A primeira mínima significativa do RSI e a mínima mais baixa subsequente do RSI são representadas por linhas de tendência e rótulos de texto. O código inicialmente estabelece uma linha de tendência entre a nova mínima mais baixa do RSI (new_rsi_low_value) e a mínima original do RSI (rsi_low_value). As linhas de tendência ajudam os traders a identificar mais facilmente a tendência de queda do RSI. Nesses pontos, rótulos de texto “L” e “LL” também são adicionados para identificá-los como mínimas notáveis; “L” indica a mínima inicial, e “LL” indica a mínima mais baixa.
O próximo conjunto de ações é focado nos níveis de preço correspondentes. De forma semelhante ao RSI, linhas de tendência e rótulos de texto são criados para conectar a primeira mínima de preço (corresponding_low_value) à nova mínima de preço (new_corresponding_low_value). Espera-se que o preço correspondente forme uma mínima mais alta, o que é fundamental para a configuração de divergência oculta de alta. O código cria uma linha de tendência entre esses dois pontos de preço e os rotula com “L” e “HL”, onde “L” marca a primeira mínima significativa de preço e “HL” indica a mínima mais alta formada pelo preço. Esses elementos visuais ajudam a confirmar que o movimento do preço está mostrando a mínima mais alta esperada, enquanto o RSI mostra uma mínima mais baixa, um indicador clássico de divergência oculta de alta.
A função ObjectDelete() é responsável por limpar os objetos visuais no gráfico quando as condições para divergência oculta de alta deixam de ser válidas. Especificamente, ela verifica se o preço de fechamento atual está abaixo da média móvel (ma_buffer[0]) ou se o menor preço de fechamento desde a última mínima significativa do RSI é menor do que a mínima de preço correspondente (corresponding_low_value). Se qualquer uma dessas condições for atendida, as linhas de tendência, rótulos de texto e outros objetos previamente desenhados que marcam as mínimas do RSI e do preço são excluídos. Isso garante que o gráfico permaneça livre de marcadores visuais desatualizados ou irrelevantes, permitindo que os traders se concentrem nas condições de mercado mais atuais e válidas.
SAÍDA:

4.2. Encontrando Divergência Oculta de Baixa
Uma divergência oculta de baixa ocorre quando o RSI forma uma máxima mais alta enquanto o preço cria uma máxima mais baixa, sinalizando um possível momentum de queda apesar de uma recuperação temporária do preço. Para identificar esse padrão, a máxima mais recente do RSI é detectada usando uma lógica específica: ela deve ocorrer após pelo menos um movimento de alta seguido por três movimentos consecutivos de baixa, indicando um pico significativo de momentum. Uma vez identificada a máxima do RSI, seu preço correspondente e o valor da Média Móvel (MA) são recuperados para confirmar o alinhamento com a tendência de baixa predominante. Uma divergência oculta de baixa válida exige que a máxima do preço permaneça abaixo da MA, reforçando o viés de baixa.
Diferentemente da divergência oculta de alta, em que o RSI forma uma mínima mais baixa e o preço cria uma mínima mais alta (sinalizando possível momentum de alta), a divergência oculta de baixa funciona na direção oposta. Após identificar a máxima do RSI, a lógica também inclui a verificação de uma nova máxima do RSI que supere a primeira, com o preço correspondente formando uma máxima mais baixa. Essa divergência destaca o enfraquecimento do momentum de alta, em contraste com a divergência oculta de alta, que indica o enfraquecimento do momentum de baixa. Essas distinções garantem uma abordagem estruturada para detectar e diferenciar ambos os tipos de divergências de forma eficaz.
Exemplo:
//DECLEAR VARIBLE ROR RSI HIGH AND CORESPONDING PRICE double rsi_high_value; double corresponding_high_value; double corresponding_high_ma; datetime rsi_high_time; //DECLEAR VARIABLE FOR THE MAXIMUM CORRESPONDING PRICE VALUE int maximum_value_high; // DECLEAR VARIBLE ROR NEW RSI HIGH AND CORESPONDING PRICE double new_rsi_high_value; datetime new_rsi_high_time; double new_corresponding_high_value;
//LOOP THROUGH THE LAST 30 BARS ON THE CHART for(int i = 0; i < 30; i++) { //PREVENT ARRAY OUT OF RANGE ERROR if((i+1 < 30) && (i+2 < 30) && (i < 30) && (i+3 < 30) && (i+4 < 30)) { //LOGIC TO IDENTIFY THE LATEST RSI HIGH if(rsi_buffer[i+4] < rsi_buffer[i+3] && rsi_buffer[i+2] < rsi_buffer[i+3] && rsi_buffer[i+1] < rsi_buffer[i+2] && rsi_buffer[i] < rsi_buffer[i+1]) { //GETTING LATEST RSI HIGH, CORRESPONDING PRICE, CORRESPONDING MA VALUE, and RSI TIME rsi_high_value = rsi_buffer[i+3]; corresponding_high_value = close[i+3]; corresponding_high_ma = ma_buffer[i+3]; rsi_high_time = time[i+3]; break; } } } //TOTAL NUMBERS OF BARS FROM THE LAST SIGNIFICANT RSI HIGH int total_bars_3 = 0; total_bars_3 = Bars(_Symbol,PERIOD_CURRENT,time[0],rsi_high_time); //MAXIMUM CLOSE PRICE FROM THE LAST SIGNIFICANT RSI LOW maximum_value_high = ArrayMaximum(close,0,total_bars_3); if(corresponding_high_value < corresponding_high_ma && close[0] < ma_buffer[0] && close[maximum_value_high] <= corresponding_high_value) { //CREATE LINES TO MARK RSI AND CORRESPONDING PRICE ObjectCreate(ChartID(),"RSI HIGH VALUE",OBJ_TREND,1,rsi_high_time,rsi_high_value,TimeCurrent(),rsi_high_value); ObjectCreate(ChartID(),"C-CANDLE HIGH",OBJ_TREND,0,rsi_high_time,corresponding_high_value,TimeCurrent(),corresponding_high_value); //SETTING OBJECTS COLOUR ObjectSetInteger(ChartID(),"RSI HIGH VALUE",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"C-CANDLE HIGH",OBJPROP_COLOR,clrBlack); //CREATE TWO LINES TO CONNECT RSI HIGH AND THE CORRESPONDING PRICE ON THE CHART ObjectCreate(ChartID(),"C-CANDLE LINE HIGH",OBJ_TREND,0,rsi_high_time,corresponding_high_value,rsi_high_time,0); ObjectCreate(ChartID(),"RSI HIGH LINE",OBJ_TREND,1,rsi_high_time,rsi_high_value,rsi_high_time,100); //SETTING OBJECTS COLOUR ObjectSetInteger(ChartID(),"C-CANDLE LINE HIGH",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"RSI HIGH LINE",OBJPROP_COLOR,clrBlack); //CREATE TEXTS TO MART RSI HIGH AND CORRESPONDING PRICE (C-PRICE) ObjectCreate(ChartID(),"C-CANDLE TEXT HIGH",OBJ_TEXT,0,TimeCurrent(),corresponding_high_value); ObjectSetString(ChartID(),"C-CANDLE TEXT HIGH",OBJPROP_TEXT,"C-PRICE"); ObjectCreate(ChartID(),"RSI HIGH TEXT",OBJ_TEXT,1,TimeCurrent(),rsi_high_value); ObjectSetString(ChartID(),"RSI HIGH TEXT",OBJPROP_TEXT,"RSI HIGH"); //SETTING TEXT COLOUR ObjectSetInteger(ChartID(),"C-CANDLE TEXT HIGH",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"RSI HIGH TEXT",OBJPROP_COLOR,clrBlack); //LOGIC TO GET THE NEW RSI HIGH if(rsi_buffer[0] < rsi_buffer[1] && rsi_buffer[1] > rsi_buffer[2] && rsi_buffer[1] > rsi_high_value && close[1] < corresponding_high_value) { new_rsi_high_value = rsi_buffer[1]; new_rsi_high_time = time[1]; new_corresponding_high_value = close[1]; } if(rsi_high_value < new_rsi_high_value && corresponding_high_value > new_corresponding_high_value) { //for rsi ObjectCreate(ChartID(),"RSI HIGH TREND LINE",OBJ_TREND,1,rsi_high_time,rsi_high_value,new_rsi_high_time,new_rsi_high_value); ObjectCreate(ChartID(),"H",OBJ_TEXT,1,rsi_high_time,rsi_high_value); ObjectSetString(ChartID(),"H",OBJPROP_TEXT,"H"); ObjectSetInteger(ChartID(),"H",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"RSI HIGH TREND LINE",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"H",OBJPROP_COLOR,clrBlack); ObjectCreate(ChartID(),"HH",OBJ_TEXT,1,new_rsi_high_time,new_rsi_high_value); ObjectSetString(ChartID(),"HH",OBJPROP_TEXT,"HH"); ObjectSetInteger(ChartID(),"HH",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"HH",OBJPROP_COLOR,clrBlack); //for candle ObjectCreate(ChartID(),"C-CANDLE TREND LINE HIGH",OBJ_TREND,0,rsi_high_time,corresponding_high_value,new_rsi_high_time,new_corresponding_high_value); ObjectCreate(ChartID(),"CH",OBJ_TEXT,0,rsi_high_time,corresponding_high_value); ObjectSetString(ChartID(),"CH",OBJPROP_TEXT,"H"); ObjectSetInteger(ChartID(),"CH",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"C-CANDLE TREND LINE HIGH",OBJPROP_COLOR,clrBlack); ObjectSetInteger(ChartID(),"CH",OBJPROP_COLOR,clrBlack); ObjectCreate(ChartID(),"CLH",OBJ_TEXT,0,new_rsi_high_time,new_corresponding_high_value); ObjectSetString(ChartID(),"CLH",OBJPROP_TEXT,"LH"); ObjectSetInteger(ChartID(),"CLH",OBJPROP_FONTSIZE,15); ObjectSetInteger(ChartID(),"CLH",OBJPROP_COLOR,clrBlack); } } //LOGIC TO DELETE THE OBJECTS WHEN ITS NO LONGER RELEVEANT else if((close[0] > ma_buffer[0]) || (close[maximum_value_high] > corresponding_high_value)) { ObjectDelete(ChartID(),"RSI HIGH VALUE"); ObjectDelete(ChartID(),"C-CANDLE HIGH"); ObjectDelete(ChartID(),"C-CANDLE LINE HIGH"); ObjectDelete(ChartID(),"RSI HIGH LINE"); ObjectDelete(ChartID(),"C-CANDLE TEXT HIGH"); ObjectDelete(ChartID(),"RSI HIGH TEXT"); ObjectDelete(ChartID(),"RSI HIGH TREND LINE"); ObjectDelete(ChartID(),"H"); ObjectDelete(ChartID(),"HH"); ObjectDelete(ChartID(),"C-CANDLE TREND LINE HIGH"); ObjectDelete(ChartID(),"CH"); ObjectDelete(ChartID(),"CLH"); }
Explicação:
Este segmento de código foi projetado para identificar divergência oculta de baixa ao detectar máximas do RSI e suas máximas de preço correspondentes, seguindo uma lógica semelhante à da seção 4.1. Encontrando Divergência Oculta de Alta. Não será dada muita ênfase aqui, pois a maior parte da lógica já foi explicada na seção 4.1. Encontrando Divergência Oculta de Alta; a única diferença é que agora o foco está no cenário oposto. Embora a abordagem subjacente permaneça consistente, esta implementação visa o momentum de baixa ao focar nas máximas do RSI em vez das mínimas.
A primeira parte do código declara variáveis como rsi_high_value, corresponding_high_value e corresponding_high_ma para armazenar a máxima do RSI, seu preço correspondente e o valor da Média Móvel (MA), respectivamente. Essas variáveis são usadas para identificar a máxima mais recente do RSI percorrendo as últimas 30 barras e aplicando a condição de um movimento de alta seguido por três movimentos consecutivos de baixa. Uma vez encontrada uma máxima do RSI, o preço correspondente e o valor da MA são recuperados, e o registro de tempo (rsi_high_time) é armazenado. Uma etapa de validação garante que a máxima de preço correspondente esteja abaixo da MA, reforçando a tendência de baixa.

Em seguida, detectamos uma nova máxima do RSI, na qual o RSI forma uma máxima mais alta e o preço forma uma máxima mais baixa (LH). Isso atende aos critérios de divergência oculta de baixa, sinalizando o enfraquecimento do momentum de alta na ação do preço. Se essa condição for atendida, linhas de tendência e rótulos são criados para marcar visualmente as máximas do RSI (H e HH) e suas máximas de preço correspondentes (H e LH) no gráfico. Esses marcadores visuais ajudam os traders a identificar rapidamente possíveis pontos de divergência oculta de baixa.
O código também inclui lógica para excluir objetos quando as condições para divergência oculta de baixa são invalidadas, como quando o preço atual fecha acima da MA ou quando o preço máximo desde a máxima do RSI identificada excede o valor da máxima correspondente. Isso garante que o gráfico permaneça limpo e reflita apenas sinais de divergência válidos.

5. Incorporando o Oscilador Estocástico e Executando Negociações
O Oscilador Estocástico é apresentado como a ferramenta final de confirmação agora que entendemos como usar a Média Móvel e o RSI para encontrar divergências ocultas de alta e de baixa. Ao garantir que a divergência corresponda a mudanças no momentum do mercado, o oscilador serve para aumentar a precisão da entrada nas negociações. Com diretrizes rigorosas de tempo e gerenciamento de risco, a lógica de confirmação para ambos os tipos de divergência depende do desempenho do oscilador em relação aos níveis de sobrecompra e sobrevenda.
5.1. Incorporando o Oscilador Estocástico
Após a confirmação da divergência oculta de alta pelo RSI e pelo movimento do preço, monitoraremos o Oscilador Estocástico para que ele caia abaixo do nível de sobrevenda (20) e, em seguida, volte a subir acima dele. Esse cruzamento deve ocorrer até 11 barras após a detecção da divergência para validar o sinal. Se confirmado, uma operação de compra será iniciada, com o stop-loss (SL) definido na última mínima de oscilação. O take-profit (TP) será estabelecido por uma relação risco-recompensa (RRR) predefinida para garantir um gerenciamento disciplinado da negociação.
Exemplo:
if(total_bars < 11) { if(stoch_buffer_k[0] < 20 && stoch_buffer_k[1] > 20 && currentBarTime != lastTradeBarTime && totalPositions < 1) { // } }
Explicação:
Este código confirma uma configuração de divergência oculta de alta validando-a com o Oscilador Estocástico. Primeiro, ele calcula o número de barras desde a mínima do RSI (new_rsi_low_time) usando a função Bars e garante que a configuração da negociação permaneça válida dentro de uma janela de 11 barras (“if(total_bars < 11)”). Dentro desse período, ele verifica se a linha %K do Oscilador Estocástico cruzou acima do nível de sobrevenda de 20 (stoch_buffer_k[1] < 20 e stoch_buffer_k[0] > 20). Esse cruzamento confirma um possível momentum de alta, fortalecendo o sinal altista. Se ambas as condições forem atendidas, o código prossegue para executar a lógica da negociação, garantindo que todos os critérios para uma divergência oculta de alta sejam cumpridos.
Da mesma forma, aguardaremos que o Oscilador Estocástico suba acima do nível de sobrecompra (80) e depois cruze novamente para baixo para confirmar a divergência oculta de baixa. Além disso, esse cruzamento de baixa precisa ocorrer dentro de 11 barras após a detecção da divergência. Se verificado, uma operação de venda será realizada, com o TP calculado usando o RRR especificado e o SL definido na máxima de oscilação mais recente. Ao combinar esses procedimentos com o método original de detecção de divergência, garante-se que as negociações sejam realizadas apenas quando houver gerenciamento de risco claro e bom alinhamento de momentum.
Exemplo:
int total_bars = Bars(_Symbol,PERIOD_CURRENT,new_rsi_high_time,TimeCurrent()); if(total_bars < 11) { if(stoch_buffer_k[0] < 80 && stoch_buffer_k[1] > 80) { // } }
Explicação:
O número de barras entre o tempo atual (TimeCurrent()) e o momento em que a nova máxima do RSI (new_rsi_high_time) foi descoberta é determinado pela variável total_bars. Ela garante que a configuração ainda esteja ativa e não tenha expirado se houver menos de onze barras. Em seguida, o código determina se a linha %K do oscilador estocástico (stoch_buffer_k) cruzou abaixo do limite de sobrecompra (80) na barra atual (stoch_buffer_k[0] < 80) e estava acima dele na barra anterior (stoch_buffer_k[1] > 80). Se ambos os requisitos forem atendidos, a configuração da negociação é validada e o código inicia a lógica necessária para entrar na operação.
5.2. Execução da Operação
5.2.1. Mínima de Oscilação e Máxima de Oscilação
Esta seção se concentrará em todos os componentes essenciais necessários para executar negociações após a confirmação de uma divergência válida e do sinal do Oscilador Estocástico. Ela garante que as negociações sejam executadas de forma sistemática e com gerenciamento de risco adequado.
Para definir o stop-loss (SL), devemos primeiro determinar a última máxima ou mínima de oscilação. A última mínima de oscilação será o SL para uma divergência oculta de alta, e a última máxima de oscilação para uma divergência oculta de baixa. Isso garante que, com base no comportamento anterior do preço, as negociações tenham um limite de risco claramente definido.
Exemplo:
double last_high; double last_low; //LOGIC FOR LAST HIGH for(int i = 0; i < 30; i++) { if(i < 30 && i+1 < 30) { if(close[i] < open[i] && close[i+1] > open[i+1]) { last_high = MathMax(high[i],high[i+1]); break; } } } //LOGIC FOR LAST LOW for(int i = 0; i < 30; i++) { if(i < 30 && i+1 < 30) { if(close[i] > open[i] && close[i+1] < open[i+1]) { last_low = MathMin(low[i],low[i+1]); break; } } } }
Explicação:
Para determinar a máxima e a mínima mais recentes, este código examina as 30 barras anteriores. Ele determina o preço mais alto (last_high) detectando uma vela de baixa seguida por uma de alta, e o preço mais baixo (last_low) detectando uma vela de alta seguida por uma de baixa. Ao determinar os níveis de stop-loss, esses valores são essenciais.
5.2.2. Gerenciando a execução de ordens e prevenindo o excesso de negociações.
O sistema permitirá apenas uma posição aberta por vez para desencorajar negociações excessivas e reduzir riscos desnecessários. O código garantirá que não haja posições em aberto antes de realizar uma nova transação. Isso garante um comportamento de negociação mais controlado, impedindo que o sistema conclua transações a cada sinal. A execução eficaz de negociações requer a inclusão da biblioteca #include <Trade/Trade.mqh>, que concede acesso à classe CTrade para gerenciamento de negociações.
Exemplo:
#include <Trade/Trade.mqh> CTrade trade; input int MagicNumber = 9097; //MAGIC NUMBER //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //SET MAGIC NUMBER trade.SetExpertMagicNumber(MagicNumber); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // Getting total positions int totalPositions = 0; for(int i = 0; i < PositionsTotal(); i++) { ulong ticket = PositionGetTicket(i); if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && PositionGetString(POSITION_SYMBOL) == ChartSymbol(ChartID())) { totalPositions++; } } }
Explicação:
O código começa incluindo a biblioteca Trade.mqh, que fornece acesso às funções de negociação no MetaTrader. Em seguida, o objeto CTrade, trade, é instanciado para gerenciar as operações de negociação. O MagicNumber é definido como uma entrada, definido como 9097 neste caso, o que identifica exclusivamente as negociações abertas por este Expert Advisor (EA) específico para distingui-las de outras na mesma conta. Na função OnInit(), o magic number é aplicado ao objeto trade usando SetExpertMagicNumber(MagicNumber). Isso garante que o EA reconheça suas negociações ao realizar operações como abrir, modificar ou fechar posições.
Na função OnTick(), o código verifica o número total de posições abertas para o símbolo no gráfico atual percorrendo todas as posições usando PositionsTotal(). Ele recupera o número do ticket de cada posição com PositionGetTicket(i) e verifica se o magic number da posição corresponde ao magic number do EA usando PositionGetInteger(POSITION_MAGIC). Além disso, o código verifica se a posição pertence ao símbolo do gráfico atual usando PositionGetString(POSITION_SYMBOL). Se ambas as condições forem verdadeiras, ele incrementa a variável totalPositions, mantendo o controle do número de negociações abertas relacionadas ao EA e ao símbolo específicos, garantindo que apenas uma posição esteja aberta por vez.
5.2.3. Gestão de Risco
O sistema de negociação garante uma abordagem metódica para o gerenciamento de risco e a maximização da lucratividade ao integrar esses dois elementos essenciais. Essa estratégia apoia o sucesso de longo prazo no mercado e ajuda a proteger a conta de negociação. O principal objetivo desta seção será a implementação de um sistema robusto de gerenciamento de risco, permitindo que os traders indiquem o valor exato de dinheiro que desejam arriscar em cada operação. Também será descrito como calcular a relação risco-recompensa (RRR) para cada negociação, a fim de garantir que os ganhos potenciais superem os riscos potenciais.
Exemplo:
//INPUTS input double risk_amount = 20; // $ PER TRADE input double rrr = 4; //RRR input int MagicNumber = 9097; //MAGIC NUMBER double take_profit; double points_risk; double lot_size; //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //BULLISH HIDDEN DIVERGENCE if(stoch_buffer_k[0] > 20 && stoch_buffer_k[1] < 20 && currentBarTime != lastTradeBarTime && totalPositions < 1) { take_profit = ((ask_price - last_low) * rrr) + ask_price; points_risk = ask_price - low[0]; lot_size = CalculateLotSize(_Symbol, risk_amount, points_risk); trade.Buy(lot_size,_Symbol,ask_price,last_low,take_profit); lastTradeBarTime = currentBarTime; } //BEARISH HIDDEN DIVERGENCE if(stoch_buffer_k[0] < 80 && stoch_buffer_k[1] > 80 && currentBarTime != lastTradeBarTime && totalPositions < 1) { take_profit = MathAbs(((last_high - ask_price) * rrr) - ask_price); points_risk = high[0] - ask_price; lot_size = CalculateLotSize(_Symbol, risk_amount, points_risk); trade.Sell(lot_size,_Symbol,ask_price,last_high,take_profit); lastTradeBarTime = currentBarTime; } } //+-----------------------------------------------------------------------+ //| Function to calculate the lot size based on risk amount and stop loss | //+-----------------------------------------------------------------------+ double CalculateLotSize(string symbol, double riskAmount, double stopLossPips) { // Get symbol information double point = SymbolInfoDouble(symbol, SYMBOL_POINT); double tickValue = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); // Calculate pip value per lot double pipValuePerLot = tickValue / point; // Calculate the stop loss value in currency double stopLossValue = stopLossPips * pipValuePerLot; // Calculate the lot size double lotSize = riskAmount / stopLossValue; // Round the lot size to the nearest acceptable lot step double lotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP); lotSize = MathFloor(lotSize / lotStep) * lotStep; // Ensure the lot size is within the allowed range double minLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX); return lotSize; }
Explicação:
Com base em um valor de risco determinado (em dólares) e na distância do stop-loss (em pip), a função CalculateLotSize calcula o tamanho de lote adequado para uma negociação. O tamanho do lote é determinado dividindo o valor do risco pelo valor do stop-loss, convertendo a distância do stop-loss em um valor monetário e calculando o valor do pip por lote usando dados específicos do símbolo. O resultado é ajustado para atender aos requisitos do corretor quanto aos tamanhos mínimo e máximo de lote, bem como aos incrementos de lote. Para que essa função seja reutilizável em todo o código e para tornar o gerenciamento de risco uniforme e eficaz, ela deve ser declarada na área global.
Para uma negociação de compra, a linha %K do Oscilador Estocástico deve subir acima de 20 após ter caído abaixo desse nível. As negociações são executadas apenas se não houver posições abertas (totalPositions < 1) e se a barra atual for diferente da última barra negociada. O stop-loss é definido na última mínima de oscilação, e o take-profit é calculado usando a relação risco-recompensa (rrr) e a distância entre o preço ask e a mínima de oscilação. O tamanho do lote é determinado usando a função CalculateLotSize, com base no valor do risco e na distância do stop-loss. Após a execução, lastTradeBarTime é atualizado para evitar negociações duplicadas na mesma barra.

A linha %K do oscilador deve primeiro estar acima do nível 80 (sobrecompra) antes de cruzar para baixo para indicar uma negociação de venda. De forma semelhante, a operação só será executada se não houver posições abertas e se a barra for nova. A relação risco-recompensa e a diferença entre o preço ask e a máxima de oscilação mais recente (last_high) são usadas para determinar o take-profit (take_profit). Na máxima final de oscilação, o stop-loss é estabelecido. A função CalculateLotSize é utilizada novamente para determinar o tamanho do lote. Para evitar negociações duplicadas, a função de venda atualiza lastTradeBarTime e envia a ordem de venda.
Ao seguir limites de negociação, gerenciamento de risco adequado e sinais de confirmação, este código garante negociações disciplinadas e aumenta a confiabilidade da estratégia de trading.

Conclusão
Este artigo forneceu um guia passo a passo para identificar e negociar divergências ocultas de alta e de baixa usando MQL5, integrando indicadores como a Média Móvel, o RSI e o Oscilador Estocástico. Ele enfatizou o gerenciamento de risco, a execução de negociações e a automação para ajudar os traders a identificar esses padrões de forma eficaz no mercado. Este conteúdo educacional tem como objetivo ensinar os fundamentos da detecção de divergências e do trading sistemático. Um código-fonte bem detalhado, completo com comentários abrangentes, será anexado para servir como referência prática para a implementação dos conceitos discutidos.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/16956
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.
Desenvolvimento do Toolkit de Análise de Price Action (Parte 8): Painel de Métricas
Visão computacional para trading (Parte 1): Criando uma funcionalidade básica simples
Trading de arbitragem no Forex: sistema de negociação matricial para retorno ao valor justo com limitação de risco
Redes neurais em trading: Otimização de LSTM para fins de previsão de séries temporais multidimensionais (Conclusão)
- 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
Obrigado, senhor
De nada, obrigado por suas palavras gentis.