English Русский 中文 Español Deutsch 日本語
preview
Introdução ao MQL5 (Parte 8): Guia do Iniciante para Construção de Expert Advisors (II)

Introdução ao MQL5 (Parte 8): Guia do Iniciante para Construção de Expert Advisors (II)

MetaTrader 5Negociação |
196 0
Israel Pelumi Abioye
Israel Pelumi Abioye

Introdução

Tendo já estudado os fundamentos do MQL5, você agora está preparado para enfrentar uma das tarefas mais importantes associadas ao trading algorítmico: criar um Expert Advisor funcional. Como mencionei no artigo anterior, utilizaremos uma abordagem baseada em projetos para esta série. Esse método ajuda tanto a compreender ideias abstratas quanto a reconhecer como elas são aplicadas em situações práticas. Ao final deste guia, você terá um sólido entendimento de como automatizar decisões de negociação baseadas em padrões de velas e condições predefinidas. 

Muitos iniciantes frequentemente postam perguntas no fórum, e embora membros incríveis da comunidade respondam com ótimos conselhos, alguns usuários autodidatas têm dificuldades em incorporar essas respostas em seus programas. Embora a resposta para uma pergunta específica seja fornecida, muitas vezes é impraticável explicar em detalhes todo o código. Mesmo que os trechos de código e dicas possam ser úteis, como iniciante autodidata, você ainda pode ter dificuldade em juntar todas as informações. Com uma abordagem baseada em projetos, este artigo busca responder a essas perguntas frequentes e garantir que as soluções possam ser aplicadas por qualquer EA.

Neste artigo, nos concentraremos em desenvolver um EA que utiliza a análise de velas do dia anterior para determinar sua direção de negociação. O EA se concentrará em vender no dia se a vela diária mais recente for de baixa e em comprar se for de alta. O EA também verificará seus sinais de negociação utilizando o preço de fechamento da primeira vela de 1 hora do dia. Não haverá mais de uma posição aberta a qualquer momento, e o máximo diário de duas negociações será respeitado. Ele funcionará sob limites rigorosos de operação. Além disso, sua operação será limitada aos horários designados de negociação, de segunda a quarta-feira.

Ao longo deste projeto, abordaremos várias perguntas comuns que os iniciantes frequentemente têm, especialmente aquelas frequentemente postadas nos fóruns de MQL5. Algumas dessas perguntas incluem:

  • Como comprar e vender no MQL5?
  • Como obter os preços de abertura e fechamento das velas?
  • Como evitar negociar a cada tick?
  • Como posso limitar um EA para entrar em apenas uma negociação por vez?
  • Como definir o período de negociação para um EA?
  • Como especificar os dias da semana em que um EA pode negociar?
  • Como definir limites de lucro e perda para operações?

Adotando essa abordagem baseada em projetos, meu objetivo é fornecer respostas claras e práticas a essas perguntas, permitindo que você implemente as soluções diretamente em seu Expert Advisor. Esse método prático não apenas ajuda a entender conceitos teóricos, mas também a visualizar sua aplicação em cenários do mundo real. Vamos mergulhar no mundo do MQL5 e começar a construir suas ferramentas de negociação!


1. Configurando o Projeto

1.1. Pseudocódigo

É crucial usar pseudocódigo para descrever a lógica do nosso Expert Advisor antes de começarmos a escrever o código. A importância do pseudocódigo foi abordada no artigo anterior, destacando como ele facilita o planejamento e a organização clara das suas ideias, acelerando o processo de codificação real. Para aprender MQL5, lembre-se de que a aprendizagem baseada em projetos é preferível a estudar tudo de uma vez. Você melhora à medida que trabalha em mais projetos. Este é o pseudocódigo básico do nosso EA: 

1. Inicialize o EA:

  • Define o número mágico para a identificação das negociações.
  • Defina os horários de início e fim para negociação.
  • Inicialize variáveis para armazenar preços.

2. Em cada Tick:

  • Certifique-se de que o horário está dentro do período de negociação, verificando a hora atual.
  • Obtenha os preços de abertura e fechamento do dia anterior.
  • Faça uma operação de venda se o fechamento do dia anterior for menor que a abertura (tendência de baixa).
  • Faça uma operação de compra se o fechamento do dia anterior for maior que a abertura (tendência de alta).
  • Garanta que apenas uma operação esteja aberta por vez.
  • Negocie apenas de segunda a quinta-feira.
  • Garanta um máximo de uma posição aberta.
  • Limite diário de duas operações por dia.
  • Limite diário de lucro.
  • Feche as operações no final do período de negociação.

1.2. Importando Bibliotecas Necessárias

As bibliotecas são conjuntos de classes e funções pré-escritas em MQL5 que tornam a codificação mais fácil. Elas permitem que você se concentre nas características exclusivas do seu Expert Advisor (EA), em vez de reescrever funcionalidades comuns. Em um dos nossos artigos anteriores, discutimos a ideia de incluir arquivos. Não se preocupe se você não entender completamente os Arquivos de Inclusão; você ainda pode acompanhar este artigo. Você não precisa saber tudo de uma vez para usar o MQL5; aprender por meio de projetos permite que você progrida gradualmente. Se você apenas seguir as instruções, poderá usar os trechos de código e explicações de forma eficaz em seus programas.

Analogia

Considere o trabalho que você faz como programador como uma vasta e encantada estante de livros. Essa estante contém inúmeros livros. Cada livro contém diretrizes e narrativas únicas que ajudam você a alcançar diversos objetivos. De forma semelhante, essas bibliotecas em MQL5 são como esses raros livros na sua estante encantada. As histórias (ou códigos) pré-escritas nesses livros podem ser usadas para construir seu robô de negociação. Você pode simplesmente pegar o livro apropriado e usar as histórias dentro dele para se guiar, poupando o trabalho de começar do zero a cada vez que for escrever. 

Portanto, você não precisa escrever cada detalhe por conta própria ao desenvolver seu Expert Advisor. Esses livros específicos contêm instruções que podem simplificar sua codificação. Isso permitirá que você se concentre nos aspectos especiais e interessantes do seu robô de negociação, em vez de se perder nos detalhes mundanos.

