English Русский 中文 Español Deutsch 日本語
Fundamentos Básicos da Programação: Variáveis Globais do Terminal  MetaTrader 5

Fundamentos Básicos da Programação: Variáveis Globais do Terminal MetaTrader 5

MetaTrader 5Exemplos | 14 dezembro 2016, 15:26
3 686 0
Dmitry Fedoseev
Dmitry Fedoseev

Conteúdo


Fig. 1. Parte do código com as variáveis globais

Cuidado para não confundir as variáveis globais com as variáveis globais de programas já conhecidos do terminal (Fig. 2), tentando encontrar os seus homólogos de outras linguagens de programação.


Fig. 2. Exemplos de parte do código do EA MovingAverage a partir do terminal. As dvariáveis globais de programas são destacadas em vermelho

Devido as variáveis globais do terminal não serem tão compatíveis com outras linguagens de programação, elas não são muito popular entre os aprendizes do MQL5. Talvez eles simplesmente não têm idéia de como e por que usá-las ou suas aplicações são muito complicadas devido ao nome das funções: GlobalVariableSet(), GlobalVariableGet(), GlobalVariableCheck(), etc.

A principal característica das variáveis globais é a manutenção de seus valores, mesmo depois de fechado o terminal. Isso é muito prático, pois fornecem meios para armazenar dados importantes e quase indispensáveis no desenvolvimento de EAs confiáveis, envolvendo a interação complexa entre as ordens. Depois de dominar as variáveis globais, você não vai mais conseguir imaginar o desenvolvimento de EAs no MQL5 sem elas.

O artigo fornece exemplos práticos, permitindo que você aprenda todas as funções para trabalhar com as variáveis globais, análise das características e aplicação de seus métodos, bem como desenvolver uma classe significativamente simples e que acelera o trabalho com elas.

As funções para trabalhar com as variáveis globais estão na Documentação do MQL5, veja aqui

Visualizando as variáveis globais no terminal

Ainda no terminal, execute o seguinte comando: Menu Principal - Ferramentas - Variáveis globais. A janela Variáveis Globais aparece (Fig. 3).

 
Fig. 3. A janela Variáveis Globais no terminal 

Basicamente, todas as variáveis globais são realizadas por meio de programação. No entanto, essa janela pode ser útil ao testar os EAs. Permite que você veja todas as variáveis globais do terminal, bem como editar nomes e valores. Para alterar uma variável, clique no campo com seu nome ou valor, além disso, a janela permite a criação de novas variáveis, para fazer isso, clique em Adicionar, no canto superior direito. O botão excluir é usado para apagar as variáveis globais. Antes de excluir, clique na variável necessária para tornar o botão ativo. Práticas de criação, alteração e exclusão de variáveis globais. Nota: se a janela contém já algumas variáveis, ao abri-la, deixe-as intactas, pois elas podem ser necessárias para que um EA seja anexado na sua conta.

Uma variável global tem três atributos: nome, valor e tempo. O campo Tempo é exibido quando a variável foi acessada pela última vez. Após quatro semanas, depois do último acesso, a variável é apagada automaticamente. No entanto, se a variável armazena dados importantes, ela deve ser acessada periodicamente para estender sua vida útil.  

Criando uma variável global do terminal

A variável é gerada automaticamente quando um valor é atribuído a ela. Se já existir o nome da variável, seu valor é atualizado. A função GlobalVariableSet() é usada para atribuir um valor à variável. Os dois parâmetros são transmitidos para a função: nome da variável (string) e seu valor (tipo double). Vamos tentar criar uma variável. Abra o MetaEditor, crie um script e escreva o seguinte código para a função OnStart():

GlobalVariableSet("test",1.23);

 Execute o script e abra as variáveis globais a partir da janela do terminal. A janela deve conter uma nova variável chamada "test" e o valor de 1.23 (Fig. 4).

 
Fig. 4. Parte da janela das variáveis globais com a nova variável "test"

O exemplo do código pode ser encontrado no script sGVTestCreate.  

Recebendo o valor de uma variável global

Depois que o script do exemplo anterior completar o seu trabalho, a variável ainda existirá. Vamos olhar para o seu valor. A função GlobalVariableGet() é usada para receber o valor. Existem duas funções de métodos de chamadas. Ao aplicar a primeira, só um nome é transmitido para a função. A função retorna o valor do tipo double:

double val=GlobalVariableGet("test");
Alert(val);

Ao executar o código, um indicador com o valor de 1,23 é aberto. O exemplo pode ser encontrado no script sGVTestGet1 anexo ao artigo.

Ao aplicar o segundo método, os dois parâmetros - as variáveis name e double para o valor (o segundo parâmetro é transmitido pelo link) são transmitidas para a função que, por sua vez, retorna verdadeira ou falsa, dependendo dos resultados:

double val;
bool result=GlobalVariableGet("test",val);
Alert(result," ",val);

A janela com a mensagem "true 1,23" é aberta como um resultado.

