
Criação de um EA em MQL5 com base na estratégia PIRANHA utilizando Bandas de Bollinger
Introdução
Neste artigo, analisamos como criar um EA na linguagem MetaQuotes Language 5 (MQL5) com base na estratégia PIRANHA, com foco na integração das Bandas de Bollinger. Diante da busca por soluções eficazes para o trading automatizado, a estratégia PIRANHA surgiu como uma abordagem sistemática que aproveita as oscilações do mercado, tornando-se uma escolha atraente para os entusiastas do mercado Forex.
Começaremos com a exposição dos princípios fundamentais da estratégia PIRANHA, que servem como base sólida para sua implementação no trading automatizado. Em seguida, analisamos as Bandas de Bollinger, um indicador técnico popular que ajuda a identificar potenciais pontos de entrada e saída ao medir a volatilidade do mercado.
Depois, explicamos o processo de escrita do código em MQL5, destacando as principais funções e a lógica por trás da estratégia. Além disso, discutimos os testes de funcionamento do EA, a otimização dos parâmetros e recomendações para seu uso em ambientes de trading reais. Os temas abordados neste artigo são:
- Visão geral da estratégia PIRANHA
- Familiarização com as Bandas de Bollinger
- Plano da estratégia
- Implementação com MQL5
- Testes
- Considerações finais
Ao final deste artigo, você estará munido com os conhecimentos necessários para desenvolver um EA em MQL5 que utilize com eficiência a estratégia PIRANHA e as Bandas de Bollinger, aprimorando sua abordagem de trading. Então, vamos começar.
Visão geral da estratégia PIRANHA
A estratégia PIRANHA é um sistema de trading dinâmico, capaz de tirar proveito das oscilações de preço no mercado cambial. Essa estratégia é caracterizada por um estilo de negociação rápido e oportunista, batizado em referência ao peixe predador ágil, por sua velocidade e precisão, que se assemelha a esse tipo de operação. Conjunto de habilidades: A estratégia PIRANHA é baseada na volatilidade, projetada para ajudar os traders a identificar com precisão os pontos de entrada e saída do mercado, por meio de sua abordagem altamente relativa.
Um dos componentes da estratégia PIRANHA incluído é o uso das Bandas de Bollinger, que são indicadores amplamente utilizados e ajudam os traders a visualizar a volatilidade em seus mercados. Para o nosso método, utilizaremos uma Banda de Bollinger de 12 períodos simplesmente porque é uma excelente ferramenta que, com o tempo, adquire uma topologia que nos permite entender melhor o comportamento do preço. Também definiremos um desvio padrão duplo, o que, essencialmente, significa capturar as principais mudanças de preço ao mesmo tempo em que filtramos o ruído de oscilações insignificantes. Esses canais criam um teto e um piso que refletem potenciais condições de sobrecompra ou sobrevenda no mercado. Se o preço cair abaixo da banda inferior, isso é considerado uma excelente oportunidade de compra, enquanto a subida acima da banda superior indica que pode ser um bom momento para vender. Abaixo está uma ilustração:
A gestão de riscos é outro elemento importante da estratégia PIRANHA. Isso destaca a importância de proteger o capital com níveis bem definidos de stop-loss e take-profit. Para nossa estratégia, definiremos um stop-loss de 100 pontos abaixo do preço de entrada para operações de compra, e também estabeleceremos um nível de take-profit de 50 pontos acima do preço de entrada. Essa abordagem disciplinada garante que possamos reduzir possíveis prejuízos ao mesmo tempo em que asseguramos lucros, promovendo uma metodologia de trading mais sustentável.
Assim, a estratégia PIRANHA combina análise técnica com foco em volatilidade e gerenciamento de risco. Compreendendo esses princípios e configurações, os traders podem navegar com mais eficácia no mercado Forex, tomando decisões fundamentadas que se alinham aos seus objetivos de negociação. À medida que avançamos, veremos como implementar essa estratégia em MQL5, trazendo a estratégia PIRANHA à vida em um sistema de trading automatizado.
Familiarização com as Bandas de Bollinger
Os traders podem utilizar as Bandas de Bollinger, uma ferramenta confiável da análise técnica, para identificar possíveis mudanças de preço em um mercado volátil. John Bollinger desenvolveu esse indicador na década de 1980. Ele é composto por três elementos: uma média móvel, a banda superior e a banda inferior. Os cálculos realizados pelos traders permitem avaliar o quão distante o preço está do seu valor médio em qualquer direção.
Para começar, calculamos a banda média (média móvel), que normalmente é uma média móvel simples de 20 períodos, ou SMA. A fórmula da SMA é a seguinte:
Onde 𝑃𝑖 representa o preço de fechamento de cada período, e 𝑛 é o número de períodos (neste caso, 20). Por exemplo, se temos os seguintes preços de fechamento nos últimos 20 períodos:
Período | Preço de fechamento (𝑃𝑖) |
---|---|
1 | 1.1050 |
2 | 1.1070 |
3 | 1.1030 |
4 | 1.1080 |
5 | 1.1040 |
6 | 1.1100 |
7 | 1.1120 |
8 | 1.1150 |
9 | 1.1090 |
10 | 1.1060 |
11 | 1.1085 |
12 | 1.1105 |
13 | 1.1130 |
14 | 1.1110 |
15 | 1.1075 |
16 | 1.1055 |
17 | 1.1080 |
18 | 1.1095 |
19 | 1.1115 |
20 | 1.1120 |
Somamos esses preços e dividimos por 20:
Em seguida, calculamos o desvio padrão, que mede a dispersão dos preços de fechamento em relação à SMA. A fórmula do desvio padrão (𝜎):
Utilizando a SMA que calculamos, igual a 1.1080, calculamos o quadrado da diferença para cada preço de fechamento, depois tiramos a média desses valores e, por fim, extraímos a raiz quadrada. Por exemplo, os primeiros quadrados das diferenças:
Após calcular os 20 quadrados das diferenças, encontramos:
- Banda Superior = SMA + (k × σ)
- Banda Inferior = SMA − (k × σ)
Aqui normalmente definimos k=2 (o que corresponde a dois desvios padrão). Substituímos nossos valores:
- Banda Superior = 1.1080 + (2 × 0.0030) = 1.1140
- Banda Inferior = 1.1080 − (2 × 0.0030) = 1.1020
As Bandas de Bollinger resultantes são:
- Banda Média (SMA): 1.1080
- Banda Superior: 1.1140
- Banda Inferior: 1.1020
Essas três bandas se apresentam da seguinte forma:
A distância entre essas bandas muda conforme as condições do mercado. Quando elas se expandem, isso indica aumento da volatilidade, e os mercados em movimento tendem a ser voláteis. Quando as bandas se estreitam, isso indica consolidação do mercado. Os traders gostam de buscar relações entre os preços e as bandas para gerar sinais de trading. Eles tendem a interpretar a interação do preço com a banda superior como uma condição de sobrecompra do mercado, e a interação do preço com a banda inferior como uma condição de sobrevenda.
Em resumo, os cálculos das Bandas de Bollinger envolvem o cálculo da SMA, do desvio padrão, bem como das bandas superior e inferior. Compreender esses cálculos não é apenas um exercício de análise quantitativa, mas também uma forma de fornecer aos traders o conhecimento necessário para tomar decisões de trading fundamentadas, especialmente ao aplicar a estratégia PIRANHA em sua atividade de negociação.
Plano da estratégia
Esquema da Banda Superior: Condição de venda
Quando o preço cruza a Banda Superior de Bollinger e fecha acima dela, isso sinaliza que o mercado pode estar em condição de sobrecompra. Essa condição indica que os preços subiram excessivamente e, provavelmente, serão corrigidos para baixo. Como resultado, consideramos esse cenário como um sinal de venda. Assim, abrimos uma posição de venda quando o preço de fechamento da barra atual permanece acima da banda superior. O objetivo é lucrar com um possível movimento de reversão ou recuo.
Esquema da Banda Inferior: Condição de compra
Por outro lado, quando o preço cruza a Banda Inferior de Bollinger e fecha abaixo dela, isso indica que o mercado pode estar em condição de sobrevenda. Esse cenário sugere que os preços caíram significativamente e podem estar prontos para se recuperar. Consequentemente, isso é considerado um sinal de compra. Assim, abrimos uma posição de compra quando o preço de fechamento da barra atual está abaixo da banda inferior, esperando por uma possível reversão para cima.
Essas imagens esquemáticas da estratégia serão úteis quando formos implementar essas condições de trading no MQL5 e servirão como referência para escrever regras precisas de entrada e saída.
Implementação com MQL5
Depois de estudar toda a teoria da estratégia de trading Piranha, vamos automatizar essa teoria e criar um EA em MetaQuotes Language 5 (MQL5) para o MetaTrader 5.
Para criar um EA, no seu terminal MetaTrader 5 vá até a aba "Ferramentas" e selecione o editor de linguagem MetaQuotes ou simplesmente pressione a tecla F4 no teclado. Alternativamente, você pode clicar no ícone IDE (ambiente de desenvolvimento integrado) na barra de ferramentas. Isso abrirá o ambiente de desenvolvimento no MetaQuotes Language Editor, que permite escrever robôs de trading, indicadores técnicos, scripts e bibliotecas de funções.
Após abrir o MetaEditor, na barra de ferramentas selecione "Arquivo" - "Novo arquivo" ou pressione CTRL + N para criar um novo documento. Você também pode clicar no ícone "Criar" na barra de ferramentas. Isso abrirá a janela do Assistente MQL.
Na janela aberta do Assistente, selecione "Expert Advisor (modelo)" e clique em "Avançar".
Nas propriedades gerais, defina o nome do arquivo do seu EA. Para especificar ou criar uma pasta caso ela não exista, utilize uma barra invertida antes do nome do EA. Por padrão, a pasta especificada é "Experts". Isso significa que nosso EA será criado dentro dessa pasta. Os outros campos são bastante simples, mas você pode acessar um link na parte inferior do assistente para obter mais detalhes.
Após definir o nome do arquivo do EA, clique em "Avançar" > "Avançar" > "Concluir". Agora estamos prontos para implementar a estratégia no código.
Primeiramente, vamos começar definindo alguns metadados sobre o EA. Isso inclui: o nome do EA, informações de direitos autorais e o link para o site da MetaQuotes. Também especificamos a versão do EA, que está definida como "1.00".
//+------------------------------------------------------------------+ //| PIRANHA.mq5 | //| Allan Munene Mutiiria, Forex Algo-Trader. | //| https://forexalgo-trader.com | //+------------------------------------------------------------------+ //--- Properties to define metadata about the Expert Advisor (EA) #property copyright "Allan Munene Mutiiria, Forex Algo-Trader." //--- Copyright information #property link "https://forexalgo-trader.com" //--- Link to the creator's website #property version "1.00" //--- Version number of the EA
Quando o programa é carregado, é exibida uma informação conforme mostrado abaixo.
Em primeiro lugar, incluímos o módulo de trading utilizando a diretiva #include no início do código-fonte. Isso nos permite acessar a classe CTrade, que usaremos para criar um objeto de negociação. Isso é muito importante, pois é necessário para a abertura de ordens.
//--- Including the MQL5 trading library #include <Trade/Trade.mqh> //--- Import trading functionalities CTrade obj_Trade; //--- Creating an object of the CTrade class to handle trading operations
O pré-processador substituirá a linha #include <Trade/Trade.mqh> pelo conteúdo do arquivo Trade.mqh. Os sinais de menor e maior indicam que o arquivo Trade.mqh será carregado a partir do diretório padrão (normalmente localizado em terminal_installation_directory\MQL5\Include). O diretório atual não é incluído na busca. Embora essa linha possa ser colocada em qualquer parte do programa, geralmente todas as inclusões são posicionadas no início do código-fonte para melhorar a estrutura e facilitar as referências. Graças aos desenvolvedores do MQL5, a declaração do objeto obj_Trade da classe CTrade nos dará acesso direto aos métodos disponíveis nessa classe.
Precisaremos criar os handles dos indicadores para que possamos incluir os indicadores necessários em nossa estratégia.
//--- Defining variables for Bollinger Bands indicator and price arrays int handleBB = INVALID_HANDLE; //--- Store Bollinger Bands handle; initialized as invalid double bb_upper[], bb_lower[]; //--- Arrays to store upper and lower Bollinger Bands values
Aqui declaramos e inicializamos uma variável inteira chamada "handleBB", que servirá como o handle do indicador Bandas de Bollinger no nosso EA. No MQL5, um handle é um identificador único atribuído a um indicador, o que facilita sua manipulação em todo o código. Inicializando "handleBB" com INVALID_HANDLE, garantimos que o programa não tente usar um handle inválido antes que ele seja devidamente criado, evitando assim erros inesperados. Junto ao handle, também definimos dois arrays dinâmicos, "bb_upper" e "bb_lower", nos quais armazenaremos os valores das Bandas Superior e Inferior de Bollinger, respectivamente. Esses arrays nos ajudarão a registrar e analisar o estado atual do indicador, oferecendo uma base sólida para a implementação de nossa estratégia de trading baseada nas condições das Bandas de Bollinger. Mais uma vez, precisamos garantir que abrimos apenas uma posição por vez em uma única direção.
//--- Flags to track if the last trade was a buy or sell bool isPrevTradeBuy = false, isPrevTradeSell = false; //--- Prevent consecutive trades in the same direction
Aqui declaramos e inicializamos dois flags booleanos, "isPrevTradeBuy" e "isPrevTradeSell", para rastrear a direção da última operação realizada. Inicialmente, ambos os parâmetros são definidos como false, o que indica que ainda não foram feitas operações. Esses flags terão um papel crucial na gestão da lógica de trading, garantindo que o EA não abra operações consecutivas na mesma direção. Por exemplo, se a operação anterior foi de compra, o parâmetro "isPrevTradeBuy" será definido como true, impedindo que outra operação de compra seja executada até que ocorra uma operação de venda. Esse mecanismo ajuda a evitar operações desnecessárias e mantém uma estratégia de trading equilibrada.
A seguir, precisaremos do manipulador de eventos OnInit. Esse manipulador é importante, pois é automaticamente chamado quando o EA é inicializado no gráfico. Esta função é responsável por configurar o EA, incluindo a criação dos handles dos indicadores, a inicialização de variáveis e a preparação de recursos. Em outras palavras, OnInit é uma função embutida que garante que tudo esteja devidamente configurado antes que o EA comece a processar os dados de mercado. Ela é estruturada da seguinte forma.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit(){ // OnInit is called when the EA is initialized on the chart //... }
o manipulador de eventos OnInit, precisamos inicializar o handle do indicador para que os dados possam ser atribuídos a ele.
//--- Create Bollinger Bands indicator handle with a period of 12, no shift, and a deviation of 2 handleBB = iBands(_Symbol, _Period, 12, 0, 2, PRICE_CLOSE);
Aqui criamos o handle para o indicador Bandas de Bollinger, chamando a função iBands, que gera o indicador com base nos parâmetros definidos. Passamos a essa função vários argumentos: _Symbol representa o par de moedas que estamos analisando, enquanto _Period representa o timeframe do indicador, que pode variar de minutos a horas ou dias. Os parâmetros das Bandas de Bollinger incluem um período de 12, que determina a quantidade de barras utilizadas no cálculo do indicador, um deslocamento de 0, o que significa que não há ajuste aplicado às bandas, e um desvio padrão de 2, que define a distância entre as bandas e a média móvel. O uso do parâmetro PRICE_CLOSE indica que basearemos nossos cálculos nos preços de fechamento das barras. Após a execução bem-sucedida, nossa variável handle "handleBB" armazenará o identificador válido do indicador Bandas de Bollinger, o que nos permitirá referenciá-lo para busca e análise de dados. Assim, antes de prosseguir com o processo, precisamos verificar se o handle foi criado com sucesso.
//--- Check if the Bollinger Bands handle was created successfully if (handleBB == INVALID_HANDLE){ Print("ERROR: UNABLE TO CREATE THE BB HANDLE. REVERTING"); //--- Print error if handle creation fails return (INIT_FAILED); //--- Return initialization failed }
Aqui verificamos se o handle para o indicador Bandas de Bollinger foi criado corretamente, conferindo se ele é igual a INVALID_HANDLE. Se algum desses handles for inválido, exibimos uma mensagem de erro ("ERROR: UNABLE TO CREATE THE BB HANDLE. REVERTING,"), o que ajuda a identificar possíveis falhas durante a inicialização. Em seguida, retornamos INIT_FAILED, indicando que o EA não conseguiu se inicializar adequadamente. Se tudo correr bem, continuaremos utilizando os arrays de dados como séries temporais.
//--- Set the arrays for the Bollinger Bands to be time-series based (most recent data at index 0) ArraySetAsSeries(bb_upper, true); //--- Set upper band array as series ArraySetAsSeries(bb_lower, true); //--- Set lower band array as series return(INIT_SUCCEEDED); //--- Initialization successful
Aqui configuramos os arrays para as Bandas de Bollinger "bb_upper" e "bb_lower" para que sejam tratados como dados de séries temporais, chamando a função ArraySetAsSeries e definindo o segundo parâmetro como true. Isso garante que os dados mais recentes sejam armazenados no índice 0, o que facilita o acesso aos valores mais atualizados durante a análise das condições de mercado. Ao organizar os arrays dessa maneira, alinhamos nossa estrutura de dados com o uso típico em algoritmos de trading, nos quais as informações mais recentes costumam ser as mais relevantes. Por fim, retornamos INIT_SUCCEEDED, indicando que o processo de inicialização foi concluído com sucesso, permitindo que o EA continue sua execução.
Até este ponto, tudo na seção de inicialização funcionou corretamente. O código-fonte completo responsável pela inicialização do programa se apresenta da seguinte forma:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Create Bollinger Bands indicator handle with a period of 12, no shift, and a deviation of 2 handleBB = iBands(_Symbol, _Period, 12, 0, 2, PRICE_CLOSE); //--- Check if the Bollinger Bands handle was created successfully if (handleBB == INVALID_HANDLE){ Print("ERROR: UNABLE TO CREATE THE BB HANDLE. REVERTING"); //--- Print error if handle creation fails return (INIT_FAILED); //--- Return initialization failed } //--- Set the arrays for the Bollinger Bands to be time-series based (most recent data at index 0) ArraySetAsSeries(bb_upper, true); //--- Set upper band array as series ArraySetAsSeries(bb_lower, true); //--- Set lower band array as series return(INIT_SUCCEEDED); //--- Initialization successful }
A seguir, passamos ao manipulador de eventos OnDeinit, que é uma função chamada durante a desinicialização do programa.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ // OnDeinit is called when the EA is removed from the chart or terminated //... }
A função OnDeinit é executada quando o EA é removido do gráfico ou quando o terminal é desligado. Devemos utilizar esse manipulador de eventos para garantir o gerenciamento adequado dos recursos utilizados. Quando o EA termina sua execução, devemos liberar todos os handles dos indicadores que criamos na fase de inicialização. Se não fizéssemos isso, poderíamos deixar de liberar áreas de memória utilizadas, o que seria ineficiente. Evidentemente, não queremos correr o risco de deixar para trás recursos desnecessários. É por isso que a função OnDeinit é importante e por que as etapas de limpeza são fundamentais em qualquer ambiente de programação.
IndicatorRelease(handleBB); //--- Release the indicator handle
Aqui simplesmente chamamos a função "IndicatorRelease" com o argumento "handleBB" para liberar o handle do indicador Bandas de Bollinger que havíamos criado anteriormente. A limpeza é essencial para manter a performance da plataforma, especialmente se você estiver utilizando vários EAs ou operando com a plataforma por longos períodos. Assim, o código-fonte completo para a liberação de recursos se apresenta da seguinte forma:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Function to handle cleanup when the EA is removed from the chart IndicatorRelease(handleBB); //--- Release the indicator handle }
A seguir, precisamos verificar a existência de oportunidades de trading sempre que os preços forem atualizados. Isso é feito através do manipulador de eventos OnTick.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick(){ // OnTick is called whenever there is a new market tick (price update) //... }
A função do manipulador de eventos OnTick executa e processa as informações mais recentes de preços sempre que um novo tick aparece ou ocorre uma mudança nas condições de mercado. Essa é uma parte crucial do funcionamento do nosso EA, pois é aqui que implementamos nossa lógica de trading, cujas condições esperamos que estejam estruturadas para gerar operações lucrativas. Quando os dados de mercado mudam, avaliamos o estado atual do mercado e tomamos decisões sobre abrir ou fechar uma posição. Essa função é acionada com a mesma frequência que ocorrem alterações no mercado, garantindo que nossa estratégia opere em tempo real e reaja aos preços atuais e às mudanças nos valores de nossos indicadores de mercado.
Para acompanhar as condições atuais do mercado, precisamos obter os valores das cotações de preço mais recentes.
//--- Get current Ask and Bid prices double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits); //--- Normalize Ask price to correct digits double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits); //--- Normalize Bid price to correct digits
Aqui obtemos os preços mais atualizados de compra e venda do instrumento que está sendo negociado. Para obter esses preços, usamos a função SymbolInfoDouble. Para capturar o preço de venda (ask), especificamos SYMBOL_ASK, e para o preço de compra (bid), especificamos SYMBOL_BID. Após obter os preços, utilizamos a função NormalizeDouble para arredondar os valores ao número de casas decimais definido pelo parâmetro _Digits. Essa etapa é essencial, pois garante que nossas operações de trading sejam realizadas com preços que estejam tanto padronizados quanto precisos. Se não arredondássemos os valores, imprecisões de ponto flutuante poderiam levar a erros nos cálculos de preço das ordens. Em seguida, copiamos os valores do indicador para utilizá-los na análise e nas operações de trading.
//--- Retrieve the most recent Bollinger Bands values (3 data points) if (CopyBuffer(handleBB, UPPER_BAND, 0, 3, bb_upper) < 3){ Print("UNABLE TO GET UPPER BAND REQUESTED DATA. REVERTING NOW!"); //--- Error if data fetch fails return; } if (CopyBuffer(handleBB, LOWER_BAND, 0, 3, bb_lower) < 3){ Print("UNABLE TO GET LOWER BAND REQUESTED DATA. REVERTING NOW!"); //--- Error if data fetch fails return; }
Aqui usamos a função CopyBuffer para obter os valores mais recentes das Bandas de Bollinger, especificamente três pontos de dados tanto para a banda superior quanto para a inferior. A primeira chamada à CopyBuffer solicita os dados da banda superior, começando pelo índice 0, e os armazena no array "bb_upper". Se a função retornar um valor inferior a 3, isso indica que a extração dos dados falhou, e exibimos a seguinte mensagem de erro: "UNABLE TO GET UPPER BAND REQUESTED DATA. REVERTING NOW!" Em seguida, saímos da função para evitar a continuação da execução. O mesmo processo é aplicado à banda inferior, garantindo que também tratemos qualquer falha ao extrair dados dela. Observe que, ao acessar os índices dos buffers, utilizamos os identificadores das linhas do indicador, válidos para a cópia dos valores do indicador Bandas de Bollinger, em vez de números de buffer. Essa é a forma mais simples de executar o processo e evita confusão, embora a lógica permaneça a mesma. A seguir, está uma representação visual dos números dos buffers.
BUFFER VISUALIZATIONBUFFER VISUALIZATION
Como precisaremos fazer comparações entre os valores do indicador e os preços, devemos obter os preços das barras que são relevantes para nós — neste caso, os preços mínimo e máximo.
//--- Get the low and high prices of the current bar double low0 = iLow(_Symbol, _Period, 0); //--- Lowest price of the current bar double high0 = iHigh(_Symbol, _Period, 0); //--- Highest price of the current bar
Aqui obtemos os preços mínimo e máximo da barra atual, chamando as funções iLow e iHigh. A função iLow extrai o menor preço da barra atual (índice 0) para o símbolo especificado (_Symbol) e timeframe (_Period), salvando esse valor na variável "low0". De forma semelhante, a iHigh captura o preço mais alto da barra atual e o atribui à variável "high0". Ainda assim, precisamos garantir que apenas um sinal seja executado por barra. Veja abaixo a lógica usada.
//--- Get the timestamp of the current bar datetime currTimeBar0 = iTime(_Symbol, _Period, 0); //--- Time of the current bar static datetime signalTime = currTimeBar0; //--- Static variable to store the signal time
Aqui obtemos o timestamp da barra atual utilizando a função iTime, que retorna o horário da barra especificada (índice 0) para o símbolo (_Symbol) e timeframe (_Period) definidos. Esse timestamp é armazenado na variável "currTimeBar0". Além disso, declaramos uma variável estática chamada "signalTime" e a inicializamos com o valor de "currTimeBar0". Ao tornar "signalTime" estática, garantimos que seu valor seja preservado entre chamadas da função, permitindo que rastreemos quando foi gerado o último sinal de trading. Isso é essencial para nossa estratégia, pois ajuda a impedir a emissão de múltiplos sinais na mesma barra, garantindo que operemos com apenas um sinal por período. Tendo feito isso, podemos iniciar a verificação dos sinais. A primeira coisa a ser feita é checar a existência de um sinal de compra.
//--- Check for a buy signal when price crosses below the lower Bollinger Band if (low0 < bb_lower[0]){ Print("BUY SIGNAL @ ", TimeCurrent()); //--- Log the buy signal with the current time }
Aqui verificamos a possibilidade de um sinal de compra, avaliando se o menor preço da barra atual, armazenado na variável "low0", está abaixo do valor mais recente da Banda Inferior de Bollinger, armazenado no array "bb_lower" na posição de índice 0. Se "low0" for menor que "bb_lower[0]", isso indica que o preço atravessou a banda inferior, sugerindo uma possível condição de sobrevenda e uma provável oportunidade de compra. Quando essa condição for satisfeita, o programa registra uma mensagem usando a função Print, exibindo "BUY SIGNAL @" juntamente com o horário atual obtido através da função TimeCurrent. Esse alerta nos ajuda a acompanhar a ocorrência de sinais de compra, garantindo transparência e rastreabilidade no processo de tomada de decisão do EA. Durante a execução, obtemos o seguinte resultado.
Pelos dados exibidos, vemos que os sinais são gerados a cada tick sempre que as condições de compra são atendidas. Precisamos exibir o sinal apenas uma vez por barra sempre que as condições forem cumpridas. Para isso, usamos a seguinte lógica.
//--- Check for a buy signal when price crosses below the lower Bollinger Band if (low0 < bb_lower[0] && signalTime != currTimeBar0){ Print("BUY SIGNAL @ ", TimeCurrent()); //--- Log the buy signal with the current time signalTime = currTimeBar0; //--- Update signal time to avoid duplicate trades }
Aqui refinamos as condições do nosso sinal de compra, adicionando uma verificação extra para garantir que não sejam geradas operações repetidas dentro da mesma barra. Inicialmente, verificávamos se o menor preço da barra atual, armazenado na variável "low0", era inferior ao valor mais recente da Banda Inferior de Bollinger ("bb_lower[0]"). Agora introduzimos uma condição adicional: "signalTime != currTimeBar0", que garante que o timestamp da barra atual ("currTimeBar0") seja diferente do horário do último sinal registrado ("signalTime"). Em seguida, atualizamos o valor de "signalTime" para que corresponda a "currTimeBar0", confirmando que apenas um sinal de compra será considerado por barra, mesmo que o preço atravesse a banda inferior mais de uma vez. Após executar essa atualização, obtemos o seguinte resultado.
A operação foi bem-sucedida. Agora podemos ver que os sinais são exibidos apenas uma vez por barra. A seguir, podemos continuar a agir com base nos sinais gerados, abrindo posições de compra.
if (PositionsTotal() == 0 && !isPrevTradeBuy){ obj_Trade.Buy(0.01, _Symbol, Ask, Ask - 100 * _Point, Ask + 50 * _Point); //--- Open a buy position with predefined parameters isPrevTradeBuy = true; isPrevTradeSell = false; //--- Update trade flags }
Aqui adicionamos condições que garantem que uma operação de compra será executada apenas em determinadas circunstâncias. Primeiro, verificamos se o número total de posições abertas é igual a zero, utilizando a função PositionsTotal, o que assegura que nenhuma outra operação esteja ativa no momento. Em seguida, verificamos se a última operação realizada não foi uma compra, avaliando "!isPrevTradeBuy". Isso evita ordens de compra consecutivas e garante que o nosso EA não abrirá uma nova posição de compra se a última operação já tiver sido uma compra.
Se ambas as condições forem satisfeitas, seguimos para a abertura da posição de compra utilizando "obj_Trade.Buy". Especificamos o volume da ordem como "0,01" lote, com o símbolo de negociação atual (_Symbol) e o preço "Ask". Os níveis de stop-loss e take-profit são definidos 100 e 50 pontos abaixo e acima do preço solicitado, respectivamente, o que define nossas regras de gerenciamento de risco. Após a abertura bem-sucedida da operação de compra, atualizamos os flags de controle de operação: "isPrevTradeBuy" é definido como "true" e "isPrevTradeSell" como "false", indicando que a última operação foi de compra e impedindo uma nova compra até que ocorra um sinal de venda. Para a lógica de venda, aplicamos um processo semelhante conforme mostrado a seguir.
//--- Check for a sell signal when price crosses above the upper Bollinger Band else if (high0 > bb_upper[0] && signalTime != currTimeBar0){ Print("SELL SIGNAL @ ", TimeCurrent()); //--- Log the sell signal with the current time signalTime = currTimeBar0; //--- Update signal time to avoid duplicate trades if (PositionsTotal() == 0 && !isPrevTradeSell){ obj_Trade.Sell(0.01, _Symbol, Bid, Bid + 100 * _Point, Bid - 50 * _Point); //--- Open a sell position with predefined parameters isPrevTradeBuy = false; isPrevTradeSell = true; //--- Update trade flags } }
Após compilar e executar o programa, obtemos o seguinte resultado.
Vemos que a posição de compra foi executada com sucesso. Ao concluir a implementação, integramos a estratégia PIRANHA utilizando as Bandas de Bollinger e configuramos o programa para reagir a sinais de compra e venda com base em condições definidas. Na próxima seção, focaremos no teste do programa, a fim de avaliar seu desempenho e ajustar precisamente os parâmetros para alcançar resultados ideais.
Testes
Após finalizar a implementação, o próximo passo importante é testar cuidadosamente o EA para avaliar seu desempenho e otimizar os parâmetros. Um teste eficaz garante que a estratégia funcione corretamente sob diversas condições de mercado, minimizando o risco de problemas inesperados durante a negociação. Aqui utilizaremos o Testador de Estratégia do MetaTrader 5 para realizar o backtest e a otimização, buscando os melhores valores de entrada possíveis para nossa estratégia.
Começamos ajustando os parâmetros de entrada iniciais para os valores de stop-loss (SL) e take-profit (TP), que influenciam significativamente o gerenciamento de risco da estratégia. Na implementação inicial, SL e TP foram definidos com valores fixos em pips. No entanto, para dar à estratégia mais margem de manobra e captar melhor os movimentos do mercado, modificaremos os parâmetros de entrada para torná-los mais flexíveis e otimizáveis durante os testes. Atualizamos o código da seguinte forma:
//--- INPUTS input int sl_points = 500; input int tp_points = 250; //--- //--- Check for a buy signal when price crosses below the lower Bollinger Band if (low0 < bb_lower[0] && signalTime != currTimeBar0){ Print("BUY SIGNAL @ ", TimeCurrent()); //--- Log the buy signal with the current time signalTime = currTimeBar0; //--- Update signal time to avoid duplicate trades if (PositionsTotal() == 0 && !isPrevTradeBuy){ obj_Trade.Buy(0.01, _Symbol, Ask, Ask - sl_points * _Point, Ask + tp_points * _Point); //--- Open a buy position with predefined parameters isPrevTradeBuy = true; isPrevTradeSell = false; //--- Update trade flags } } //--- Check for a sell signal when price crosses above the upper Bollinger Band else if (high0 > bb_upper[0] && signalTime != currTimeBar0){ Print("SELL SIGNAL @ ", TimeCurrent()); //--- Log the sell signal with the current time signalTime = currTimeBar0; //--- Update signal time to avoid duplicate trades if (PositionsTotal() == 0 && !isPrevTradeSell){ obj_Trade.Sell(0.01, _Symbol, Bid, Bid + sl_points * _Point, Bid - tp_points * _Point); //--- Open a sell position with predefined parameters isPrevTradeBuy = false; isPrevTradeSell = true; //--- Update trade flags } }
Os dados de entrada permitem realizar uma otimização dinâmica para diferentes símbolos e instrumentos de negociação. Após executar, obtemos o seguinte resultado.
A operação foi bem-sucedida! Podemos concluir que o programa funcionou conforme o esperado. O trecho final do código-fonte, responsável por criar e implementar a estratégia Piranha, tem a seguinte aparência:
//+------------------------------------------------------------------+ //| PIRANHA.mq5 | //| Allan Munene Mutiiria, Forex Algo-Trader. | //| https://forexalgo-trader.com | //+------------------------------------------------------------------+ //--- Properties to define metadata about the Expert Advisor (EA) #property copyright "Allan Munene Mutiiria, Forex Algo-Trader." //--- Copyright information #property link "https://forexalgo-trader.com" //--- Link to the creator's website #property version "1.00" //--- Version number of the EA //--- Including the MQL5 trading library #include <Trade/Trade.mqh> //--- Import trading functionalities CTrade obj_Trade; //--- Creating an object of the CTrade class to handle trading operations input int sl_points = 500; input int tp_points = 250; //--- Defining variables for Bollinger Bands indicator and price arrays int handleBB = INVALID_HANDLE; //--- Store Bollinger Bands handle; initialized as invalid double bb_upper[], bb_lower[]; //--- Arrays to store upper and lower Bollinger Bands values //--- Flags to track if the last trade was a buy or sell bool isPrevTradeBuy = false, isPrevTradeSell = false; //--- Prevent consecutive trades in the same direction //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Create Bollinger Bands indicator handle with a period of 12, no shift, and a deviation of 2 handleBB = iBands(_Symbol, _Period, 12, 0, 2, PRICE_CLOSE); //--- Check if the Bollinger Bands handle was created successfully if (handleBB == INVALID_HANDLE){ Print("ERROR: UNABLE TO CREATE THE BB HANDLE. REVERTING"); //--- Print error if handle creation fails return (INIT_FAILED); //--- Return initialization failed } //--- Set the arrays for the Bollinger Bands to be time-series based (most recent data at index 0) ArraySetAsSeries(bb_upper, true); //--- Set upper band array as series ArraySetAsSeries(bb_lower, true); //--- Set lower band array as series return(INIT_SUCCEEDED); //--- Initialization successful } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Function to handle cleanup when the EA is removed from the chart IndicatorRelease(handleBB); //--- Release the indicator handle } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Retrieve the most recent Bollinger Bands values (3 data points) if (CopyBuffer(handleBB, UPPER_BAND, 0, 3, bb_upper) < 3){ Print("UNABLE TO GET UPPER BAND REQUESTED DATA. REVERTING NOW!"); //--- Error if data fetch fails return; } if (CopyBuffer(handleBB, LOWER_BAND, 0, 3, bb_lower) < 3){ Print("UNABLE TO GET LOWER BAND REQUESTED DATA. REVERTING NOW!"); //--- Error if data fetch fails return; } //--- Get current Ask and Bid prices double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits); //--- Normalize Ask price to correct digits double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits); //--- Normalize Bid price to correct digits //--- Get the low and high prices of the current bar double low0 = iLow(_Symbol, _Period, 0); //--- Lowest price of the current bar double high0 = iHigh(_Symbol, _Period, 0); //--- Highest price of the current bar //--- Get the timestamp of the current bar datetime currTimeBar0 = iTime(_Symbol, _Period, 0); //--- Time of the current bar static datetime signalTime = currTimeBar0; //--- Static variable to store the signal time //--- Check for a buy signal when price crosses below the lower Bollinger Band if (low0 < bb_lower[0] && signalTime != currTimeBar0){ Print("BUY SIGNAL @ ", TimeCurrent()); //--- Log the buy signal with the current time signalTime = currTimeBar0; //--- Update signal time to avoid duplicate trades if (PositionsTotal() == 0 && !isPrevTradeBuy){ obj_Trade.Buy(0.01, _Symbol, Ask, Ask - sl_points * _Point, Ask + tp_points * _Point); //--- Open a buy position with predefined parameters isPrevTradeBuy = true; isPrevTradeSell = false; //--- Update trade flags } } //--- Check for a sell signal when price crosses above the upper Bollinger Band else if (high0 > bb_upper[0] && signalTime != currTimeBar0){ Print("SELL SIGNAL @ ", TimeCurrent()); //--- Log the sell signal with the current time signalTime = currTimeBar0; //--- Update signal time to avoid duplicate trades if (PositionsTotal() == 0 && !isPrevTradeSell){ obj_Trade.Sell(0.01, _Symbol, Bid, Bid + sl_points * _Point, Bid - tp_points * _Point); //--- Open a sell position with predefined parameters isPrevTradeBuy = false; isPrevTradeSell = true; //--- Update trade flags } } } //+------------------------------------------------------------------+
Resultados dos testes em dados históricos:
Gráfico do backtest:
Nesta etapa de testes, otimizamos os parâmetros de entrada e verificamos a eficácia da estratégia usando o testador de estratégias. Os ajustes que fizemos nos valores de stop-loss e take-profit deram à estratégia PIRANHA maior flexibilidade. Agora ela é capaz de lidar com as oscilações do mercado. Confirmamos que a estratégia funciona conforme planejado e apresenta resultados positivos após ser submetida ao backtest e à otimização.
Considerações finais
Neste artigo, abordamos o desenvolvimento de um EA em MetaQuotes Language 5 (MQL5) com base na estratégia PIRANHA, utilizando as Bandas de Bollinger para identificar potenciais sinais de compra e venda. Começamos compreendendo os fundamentos da estratégia PIRANHA, seguido de uma análise detalhada das Bandas de Bollinger, destacando seu papel na identificação da volatilidade do mercado e no ajuste dos pontos de entrada e saída das operações.
Ao longo de toda a implementação, ilustramos o processo de codificação passo a passo, configuramos os handles dos indicadores e implementamos a lógica de negociação. Para garantir o melhor desempenho, ajustamos parâmetros críticos de entrada e testamos o programa utilizando o Testador de Estratégia do MetaTrader 5, confirmando a eficácia da estratégia em diferentes condições de mercado.
Aviso legal: As informações apresentadas neste artigo têm finalidade exclusivamente educacional. Elas servem como base para o entendimento da criação de um EA baseado na estratégia PIRANHA e devem ser utilizadas como ponto de partida para o desenvolvimento de sistemas mais avançados, com posterior otimização e testes adicionais. As estratégias e métodos descritos não garantem nenhum tipo de resultado financeiro. Você utiliza este conteúdo por sua conta e risco. Antes de aplicar qualquer solução de trading automatizado, realize testes rigorosos e leve em consideração as condições de mercado.
De modo geral, este artigo funciona como um guia para automatizar a estratégia PIRANHA e adaptá-la ao seu estilo de negociação. Esperamos que ele tenha fornecido informações valiosas e incentive a exploração contínua das possibilidades de criação de sistemas de trading sofisticados em MQL5. Boa programação e bons trades!
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/16034
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
Muito obrigado - artigo muito interessante e condições detalhadas. Vou usá-lo como base para escrever e testar meus robôs em caracteres personalizados.
Claro, muito bem-vindo.