1.2.1. Incluir a Biblioteca de Negociação

Você deve incorporar a biblioteca de negociação ao seu EA para gerenciar operações de trading. Esta biblioteca oferece uma coleção de classes e funções para uma gestão eficiente das operações. O código a seguir é usado para incluir a biblioteca:

Analogia

Imagine possuir uma grande estante cheia de volumes. Cada livro funciona como uma espécie de caixa de ferramentas, oferecendo assistência em várias áreas. Para construir algo único, como um incrível robô de negociação, você retira o livro apropriado da estante. É como se um livro especial fosse retirado da prateleira para incluir a Biblioteca de Negociação. Você encontrará todas as ferramentas necessárias nesse livro para gerenciar operações de trading. Este livro já contém todas as instruções escritas, então você não precisa fazer isso por conta própria!

Você inclui esse livro especial em seu projeto com a seguinte linha de código:

#include <Trade/Trade.mqh> // Inclui a biblioteca de negociação para funções de trading

Seu robô de negociação aprenderá com essa linha a "pegar o livro chamado Trade.mqh da estante". Esse livro contém várias ferramentas úteis que simplificam o processo de abrir, modificar e fechar operações. Ele garante que tudo funcione sem problemas e poupa muito tempo.

Exemplo:

#include <Trade/Trade.mqh> // Include the trade library for trading functions

// Create an instance of the CTrade class for trading operations
CTrade trade;
//magic number
int MagicNumber = 103432;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// Set the magic number for the EA's trades
   trade.SetExpertMagicNumber(MagicNumber);

// Return initialization success
   return(INIT_SUCCEEDED);
  }

1.2.2.1. Criar uma Instância da Classe CTrade

A classe CTrade, parte da biblioteca Trade, encapsula métodos para executar operações de negociação. Criar uma instância dessa classe permite que você use suas funções para gerenciar suas operações de trading.

Analogia

Imagine novamente sua estante de livros. Você já escolheu o livro especial (Trade.mqh) que contém todas as instruções para negociação. Agora, pense na classe CTrade como um personagem especial nesse livro, como um super-herói que conhece tudo sobre trading. Para usar esse super-herói, você precisa trazê-lo para sua história. Você faz isso criando uma instância da classe CTrade. É como convidar o super-herói para ajudar você em seu projeto.

Aqui está como convidar o super-herói com uma simples linha de código:

CTrade trade;

Nesse código, CTrade é o super-herói, e trade é seu convite. Ao criar essa instância chamada trade, você está dizendo: "Super-herói CTrade, por favor, junte-se ao meu projeto e me ajude a gerenciar operações!" 

Agora, sempre que precisar abrir ou gerenciar uma operação, pode pedir ao seu super-herói trade para fazer isso por você. Isso torna seu trabalho muito mais fácil e garante que tudo seja feito corretamente.

1.2.2.2. Configurando o Magic Number

Um magic number é um identificador único atribuído a cada operação realizada pelo seu EA. Esse identificador ajuda a rastrear e gerenciar operações, garantindo que seu EA possa distinguir suas próprias operações das realizadas manualmente ou por outros EAs. Pense em cada livro da sua estante como uma operação. Às vezes, você pode ter vários livros (operações) que parecem semelhantes, mas cada um possui um adesivo especial com um número único. Esse adesivo ajuda você a encontrar e gerenciar rapidamente seus livros sem se confundir.

Esse adesivo único é conhecido pelo seu Expert Advisor (EA) como magic number. É uma maneira rastreável e gerenciável de identificar cada operação que seu EA realiza, garantindo que ele possa diferenciar suas operações das realizadas manualmente ou por outros EAs.

Exemplo:

int MagicNumber = 103432;
No contexto da classe CTrade, você define o magic number da seguinte forma:
trade.SetExpertMagicNumber(MagicNumber);

Essa linha garante que todas as operações realizadas pela instância trade terão o magic number especificado, facilitando a identificação e gestão.

Para usar códigos pré-escritos que simplificam tarefas complexas, você deve importar as bibliotecas necessárias no MQL5. As bibliotecas são semelhantes a conjuntos de ferramentas que economizam tempo e esforço. Usar essas bibliotecas permitirá que você se concentre nas características exclusivas do seu Expert Advisor (EA), em vez de ter que escrever todo o código do zero.


2. Recuperando e Analisando Dados de Velas

É essencial recuperar e analisar os preços de abertura e fechamento das velas. Essas informações nos ajudam a entender as tendências do mercado e a decidir se devemos comprar ou vender. Precisamos acessar os preços de abertura e fechamento das velas para obter uma visão clara dos movimentos do mercado. Usando funções como CopyOpen e CopyClose, podemos buscar esses dados de forma eficiente. Com isso, podemos identificar se uma vela é de alta ou de baixa, comparando os preços de abertura e fechamento.

2.1. Funções CopyClose e CopyOpen no MQL5

Para obter os preços de abertura e fechamento das velas para um determinado símbolo e período de tempo, utilize as funções CopyClose e CopyOpen do MQL5. Essas funções oferecem várias formas de copiar dados, dependendo de suas necessidades.

2.1.1. Chamada pela Posição Inicial e Número de Elementos Requeridos

Analogia

Considere a estante como sua fonte de dados de preços, onde cada livro representa uma vela com preços de abertura e fechamento. Você contaria os livros da esquerda e escolheria o ponto de início quando quisesse começar a copiar livros de um local específico na estante. Você pode começar, por exemplo, pelo terceiro livro, se esse for o ponto onde deseja começar.

Em seguida, você seleciona a quantidade de livros que deseja copiar a partir dessa posição inicial. Por exemplo, você terá um total de cinco livros em mãos se decidir pegar cinco livros começando pelo terceiro livro. De forma semelhante a escolher um livro inicial na estante e determinar quantos livros pegar a partir desse ponto, esse método utiliza a função CopyClose para permitir que você especifique uma posição inicial nos dados de preços e o número de elementos (velas) que deseja copiar.

Síntaxe:

