English Русский 中文 Español Deutsch 日本語
preview
Tudo o que você precisa saber sobre a estrutura de um programa MQL5

Tudo o que você precisa saber sobre a estrutura de um programa MQL5

MetaTrader 5Negociação | 11 janeiro 2024, 17:44
537 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Introdução

Todo programa em qualquer linguagem de programação possui uma estrutura. Ao entender essa estrutura, podemos criar e melhorar nossos próprios programas com facilidade. Os programas no MQL5 também têm sua própria estrutura, e os desenvolvedores devem compreendê-la para garantir o alcance sem percalços e eficaz dos objetivos de seus projetos. Vamos explorar a estrutura de um programa desenvolvido no MQL5, abordando os seguintes tópicos:

Após a leitura deste artigo, você terá um profundo entendimento da estrutura de qualquer programa MQL5 e será capaz de criar ou desenvolver qualquer software com base nessa estrutura de forma fluida e eficiente.

Atenção! Todo o conteúdo deste artigo é apresentado "como está", apenas para fins educacionais e não constitui uma recomendação de negociação. O artigo não oferece nenhuma garantia de resultados. Tudo o que você colocar em prática com base neste artigo, você faz exclusivamente por sua conta e risco, o autor não garante nenhum resultado.


Pré-processador

Nesta seção, examinaremos detalhadamente o pré-processador como um conceito de programação. O pré-processador (preparação prévia) é uma etapa importante no processo de compilação. Ele entra em ação antes da compilação real do programa. Durante a pré-processamento, várias ações são executadas, como inclusão de arquivos, definição de propriedades de software, definição de constantes e importação de funções.