Se tentarmos receber o valor de uma variável inexistente, a função retorna falsa e 0. Vamos mudar um pouco o exemplo de código anterior: 1,0 para atribuir a variável 'val' quando declarar e tente receber o valor da variável inexistente "test2":

double val=1.0;
bool result=GlobalVariableGet("test2",val);
Alert(result," ",val);

A janela com a mensagem "false 0.0" é aberta como um resultado. O exemplo pode ser encontrado no script sGVTestGet2-2 anexado abaixo.

Ao chamar a função, usando o primeiro método, nós obtemos 0.0 no caso de uma variável inexistente, ou seja, o erro é recebido. Usando o primeiro método de chamada da função e verificação de erro, podemos obter a análoga do segundo método da função:

ResetLastError();
double val=GlobalVariableGet("test2");
int err=GetLastError();
Alert(val," ",err);

Como um resultado do código de operação (o exemplo pode ser encontrado no script sGVTestGet1-2), a mensagem "4501 0.0" é aberta. 0,0 é um valor, 4501 é um código de erro - "A variável global do terminal do cliente não foi encontrada". Este não é um erro crítico, mas sim uma notificação. Você pode se referir a uma variável inexistente se o algoritmo permitir isso. Por exemplo, se você deseja rastrear o capital líquido máximo:

GlobalVariableSet("max_equity",MathMax(GlobalVariableGet("max_equity",AccountInfoDouble(ACCOUNT_EQUITY)));

O código funciona corretamente, mesmo se a variável "max_equity" não existir. Primeiro, a função MathMax() seleciona o valor máximo entre o patrimônio atual e o previamente gravado na variável "max_equity". Uma vez que a variável não existe, recebemos o valor patrimonial atual.

Nomes das variáveis globais

Como podemos ver, o nome da variável global é uma string. Não há restrições sobre os caracteres para nomes de símbolo e sua ordem. Qualquer caracter encontrado no teclado pode ser usado nos nomes, incluindo espaços e caracteres não permitidos em nomes de arquivo. No entanto, eu recomendo selecionar nomes simples e de fácil leitura, incluindo caracteres, números e sublinhado semelhantes às variáveis comuns.

Há apenas uma limitação significativa, o que exige precisão ao selecionar nomes para as variáveis globais - comprimento do nome: não mais do que 63 caracteres.

Verificar a existência de uma variável

A função GlobalVariableCheck() é utilizada para verificar se existe a variável. Um único parâmetro é transmitido para a função - o nome da variável. Se a variável existe, a função retorna true, caso contrário, false. Vamos verificar se as variáveis "test" e "test2" existem:

bool check1=GlobalVariableCheck("test");
bool check2=GlobalVariableCheck("test2");
Alert(check1," ",check2);

Este exemplo pode ser encontrado no script sGVTestCheck anexado abaixo. A mensagem "True false" é recebida como resultado da operação do script - a variável "test" existe, enquanto o "test2" não.

Às vezes, a verificação da existência da variável é necessária, por exemplo, ao acompanhar um capital líquido mínimo. Se substituir a função MathMax() pela MathMin() no exemplo relacionado acima, no rastreamento do capital líquido máximo, ele trabalhará de forma incorreta e a variável sempre irá conter 0.

Neste caso, a verificação da variável existente pode ajudar:

if(GlobalVariableCheck("min_equity")){
   GlobalVariableSet("min_equity",MathMin(GlobalVariableGet("min_equity"),AccountInfoDouble(ACCOUNT_EQUITY)));
}
else{
   GlobalVariableSet("min_equity",AccountInfoDouble(ACCOUNT_EQUITY));

Se a variável existir, selecione o menor valor usando a função MathMin(). Caso contrário, atribuir o valor do capital líquido de imediato.

Tempo de uma variável global

O Tempo variável global já vimos na FIG. 3 pode ser obtida utilizando a função GlobalVariableTime(). Um único parâmetro é transmitido para a função - o nome da variável. A função retorna o valor do tipo data e hora:

datetime result=GlobalVariableTime("test");
Alert(result);

O código pode ser encontrado no script sGVTestTime anexado abaixo. O valor atribuído da variável time é alterado apenas quando acessá-la, ou seja, nenhuma das outras funções podem ser alteradas ao usar as funções GlobalVariableSet() e GlobalVariableGet(). Se alterarmos manualmente a variável através da janela das Variáveis Globais, seu tempo é alterado também (independentemente de nós mudarmos o seu nome ou o valor).

Como já foi dito, após quatro semanas, desde o seu último acesso, a variável é excluída automaticamente pelo terminal. 

Visualizando todas as variáveis globais

Às vezes, precisamos de uma variável global, mas não sabemos o seu nome exato. Podemos nos lembrar do início, mas não do fim, por exemplo: gvar1, gvar2, etc. A fim de encontrar tais variáveis, precisamos iterar todas as variáveis globais do terminal e verificar os seus nomes. Para fazer isso, precisamos das funções GlobalVariablesTotal() e GlobalVariableName(). A função GlobalVariablesTotsl() retorna o número total de variáveis globais. A GlobalVariableName() retorna o nome da variável, pelo seu índice. Um único parâmetro do tipo int é transmitido para a função. Primeiro, vamos dar uma olhada em todas as variáveis e exibir seus nomes e valores na caixa de mensagem:

   Alert("=== Start ===");
   int total=GlobalVariablesTotal();
   for(int i=0;i<total;i++){
      Alert(GlobalVariableName(i)," = ",GlobalVariableGet(GlobalVariableName(i)));
   }

A janela com todos os nomes e valores de variáveis é aberta como um resultado (Fig. 5). O código pode ser encontrado no script sGVTestAllNames anexo no artigo.

 
Fig. 5. A janela de mensagem contém todas as variáveis globais do terminal

Vamos adicionar uma nova verificação, a fim de visualizar as variáveis com certos atributos nos nomes. O exemplo a seguir ilustra uma verificação de nomes para variáveis que iniciam com "gvar" (este exemplo pode ser encontrado no script sGVTestAllNames2 abaixo):

   Alert("=== Start ===");
   int total=GlobalVariablesTotal();
   for(int i=0;i<total;i++){
      if(StringFind(GlobalVariableName(i),"gvar",0)==0){
         Alert(GlobalVariableName(i)," = ",GlobalVariableGet(GlobalVariableName(i)));
      }
   }

A verificação é realizada pela função StringFind(). Se você quiser melhorar suas habilidades em trabalhar com funções de string, leia o artigo Fundamentos básicos da programação MQL5: Strings.

Deletando as variáveis globais

A função GlobalVariableDel(), para excluir uma variável global, recebe um único parâmetro - o nome da variável. Exclua a variável "test" criada anteriormente (sGVTestDelete script attached below):

GlobalVariableDel("test");

Para verificar os resultados da operação, você pode usar o script sGVTestGet2-1 ou sGVTestGet2-2 ou abrir a janela de variáveis globais.

A remoção de uma única variável é simples, mas na maioria das vezes você deseja excluir mais de uma variável. A função GlobalVariablesDeleteAll() é feita para isso. Dois parâmetros opcionais são transmitido para a função. Se chamarmos a função sem parâmetros, todas as variáveis globais são excluídas. Geralmente, é necessário excluir apenas um grupo de variáveis com o mesmo prefixo (início de um nome). O primeiro parâmetro de função é usado para especificar o prefixo. Vamos experimentar com esta função. Primeiro, devemos criar um número de variáveis com prefixos diferentes:

   GlobalVariableSet("gr1_var1",1.2);
   GlobalVariableSet("gr1_var2",3.4);   
   GlobalVariableSet("gr2_var1",5.6);
   GlobalVariableSet("gr2_var2",7.8);  

O código cria quatro variáveis: os dois com prefixo gr1_, bem como outros dois com o prefixo _gr2. O código pode ser encontrado no script sGVTestCreate4 anexo. Examine os resultados da operação do script, iniciando o script sGVTestAllNames (Fig. 6).

 
Fig. 6. Variáveis criadas pelo script sGVTestCreate4

Agora, vamos excluir as variáveis começando com gr1_ (script sGVTestDeleteGroup anexado abaixo):

GlobalVariablesDeleteAll("gr1_");

Depois de executar o código, veja todas as variáveis novamente usando o script sGVTestAllNames (Fig. 7). Veremos novamente a lista de todas as variáveis, exceto as duas que começam com gr1_.

 
Fig. 7. As variáveis que começam com gr1_ foram excluídas

O segundo parâmetro da função GlobalVariableDeleteAll() é usado se você precisar excluir somente as variáveis antigas. A data é especificada neste parâmetro. Se a data do último acesso à variável for menor do que a especificada, a variável é excluída. Observe que apenas as variáveis com menor tempo são excluídas, enquanto as com maior ou igual tempo permanecem. As variáveis podem ser adicionalmente selecionadas pelo prefixo. Se a seleção por prefixo não for necessária, o valor NULL padrão é definido como o primeiro parâmetro:

GlobalVariablesDeleteAll(NULL,StringToTime("2016.10.01 12:37"));

Na realidade, a supressão de variáveis pelo tempo pode ser necessária apenas para resolver algumas tarefas muito raras e incomuns, portanto, não vou me alongar demais sobre esse tópico.

Função GlobalVariablesFlush

Ao fechar o terminal, as variáveis globais são salvas automaticamente no arquivo e serão baixadas novamente pelo terminal durante próxmo acesso. Não há necessidade de conhecer todas as sutilezas do processo (nome do arquivo, formato de armazenamento de dados, etc.) ao usar variáveis globais.

No caso do desligamento de emergência do terminal, as variáveis globais podem ser perdidas. A função GlobalVariableFlush() ajuda a evitar isso. A função força o salvamento das variáveis globais. Depois que os valores são definidos pela função GlobalVariableSet() ou as variáveis são excluídas, ou basta chamar a função GlobalVariableFlush(). A função é chamada sem parâmetros: 

   GlobalVariableSet("gr1_var1",1.2);
   GlobalVariableSet("gr1_var2",3.4);   
   GlobalVariableSet("gr2_var1",5.6);
   GlobalVariableSet("gr2_var2",7.8);   
   
   GlobalVariablesFlush();

O código pode ser encontrado no arquivo sGVTestFlush anexo. 

Seria bom ilustrar o funcionamento da função GlobalVariableFlush(), mas infelizmente, não consegui fazer desaparecer as variáveis globais durante um encerramento de emergência do terminal. A operação do terminal foi interrompida através da aba Processos do Gerenciador de Tarefas. Talvez, as variáveis globais desapareçam do PC no caso de uma queda de energia. Um blackout do PC raramente acontece hoje em dia, a maioria dos usuários possuem laptops, enquanto os usuários de desktop geralmente usam dispositivos ininterruptos de fonte de alimentação. Se um terminal funciona num servidor dedicado, então a proteção contra falha na fonte de alimentação é ainda mais significativa. Portanto, as variáveis globais são meio confiáveis para salvar dados, mesmo sem a função GlobalVariableFlush().    

Variável temporária, função GlobalVariableTemp

A função GlobalVariableTemp() cria uma variável global temporária (que existe até o terminal ser interrompido). Eu desenvolvo EAs no MQL5 a anos e nunca enfrentei a necessidade de tal variável. Além disso, o próprio conceito de uma variável global temporária contradiz o princípio básico de sua aplicação - o armazenamento de dados à longo prazo não é afetado pelo relançamento dos terminais. Mas uma vez que a função existe na linguagem MQL5, vamos prestar alguma atenção, pode ser que um dia precise.

Ao chamar a função, um único parâmetro - o nome da variável - é transmitido a ele. Se a variável com tal nome não existir, uma variável temporária com o valor de 0 é criada. Depois disso, use a função GlobalVariableSet() para atribuir um valor a ela para que use como de costume. Se a variável já existir (criada pela função GlobalVariableSet() anteriormente), ela não será convertida naquela temporária:

   GlobalVariableSet("test",1.2); // Defina a variável de valor para se certificar de que a variável existe
   GlobalVariableTemp("temp"); // Criar uma variável temporária
   Alert("temp variable value right after creation - ",GlobalVariableGet("temp"));
   GlobalVariableSet("temp",3.4); // Definir o valor da variável temporária
   GlobalVariableTemp("test"); // tentar converter a variável "test" em uma variável temporária

Este exemplo pode ser encontrado no arquivo sGVTestTemp anexo abaixo. Depois de iniciar o script, abra a janela de variáveis globais. Deve conter a variável "temp" com o valor de 3.4 e "test" com o valor de 1.2. Feche a janela das variáveis globais, reinicie o terminal e abra a janela novamente. A variável "test" é salva, enquanto "temp" não está mais lá.

Alterando a variável pela condição, função GlobalVariableSetOnCondition

Agora, finalmente é o momento de considerar a última função e, na minha opinião, a mais interessante: GlobalVariableSetOnCondition(). Três parâmetros são passados para a função: nome, novo valor e valor de teste. Se o valor da variável for igual ao teste um, ela recebe um novo valor e a função retorna verdadeiro, caso contrário retorna falso (o mesmo acontece se a variável não existir).

Nos termos dos princípios de operação, a função é semelhante ao seguinte código:

   double check_value=1;
   double value=2;

   if(GlobalVariableGet("test")==check_value){
      GlobalVariableSet("test",value);
      return(true);
   }
   else {
      return(false);
   }

Se a variável global "test" for igual ao check_value, o valor é atribuído a ela e retorna verdadeiro, caso contrário — falso. A variável check_value tem o valor padrão de 1, de forma que retorna falso no caso da não existência da variável global "test".

O objetivo principal da função GlobalVariableSetOnCondition() é fornecer uma execução consistente de vários EAs. Uma vez que os sistemas operacionais atuais são programas de multitarefas, considerando que cada EA pode ser um segmento separado, ninguém pode garantir que todos os EAs serão capazes de executar todas as suas tarefas um após o outro.

Se você tiver alguma experiência em trabalhar com o MetaTrader 4, você pode se lembrar dos fluxos de negociação ocupados. Agora, vários EAs podem enviar solicitações de negociação ao servidor simultaneamente e elas serão executadas, ao contrário de tempos anteriores, quando apenas um EA era capaz de enviar uma solicitação em um certo momento. Se existissem vários EAs no terminal, um erro de fluxo de tráfego ocupado ocorria frequentemente ao executar operações de mercado. Ao abrir e fechar ordens, o erro era mais como um incômodo, pois os bons EAs repetiam suas tentativas de fechar ou abrir uma posição. Além disso, diferentes EAs abrindo ou fechando posições ao mesmo ponto a tempo, era uma coisa rara. No entanto, se uma função de trailing stop (construída no EA, ao invés do terminal) fosse ativada em vários EAs, apenas um deles seria capaz de modificar o stop loss pelo tick, isto sim era um problema. Apesar de não existir tal situação agora, ainda pode haver tarefas que exigem a execução seqüencial de alguns EAs. 

A referida variável global é utilizada para assegurar o trabalho consistente de um grupo de EAs. No início da execução da função OnTick(), atribua um valor à variável, para os EAs identificarem o que cada um está fazendo, interrompendo a sua função OnTick() ou entrando no ciclo de espera. Depois que um EA conclui todas as ações necessárias, atribuímos o check_value à variável, e assim outro EA poderá executar sua função OnTick(), etc.

O código exibido abaixo é adequado para resolver a tarefa, mas não podemos ter certeza que a string:

if(GlobalVariableGet("test")==check_value){

Será seguida imediatamente pela string: 

GlobalVariableSet("test",value);

Outro EA pode interpor entre eles e começar a trabalhar depois de detectar o check_value. Após a execução parcial da sua tarefa, o primeiro EA pode continuar a operar, assim, dois EAs podem funcionar simultaneamente. A função GlobalVariableSetOnCondition() resolve esse problema. Conforme observado na documentação, a função fornece acesso atômico à variável global". Atômico significa "indivisível". Assim, nenhum outro programa pode interpor durante uma verificação de valor de variável e atribuir um novo valor a ela.

O único inconveniente da função é que ela não cria uma variável se esta última não existir. Isso significa que devemos realizar uma verificação adicional (preferível durante a inicialização do EA) e gerar a variável. 

Vamos escrever os dois EAs para realizar uma experiência. Ambos os EAs são completamente idênticos. A janela com a mensagem "EA1 start" aparece no início da função OnTick(), seguida por uma pausa de três segundos,a função Sleep(). A mensagem "EA1 end" aparece no final:

void OnTick(){
   Alert("EA1 start");   
   Sleep(3000);   
   Alert("EA1 end");
}

O segundo EA é semelhante, embora as mensagens sejam diferentes: "EA2 start" e "EA2 end". Os EAs anexos são denominados eGVTestEA1 e eGVTestEA2. Abra dois gráficos idênticos no terminal e coloque os EAs neles. A janela de mensagem mostra que os EAs iniciam e terminam o trabalho simultaneamente (Fig. 8).


Fig. 8. Mensagens do EA sobre o início e fim da execução da função OnTick()

Agora, vamos aplicar a função GlobalVariableSetOnCondition() para possibiitar uma operação consistente dos EAs. As alterações inseridas são idênticas para ambos os EAs, portanto vamos escrever um código no arquivo incluído. O arquivo é chamado GVTestMutex.mqh (anexado abaixo).

Agora, vamos examinar as funções de arquivo GVTestMutex.mqh. Verifique se a variável global existe durante a inicialização do EA e crie uma se necessário, a função Mutex_Init (). Um único parâmetro - nome da variável - é transmitidaopara a função:

void Init(string name){
   if(!GlobalVariableCheck(name)){
      GlobalVariableSet(name,0);
   }
}

A segunda função (Mutex_Check()) é usada para verificação. Um ciclo aguardando a liberação da variável global é executado na função. Assim que a variável é liberada, a função retorna verdadeiro, e o EA continua executando sua função OnTick(). Se a variável não for liberada dentro de um tempo específico, a função retornará falso. A execução da função OnTick() deve ser interrompida nesse caso:

bool Mutex_Check(string name,int timeout){   
   datetime end_time=TimeLocal()+timeout; // Tempo final de espera
   while(TimeLocal()<end_time){ // dentro de um período específico
      if(IsStopped()){
         return(false); // Se um EA for removido de um gráfico
      }
      if(GlobalVariableSetOnCondition(name,1,0)){ 
         return(true);
      }
      Sleep(1); // pequena pausa
   }   
   return(false); // Falha ao aguardar uma liberação
}

O nome da variável global e o tempo de espera em segundos são transmitidos para a função.

A terceira função é Mutex_Release(). Define o valor 0 para a variável global (relançamento) para que outros EAs possam iniciar seu trabalho:

void Mutex_Release(string name){
   GlobalVariableSet(name,0);
}

Faça uma cópia de um EA, inclua um arquivo e adicione uma chamada de função a ele. O nome da variável é "mutex_test". Vamos chamar a função Mutex_Check() com um tempo limite de 30 segundos. O código completo do EA é exibido abaixo:

#include <GVTestMutex.mqh>

int OnInit(){
   Mutex_Init("mutex_test");
   return(INIT_SUCCEEDED);
}

void OnTick(){

   if(!Mutex_Check("mutex_test",30)){
      return;
   }

   Alert("EA1 start");
   Sleep(3000);
   Alert("EA1 end");

   Mutex_Release("mutex_test");

}

Vamos fazer uma cópia do EA e alterar o texto das mensagens exibidas. Os EAs anexos são denominados eGVTestEA1-2 e eGVTestEA2-2. Lançamento dos EAs em dois gráficos semelhantes para se certificar de que agora trabalham em turnos (Fig. 9).

 
Fig. 9. Os EAs estão trabalhando em turnos

Observe o parâmetro time-out: define o tempo que excede o tempo de operação de todos os EAs no grupo. Pode acontecer que alguns EAs sejam removido de um gráfico durante a execução da função OnTick(), mas a função Mutex_Release() não é executada. Nesse caso, nenhuma EA esperará pelo seu turno. Portanto, para o caso de expiração do tempo limite, devemos definir a variável global como 0 ou descobrir alguma outra maneira de rastreá-la. Isso depende de uma tarefa específica. Às vezes, a operação simultânea dos EAs pode ser aceitável, porém em algunsoutros casos, devem ser executados em turnos.

Classe para facilitar o trabalho com as variáveis globais

Preste atenção aos seguintes pontos para trabalhar com variáveis globais de forma mais eficiente.

  1. São necessários nomes individuais das variáveis para cada cópia do EA.
  2. Os nomes das variáveis usadas no testador devem ser diferentes dos usados na conta.
  3. Se um EA trabalha no testador, o EA deve excluir todas as variáveis criadas durante o teste e após a conclusão de cada teste.
  4. Providenciar uma chamada de funções mais prática para trabalhar com variáveis globais, usando nomes abreviados para as funções.
Ao usar as variáveis globais num EA, é possível dividi-las modo em dois tipos: as comuns e as vinculadas às ordens. As comuns são usados para armazenar alguns dados corriqueiros relacionados à operação do EA: por exemplo, um tempo de algum evento, lucro máximo de um grupo de posições, etc. As variáveis vinculadas a ordens contêm dados adicionais relacionados a uma única ordem (ou posição): por exemplo, índice da ordem na série de progressão do lote, Preço de abertura do pedido, etc. Cada pedido tem seu próprio índice - o ticket. Portanto, apenas precisamos formar um nome a partir do ticket de ordem e a parte que define o nome dos dados salvos na variável (por exemplo, "index", "price"). O ticket de ordem é uma variável de tipo ulong com o comprimento máximo de 20 caracteres, enquanto o comprimento máximo da variável é de 63 caracteres, o que significa que ainda temos 43 caracteres.

A situação é um pouco mais complicada quando se formam nomes para variáveis comuns. Vamos fazer uma estimativa aproximada do possível comprimento da variável. O primeiro atributo que podemos usar para separar as variáveis de um EA a partir de outro é através do nome, consistindo de, digamos, 20 caracteres. Os mesmos EAs podem funcionar em símbolos diferentes. Isso significa que o segundo recurso exclusivo é um símbolo (mais 4 caracteres). Os EAs que trabalham em um único símbolo têm identificações de pedido diferentes - números mágicos de tipos ulong (comprimento máximo - 20 caracteres). É possível alternar entre contas a partir de um único terminal. O número de uma conta é uma variável de tipo long (comprimento máximo - 19 caracteres). Totalmente, recebemos 63 caracteres, que abrange todo o comprimento da variável permitida, e atingimos apenas o comprimento do prefixo!

Isso significa que temos que sacrificar algo. Vamos seguir a regra: um terminal só funciona com uma conta. Se você tiver várias contas, defina uma instância do terminal para cada uma. Isso significa que podemos excluuir o número da conta, com o tamanho máximo do prefixo reduzindo para 43 caracteres e liberando 20 caracteres. Podemos acrescentar ainda outra regra: não use números mágicos longos Finalmente, seria sensato prestar atenção aos nomes da EA, dando-lhes nomes mais curtos. O nome de uma variável global formada a partir do nome de um EA, o símbolo e o número mágico podem ser considerados aceitáveis. Talvez, você consiga chegar a uma forma mais prática de formar nomes, mas vamos ficar com este método neste artigo.

Vamos começar a escrever uma classe. A classe é denominada CGlobalVariables, o próprio arquivo é chamado de CGlobalVariables.mqh e anexado abaixo. Declare duas variáveis para prefixos na seção 'private': a primeira - para as variáveis comuns, a segunda - para as ligadas às ordens:

class CGlobalVariables{
   private:
      string m_common_prefix; // Prefixo de variáveis comuns
      string m_order_prefix; // Prefixo de variáveis de ordem
   public:
      // construtor
      void CGlobalVariables(){}
      // destrutor
      void ~CGlobalVariables(){}
}

Vamos criar o método Init() na seção 'pública'. O método deve ser chamado durante a inicialização de um EA. Os dois parâmetros - símbolo e número mágico - devem passar para ele. Os prefixos devem ser formados neste método. Os prefixos das variáveis da ordem são simples, pois você apenas precisa separar as variáveis do EA, trabalhando na conta a partir de um EA rodando no testador. Assim, as variáveis da ordem na conta começam com "order_", enquanto os testadores - com "tester_order_". Apenas "t_" pode ser adicionado ao prefixo de variáveis comuns no testador (uma vez que eles são únicos, além de que devemos usar os caracteres com moderação). Variáveis globais antigas também devem ser excluídas durante a inicialização no testador. Claro, elas devem ser excluídas durante a desinicialização também, mas não podemos ter certeza nos resultados do teste, pois as variáveis podem permanecer. Por enquanto, vamos criar o método DeleteAll() e chamá-lo. Eu recomendo colocar o método na seção 'privada'. O código para esta finalidade será adicionado mais tarde. O código do método Init() é exibido abaixo:

void Init(string symbol,int magic){
   m_order_prefix="order_";
   m_common_prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_"+symbol+"_"+IntegerToString(magic)+"_";
   if(MQLInfoInteger(MQL_TESTER)){
      m_order_prefix="tester_"+m_order_prefix;
      m_common_prefix="t_"+m_common_prefix;
      DeleteAll();
   }         
}

Vamos adicionar o método, retornando o prefixo das variáveis comuns, pois pode ser útil para algum trabalho especial envolvendo as variáveis globais:

string Prefix(){
   return(m_common_prefix);
} 

Adicione os métodos básicos: para verificar, definir, receber valores e excluir variáveis separadas. Como temos dois prefixos, devemos ter dois métodos com sobrecarga de nomes para cada função (duas funções com o mesmo nome, mas um conjunto diferente de parâmetros). Somente um parâmetro - o nome da variável - deve ser transmitido para um grupo de métodos. Estes são os métodos para as variáveis comuns. Um ticket e o nome de uma variável são transmitidos para outro grupo de funções. Estes são os métodos para variáveis da ordem:

// Para variáveis comuns
bool Check(string name){
   return(GlobalVariableCheck(m_common_prefix+name));
}
void Set(string name,double value){
   GlobalVariableSet(m_common_prefix+name,value);      
}      
double Get(string name){
   return(GlobalVariableGet(m_common_prefix+name));
} 
void Delete(string name){
   GlobalVariableDel(m_common_prefix+name); 
}
// Para variáveis da ordem
bool Check(ulong ticket,string name){
   return(GlobalVariableCheck(m_order_prefix+IntegerToString(ticket)+"_"+name));
}
void Set(ulong ticket,string name,double value){
   GlobalVariableSet(m_order_prefix+IntegerToString(ticket)+"_"+name,value);      
}      
double Get(ulong ticket,string name){
   return(GlobalVariableGet(m_order_prefix+IntegerToString(ticket)+"_"+name));
} 
void Delete(ulong ticket,string name){
   GlobalVariableDel(m_order_prefix+IntegerToString(ticket)+"_"+name); 
} 

Vamos voltar ao método DeleteAll() e escrever um código para excluir variáveis por prefixos:

GlobalVariablesDeleteAll(m_common_prefix);
GlobalVariablesDeleteAll(m_order_prefix);  

A exclusão pode ser realizada no testador após o teste, então vamos adicionar o método Deinit() que deve ser chamado durante uma desinicialização do EA:

 void Deinit(){
    if(MQLInfoInteger(MQL_TESTER)){
        DeleteByPrefix();
    }
 }

Para melhorar a confiabilidade das variáveis globais, devemos usar a função GlobalVariablesFlush(). Vamos adicionar ainda outro método com a função. É muito mais fácil chamar a classe de método em vez de escrever o nome longo da função (cumprindo os requisitos indicados no ponto 4):

void Flush(){
   GlobalVariablesFlush();
} 

Às vezes, talvez seja necessário combinar variáveis comuns em grupos, adicionando-lhes prefixos adicionais, e então, excluí-las durante uma operação do EA. Vamos adicionar ainda outro método DeletByPrefix():

void DeleteByPrefix(string prefix){
   GlobalVariablesDeleteAll(m_common_prefix+prefix);
}

Como resultado, obtivemos uma funcionalidade de classe suficiente que nos permite resolver 95% das tarefas ao trabalhar com variáveis globais.

Para usar a classe, inclua o seguinte arquivo num EA:

#include <CGlobalVariables.mqh>

Criar um objeto:

CGlobalVariables gv;

Chamar o método Init() durante a inicialização de um EA, transmitindo um símbolo e o número mágico a ele:

gv.Init(Symbol(),123);

Chamar o método Deinit() durante a inicialização para excluir as variáveis do testador:

gv.Deinit();

Depois disso, tudo o que temos que fazer ao desenvolver um EA é usar os métodos Check(), Set(), Get() e Delete(), trnsmitindo-os para uma parte exclusiva do nome da variável, por exemplo:

   gv.Set("name1",123.456);
   double val=gv.Get("name1");

Como resultado da operação do EA, a variável denominada eGVTestClass_GBPJPY_123_name1 aparece na lista das variáveis globais (Fig. 10).

 
Fig. 10. Parte da janela das variáveis globais mostrando a variável criada usando a classe CGlobalVariables

O comprimento da variável é de 29 caracteres, o que significa que estamos relativamente folgados na seleção de nomes das variáveis. Para variáveis de ordem, precisamos transmitir um ticket de ordem, sem a necessidade de formar constantemente um nome completo e chamar a função IntegerToSTring() para converter um ticket em uma linha, simplificando assim bastante o uso das variáveis globais. Um exemplo do uso da classe está disponível no EA eGVTestClass anexado abaixo.

Também é possível alterar ligeiramente a classe para simplificar ainda mais sua utilização. Agora, é hora de melhorar o construtor e destrutor de classe. Vamos adicionar a chamada do método Init() ao construtor com os parâmetros apropriados e a chamada do método Deinit() para o destrutor:

void CGlobalVariables(string symbol="",int magic=0){
   Init(symbol,magic);
}
// destrutor
void ~CGlobalVariables(){
   Deinit();
}

Depois disso, não há necessidade de chamar os métodos Init() e Deinit(). Em vez disso, só precisamos especificar um símbolo e um número mágico ao criar uma instância de classe:

CGlobalVariables gv(Symbol(),123);

Conclusão

Neste artigo, examinamos todas as funções para trabalhar com as variáveis globais do terminal, incluindo a função GlobalVariableSetOnCondition(). Também criamos uma classe simplificando significativamente o uso das variáveis globais ao criar EAs. É claro que a classe não inclui todos os recursos relacionados ao trabalho com variáveis globais, mas tem os mais necessários e freqüentemente usados. Você pode sempre melhorar ou desenvolver a sua própria classe, se necessário. 

Anexos

  • sGVTestCreate — Criando uma variável.
  • sGVTestGet1 — Primeiro método para receber um valor.
  • sGVTestGet2  — Segundo método para receber um valor.
  • sGVTestGet1-2 — Primeiro método para receber um valor de uma variável inexistente.
  • sGVTestGet2-2 — Segundo método para receber um valor de uma variável inexistente.
  • sGVTestCheck — Verificando a existência de uma variável.
  • sGVTestTime — Recebendo uma variável de tempo.
  • sGVTestAllNames — Recebendo a lista de nomes de todas as variáveis.
  • sGVTestAllNames2 — Recebendo a lista de nomes com um prefixo especificado.
  • sGVTestDelete — Excluir uma variável.
  • sGVTestCreate4 — Criando as quatro variáveis (dois grupos com duas variáveis cada).
  • sGVTestDeleteGroup — Excluindo um grupo de variáveis.
  • sGVTestFlush — Salvamento forçado das variáveis.
  • sGVTestTemp — Criando uma variável temporária.
  • eGVTestEA1, eGVTestEA2 — Demonstrando uma operação simultânea de EAs.
  • GVTestMutex.mqh — Funções para o desenvolvimento do Mutex.
  • eGVTestEA1-2, eGVTestEA1-2 — Demonstrando EAs trabalhando em turnos.
  • CGlobalVariables.mqh — Classe CGlobalVariables para trabalhar com variáveis globais.
  • eGVTestClass — EA demonstrando como usar a classe CGlobalVariables.



Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/2744

Arquivos anexados |
files.zip (10.44 KB)
Distribuições estatísticas em forma de histogramas sem buffers de indicador e matrizes Distribuições estatísticas em forma de histogramas sem buffers de indicador e matrizes
O artigo considera a possibilidade de criar histogramas, distribuições estatísticas das características do mercado usando memória gráfica, ou seja, sem o uso de buffers de indicador e matrizes. Aqui você tem à sua disposição não só exemplos detalhados de como construir esses histogramas, mas também pode conhecer a funcionalidade "oculta" dos objetos gráficos da linguagem MQL5.
Oscilador universal com interface gráfica do usuário Oscilador universal com interface gráfica do usuário
No artigo, descreve-se a criação de um indicador universal baseado em todos os osciladores do terminal com uma interface gráfica do usuário própria. Isto permite rápida e facilmente alterar os parâmetros de cada oscilador individual diretamente a partir da janela do gráfico (em vez de abrir a janela de opções), comparar seu desempenho e selecionar a melhor opção para uma tarefa específica.
Como desenvolver e testar uma estratégia para Opções Binárias com o Testador de Estratégia do MetaTrader 4 Como desenvolver e testar uma estratégia para Opções Binárias com o Testador de Estratégia do MetaTrader 4
Tutorial para desenvolver uma estratégia para Opções Binárias e testa-la no Testador de Estratégia do MetaTrader 4 com o utilitário do Mercado Binary-Options-Strategy-Tester.
LifeHack para traders: relatório comparativo de vários testes LifeHack para traders: relatório comparativo de vários testes
No artigo, é tratada a execução simultânea do teste de Experts em quatro símbolos diferentes. A comparação final dos quatro relatórios respetivos é realizada numa tabela, como seria feito durante a seleção de produtos numa loja. Uma vantagem adicional consiste na geração automática de gráficos de distribuição para cada símbolo.