CopyClose(symbol_name, timeframe,  start_pos, count, close_array);
CopyOpen(symbol_name, timeframe,  start_pos, count, open_array);

Exemplo:

double close_prices[];
double open_prices[]; 
CopyClose(_Symbol, PERIOD_D1, 2, 5, close_prices); // Copy the close prices of 5 daily candlesticks starting from the 3rd candlestick
CopyOpen(_Symbol, PERIOD_D1, 2, 5, open_prices); // Copy the open prices of 5 daily candlesticks starting from the 3rd candlestick

Os dados de preços para um símbolo e período de tempo específicos são simbolizados pela estante de livros nesta analogia. A decisão de pegar cinco livros a partir de uma posição inicial (count) é equivalente a selecionar o terceiro livro na estante. A posição inicial (start_pos) é semelhante a essa decisão. Assim como segurar os livros escolhidos nas mãos, você armazena os dados copiados no array de destino (close_array).


2.1.2. Chamada pela Data Inicial e Número de Elementos Requeridos

Analogia

Considere a estante como seus dados de preços, onde um único livro corresponde a um dia de leituras de velas. Para começar a copiar preços de fechamento a partir de uma determinada data, localize o livro na estante que corresponde a essa data. A data "1º de junho", por exemplo, é onde você deve começar se quiser iniciar nesse ponto.

Em seguida, você seleciona a quantidade de livros que deseja pegar se quiser duplicar um número específico de preços de fechamento a partir dessa data. Se você pegar, por exemplo, os preços de fechamento de cinco livros a partir de "1º de junho", obterá os preços de fechamento desses cinco livros. Esse método, semelhante a escolher um livro inicial na estante e determinar quantos livros pegar a partir desse ponto, utiliza a função CopyClose para permitir que você especifique uma data inicial nos dados de preços e o número de elementos (velas) que deseja copiar.

Da mesma forma, você utilizaria a função CopyOpen para obter os preços de abertura. Você seleciona o livro que corresponde a uma determinada data e escolhe a quantidade de livros que deseja pegar para obter os preços de abertura.

 Síntaxe:

CopyClose(symbol_name, timeframe,  timeframe, count, close_array[]);
CopyOpen(symbol_name, timeframe,  timeframe, count, open_array[]);

Exemplo:

close_prices[];
double open_prices[];
datetime start_date = D'2023.06.01 00:00';  // Starting from June 1st, 2023
// Copy the close prices of 5 daily candlesticks starting from June 1st, 2023
CopyClose(_Symbol, PERIOD_D1, start_date, 5, close_prices);
// Copy the open prices of 5 daily candlesticks starting from June 1st, 2023 CopyOpen(_Symbol, PERIOD_D1, start_date, 5, open_prices);

Os dados de preços para um símbolo e período de tempo específicos são simbolizados pela estante de livros nesta analogia. Selecionar o livro na estante que corresponde a "1º de junho" é semelhante à data de início (start_time), e escolher cinco livros a partir dessa data de início é análogo ao número de elementos (count). Assim como segurar os livros selecionados nas mãos, você armazena os dados copiados nos arrays de destino (close_array e open_array).

Seguindo essa analogia, você verá como as funções CopyClose e CopyOpen facilitam a recuperação organizada e intuitiva de dados específicos da sua "estante de preços", com base em uma data de início.

2.1.3. Chamada pelas Datas de Início e Fim de um Intervalo de Tempo

Analogia

Considere que cada livro em sua estante é uma vela que mostra os preços de abertura e fechamento para um período de tempo específico. Se você quiser recuperar preços de fechamento para um determinado período, deverá procurar livros que cubram todo esse intervalo de tempo.

Por exemplo, digamos que você deseja duplicar os preços de fechamento de 1º a 5 de junho. Você localizaria o livro que corresponde ao seu ponto de partida em 1º de junho e o livro que corresponde ao ponto final em 5 de junho. Os preços de fechamento para esse período podem ser obtidos escolhendo todos os livros publicados entre essas duas datas.

De forma semelhante a escolher um livro de início e um livro de fim para cobrir um intervalo na estante, esse método permite que você especifique tanto a data de início quanto a data de término. Da mesma forma, você pode utilizar a função CopyOpen para obter os preços de abertura.

Síntaxe:
CopyClose( symbol_name, timeframe, start_time, stop_time, close_array[]);
CopyOpen(symbol_name, timeframe, start_time, stop_time, open_array[]);
Exemplo:
double close_prices[];
double open_prices[];
datetime start_date = D'2023.06.01 00:00'; // Starting from June 1st, 2023
datetime end_date = D'2023.06.05 00:00'; // Ending on June 5th, 2023
// Copy the close prices from June 1st to June 5th
CopyClose(_Symbol, PERIOD_D1, start_date, end_date, close_prices);
// Copy the open prices from June 1st to June 5th
CopyOpen(_Symbol, PERIOD_D1, start_date, end_date, open_prices);

Os dados de preços para um símbolo e período de tempo específicos são simbolizados pela estante de livros nesta analogia. A data de início (start_time) é semelhante a escolher o livro correspondente a "1º de junho" na estante, e a data de término (stop_time) é como encontrar o livro correspondente a "5 de junho". Assim como segurar os livros selecionados nas mãos, você armazena os dados copiados nos arrays de destino (close_array e open_array).

Ao compreender essa analogia, você verá como as funções CopyClose e CopyOpen ajudam a recuperar dados específicos da sua "estante de preços" com base em uma data de início e fim, tornando o processo de recuperação de dados intuitivo e organizado.

Convertendo String para Time

Pode ser complicado usar o método de chamada por datas de início e fim de um intervalo de tempo ao trabalhar com Expert Advisors que operam em uma janela de tempo específica durante o dia. O principal problema é que as datas mudam, mas o horário não. Automatizamos nossos Expert Advisors, por isso não é viável inserir manualmente a data todos os dias.

Analogia

Considere uma biblioteca onde as estantes são organizadas de acordo com a data e o horário do dia. Você precisa estar ciente do dia e do horário se quiser ler livros (ou recuperar dados) em um momento específico do dia. Pode ser trabalhoso atualizar a data diariamente para recuperar os livros apropriados das estantes. Considere as strings de horário como etiquetas que você coloca nos horários específicos em que está interessado, a fim de simplificar esse processo (recuperar dados).

