English Русский 中文 Español Deutsch 日本語
Os Erros Mais Comuns nos Programas MQL4 e Como Evitá-los

Os Erros Mais Comuns nos Programas MQL4 e Como Evitá-los

MetaTrader 4Exemplos | 3 julho 2015, 17:07
5 142 0
MetaQuotes
MetaQuotes

Introdução

Alguns programas mais antigos podem retornar erros na nova versão do compilador MQL4.

Para evitar o término dos programas por erros críticos, a versão anterior do compilador tratava muitos erros no ambiente de tempo de execução. Por exemplo, a divisão por zero ou o array fora do intervalo são erros críticos, que geralmente levam a uma falha do aplicativo. Esses erros ocorrem somente em algumas condições para determinados valores das variáveis. Leia este artigo para saber como lidar com essas situações.

O novo compilador pode detectar a origem real ou potencial dos erros e melhorar a qualidade do código.

Neste artigo, discutimos os possíveis erros que podem ser detectados durante a compilação de programas antigos e as maneiras de corrigi-los.

  1. Erros de Compilação
  2. Erros de Tempo de Execução
  3. Avisos do Compilador

1. Erros de Compilação

Se o código do programa contiver erros, ele não poderá ser compilado.

Para o controle pleno de todos os erros, recomenda-se a utilização do modo de compilação estrito, que é definido na diretiva a seguir:

#property strict

Este modo simplifica muito a solução de problemas.


1.1. O Identificador coincide com uma palavra reservada

Se o nome de uma variável ou função coincide com uma das palavras reservadas

int char[];  // incorreto
int char1[]; // correto
int char()   // incorreto
{
 return(0);
}

o compilador retorna uma mensagem de erro:

Figura 1. Erros "unexpected token" e "name expected"

Figura 1. Erros "unexpected token" e "name expected"

Para corrigir esse erro, você precisará usar o nome correto da variável ou da função.


1.2. Caracteres especiais nos nomes de variáveis ​​e funções

Se os nomes das variáveis ​​ou funções contêm caracteres especiais ($, @, ponto):

int $var1; // incorreto
int @var2; // incorreto 
int var.3; // incorreto
void f@()  // incorreto
{
 return;
}

o compilador retorna uma mensagem de erro:

Figura 2. Erros "unknown symbol" e "semicolon expected"

Figura 2. Erros "unknown symbol" e "semicolon expected"

Para corrigir esse erro, você precisará usar a função ou os nomes das variáveis corretos.


1.3. Erros usando o operador switch

Na versão antiga do compilador você podia usar quaisquer valores nas expressões e constantes do operador switch:

void start()
  {
   double n=3.14;
   switch(n)
     {
      case 3.14: Print("Pi");break;
      case 2.7: Print("E");break;
     }
  }

No novo compilador, as constantes e expressões do operador switch deve ser de inteiros, assim, os erros ocorrem quando você tenta usar tais construções:

Figura 3. Erros "illegal switch expression type" e "constant expression is not integral"

Figura 3. Erros "illegal switch expression type" e "constant expression is not integral"

Nesses casos, você pode usar a comparação explícita de valores numéricos, por exemplo:

void start()
  {
   double n=3.14;
   if(n==3.14) Print("Pi");
   else
      if(n==2.7) Print("E");
  }

1.4. Valores de retorno das funções

Todas as funções, exceto a void, devem retornar o valor do tipo declarado. Por exemplo:

int function()
{
}

Ela ocorre um erro no modo de compilação estrita:


Figura 4. Erro "not all control paths return a value"

Figura 4. Erro "not all control paths return a value"

No modo de compilação padrão, o compilador retorna um aviso:

Figura 5. Aviso "not all control paths return a value"

Figura 5. Aviso "not all control paths return a value"

Se o valor de retorno da função não corresponde com a declarada:

int init()                         
  {
   return;                          
  }

um erro é detectado durante a compilação estrita:

Figura 6. Erro "function must return a value"

Figura 6. Erro "function must return a value"

No modo de compilação padrão, o compilador retorna um aviso:

Figura 7. Aviso 'return - function must return a value"

Figura 7. Aviso 'return - function must return a value"

Para corrigir esses erros, adicione o operador return com o valor de retorno do tipo correspondente ao código da função.



1.5. Arrays em argumentos da função

Agora, nos argumentos da função, os arrays são passados apenas ​​por referência.

double ArrayAverage(double a[])
{
 return(0);
}
No modo de compilação estrita, esse código irá causar um erro:

Figura 8. Erro do compilador "arrays passed by reference only"

Figura 8. Erro do compilador "arrays passed by reference only"

No modo de compilação padrão, o compilador retorna um aviso:

Figura 9. Aviso do compilador "arrays passed by reference only"

Figura 9. Aviso do compilador "arrays passed by reference only"

Para corrigir esse erro, você deve especificar explicitamente que o array é passado por referência, acrescentando o prefixo & antes do nome do array:

double ArrayAverage(double &a[])
{
 return(0);
}

Deve-se notar que agora os arrays de constantes (Time[], Open[], High[], Low[], Close[], Volume[]) não podem ser passados por referência. Por exemplo, a seguinte chamada:

ArrayAverage(Open);

independentemente do modo de compilação, ela nos leva a um erro:

Figura 10. Erro 'Open' - constant variable cannot be passed as reference

Figura 10. Erro 'Open' - constant variable cannot be passed as reference

Para evitar esses erros, copie os dados necessários a partir do array de constante:

   //--- Um array que armazena os valores de preços de abertura
   double OpenPrices[];
   //--- Copia os valores dos preços de abertura para o array OpenPrices[]
   ArrayCopy(OpenPrices,Open,0,0,WHOLE_ARRAY);
   //--- Chamada da função
   ArrayAverage(OpenPrices);



2. Erros de Tempo de Execução

Os erros que ocorrem durante a execução do código do programa são chamados de erros em tempo de execução. Tais erros geralmente dependerá do estado de um programa e está associado com valores incorretos das variáveis.

Por exemplo, se uma variável é usada como um índice de elementos do array, os seus valores negativos conduziram inevitavelmente ao erro do Array fora do intervalo.


2.1. Array fora do Intervalo

Este erro ocorre frequentemente em indicadores ao acessar os buffers dos indicadores. A função IndicatorCounted() retorna o número de barras inalteradas desde a última chamada do indicador. Os valores dos indicadores nas barras previamente calculadas não precisam de novos cálculos, assim, para cálculos mais rápidos você só precisa processar as últimas barras.

A maioria dos indicadores que utilizam este método de otimização de cálculo se parece como este:

//+------------------------------------------------------------------+
//| Função de iteração do indicador personalizado                    |
//+------------------------------------------------------------------+
int start()
  {
   //--- Alguns cálculos não necessitam mais que N barras (por exemplo, 100)      
   if (Bars<100) // Se menos barras estão disponíveis em um gráfico (por exemplo, no período MN)
     return(-1); // Para o cálculo e sai

   //--- O número de barras que não mudaram desde a última chamada do indicador
   int counted_bars=IndicatorCounted();
   //--- Sai se tiver ocorrido um erro
   if(counted_bars<0) return(-1);
      
   //--- Posição da barra em que o cálculo no loop começa
   int limit=Bars-counted_bars;

   //--- Se counted_bars = 0, reduz a posição de partida no loop por 1,   
   if(counted_bars==0) 
     {
      limit--;  // Para evitar o problema em que o array fique fora do intervalo quando counted_bars == 0
      //--- Nós usamos um deslocamento de 10 barras para trás no histórico, assim, ele adiciona essa mudança durante o primeiro cálculo
      limit-=10;
     }
   else// --- O indicador já foi calculado, counted_bars > 0
     {     
      //--- Para chamadas repetidas aumente o limite de 1 para atualizar os valores do indicador para a último barra
      limit++;
     } 
   //--- O loop principal do cálculo
   for (int i=limit; i>0; i--)
   {
     Buff1[i]=0.5*(Open[i+5]+Close[i+10]) // são usados os valores das barras das 5 e 10 barras mais profundas do histórico
   }
}

Muitas vezes, o caso de counted_bars == 0 é manuseado incorretamente (a posição limite inicial deve ser reduzida pelo valor igual a 1 + índice máximo relativo à variável loop).

Além disso, lembre-se que, no momento da execução da função start() nós podemos acessar os elementos do arrays dos buffers do indicador de 0 a Bars()-1. Se você precisa trabalhar com os arrays que não são buffers de indicadores, aumente o seu tamanho usando a função ArrayResize() de acordo com o tamanho atual dos buffers de indicadores. O índice máximo do elemento de endereço também pode ser obtido através da chamada ArraySize() com um dos buffers dos indicadores utilizadas como um argumento.


2.2. Divisão por zero

O erro da divisão por zero ocorre quando um divisor em uma operação de divisão é igual a zero:

void OnStart()
  {
//---
   int a=0, b=0,c;
   c=a/b;
   Print("c=",c);
  }

Quando você executar este script, uma mensagem de erro aparecerá na guia Experts e o programa é encerrado:

Figura 11. Mensagem de erro "zero divide"

Figura 11. Mensagem de erro "zero divide"

Geralmente este erro ocorre quando o valor do divisor é determinado pelos valores de quaisquer dados externos. Por exemplo, se os parâmetros de negociação são analisados, o valor da margem utilizada é igual a 0 se não há ordens em aberto. Outro exemplo: se os dados analisados ​​são lidos a partir de um arquivo, nós não podemos garantir o funcionamento correto se o arquivo não está disponível. Assim, você deve levar em conta esses casos e processá-los corretamente.

A maneira mais fácil é verificar o divisor antes da operação de divisão e relatar um valor de parâmetro incorreto:

void OnStart()
  {
//---
   int a=0, b=0,c;
   if(b!=0) {c=a/b; Print(c);}
   else {Print("Error: b=0"); return; };
  }

Isso não causa um erro crítico, mas uma mensagem sobre o valor do parâmetro incorreto aparecerá e o programa é encerrado:

Figura 12. Mensagem incorreta do divisor

Figura 12. Mensagem incorreta do divisor


2.3. Use de 0 em vez de NULL para o caractere atual

Na versão antiga do compilador, o 0 (zero) pode ser utilizado como argumento em funções que requerem especificação de um instrumento financeiro.

Por exemplo, o valor do indicador técnico Média Móvel para o símbolo atual poderá ser solicitado como se segue:

AlligatorJawsBuffer[i]=iMA(0,0,13,8,MODE_SMMA,PRICE_MEDIAN,i);    // incorreto

No novo compilador você deve especificar explicitamente o valor NULL para o símbolo atual:

AlligatorJawsBuffer[i]=iMA(NULL,0,13,8,MODE_SMMA,PRICE_MEDIAN,i); // correto

Além disso, o símbolo atual e o período do gráfico pode ser especificado usando as funções Symbol() e Period().

AlligatorJawsBuffer[i]=iMA(Symbol(),Period(),13,8,MODE_SMMA,PRICE_MEDIAN,i); // correto


2.4. Strings no formato Unicode e seu uso em uma DLL

Agora, as strings são representadas como uma sequência de caracteres Unicode.

Lembre-se disso e utilize as funções apropriadas do Windows. Por exemplo, quando se usa a biblioteca wininet.dll em vez da InternetOpenA() e InternetOpenUrlA(), você deve chamar a InternetOpenW() e InternetOpenUrlW().

A estrutura interna das strings foi alterada no MQL4 (agora ela leva 12 bytes), e a estrutura MqlString deve ser usada ao passar as strings para DLL:

#pragma pack(push,1)
struct MqlString
  {
   int      size;       // inteiro de 32 bit, contém o tamanho da memória alocada para a string
   LPWSTR   buffer;     // endereço de 32 bit do buffer que contém a string
   int      reserved;   // inteiro de 32 bit, reservado, não utilizar
  };
#pragma pack(pop,1)


2.5. Compartilhamento de arquivos

Na nova MQL4, as flags FILE_SHARE_WRITE e FILE_SHARE_READ devem ser explicitamente especificadas para uso compartilhado ao abrir os arquivos.

Se as flags estão ausentes, o arquivo é aberto no modo exclusivo, não podendo ser aberto por qualquer outra pessoa até que ela seja fechada pelo usuário que abriu.

Por exemplo, quando se trabalha com gráficos offline as flags de compartilhamento devem ser explicitamente especificadas:

   // Primeira mudança - adicione as flags de compartilhamento
   ExtHandle=FileOpenHistory(c_symbol+i_period+".hst",FILE_BIN|FILE_WRITE|FILE_SHARE_WRITE|FILE_SHARE_READ);

Para maiores informações, por favor leia Offline Charts in the New MQL4.


2.6. Conversão da Datetime

Agora, a conversão da datetime para uma string depende do modo de compilação:

  datetime date=D'2014.03.05 15:46:58';
  string str="mydate="+date;
//--- str="mydate=139403 - compilador antigo, nenhuma diretiva #property estrita no novo compilador
//--- str="mydate=2014.03.05 15:46:58" - novo compilador com a diretiva #property estrita

Por exemplo, tentar trabalhar com ficheiros cujo nome contém uma vírgula, causaria um erro.


3. Avisos do Compilador