Todas as diretivas do pré-processador começam com (#). Essas diretivas não são consideradas declarações de linguagem, ou seja, não devem terminar com ponto e vírgula (;). Incluir um ponto e vírgula no final de uma diretiva do pré-processador pode levar a erros, dependendo do tipo de diretiva.

Em outras palavras, podemos dizer que o pré-processador é destinado a preparar o código-fonte do programa antes do processo de compilação. Existem vários tipos de diretivas do pré-processador com base nos parâmetros que precisamos definir em um programa MQL5, como:

  • Macro substituição (#define)
  • Propriedades do programa (#property)
  • Inclusão de arquivos (#include)
  • Importação de funções (#import)
  • Compilação condicional (#ifdef, #ifndef, #else, #endif)

Macro substituição (#define):

A diretiva do pré-processador #define pode ser usada para criar constantes simbólicas ou para definir constantes que serão usadas no programa. Uma constante é um identificador cujo valor não muda. A diretiva #define pode ser usada para atribuir nomes mnemônicos a constantes, já que usaremos um valor substituto para um identificador específico. O primeiro formato dessa diretiva do pré-processador é o seguinte:

#define identifier replacement-value

Assim, em nosso programa, essa linha de código significa que, antes da compilação, o identificador será substituído pelo valor substituto. Este formato representa a diretiva #define sem parâmetros, ou formato sem parâmetros. No MQL5, há outro formato, que é o formato paramétrico com um máximo de oito parâmetros que podem ser usados com a diretiva #define, como mostrado abaixo:

#define identifier (param1, param2,... param5)

As mesmas regras das variáveis se aplicam aos identificadores de constantes:

  • O valor pode ser de qualquer tipo, como inteiro, duplo ou string.
  • A expressão pode consistir em vários tokens. Ele termina quando a linha termina e não pode ser transferido para a próxima linha de código.

Aqui está um exemplo:

//Parameter-free format
#define INTEGER               10                                     //int
#define DOUBLE                10.50                                  //double
#define STRING_VALUE      "MetaQuotes Software Corp."                //str
#define INCOMPLETE_VALUE INTEGER+DOUBLE                              //Incomlete
#define COMPLETE_VALUE (INTEGER+DOUBLE)                              //complete
//Parametic format
#define A 2+3
#define B 5-1
#define MUL(a, b) ((a)*(b))
double c=MUL(A,B);
//function to print values
void defValues()
  {

   Print("INTEGER Value, ",INTEGER);         //result: INTEGER Value, 10
   Print("DOUBLE Value, ",DOUBLE);           //result: DOUBLE Value, 10.50
   Print("STRING Value, ",STRING_VALUE);     //result: STRING Value, MetaQuotes Software Corp.
   Print("INCOMPLETE Value, ",INCOMPLETE_VALUE*2);     //result: INCOMPLETE Value, 31
   Print("COMPLETE Value, ",COMPLETE_VALUE*2);     //result: STRING Value, 41
   Print("c= ",c);                                  //result: c= 41
  }

Também existe a diretiva do pré-processador (#undef), que anula o que foi declarado ou definido anteriormente.

Propriedades do programa (#property):

Ao criar um programa, podemos precisar especificar parâmetros adicionais. Podemos fazer isso usando #property. Essas propriedades devem ser especificadas no arquivo principal MQL5 e não no arquivo incluído, e as que forem especificadas nos arquivos incluídos serão ignoradas. Desse modo, a diretiva #property define propriedades adicionais para o programa. Se você perguntar o que precisamos especificar nesse contexto, direi que temos muitas coisas, como indicadores, scripts, informações descritivas e propriedades de bibliotecas. Como outras diretivas do pré-processador, #property será declarado na parte superior do código-fonte e será exibido na guia geral na janela do programa durante a execução.

Aqui está um exemplo da diretiva do pré-processador deste tipo:

#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property description "Property preprocessor"

Esses valores podem ser vistos na janela do programa:

property

Como podemos ver na imagem anterior, temos certas propriedades que precisamos na guia geral ao iniciar o Expert Advisor (EA). O texto 'Copyright 2023, MetaQuotes Ltd.' é um hiperlink. Ao passar o mouse sobre ele, vemos para onde ele leva (propriedade link).

Inclusão de arquivos (#include):

Como de costume, todas as diretivas #include são colocadas no início do programa. Elas apontam para o arquivo que deve ser incluído no programa para utilizar seu conteúdo, como variáveis, funções e classes.

Existem dois formatos para inclusão de arquivos com a diretiva #include:

#include <File_Name.mqh>
#include "File_Name.mqh"

A diferença entre esses dois formatos está em onde o compilador deve procurar o arquivo incluído: o primeiro permite que o compilador procure o arquivo na pasta "Include" da instalação do MetaTrader 5 ou no arquivo de cabeçalho da biblioteca padrão, enquanto o segundo permite que o compilador procure o arquivo no mesmo diretório que o arquivo do programa.

Importação de funções (#import):

A diretiva #import é usada para importar funções para o programa a partir de módulos MQL5 compilados (arquivos *.ex5) e módulos do sistema operacional (arquivos *.dll). A função deve ser completamente descrita, e seu formato deve ser o mesmo que o seguinte:

#import "File_Name"
    func1 define;
    func2 define;
    ...
    funcN define;
#import

Compilação condicional (#ifdef, #ifndef, #else, #endif):

A compilação condicional nos permite controlar a execução das diretivas de pré-processamento, além da compilação do programa. Isso nos permite controlar a compilação ou pular partes do código do programa com base em uma condição específica, que pode estar em um dos seguintes formatos:

#ifdef identifier
   //If the identifier has been defined, the code here will be compiled.
#endif
#ifndef identifier
   // If the identifier is not defined, the code here will be compiled.
#endif

Como mencionei antes, se pulamos para uma nova linha, as diretivas do pré-processador não serão continuadas. No entanto, neste caso, qualquer quantidade de linhas pode seguir uma diretiva desse tipo quando usamos #else e #endif. Quando a condição é verdadeira, as linhas entre #else e #endif serão ignoradas, mas se a condição não for atendida, as linhas entre o #ifdef (ou #ifndef) e o #else (ou #endif, se o primeiro estiver ausente) serão ignoradas.

Você pode aprender mais sobre o pré-processador MQL5 na documentação.


Variáveis de entrada e globais

Nesta seção, vamos abordar outros componentes da estrutura de um programa MQL5 após as diretivas do pré-processador, que são as variáveis de entrada e globais. Começaremos com as variáveis de entrada (input), que definem uma variável externa. Após a escrita do modificador de entrada, especificamos o tipo de dados. Desse modo, temos o modificador de entrada e os valores da variável de entrada. O modificador de entrada não pode ser alterado dentro do programa MQL5, apenas os valores podem ser alterados pelo usuário do programa na janela "Parâmetros de entrada" ou na guia de propriedades do programa. Quando definimos essas variáveis externas com o modificador de entrada, elas sempre são reinicializadas antes da chamada OnInIt().

Aqui está o formato das variáveis de entrada:

input int            MA_Period=20;
input int            MA_Shift=0;
input ENUM_MA_METHOD MA_Method=MODE_SMA;

Após isso, podemos encontrar a janela de entrada definida pelo usuário:

inputs

Como podemos ver, podemos configurar o período, o deslocamento e o tipo da média móvel. Também podemos definir como os parâmetros de entrada aparecem na guia "Parâmetros de entrada", adicionando um comentário sobre o que queremos ver na janela, como mostrado abaixo no mesmo exemplo anterior:

input int            MA_Period=20;        //Moving Average Period 
input int            MA_Shift=0;          //Moving Average Shift
input ENUM_MA_METHOD MA_Method=MODE_SMA;  //Moving Average Type

Na guia "Parâmetros de entrada", podemos encontrar os seguintes parâmetros:

inputs1

Como podemos observar, os parâmetros têm uma aparência diferente em comparação com a imagem anterior. Você pode aprender mais sobre as variáveis de entrada (input) no MQL5 na documentação.

As variáveis globais devem ser criadas fora dos manipuladores de eventos ou dentro de funções no mesmo nível das funções:

int Globalvar;   // Global variable before or outside the event handler and functions
int OnInit()
  {
   ...
  }

Por esse motivo, podemos dizer que as variáveis globais têm escopo em todo o programa e são acessíveis a partir de todas as funções no programa. Elas são inicializadas uma vez durante o carregamento do programa e antes do tratamento do evento OnInit ou do tratamento do evento OnStart(). Falaremos sobre manipuladores de eventos mais tarde. Aqui, apenas são mencionados para apresentar a posição das variáveis globais na estrutura do programa MQL5.

Você pode aprender mais sobre as variáveis globais do MQL5 na documentação.


Funções, classes

Nesta seção, abordaremos outros componentes da estrutura de programas MQL5, nomeadamente funções e classes. As funções são detalhadamente descritas em um dos artigos anteriores, "Funções em Aplicativos MQL5". Também recomendo ler o artigo sobre classes no contexto da programação orientada a objetos (POO) no MQL5, "Programação Orientada a Objetos (POO) no MQL5". Espero que eles sejam úteis para você.

Aqui, mencionaremos a posição deste importante componente em qualquer programa, pois podemos defini-lo em qualquer lugar do programa, incluindo arquivos incluídos que podem ser incluídos com a diretiva #include. Eles podem ser colocados antes ou depois dos manipuladores de eventos, bem como após variáveis de entrada e globais.

O formato das funções é o seguinte:

returnedDataType functionName(param1, param2)
{
        bodyOfFunction
}

O formato das classes é o seguinte:

class Cobject
{
   int var1;       // variable1
   double var2;    // variable1
   void method1(); // Method or function1
};

Você pode aprender mais sobre funções e classes no MQL5 na documentação.


Manipuladores de eventos

Nesta seção, abordaremos os manipuladores de eventos, que são componentes muito importantes dos programas MQL5. Um manipulador de eventos é uma função executável. Quando ocorre um evento específico, como um novo preço, que representa um novo evento de tick, o manipulador de eventos OnTick() se torna executável, pois ele contém o trecho de código que pode ser executado quando um novo preço ou tick é recebido.

Dependendo do tipo de programa, existem diferentes manipuladores de eventos:

Manipulador de eventos Descrição Formato 
OnStart Pode ser usado em programas como scripts para chamar uma função quando ocorre um evento de acionamento.
  • Versão com valor de retorno: 
int  OnStart(void);
  • Versão sem valor de retorno:
void  OnStart(void);
OnInit Ele pode ser usado em programas de Expert Advisor e indicadores para chamar a função na inicialização do programa.
  •  Versão com valor de retorno:
int  OnInit(void);
  • Versão sem valor de retorno:
void  OnInit(void);

OnDeinit Pode ser usado em programas de Expert Advisors e indicadores para chamar a função quando o programa for desinicializado
void  OnDeinit(
   const int  reason         // deinitialization reason code
   );
OnTick Pode ser usado em Expert Advisors e indicadores para chamar a função ao receber novas cotações.
void  OnTick(void);
OnCalculate Pode ser usado em indicadores para chamar a função ao enviar o evento Init e a qualquer alteração dos dados de preço.
  • Cálculos baseados no conjunto de dados
int  OnCalculate(
   const int        rates_total,       // price[] array size
   const int        prev_calculated,   // number of handled bars at the previous call
   const int        begin,             // index number in the price[] array meaningful data starts from
   const double&    price[]            // array of values for calculation
   );
  • Cálculos baseados na série temporal do período atual
int  OnCalculate(
   const int        rates_total,       // size of input time series
   const int        prev_calculated,   // number of handled bars at the previous call
   const datetime&  time{},            // Time array
   const double&    open[],            // Open array
   const double&    high[],            // High array
   const double&    low[],             // Low array
   const double&    close[],           // Close array
   const long&      tick_volume[],     // Tick Volume array
   const long&      volume[],          // Real Volume array
   const int&       spread[]           // Spread array
   );
OnTimer Pode ser usado em Expert Advisors e indicadores para chamar a função no evento Timer.
void  OnTimer(void);
OnTrade Pode ser usado em Expert Advisors para chamar a função quando uma operação de negociação for concluída no servidor de negociação.
void  OnTrade(void);
OnTradeTransaction Pode ser usado em Expert Advisors para chamar a função ao executar determinadas ações na conta de negociação.
void  OnTradeTransaction()
   const MqlTradeTransaction&    trans,     // trade transaction structure
   const MqlTradeRequest&        request,   // request structure
   const MqlTradeResult&         result     // response structure
   );
OnBookEvent Pode ser usado em Expert Advisors para chamar uma função quando o livro de ofertas muda.
void  OnBookEvent(
   const string&  symbol         // symbol
   );
OnChartEvent Pode ser usado em indicadores para chamar uma função quando o usuário trabalha com um gráfico.
void  OnChartEvent()
   const int       id,       // event ID 
   const long&     lparam,   // long type event parameter
   const double&   dparam,   // double type event parameter
   const string&   sparam    // string type event parameter
   );
OnTester Pode ser usado em Expert Advisors para chamar a função quando o EA terminar de testar com dados históricos.
double  OnTester(void);
OnTesterInit Pode ser usado em Expert Advisors para chamar uma função com o início da otimização no testador de estratégia antes da primeira passagem da otimização.
  • Versão com valor de retorno
int  OnTesterInit(void);
  • Versão sem valor de retorno
void  OnTesterInit(void);
OnTesterDeinit Pode ser usado para chamar a função depois que o EA tiver sido otimizado no testador de estratégias.
void  OnTesterDeinit(void);
OnTesterPass Pode ser usado em Expert Advisors para chamar uma função quando uma nova porção de dados é recebida.
void  OnTesterPass(void);

Você pode aprender mais sobre o tratamento de eventos lendo a documentação do MQL5.


Exemplo de programa no MQL5

Nesta seção, aplicaremos o conhecimento adquirido para criar um aplicativo simples usando a estrutura certa respetiva ao MQL5. Mencionamos que podemos usar os componentes da estrutura do MQL5, dependendo do tipo de programa e da tarefa necessária. Não há obrigações de usar alguns desses componentes, como a diretiva #include, pois pode não ser necessário incluir componentes externos. O mesmo se aplica ao #property. Criar classes ou funções personalizadas no programa também pode não ser necessário. De qualquer forma, você usará o que for necessário para o seu programa. Abaixo, estão exemplos simples de aplicação de todos os componentes estruturais necessários, com base em diferentes tipos de programas.

Script:

Aqui está um exemplo simples de um script MQL5 que pode calcular e somar dois números inseridos pelo usuário usando dados de entrada e imprimir o resultado na guia "Experts" usando a função Print. Vamos adicionar a propriedade #property, que permitirá exibir os dados de entrada do script para que o usuário possa inserir os números.

//+------------------------------------------------------------------+
//|                                       Script program example.mq5 |
//|                                   Copyright 2023, MetaQuotes Ltd.|
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
//property preprocessor
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property script_show_inputs
//inputs
input int userEntryNum1;
input int userEntryNum2;
//global variable
int result;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
//event handler
void OnStart()
  {
   result=userEntryNum1+userEntryNum2;
   Print("Result: ", result);
  }
//+------------------------------------------------------------------+

Se desejarmos criar outro EA ou indicador, precisaremos usar manipuladores de eventos diferentes, dependendo do tipo de programa. Por exemplo, um EA pode realizar uma ação quando receber um novo tick, usando o manipulador OnTick().

Agora que definimos a estrutura de um programa MQL5, podemos ver que alguns componentes variam de acordo com o tipo de programa e seus objetivos. Esse entendimento nos ajuda a determinar a posição de cada componente no programa.

Para aplicar esse conhecimento, podemos começar com um simples script, como mencionado anteriormente.


Considerações finais

Analisamos a estrutura de um programa MQL5 e podemos identificar quais componentes são necessários:

  • Pré-processador
    • Substituição de macro (#define)
    • Propriedades do programa (#property):
    • Inclusão de arquivos (#include):
    • Importação de funções (#import):
    • Compilação condicional (#ifdef, #ifndef, #else, #endif)
  • Variáveis de entrada e globais
  • Funções e classes
  • Manipuladores de eventos
    • OnStart
    • OnInit
    • OnDeinit
    • OnTick
    • OnCalculate
    • OnTimer
    • OnTrade
    • OnTradeTransaction
    • OnBookEvent
    • OnChartEvent
    • OnTester
    • OnTesterInit
    • OnTesterDeinit
    • OnTesterPass

Espero que este artigo tenha sido útil para você. Se desejar aprender mais sobre a criação de um sistema de negociação usando indicadores técnicos populares, você pode consultar meus outros artigos.

Além disso, escrevi sobre a criação e o uso de indicadores personalizados em qualquer EA e outros tópicos importantes de programação no MQL5, como programação orientada a objetos (POO) e funções. Acredito que esses artigos serão úteis para aprendizado e negociação.

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

Arquivos anexados |
Desenvolvendo um sistema de Replay (Parte 40): Iniciando a segunda fase (I) Desenvolvendo um sistema de Replay (Parte 40): Iniciando a segunda fase (I)
Esta é a nova fase do sistema de replay / simulação. Nesta fase a conversa de fato irá ser seria. E o conteúdo irá ser tornar bastante denso. Peço que você leia com calma o artigo e sempre procure usar as referencias que possivelmente estarão sendo indicadas nos artigos. Isto para lhe ajudar a compreender melhor o que estará sendo explicado.
Desenvolvendo um sistema de Replay (Parte 39): Pavimentando o Terreno (III) Desenvolvendo um sistema de Replay (Parte 39): Pavimentando o Terreno (III)
Antes de começarmos a segunda fase de desenvolvimento, é preciso reforçar algumas ideias. Então você sabe como forçar o MQL5 a fazer o que é preciso ser feito ?!?! Já tentou ir além do que a documentação informar ?!?! Se não. Se prepare. Pois irei começar a fazer coisas muito além do que grande parte faz normalmente.
Operações de negociação Estruturas das solicitações e das resposta, descrição e registro Operações de negociação Estruturas das solicitações e das resposta, descrição e registro
Neste artigo, veremos como trabalhar com as estruturas das solicitações de negociação, criar a solicitação, verificá-la antes de enviá-la ao servidor, gerar a resposta do servidor quanto a ela e usar a estrutura das transações. Além disso, criaremos funções simples e convenientes para enviar ordens para o servidor e, com base em tudo o que foi mencionado acima, criar um Expert Advisor que informe sobre as transações.
Desenvolvendo um agente de Aprendizado por Reforço em MQL5 com Integração RestAPI (Parte 3): Criando jogadas automáticas e Scripts de Teste em MQL5 Desenvolvendo um agente de Aprendizado por Reforço em MQL5 com Integração RestAPI (Parte 3): Criando jogadas automáticas e Scripts de Teste em MQL5
Este artigo explora a implementação de jogadas automáticas no jogo da velha Python, integrado com funções MQL5 e testes unitários. O objetivo é aprimorar a interatividade do jogo e garantir a robustez do sistema através de testes MQL5. Ele aborda desde o desenvolvimento da lógica de jogo até a integração e testes práticos, culminando na criação de um ambiente de jogo dinâmico e um sistema integrado confiável.