Exemplo:

// Declaring time strings
string start_time_str = "00:00";  // Start time
string end_time_str = "20:00";    // End time

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {

// Converting time strings to datetime values
   datetime start_time = StringToTime(start_time_str);
   datetime end_time = StringToTime(end_time_str);

   Print("start_time: ", start_time,"\nend_time: ",end_time);

  }

Explicação:

// Declaring time strings string start_time_str = "00:00"; // Start time string end_time_str = "20:00"; // End time

  • Considere as strings de horário como etiquetas que você coloca nos horários específicos em que está interessado, a fim de simplificar esse processo (recuperar dados).

// Converting time strings to datetime values datetime start_time = StringToTime(start_time_str); datetime end_time = StringToTime(end_time_str);

  • Ao usar a função StringToTime, é como se você tivesse um marcador mágico que, em qualquer dia, sabe exatamente qual prateleira apontar. Isso ocorre independentemente da data. Dessa forma, você não precisará se preocupar em alterar a data manualmente todos os dias. Garantindo que start_time e end_time se refiram consistentemente ao horário atual na prateleira, torna-se simples recuperar os dados corretos sem a necessidade de atualizações manuais.

Saída:

Figura 1. Resultado do Código


Implementação do EA

Exemplo:

#include <Trade/Trade.mqh>

// Create an instance of the CTrade class for trading operations
CTrade trade;

// Unique identifier for the EA's trades
int MagicNumber = 103432;

// Arrays to store the previous day's open and close prices
double daily_close[];
double daily_open[];

// Arrays to store the first H1 bar's open and close prices of the day
double first_h1_price_close[];

// Arrays to store H1 bars' open and close prices
double H1_price_close[];
double H1_price_open[];

// Strings to define the trading start and end times and the first trade time
string start = "00:00";
string end = "20:00";
string firsttrade  = "02:00";

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   trade.SetExpertMagicNumber(MagicNumber);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Convert time strings to datetime format
   datetime start_time = StringToTime(start); // Convert start time string to datetime
   datetime end_time = StringToTime(end); // Convert end time string to datetime
   datetime current_time = TimeCurrent(); // Get the current time
   datetime first_tradetime = StringToTime(firsttrade); // Convert first trade time string to datetime

// Copy daily close and open prices
   CopyClose(_Symbol, PERIOD_D1, 1, 1, daily_close); // Copy the close price of the previous day
   CopyOpen(_Symbol, PERIOD_D1, 1, 1, daily_open); // Copy the open price of the previous day


// Set the arrays to be copied from right to left (latest to oldest)
   ArraySetAsSeries(daily_close, true); // Set daily_close array as series
   ArraySetAsSeries(daily_open, true); // Set daily_open array as series

// Copy close and open prices for the first H1 bar of the day
   CopyClose(_Symbol, PERIOD_H1, start_time, 1, first_h1_price_close); // Copy the close price of the first H1 bar

// Copy close prices for the latest 5 H1 bars
   CopyClose(_Symbol, PERIOD_H1, 0, 5, H1_price_close); // Copy the close prices of the latest 5 H1 bars
   CopyOpen(_Symbol, PERIOD_H1, 0, 5, H1_price_open); // Copy the open prices of the latest 5 H1 bars

// Set the arrays to be copied from right to left (latest to oldest)
   ArraySetAsSeries(H1_price_close, true); // Set H1_price_close array as series
   ArraySetAsSeries(H1_price_open, true); // Set H1_price_open array as series

// If the last daily bar is bearish
   if(daily_close[0] < daily_open[0])
     {
      // Check specific conditions for a sell trade
      if(H1_price_close[2] >= first_h1_price_close[0] && H1_price_close[1] < first_h1_price_close[0] && current_time >= first_tradetime)
        {

         Comment("Its a sell");

        }

     }

// If the last daily bar is bullish
   if(daily_close[0] > daily_open[0])
     {
      // Check specific conditions for a buy trade
      if(H1_price_close[2] <= first_h1_price_close[0] && H1_price_close[1] > first_h1_price_close[0] && current_time >= first_tradetime)
        {
         Comment("Its a buy");
        }
     }

  }

Explicação:

Primeiramente, importamos a biblioteca necessária com #include <Trade/Trade.mqh>, permitindo o uso de funções relacionadas a operações de trading. Em seguida, criamos uma instância da classe CTrade, usando CTrade trade;, que facilitará nossas operações de trading. Também definimos um identificador único para as operações do nosso EA com int MagicNumber = 103432;.

Em seguida, declaramos matrizes para armazenar os preços de abertura e fechamento do dia anterior, os preços de abertura e fechamento da primeira barra H1 do dia e os preços de abertura e fechamento das barras H1. Essas matrizes manterão os dados de preço recuperados, que analisaremos para tomar decisões de negociação. Os horários de início e término da negociação e o horário da primeira negociação são definidos como strings, que posteriormente converteremos para o formato datetime. Na função OnInit, definimos o número mágico do especialista para identificar nossas negociações. Na função OnTick, convertemos as strings de tempo para o formato datetime e recuperamos a hora atual. Em seguida, usamos as funções CopyClose e CopyOpen para copiar os dados diários e de velas H1 para as respectivas matrizes. A função ArraySetAsSeries define as matrizes a serem copiadas da direita para a esquerda, garantindo que os dados mais recentes estejam no índice 0.

Por fim, analisamos os dados de velas recuperados para determinar o sentimento do mercado. Se a última vela diária for de baixa, verificamos condições específicas para decidir sobre uma operação de venda. De forma semelhante, se a última vela diária for de alta, verificamos condições para uma operação de compra. A função Comment exibe a decisão de negociação no gráfico.Este exemplo de código configura a estrutura para recuperar e analisar os preços de abertura e fechamento de velas diárias e de 1 hora, utilizando essa análise para determinar a direção da operação.


3. Implementando a Execução de Operações

3.1 Como comprar e vender no MQL5?

