
Construção de um modelo de restrição de tendência de velas (Parte 1): Para EAs e indicadores técnicos
Conteúdo
- Introdução
- Anatomia das velas de timeframes superiores
- Desenvolvimento de estratégia (cruzamento de médias móveis) com código
- Justificativa e aplicação da restrição, incluindo código
- Vantagens do uso do código
- Considerações finais
Introdução
O caráter altista ou baixista das velas em timeframes mais elevados pode fornecer informações valiosas sobre a direção do mercado. Essa análise pode ser uma alternativa ao uso de médias móveis para identificar tendências de mercado. Por exemplo, uma vela diária (D1) ou de quatro horas (H4) reflete uma atividade fundamental significativa que ocorre em timeframes mais curtos, como M1 ou até mesmo em ticks. Traders podem se beneficiar aproveitando oportunidades de compra oferecidas por velas altistas em D1 e de venda durante as fases baixistas. A combinação com indicadores técnicos em timeframes mais curtos ajuda a definir pontos de entrada precisos, proporcionando uma vantagem estratégica aos traders. Ao trabalhar com uma vela diária altista, os traders devem esperar pacientemente até que as condições de mercado sejam favoráveis, antes de seguirem a tendência com segurança.
O objetivo deste artigo é classificar de maneira eficaz a vela atual como altista ou baixista, usando código em MQL5 que estabelece a condição de venda somente em caso de vela baixista e compra em caso de vela altista.
A finalidade deste modelo é limitar o gerador de sinais para emitir sinais que estejam conforme a tendência atual da vela. Isso pode ser comparado a uma cerca, que impede certos "animais" de entrarem em seu quintal com base no tamanho, mas permite a passagem de outros. Aplicamos um conceito semelhante para filtrar os sinais selecionados e manter apenas os mais otimizados. O modelo analisa velas e tendências de mercado em timeframes superiores, criando uma barreira virtual que permite apenas os sinais compatíveis com a tendência predominante. Essa filtragem seletiva aumenta a precisão e confiabilidade dos sinais gerados, garantindo que o usuário receba apenas as oportunidades de negociação mais vantajosas.
Ao final deste artigo, você será capaz de:
- Estudar o movimento de preços em uma vela diária (D1) usando timeframes mais curtos.
- Criar um buffer de indicador para cruzamento de médias móveis, que inclui uma condição de restrição de tendência em timeframes superiores.
- Compreender o conceito de seleção dos melhores sinais em uma estratégia específica.
Anatomia das velas de timeframes superiores
Fig. 1.1. Anatomia de uma vela D1 no timeframe M5 para o índice sintético Boom 500
A imagem acima mostra uma faixa vermelha da vela D1 à esquerda e a ação do preço em M5 à direita entre os separadores de períodos diários. Observa-se um claro movimento descendente, sustentado pelo caráter baixista da vela diária, o que indica uma maior probabilidade de operações de venda. Nesta configuração, dá-se atenção especial à execução de ordens alinhada com a vela D1, refletindo a ideia de limitação com base na tendência de timeframes superiores.
Desenvolvimento de estratégia (cruzamento de médias móveis)
O desenvolvimento de uma estratégia de negociação exige uma combinação de análise, testes e aprimoramento contínuo. Uma estratégia de sucesso deve se basear em uma compreensão profunda do mercado, assim como em um conjunto claro de regras e diretrizes a seguir. É essencial monitorar e ajustar a estratégia conforme as condições do mercado mudam, a fim de se adaptar a novas tendências e oportunidades. Ao analisar dados constantemente, testar diferentes abordagens e ajustar conforme necessário, os traders podem aumentar suas chances de sucesso no mercado.
Antes de abordarmos a estratégia de cruzamento de médias móveis, vamos resumir as principais dicas para o desenvolvimento de uma estratégia:
- Defina seus objetivos e tolerância ao risco
- Entenda o mercado
- Escolha seu estilo de negociação
- Defina regras de entrada e saída
- Implemente estratégias de gestão de riscos
- Teste a estratégia com dados históricos
- Otimize-a
- Faça trades simulados antes de operar com dinheiro real
- Monitore e avalie
- Estabeleça as condições da estratégia (neste caso, o cruzamento da EMA7 acima ou abaixo da EMA21)
- Defina o estilo de exibição do indicador, que pode ser uma seta ou qualquer figura geométrica disponível no MetaTrader 5.
- (Opcional) Se o indicador for configurável pelo usuário, defina as variáveis de entrada
Decidi incluir o código final aqui sem explicações detalhadas, para focar no algoritmo de restrição — tema principal desta análise. O programa a seguir está pronto para compilação e geração de sinais de compra e venda. A seguir, analisaremos os resultados no gráfico e identificaremos o problema que o algoritmo de restrição pretende resolver.
//Indicator Name: Trend Constraint #property copyright "Clemence Benjamin" #property link "https://mql5.com" #property version "1.00" #property description "A model that seek to produce sell signal when D1 candle is Bearish only and buy signal when it is Bullish" //--- indicator settings #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_width1 5 #property indicator_color1 0xFFAA00 #property indicator_label1 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Sell" #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; double myPoint; //initialized in OnInit int MA_handle; double MA[]; int MA_handle2; double MA2[]; double Low[]; double High[]; void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | Trend constraint @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } } // Custom indicator initialization function int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(0, PLOT_ARROW, 241); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(1, PLOT_ARROW, 242); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle2 = iMA(NULL, PERIOD_CURRENT, 21, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle2 < 0) { Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); } //Custom indicator iteration function int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { int limit = rates_total - prev_calculated; //--- counting from 0 to rates_total ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); } else limit++; if(BarsCalculated(MA_handle) <= 0) return(0); if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total); ArraySetAsSeries(MA, true); if(BarsCalculated(MA_handle2) <= 0) return(0); if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total); ArraySetAsSeries(MA2, true); if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); //--- main loop for(int i = limit-1; i >= 0; i--) { if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation //Indicator Buffer 1 if(MA[i] > MA2[i] && MA[i+1] < MA2[i+1] //Moving Average crosses above Moving Average ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(MA[i] < MA2[i] && MA[i+1] > MA2[i+1] //Moving Average crosses below Moving Average ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); } //copy the code to meta editor to compile it
No gráfico de resultados do teste para EURUSD em 12.04.24, marca-se o início do período observado no timeframe M1. Os cruzamentos são indicados por setas: vermelhas para sinais de venda e azuis para sinais de compra. No entanto, uma análise mais ampla revela um claro movimento descendente, indicando uma vela D1 baixista. O indicador de cruzamento gera ambos os sinais (de compra e de venda), ignorando a tendência predominante. Sinais contraditórios criam uma situação desafiadora para traders que tentam se orientar no mercado. Embora o timeframe M1 indique oportunidades de curto prazo, o movimento descendente em D1 coloca em questão a sustentabilidade de qualquer movimento ascendente. Vamos resolver esse problema limitando nossos sinais à tendência D1.
Fig. 1.2. Indicador de cruzamento de médias móveis antes da implementação das restrições.
O resultado para a vela D1 é baixista. As setas de compra e venda são geradas com base no cruzamento das médias móveis. Muitos desses sinais são considerados falsos ou estão desalinhados com a tendência predominante, problema que pode ser corrigido ao incluir uma restrição de tendência baseada em um timeframe superior. A tabela abaixo foi criada a partir das informações do gráfico, do início até o fechamento do dia.
Tipo de Sinal | Quantidade |
---|---|
Sinais de Venda | 29 |
Sinais de Compra | 28 |
Total | 57 |
Sinais Falsos e Alheios | 41 |
Sinais Bem-sucedidos | 25 |
Justificativa e aplicação da restrição
Imagine uma mistura de grãos de milho e sorgo, onde o milho é mais grosso. Para separá-los, usamos uma peneira. Ela retém os grãos de milho, permitindo que apenas o sorgo passe. Essa analogia reflete a ideia de restrição com base em timeframes superiores. Ela age como um filtro, separando sinais específicos e mantendo apenas aqueles que estão alinhados com a tendência predominante. A restrição de um timeframe superior, assim como a peneira, reforça nosso foco, permitindo distinguir os principais elementos da tendência do mercado. Ao filtrar o ruído, conseguimos entender melhor a dinâmica principal do mercado, favorecendo a tomada de decisões mais informadas. Esse enfoque estratégico aprimora nossa capacidade de navegar nas complexidades do cenário financeiro, assegurando que estejamos alinhados com a direção geral, assim como o sorgo é separado do milho, revelando a essência do movimento de mercado.
Vamos definir a natureza da vela D1 como critério para limitar a tendência.- Eu defino o sentimento de mercado atual como altista ou baixista, comparando o fechamento do dia anterior, que é similar ao preço de abertura do dia atual, com os fechamentos das velas de timeframe inferior M1.
- A seguir, vamos revisar o código. Ele está bem estruturado e é fácil de entender.
Para uma vela ALTISTA:
fechamento da última vela M1 >= fechamento da última vela D1
Para uma vela BAIXISTA:
fechamento da última vela M1 <= fechamento da última vela D1
A lógica matemática demonstra que, com uma vela altista D1 como direcionador de tendência, somente sinais de compra serão gerados, e, para uma vela baixista D1, apenas sinais de venda serão permitidos.
Optamos por usar o fechamento do timeframe curto em relação ao nosso preço de abertura D1, em vez de outros parâmetros como Bid e Ask ou o fechamento do próprio dia, pois este último não exibe setas no gráfico, como exigido pela estratégia e estilo do indicador. Ao focar no fechamento do timeframe curto em relação à abertura D1, conseguimos alinhar nossa estratégia com as sugestões visuais desejadas e com os indicadores no gráfico. Esse método aumenta a clareza e a precisão nas nossas decisões de trading, proporcionando um processo de análise mais otimizado e eficiente.
if(Close[1+barshift_M1[i]] >= Open[1+barshift_D1[i]] //Candlestick Close >= Candlestick Open ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; }
O código acima representa o estado de uma vela altista D1. A versão espelhada do código funciona também para uma tendência baixista.
- Abaixo está o código final, no qual a restrição de tendência é integrada ao indicador de cruzamento de médias móveis de forma fluida.
/Indicator Name: Trend Constraint #property copyright "Clemence Benjamin" #property link "https://mql5.com" #property version "1.00" #property description "A model that seek to produce sell signal when D1 candle is Bearish only and buy signal when it is Bullish" //--- indicator settings #property indicator_chart_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_ARROW #property indicator_width1 5/ #property indicator_color1 0xFFAA00 #property indicator_label1 "Buy" #property indicator_type2 DRAW_ARROW #property indicator_width2 5 #property indicator_color2 0x0000FF #property indicator_label2 "Sell" #define PLOT_MAXIMUM_BARS_BACK 5000 #define OMIT_OLDEST_BARS 50 //--- indicator buffers double Buffer1[]; double Buffer2[]; double myPoint; //initialized in OnInit int MA_handle; double MA[]; int MA_handle2; double MA2[]; double Close[]; double Close2[]; double Low[]; double High[]; void myAlert(string type, string message) { if(type == "print") Print(message); else if(type == "error") { Print(type+" | Trend constraint @ "+Symbol()+","+IntegerToString(Period())+" | "+message); } else if(type == "order") { } else if(type == "modify") { } } // Custom indicator initialization function int OnInit() { SetIndexBuffer(0, Buffer1); PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(0, PLOT_ARROW, 241); SetIndexBuffer(1, Buffer2); PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE); PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, MathMax(Bars(Symbol(), PERIOD_CURRENT)-PLOT_MAXIMUM_BARS_BACK+1, OMIT_OLDEST_BARS+1)); PlotIndexSetInteger(1, PLOT_ARROW, 242); //initialize myPoint myPoint = Point(); if(Digits() == 5 || Digits() == 3) { myPoint *= 10; } MA_handle = iMA(NULL, PERIOD_CURRENT, 7, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle < 0) { Print("The creation of iMA has failed: MA_handle=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } MA_handle2 = iMA(NULL, PERIOD_CURRENT, 21, 0, MODE_EMA, PRICE_CLOSE); if(MA_handle2 < 0) { Print("The creation of iMA has failed: MA_handle2=", INVALID_HANDLE); Print("Runtime error = ", GetLastError()); return(INIT_FAILED); } return(INIT_SUCCEEDED); } // Custom indicator iteration function int OnCalculate(const int rates_total, const int prev_calculated, const datetime& time[], const double& open[], const double& high[], const double& low[], const double& close[], const long& tick_volume[], const long& volume[], const int& spread[]) { int limit = rates_total - prev_calculated; //--- counting from 0 to rates_total ArraySetAsSeries(Buffer1, true); ArraySetAsSeries(Buffer2, true); //--- initial zero if(prev_calculated < 1) { ArrayInitialize(Buffer1, EMPTY_VALUE); ArrayInitialize(Buffer2, EMPTY_VALUE); } else limit++; datetime TimeShift[]; if(CopyTime(Symbol(), PERIOD_CURRENT, 0, rates_total, TimeShift) <= 0) return(rates_total); ArraySetAsSeries(TimeShift, true); int barshift_M1[]; ArrayResize(barshift_M1, rates_total); int barshift_D1[]; ArrayResize(barshift_D1, rates_total); for(int i = 0; i < rates_total; i++) { barshift_M1[i] = iBarShift(Symbol(), PERIOD_M1, TimeShift[i]); barshift_D1[i] = iBarShift(Symbol(), PERIOD_D1, TimeShift[i]); } if(BarsCalculated(MA_handle) <= 0) return(0); if(CopyBuffer(MA_handle, 0, 0, rates_total, MA) <= 0) return(rates_total); ArraySetAsSeries(MA, true); if(BarsCalculated(MA_handle2) <= 0) return(0); if(CopyBuffer(MA_handle2, 0, 0, rates_total, MA2) <= 0) return(rates_total); ArraySetAsSeries(MA2, true); if(CopyClose(Symbol(), PERIOD_M1, 0, rates_total, Close) <= 0) return(rates_total); ArraySetAsSeries(Close, true); if(CopyClose(Symbol(), PERIOD_D1, 0, rates_total, Close2) <= 0) return(rates_total); ArraySetAsSeries(Close2, true); if(CopyLow(Symbol(), PERIOD_CURRENT, 0, rates_total, Low) <= 0) return(rates_total); ArraySetAsSeries(Low, true); if(CopyHigh(Symbol(), PERIOD_CURRENT, 0, rates_total, High) <= 0) return(rates_total); ArraySetAsSeries(High, true); //--- main loop for(int i = limit-1; i >= 0; i--) { if (i >= MathMin(PLOT_MAXIMUM_BARS_BACK-1, rates_total-1-OMIT_OLDEST_BARS)) continue; //omit some old rates to prevent "Array out of range" or slow calculation if(barshift_M1[i] < 0 || barshift_M1[i] >= rates_total) continue; if(barshift_D1[i] < 0 || barshift_D1[i] >= rates_total) continue; //Indicator Buffer 1 if(MA[i] > MA2[i] && MA[i+1] < MA2[i+1] //Moving Average crosses above Moving Average && Close[1+barshift_M1[i]] >= Close2[1+barshift_D1[i]] //Candlestick Close >= Candlestick Close ) { Buffer1[i] = Low[i]; //Set indicator value at Candlestick Low } else { Buffer1[i] = EMPTY_VALUE; } //Indicator Buffer 2 if(MA[i] < MA2[i] && MA[i+1] > MA2[i+1] //Moving Average crosses below Moving Average && Close[1+barshift_M1[i]] <= Close2[1+barshift_D1[i]] //Candlestick Close <= Candlestick Close ) { Buffer2[i] = High[i]; //Set indicator value at Candlestick High } else { Buffer2[i] = EMPTY_VALUE; } } return(rates_total); }
O resultado do uso do código acima é excelente.
Fig. 1.4. Restrição de tendência aplicada. Resultado notável
Tipo de Sinal | Unidades |
---|---|
Sinal de Venda | 27 |
Sinal de Compra | 1 |
Total | 28 |
Sinais Falsos e Alheios | 3 |
Sinais Bem-sucedidos | 25 |
A tabela acima evidencia o impacto positivo da restrição de tendência com base em um timeframe superior, atuando como um filtro que resulta em mais acertos do que erros, o que o torna ideal para EAs. Comparando as tabelas de resultados anteriores e atuais, observamos que os sinais bem-sucedidos mantiveram seu valor, enquanto o número de sinais falsos diminuiu. Esse ganho em precisão demonstra a eficácia da nossa metodologia de análise de dados. Com o aprimoramento dos algoritmos e critérios, reduzimos a ocorrência de sinais falsos, aumentando a confiabilidade geral dos resultados. Esse progresso certamente contribuirá para decisões mais fundamentadas e melhores resultados nas nossas estratégias.
Vantagens do uso do código
As vantagens de aplicar restrições com base nas tendências de timeframes superiores aumentam a clareza sobre a direção do mercado, reduzem o excesso de operações e promovem uma abordagem mais disciplinada nas decisões de trading. Esse método também oferece uma perspectiva mais ampla, ajudando os traders a não se prenderem a flutuações de curto prazo e permitindo que alinhem suas estratégias ao movimento de longo prazo predominante. Ao focar na visão geral, os traders estão mais preparados para filtrar o ruído e tomar decisões mais embasadas. Esse método encoraja a paciência e um entendimento mais profundo da dinâmica do mercado, levando a resultados de negociação mais consistentes e lucrativos. Além disso, restrições baseadas em tendências de timeframes superiores podem funcionar como ferramentas valiosas de gestão de riscos, permitindo que traders definam pontos de entrada e saída claros com base em uma análise estratégica das condições de mercado.
Resumindo:
- Maior precisão dos indicadores de geração de sinais
- Melhor gestão de riscos
- Aumento da lucratividade
- Redução de trabalho
- Menos sinais desnecessários
Considerações finais
As velas de timeframes superiores influenciam substancialmente as tendências de timeframes inferiores, essencialmente direcionando o mercado. Com base em várias análises, recomenda-se considerar a compra durante velas diárias altistas nos timeframes menores e a venda durante velas baixistas. A integração de restrições de tendência em intervalos maiores pode ser decisiva para o desenvolvimento de EAs e indicadores que visam obter resultados positivos consistentes. Isso levanta a questão: devemos abandonar as médias móveis como ferramenta para identificar tendências? Talvez o próximo artigo lance luz sobre essa questão. Nele, vamos explorar e aprimorar ainda mais essa ideia. O artigo inclui os arquivos de código-fonte, prontos para visualização no MetaEditor, e os arquivos .ex5 para uso no MetaTrader 5.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/14347
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.





- 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