Os Avisos do Compilador são de caráter informativo e não são mensagens de erro, mas eles indicam as possíveis origens do erro.

Um código claro não devem conter avisos.


3.1. Nomes das variáveis ​​globais e locais iguais

Se as variáveis ​​nos níveis globais e locais têm os mesmos nomes:

int i; // Uma variável global
void OnStart()
  {
//---
   int i=0,j=0; // variáveis locais
   for (i=0; i<5; i++) {j+=i;}
   PrintFormat("i=%d, j=%d",i,j);
  }

o compilador exibe um aviso que mostra o número da linha em que a variável global foi declarada:

Figura 13. Aviso "declaration of '%' hides global declaration at line %"

Figura 13. Aviso "declaration of '%' hides global declaration at line %"

Para corrigir tais advertências corrija os nomes das variáveis ​​globais.


3.2. Incompatibilidade de Tipos

O novo compilador tem um nova operação typecasting.

#property strict
void OnStart()
  {
   double a=7;
   float b=a;
   int c=b;
   string str=c;
   Print(c);
  }

No modo de compilação estrito o compilador mostra avisos se há incompatibilidade de tipos:

Figura 14. Avisos "possible loss of data due to type conversion" e "implicit conversion from 'number' to 'string'

Figura 14. Avisos "possible loss of data due to type conversion" e "implicit conversion from 'number' to 'string'

Neste exemplo, o compilador avisa sobre uma possível perda de precisão para os diferentes tipos de dados atribuídos e converte implicitamente de int para string.

Para corrigir o aviso use o typecasting explícito:

#property strict
void OnStart()
  {
   double a=7;
   float b=(float)a;
   int c=(int)b;
   string str=(string)c;
   Print(c);
  }

3.3. Variáveis ​​não utilizadas

A presença de variáveis ​​que não são usados ​​no código do programa (entidades supérfluas) não é um bom hábito.

void OnStart()
  {
   int i,j=10,k,l,m,n2=1;
   for(i=0; i<5; i++) {j+=i;}
  }

Os relatos de tais variáveis ​​são exibidos, independentemente do modo de compilação:

Figura 15. Aviso "variable '%' not used'

Figura 15. Aviso "variable '%' not used"

Para corrigi-lo, remova as variáveis ​​não utilizadas de seu código.


Conclusões

O artigo descreve os problemas mais comuns, que podem ocorrer durante a compilação de programas antigos que contêm erros.

Em todos os casos, recomenda-se usar o modo de compilação estrito para a depuração do programa.


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

Ideias de Negociação Baseada na Direção dos Preços e na Velocidade do Movimento Ideias de Negociação Baseada na Direção dos Preços e na Velocidade do Movimento
O artigo fornece uma revisão de uma idéia com base na análise da direção do movimento dos preços e sua velocidade. Nós efetuamos a sua formalização na linguagem MQL4 apresentando-o como um Expert Advisor para explorar a viabilidade da estratégia que está em consideração. Nós também determinamos os melhores parâmetros por meio da verificação, examinação e da otimização de um exemplo dado no artigo.
Dicas para Escolher um Sinal de Negociação para Assinar. Guia Passo-a-Passo Dicas para Escolher um Sinal de Negociação para Assinar. Guia Passo-a-Passo
Este guia passo-a-passo é dedicado ao serviço de Sinais, examinação dos sinais de negociação, uma abordagem de sistema para a busca de um sinal desejado, que satisfaça os critérios de rentabilidade, risco, ambições de negociação, trabalhando em vários tipos de contas e instrumentos financeiros.
Programando os Modos do EA Usando a Abordagem Orientada a Objetos Programando os Modos do EA Usando a Abordagem Orientada a Objetos
Este artigo explica a idéia da programação multi-modo de um robô de negociação em MQL5. Cada modalidade é implementada com a abordagem orientada a objetos. São fornecidos as instâncias de ambos os modos de hierarquias de classe e das classes para testes. A programação multi-modo de robôs de negociação presumi-se levar em conta todas as peculiaridades de cada modo operacional de um EA escrito em MQL5. Funções e enumerações são criadas para identificar o modo.
Dicas para Comprar um Produto no Mercado. Guia Passo-a-Passo Dicas para Comprar um Produto no Mercado. Guia Passo-a-Passo
Este guia passo-a-passo fornece dicas e truques para uma melhor compreensão e na procura de um produto desejado. O artigo faz uma tentativa de decifrar os diferentes métodos de busca para um produto adequado, filtrando produtos indesejados, determinando a eficiência do produto e a essencialidade para você.