Esta seção abordará as etapas básicas para executar ordens de compra e venda no MQL5, incluindo a definição dos níveis de stop-loss e take-profit. Utilizaremos a classe CTrade da biblioteca Trade.mqh, que oferece métodos básicos para realizar operações de trading.

Realizando Ordens de Compra e Venda:

Usamos os métodos Buy e Sell da classe CTrade para realizar ordens de compra e venda. Esses métodos permitem executar operações com poucas linhas de código. Considere a classe CTrade como uma prateleira de funções de trading especializadas em uma biblioteca. Quando queremos executar uma operação, basta pegar o livro (método) necessário na prateleira e aplicá-lo.

Definindo Stop-Loss e Take-Profit:

Os níveis de TP (Take-Profit) e SL (Stop-Loss) são cruciais para a gestão de riscos. Enquanto o TP especifica o lucro desejado, o SL define a perda máxima que você está disposto a aceitar. Ambos os pontos de preço são especificados em relação ao preço atual do mercado. Considere SL e TP como marcadores em um livro que indicam onde você parará (SL) caso algo dê errado e onde você obterá sua recompensa (TP) caso tudo corra bem.

Exemplo:
#include <Trade/Trade.mqh> // Include the trade library for trading functions

// Create an instance of the CTrade class for trading operations
CTrade trade;

// Unique identifier for the EA's trades
int MagicNumber = 103432;

// Arrays to store the previous day's open and close prices
double daily_close[];
double daily_open[];

// Arrays to store the first H1 bar's open and close prices of the day
double first_h1_price_close[];

// Arrays to store H1 bars' open and close prices
double H1_price_close[];
double H1_price_open[];

// Strings to define the trading start and end times and the first trade time
string start = "00:00";
string end = "20:00";
string firsttrade  = "02:00";

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   trade.SetExpertMagicNumber(MagicNumber);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Convert time strings to datetime format
   datetime start_time = StringToTime(start); // Convert start time string to datetime
   datetime end_time = StringToTime(end); // Convert end time string to datetime
   datetime current_time = TimeCurrent(); // Get the current time
   datetime first_tradetime = StringToTime(firsttrade); // Convert first trade time string to datetime

// Copy daily close and open prices
   CopyClose(_Symbol, PERIOD_D1, 1, 1, daily_close); // Copy the close price of the previous day
   CopyOpen(_Symbol, PERIOD_D1, 1, 1, daily_open); // Copy the open price of the previous day

// Set the arrays to be copied from right to left (latest to oldest)
   ArraySetAsSeries(daily_close, true); // Set daily_close array as series
   ArraySetAsSeries(daily_open, true); // Set daily_open array as series

// Copy close and open prices for the first H1 bar of the day
   CopyClose(_Symbol, PERIOD_H1, start_time, 1, first_h1_price_close); // Copy the close price of the first H1 bar

// Copy close prices for the latest 5 H1 bars
   CopyClose(_Symbol, PERIOD_H1, 0, 5, H1_price_close); // Copy the close prices of the latest 5 H1 bars
   CopyOpen(_Symbol, PERIOD_H1, 0, 5, H1_price_open); // Copy the open prices of the latest 5 H1 bars

// Set the arrays to be copied from right to left (latest to oldest)
   ArraySetAsSeries(H1_price_close, true); // Set H1_price_close array as series
   ArraySetAsSeries(H1_price_open, true); // Set H1_price_open array as series

// Get the symbol point size
   double symbol_point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);

// Get the current Bid price
   double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

// Calculate the stop loss and take profit prices for sell
   double tp_sell = Bid - 400 * symbol_point;
   double sl_sell = Bid + 100 * symbol_point;

// Get the current Ask price
   double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

// Calculate the stop loss and take profit prices for buy
   double tp_buy = Ask + 400 * symbol_point;
   double sl_buy = Ask - 100 * symbol_point;

// If the last daily bar is bearish
   if(daily_close[0] < daily_open[0])
     {
      // Check specific conditions for a sell trade
      if(H1_price_close[2] >= first_h1_price_close[0] && H1_price_close[1] < first_h1_price_close[0] && current_time >= first_tradetime)
        {
         // Execute the sell trade
         trade.Sell(1.0, _Symbol, Bid, sl_sell, tp_sell); // Replace with your lot size
         Comment("It's a sell");
        }
     }

// If the last daily bar is bullish
   if(daily_close[0] > daily_open[0])
     {
      // Check specific conditions for a buy trade
      if(H1_price_close[2] <= first_h1_price_close[0] && H1_price_close[1] > first_h1_price_close[0] && current_time >= first_tradetime)
        {
         // Execute the buy trade
         trade.Buy(1.0, _Symbol, Ask, sl_buy, tp_buy); // Replace with your lot size
         Comment("It's a buy");
        }
     }
  }

Explicação:

  • Usando #include, incluímos a biblioteca de trade.
  • Construímos uma instância de trade da classe CTrade.
  • Com base nos preços Bid e Ask atuais, bem como no tamanho do ponto do símbolo, determinamos os níveis de SL (Stop Loss) e TP (Take Profit).
  • Usamos os métodos Buy e Sell para colocar ordens com os níveis de SL e TP especificados.

Parâmetros de trade.Buy e trade.Sell:

  • lotsize: O volume da transação.
  • _Symbol: O símbolo no qual a transação é executada (ex.: EURUSD).
  • Ask/Bid: O preço atual de Ask para operações de compra ou Bid para operações de venda.
  • sl: O nível de preço de stop-loss.
  • tp: O nível de preço de take-profit.

Neste artigo, discutimos como obter dados de candlestick, como preços de abertura e fechamento, e como realizar ordens de compra e venda. Essa progressão é essencial para você, como iniciante, pois explica os fundamentos de como incorporar trades em seu programa. As ordens, no entanto, podem continuar sendo enviadas a cada tick devido ao manipulador de eventos OnTick.

É crucial limitar o Expert Advisor (EA) a uma operação por vez para controlar o risco e evitar o excesso de negociações. Para isso, é necessário implementar uma lógica que verifique se existem posições abertas antes de realizar uma nova operação. Essa estratégia ajuda a evitar o excesso de operações, garantindo que trades sejam executados apenas quando necessário.


Prevenindo Operações a Cada Tick:

O manuseio de eventos pelo OnTick pode gerar novas posições a cada tick. Garantimos que operações sejam realizadas apenas quando necessário, implementando uma verificação de novos candles e posições abertas. Considere cada novo candle como um livro adicionado à nossa coleção. Certificamo-nos de que nenhum outro livro (operação) esteja sendo lido no momento e decidimos "ler" (negociar) apenas quando um novo livro (candle) é adicionado.

Exemplo:

// Flag to indicate a new bar has formed
bool newBar;

// Variable to store the time of the last bar
datetime lastBarTime;

// Array to store bar data (OHLC)
MqlRates bar[];

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {

// Check for a new bar
   CopyRates(_Symbol, PERIOD_H1, 0, 3, bar); // Copy the latest 3 H1 bars
   if(bar[0].time > lastBarTime)  // Check if the latest bar time is greater than the last recorded bar time
     {
      newBar = true; // Set the newBar flag to true
      lastBarTime = bar[0].time; // Update the last bar time
     }
   else
     {
      newBar = false; // Set the newBar flag to false
     }

// If a new bar has formed
   if(newBar == true)
     {
      // If the last daily bar is bearish
      if(daily_close[0] < daily_open[0])
        {
         // Check specific conditions for a sell trade
         if(H1_price_close[2] >= first_h1_price_close[0] && H1_price_close[1] < first_h1_price_close[0] && current_time >= first_tradetime)
           {
            // Execute the sell trade
            trade.Sell(1.0, _Symbol, Bid, sl_sell, tp_sell); // Replace with your lot size
            Comment("It's a sell");
           }
        }

      // If the last daily bar is bullish
      if(daily_close[0] > daily_open[0])
        {
         // Check specific conditions for a buy trade
         if(H1_price_close[2] <= first_h1_price_close[0] && H1_price_close[1] > first_h1_price_close[0] && current_time >= first_tradetime)
           {
            // Execute the buy trade
            trade.Buy(1.0, _Symbol, Ask, sl_buy, tp_buy); // Replace with your lot size
            Comment("It's a buy");
           }
        }

     }

  }

Explicação:

bool newBar;

  • Esta linha declara uma variável booleana chamada newBar, que indica se um novo candle foi formado.

datetime lastBarTime;

  • Declara uma variável lastBarTime do tipo datetime, que armazenará o horário do último candle processado.

MqlRates bar[];

  • Declara um array bar do tipo MqlRates. E será usado para armazenar dados de candles, como preços de abertura, máxima, mínima e fechamento (OHLC).

CopyRates(_Symbol, PERIOD_H1, 0, 3, bar); // Copia os últimos 3 candles de 1 hora (H1)

  • Essa linha copia os três candles horários mais recentes do símbolo atual (_Symbol) para o array bar, usando a função CopyRates.

if(bar[0].time > lastBarTime)

  • Determina se o horário do candle mais recente (bar[0].time) excede o horário do último candle registrado. Se for verdadeiro, um novo candle foi formado.

newBar = true;

  • A variável newBar é definida como verdadeira se um novo candle foi formado.

lastBarTime = bar[0].time;

  • O horário do candle mais recente é atualizado na variável lastBarTime.

else {

newBar = false;

        }

  • Se o horário do candle mais recente não for maior que lastBarTime, a variável newBar é definida como falsa.

if(newBar == true)

{

 // execute esta ação

}

  • Se um novo candle foi formado, execute esta ação.

Este código garante que o bloco dentro da instrução if seja executado apenas quando um novo candle for formado, e não a cada tick. Ele faz isso ao verificar se o horário do candle mais recente é maior que o último horário registrado. Com base nisso, determinamos quando um novo candle é formado e definimos a variável newBar de forma adequada. Isso evita que o bloco if(newBar == true) seja executado repetidamente a cada tick, melhorando o desempenho do EA e eliminando ações desnecessárias.

3.2 Limitando o EA a Uma Posição Aberta por Vez

Agora que a execução das operações só é iniciada com a formação de um novo candle, podemos melhorar ainda mais o EA, limitando o número de posições abertas. Dessa forma, o EA só iniciará uma nova operação se não houver outras em aberto.

A lógica é a seguinte:

  • Verificar Posições Abertas: Verificamos se existem posições abertas antes de iniciar uma nova operação. O EA colocará uma ordem se não houver posições abertas.
  • Interromper Operações a Cada Tick: Garantimos que as operações sejam realizadas apenas quando absolutamente necessário, adicionando uma verificação de novos candles e posições abertas.

Considere cada novo candle como um livro adicionado à nossa biblioteca. Decidimos "ler" (operar) apenas quando um novo livro (candle) é adicionado, após garantir que nenhum outro livro (operação) esteja sendo lido.

Exemplo:

// Initialize the total number of positions being held
int totalPositions = 0;
for(int i = 0; i < PositionsTotal(); i++)
  {
// Get the ticket number for the position
   ulong ticket = PositionGetTicket(i);

// Check if the position's magic number matches
   if(PositionGetInteger(POSITION_MAGIC) == MagicNumber)
     {
      // Increment the total positions count
      totalPositions++;
     }
  }

Explicação:

int totalPositions = 0;

  • Nesta linha, a variável inteira totalPositions é declarada e inicializada com o valor zero. O número de posições abertas que o Expert Advisor (EA) atualmente possui será contado usando essa variável.

for(int i = 0; i < PositionsTotal(); i++)

  • Cada posição aberta é percorrida neste laço for. A função PositionsTotal() retorna o número total de posições abertas no terminal de negociação.
  • i: Um contador iterativo que começa em 0 e é incrementado em 1 a cada iteração. O laço continuará enquanto i for menor que o valor retornado por PositionsTotal().

  ulong ticket = PositionGetTicket(i);

  • Nesta linha, o número do ticket da posição no índice i é recuperado. A função PositionGetTicket(i) retorna o número do ticket da posição no índice fornecido.
  • ticket: Uma variável do tipo ulong (unsigned long) que armazena o número do ticket da posição atualmente sendo analisada.

if(PositionGetInteger(POSITION_MAGIC) == MagicNumber)

  • Este if verifica se o número mágico atribuído ao EA (MagicNumber) corresponde ao número mágico da posição atual.
  • PositionGetInteger(POSITION_MAGIC): Uma função que recupera o valor inteiro da propriedade especificada (neste caso, o número mágico) da posição atual.
  • Magic Number: Uma constante predeterminada que serve como identificador único de negociação deste EA. Ele garante que apenas as posições abertas pelo EA sejam contadas.

totalPositions++;

  • Esta linha incrementa o contador totalPositions em 1 se o número mágico da posição atual corresponder ao MagicNumber. Em essência, isso conta o número de posições abertas por este EA específico.

  Este bloco de código é usado para contar o número de posições atualmente mantidas pelo EA. Ele faz isso por meio de:

  • Inicialização do contador totalPositions com zero.
  • Percorrendo todas as posições abertas usando um laço for.
  • Recuperando o número do ticket de cada posição.
  • Verificando se o número mágico da posição corresponde ao do EA.
  • Incrementando o contador totalPositions se houver correspondência.

3.3 Limitando o EA a um Máximo de Duas Operações por Dia

Garantiremos que o EA abra no máximo duas operações por dia para evitar o excesso de operações, agora que ele executa negociações com base em condições específicas a cada novo candle.

Detalhes da Implementação

Esta seção do código filtra o histórico de negociações do dia atual usando a função HistorySelect. Em seguida, utilizaremos o número mágico único do EA para percorrer o histórico de negociações filtrado e contar o número de operações realizadas pelo algoritmo. Contamos apenas as operações de entrada, verificando a natureza de cada transação. O EA não abrirá novas operações pelo restante do dia se houver um total de duas operações de entrada.

Considere isso semelhante a gerenciar uma estante, onde cada livro representa uma operação. Há espaço apenas para dois novos livros por dia. Não adicionamos mais livros até o próximo dia após inserir esses dois. Isso garante que você mantenha uma coleção organizada e gerenciável, evitando excesso de operações (overtrading) e mantendo a ordem (gestão de risco).

Exemplo:

// Select the trading history within the specified time range
bool success = HistorySelect(start_time, end_time); // Select the trading history

// Initialize the total number of trades for the day
int totalDeal = 0;
if(success)
  {
   for(int i = 0; i < HistoryDealsTotal(); i++)
     {
      // Get the ticket number for the deal
      ulong ticket = HistoryDealGetTicket(i);

      // Check if the deal's magic number matches
      if(HistoryDealGetInteger(ticket, DEAL_MAGIC) == MagicNumber)
        {
         // Check if the deal was an entry
         if(HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_IN)
           {
            // Increment the total deal count
            totalDeal++;
           }
        }
     }
  }

Explicação:

  • HistorySelect: Filtra o histórico de negociações do dia.
  • totalDeal: Contador para monitorar o volume de operações.
  • Percorrer o histórico: Para contar as operações, iteramos pelo histórico de negociações.
  • Verificar o número mágico: Garantimos que o EA seja o proprietário da operação.
  • As operações de entrada são contadas ao incrementar o contador.

Este código garante que o EA opere no máximo duas vezes por dia, mantendo uma abordagem disciplinada e reduzindo o risco de excesso de operações.

3.4 Limitando o Lucro ou Prejuízo Diário

Nesta seção, garantiremos que o Expert Advisor não ultrapasse o lucro ou prejuízo total diário.

// Initialize the total profit
double totalProfit = 0;
long dealsMagic = 0;
double profit = 0;
if(success)
  {
   for(int i = 0; i < HistoryDealsTotal(); i++)
     {
      // Get the ticket number for the deal
      ulong ticket = HistoryDealGetTicket(i);

      // Check if the deal was an entry
      if(HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_IN)
        {
         // Get the magic number of the deal
         dealsMagic = HistoryDealGetInteger(ticket, DEAL_MAGIC);
        }

      // Check if the deal was an exit
      if(HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_OUT)
        {
         // Get the profit of the deal
         profit = HistoryDealGetDouble(ticket, DEAL_PROFIT);

         // Check if the magic number matches
         if(MagicNumber == dealsMagic)
           {
            // Add the profit to the total profit
            totalProfit += profit;
           }
        }
     }
  }

Explicação:

  • HistorySelect: Filtra o histórico de negociações do dia.
  • totalProfit: Contador para monitorar o lucro ou prejuízo total do dia.
  • Itera pelo histórico de negociações em um laço para somar os ganhos e perdas.
  • Verificar operação de entrada: Verifica o número mágico de cada transação.
  • Verifica a operação de saída calculando o lucro em cada operação fechada.
  • Adicionar ao lucro total: Acumula o lucro ou prejuízo de operações que possuem o número mágico correspondente.

Ao interromper novas operações após atingir um limite predefinido de lucro ou prejuízo diário, esta estratégia reduz o risco. Ela garante operações controladas e evita o excesso de operações, que aumenta o risco.

3.5 Fechando Todas as Posições Abertas em um Horário Específicos

Nesta seção, abordaremos como implementar tal recurso utilizando o framework MQL5. Isso reduz o risco de flutuações inesperadas do mercado, já que não ficam operações abertas durante a noite ou em horários de baixa liquidez.Considere isso como o fechamento do expediente de uma biblioteca. Certificamo-nos de que todas as posições sejam fechadas no horário final designado, assim como um bibliotecário se certifica de que todos os livros (operações) sejam devolvidos e contabilizados ao final do dia.

// Close trades at the specified end time
for(int i = 0; i < PositionsTotal(); i++)
  {
// Get the ticket number for the position
   ulong ticket = PositionGetTicket(i);

// Check if the position's magic number matches and if it's the end time
   if(PositionGetInteger(POSITION_MAGIC) == MagicNumber && current_time == end_time)
     {
      // Close the position
      trade.PositionClose(ticket);
     }
  }

Explicação:

Esta parte percorre todas as posições abertas, recuperando o número de ticket de cada uma. Em seguida, verifica se o número mágico da posição corresponde ao número mágico do EA e se o horário atual está dentro do horário de fechamento designado. A função PositionClose da classe CTrade é usada para fechar a posição caso esses requisitos sejam atendidos.

3.6 Especificando os Dias da Semana em que o EA Pode Operar

Para garantir que o Expert Advisor (EA) opere apenas em dias específicos da semana, é necessário obter o dia atual e compará-lo com nossas regras de negociação.

Exemplo:
//getting the day of week and month
MqlDateTime day; //Declare an MqlDateTime structure to hold the current time and date
TimeCurrent(day); // Get the current time and fill the MqlDateTime structure
int week_day = day.day_of_week; //Extract the day of the week (0 = Sunday, 1 = Monday, ..., 6 = Saturday)

//getting the current month
MqlDateTime month; //Declare a structure to hold current month information
TimeCurrent(month); //Get the current date and time
int year_month = month.mon; //Extract the month component (1 for January, 2 for February, ..., 12 for December)

if(week_day == 5)
  {
   Comment("No trades on fridays", "\nday of week: ",week_day);
  }
else
   if(week_day == 4)
     {
      Comment("No trades on Thursdays", "\nday of week: ",week_day);
     }
   else
     {
      Comment(week_day);
     }

Explicação:

Precisamos determinar o dia da semana atual e compará-lo a diretrizes predefinidas para controlar em quais dias o EA pode operar. Para isso, primeiro declaramos uma estrutura MqlDateTime para armazenar a data e hora atual. Utilizamos a função TimeCurrent() para preencher essa estrutura com o mês e o dia da semana atuais.

Em seguida, verificamos o dia da semana usando instruções condicionais. O código exibe uma mensagem indicando que não são permitidas operações nas sextas-feiras, caso o dia atual seja sexta-feira (valor 5). De forma semelhante, o valor 4 indica que não são permitidas operações nas quintas-feiras. O código indica que, nos outros dias, as operações são permitidas ao simplesmente exibir o dia da semana atual.

Analogia

Considere cada dia da semana como um tipo de livro encontrado em uma biblioteca.

  • Sexta-feira (5): O código proíbe operações nas sextas-feiras, assim como não permite o empréstimo de livros de mistério nesse dia.
  • Quinta-feira (4): O código interrompe operações nas quintas-feiras, assim como livros de ficção científica não podem ser emprestados nesse dia.
  • Outros Dias: O código permite operações em todos os outros gêneros (dias), assim como ocorre para outros tipos de livros.


Conclusão

Utilizamos uma metodologia de aprendizado baseada em projetos neste artigo para tornar fácil o entendimento dos fundamentos de negociação algorítmica com MQL5, mesmo para iniciantes completos. Ao acompanhar, você adquiriu conhecimentos sobre como realizar tarefas fundamentais, como comprar e vender em MQL5, obter preços de abertura e fechamento de candles, e implementar estratégias para evitar operações a cada tick. Você também aprendeu a controlar aspectos importantes do trading automatizado, como limitar o EA a uma operação por vez, definir dias e períodos de operação, além de estabelecer limites de lucro e prejuízo.

Sinta-se à vontade para fazer perguntas sobre os tópicos abordados neste artigo enquanto avança em sua jornada. Estou aqui para ajudar, seja com a compreensão de implementações específicas de código ou com esclarecimentos sobre como esses conceitos se relacionam a diferentes estratégias de negociação. Entre em contato conosco, e juntos podemos discutir maneiras de melhorar sua compreensão e utilização da negociação algorítmica com MQL5.Lembre-se de que dominar qualquer linguagem de programação, incluindo o MQL5, é uma jornada em direção à negociação algorítmica. Naturalmente, não se pode compreender tudo de uma só vez. Você aumentará gradualmente seu conhecimento e habilidades ao adotar o aprendizado baseado em projetos, aplicando conceitos a projetos reais semelhantes aos que estudamos. Cada projeto serve como um degrau que constrói progressivamente sua proficiência e confiança.


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

Arquivos anexados |
MQL5Project2.mq5 (10.02 KB)
Redes neurais em trading: Método abrangente de previsão de trajetórias (Traj-LLM) Redes neurais em trading: Método abrangente de previsão de trajetórias (Traj-LLM)
Neste artigo, quero apresentar a você um método interessante de previsão de trajetórias, desenvolvido para resolver problemas relacionados ao movimento autônomo de veículos. Os autores do método combinaram os melhores elementos de diferentes soluções arquitetônicas.
Métodos de William Gann (Parte II): Criando um Indicador do Quadrado de Gann Métodos de William Gann (Parte II): Criando um Indicador do Quadrado de Gann
Vamos tentar criar um indicador baseado no Quadrado de 9 de Gann, construído com base na quadratura do tempo e do preço. Escreveremos o código e testaremos o indicador na plataforma em diferentes intervalos de tempo.
Algoritmo de algas artificiais (AAA) Algoritmo de algas artificiais (AAA)
Este artigo aborda o algoritmo de algas artificiais (AAA), desenvolvido com base nos processos biológicos característicos das microalgas. Ele incorpora movimento espiral, processo evolutivo e adaptação, e possibilita a resolução de problemas de otimização. O artigo oferece uma análise detalhada dos princípios de funcionamento do AAA e seu potencial na modelagem matemática, destacando a conexão entre a natureza e as soluções algorítmicas.
Algoritmo de otimização da sociedade anárquica — Anarchic society optimization (ASO) Algoritmo de otimização da sociedade anárquica — Anarchic society optimization (ASO)
No próximo artigo, conheceremos o algoritmo Anarchic Society Optimization (ASO) e discutiremos como um algoritmo baseado no comportamento irracional e aventureiro dos participantes de uma sociedade anárquica — um sistema anômalo de interação social, livre de autoridade centralizada e de qualquer tipo de hierarquia — é capaz de explorar o espaço de soluções e evitar armadilhas de ótimos locais. O artigo apresentará uma estrutura unificada do ASO, aplicável tanto a problemas contínuos quanto a problemas discretos.