Erro 'array out of range'

 

Tenho um código de EA que utiliza duas faixas de tempo, uma D1 e outra definida pelo usuário.

Ao executar ele devia pegar o fechamento do dia anterior, no array D1, e com isso calcular e colocar ordens no dia seguinte.

O problema é que quando mando executar retorna o erro "array out of range" e enseguida: "OnTick critical error". Após isso, ele fecha o EA.

O que pode estar causando isso? Se precisa envio cópia do código criado.

Obrigado

Pablo

 
Juan Pablo Silenzi de Stagni:

Tenho um código de EA que utiliza duas faixas de tempo, uma D1 e outra definida pelo usuário.

Ao executar ele devia pegar o fechamento do dia anterior, no array D1, e com isso calcular e colocar ordens no dia seguinte.

O problema é que quando mando executar retorna o erro "array out of range" e enseguida: "OnTick critical error". Após isso, ele fecha o EA.

O que pode estar causando isso? Se precisa envio cópia do código criado.

Obrigado

Pablo

Boa noite Juan,

isso acontece quando você tenta acessar uma posição do array que não existe. Pode ser que a causa esteja na manipulação incorreta da função CopyClose ou CopyRates, que por algum motivo não está preenchendo o seu array.

Eu separei dois artigos que podem ser úteis para você:

https://www.mql5.com/pt/articles/567 - Arrays

https://www.mql5.com/pt/articles/496 - Exemplo com a função CopyClose

Fique a vontade em postar o pedaço do código onde aconteceu o erro, desse modo facilita a identificação do erro pela comunidade.

Um abraço,

Romeu. 

Fundamentos básicos da programação MQL5: Arrays
Fundamentos básicos da programação MQL5: Arrays
  • 2014.03.18
  • Dmitry Fedoseev
  • www.mql5.com
Juntamente com as variáveis e funções, os arrays são partes integrais de quase todas as linguagens de programação. O artigo deve ser de interesse principalmente para programadores MQL5 novatos, enquanto os desenvolvedores mais experientes terão uma boa oportunidade para resumir e sistematizar seu conhecimento.
 
Romeu Bertho:

Boa noite Juan,

isso acontece quando você tenta acessar uma posição do array que não existe. Pode ser que a causa esteja na manipulação incorreta da função CopyClose ou CopyRates, que por algum motivo não está preenchendo o seu array.

Eu separei dois artigos que podem ser úteis para você:

https://www.mql5.com/pt/articles/567 - Arrays

https://www.mql5.com/pt/articles/496 - Exemplo com a função CopyClose

Fique a vontade em postar o pedaço do código onde aconteceu o erro, desse modo facilita a identificação do erro pela comunidade.

Um abraço,

Romeu. 

Valeu, vou verificar os artigos!

 

Romeu Bertho, Olha o código ai.

//+------------------------------------------------------------------+
//|                                                    Marquito1.mq5 |
//|                                                          Pablito |
//|                 www.linkedin.com/in/juan-pablo-silenzi-de-stagni |
//+------------------------------------------------------------------+
#property copyright "Pablito"
#property link      "www.linkedin.com/in/juan-pablo-silenzi-de-stagni"
#property version   "1.00"
//#include <Trade\Trade.mqh>

//--- input parameters
string Papel=Symbol();
//input string      Papel = Ativo;                         //Papel do Gráfico
input int         PontosVenda = 10;                      //Pontos para Venda
input int         PontosCompra = 10;                     //Pontos para Compra
input int         DefesaVenda = 30;                      //Pontos para a Defesa da Venda
input int         DefesaCompra = 30;                     //Pontos para a Defesa da Compra
input int         DesvioDefesa = 2;                      //Desvio do Take Profit na Defesa
input double      Lot = SYMBOL_VOLUME_MIN;               // Volume a Negociar

int               EA_Magic = 7585577;                    // EA Magic Number


//Variáveis de trabalho D1

double            TKP1;                                  //Valor do Take Profit do 1o Nível da Ordem 1
double            TKP2;                                  //Valor do Take Profit do 10 Nível da Ordem 2
double            TKPV;                                  //Valor do Take Profit da Venda do 2o Nível
double            TKPC;                                  //Valor do Take Profit da Compra do 2o Nível

int               CloseHandle;                           //Handle para os precos de fechamento D1
double            CloseVal[];                            //Array para conter os valores dos fechamentos D1
double            p_close;                               //Variável para gravar o valor do fechamento do candle anterior D1
long              position_type;                         //Tipo de posição
static datetime   Old_Time_D1;                           //Variável Estática para gravar o valor da barra de fechamento do dia anterior
datetime          New_Day[1];
bool              IsNewDay=false;
static datetime   Old_Time_M1;                 
datetime          New_Time[1];
bool              IsNewBar=false;
bool              OrdemColocadaNoDia=false;
bool              PrimeiraOrdem=false;
bool              SegundaOrdem=false;
ulong             IDOrdem1=0;
ulong             IDOrdem2=0;
ulong             IDOrdem3=0;
ulong             IDOrdem4=0;
bool              OrdensDeletadas=false;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
  
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   // Temos suficientes barras para trabalhar?
   if(Bars(_Symbol,_Period)<30) // se o total for menor que 30
     {
      Alert("Temos menos de 30 barras, não se pode trabalhar!!");
      return;
     }
//--- analisa a situação
//--- verifica se existe ordem colocada
   if(PositionSelect(_Symbol)==true)
     {
      position_type=PositionGetInteger(POSITION_TYPE); // COMPRAR=0, VENDER=1
     }
   else
     {
      position_type=-1; // sem posição para o símbolo
     }

//--- Temos barras suficientes para trabalhar?
   int Mybars=Bars(_Symbol,PERIOD_D1);
   if(Mybars<1) // se o total de barras for menor que 1
     {
      Alert("Não temos barras, não se pode trabalhar!!");
      return;
     }
 

// Utilizaremos a variável estática Old_Time_D1 para servir o tempo da barra D1
// A cada OnTick iremos checar o tempo da barra comparando com o tempo salvo
// Se o tempo não for igual, indicará um novo dia.

// copiar a hora da ultima barra no elemento New_Day[0]

   int dia = CopyTime(_Symbol,PERIOD_D1,0,1,New_Day);
   if(dia>0)
      {
         if(Old_Time_D1!=New_Day[0]) // Se Old_Time_D1 diferente do dia da nova barra
            {
               IsNewDay=true;
               OrdemColocadaNoDia=false;
               PrimeiraOrdem=false;
               SegundaOrdem=false;
               OrdensDeletadas=false;
               if(MQL5InfoInteger(MQL5_DEBUGGING)) Print("Nova barra aquí em ",New_Day[0]," antes era em ",Old_Time_D1);
               Old_Time_D1=New_Day[0];
            }  
      }
    else
      {
         Alert("Erro ao copiar os dados históricos, error =",GetLastError());
         ResetLastError();
         return;
      }


// Pegar o fechamento do dia anterior

   ArrayResize(CloseVal,1);
   ArraySetAsSeries(CloseVal,true);
   CopyClose(_Symbol,PERIOD_D1,0,1,CloseVal);

     
double            FechamentoDiaAnterior = CloseVal[1];
double            VendaEm = FechamentoDiaAnterior + (PontosVenda * _Point);         //Valor da Venda
double            DefesaVendaEm = FechamentoDiaAnterior + (DefesaVenda * _Point);   //Valor da Defesa da Venda
double            CompraEm = FechamentoDiaAnterior - (PontosCompra * _Point);       //Valor da Compra
double            DefesaCompraEm = FechamentoDiaAnterior - (DefesaCompra * _Point); //Valor da Defesa da Compra
                  TKP1 = CompraEm;                                                  //Valor do Take Profit do 1o Nível da Ordem 1
                  TKP2 = VendaEm;                                                   //Valor do Take Profit do 1o Nível da Ordem 2
                  TKPV = VendaEm - (DesvioDefesa * _Point);                         //Valor do Take Profit da Venda do 2o Nível
                  TKPC = CompraEm + (DesvioDefesa * _Point);                        //Valor do Take Profit da Compra do 2o Nível
  

// Utilizaremos a variável estática Old_Time_M1 para servir o tempo da barra M1
// A cada OnTick iremos checar o tempo da barra comparando com o tempo salvo
// Se o tempo não for igual, indicará um novo tick.

// copiar a hora da ultima barra no elemento New_Time[0]
   int Tempo = CopyTime(_Symbol,_Period,0,1,New_Time);
   if(Tempo>0) // copia de dados OK
     {
      if(Old_Time_M1!=New_Time[0]) // se Old_Time_M1 diferente da hora da nova barra
        {
         IsNewBar=true;   // se não for a primeira chamada, uma nova barra apareceu
         if(MQL5InfoInteger(MQL5_DEBUGGING)) Print("Nova barra aquí em ",New_Time[0]," antes era em ",Old_Time_M1);
         Old_Time_M1=New_Time[0];            // salva a hora da barra
        }
     }
   else
     {
      Alert("Erro ao copiar os dados históricos, error =",GetLastError());
      ResetLastError();
      return;
     }

//--- EA somente checa por operações se houver uma barra nova
   if(IsNewBar==false)
     {
      return;
     }
 

//--- Definir estruturas MQL5 que usaremos nas operações
   MqlTick latest_price;      // Usado para obter as ultimas cotações de preços
   MqlRates mrate[];          // Usado para guardar os preços, volumes e spread de cada barra

//   datetime          DiaAtual;
//   datetime          DataAtual;

//--- Obter o último preço cotado usando a estrutura MQL5 MqlTick
   if(!SymbolInfoTick(_Symbol,latest_price))
     {
      Alert("Erro ao obter a última cotação - preço - erro:",GetLastError(),"!!");
      return;
     }
    
//--- obter os detalhes das duas ultimas barras
   if(CopyRates(_Symbol,_Period,0,2,mrate)<0)
     {
      Alert("Erro ao obter os dados das últimas barras - erro:",GetLastError(),"!!");
      return;
     }

//--- Sem erros, continuar
//--- Temos posições abertas já?
    bool Buy_opened=false;  // variável para guardar a posição de uma COMPRA
    bool Sell_opened=false; // variável para guardar a posição de uma VENDA
   
    if (PositionSelect(_Symbol) ==true)  // posição aberta
      {
         if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         {
            Buy_opened = true;  //É uma compra
         }
         else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
         {
            Sell_opened = true; // É uma venda
         }
      }

// Copiar o preço de fechamento da barra prévia à barra atual, isto é barra 1.

   p_close=mrate[0].close;  // fechamento da barra 0

   if (IsNewDay==true)
      {
         IsNewDay=false;
         if (OrdemColocadaNoDia==false)
            {
               //Definir chamada de colocação das 4 ordens pendentes
               // Ordem 1
               func_send_order(ORDER_TYPE_SELL,Lot,VendaEm,CompraEm,1, TKP1);
               // Ordem 2
               func_send_order(ORDER_TYPE_BUY,Lot,VendaEm,CompraEm,2, TKP2);
               OrdemColocadaNoDia=true;
            }
         else
            {
               //Verificar preços e se houve realizado.
               //Caso chegou na 1a Ordem (qqr uma), deletar as ordens pendentes de signo invertido
               if (p_close >= VendaEm || p_close<=CompraEm)
                  {
                     PrimeiraOrdem=true;
                     if (p_close>=VendaEm && p_close<=DefesaVendaEm)
                        {
                           // Deletar ordens de compra no servidor
                           func_delete_order(IDOrdem2);
                           IDOrdem2=0;
                           OrdensDeletadas=true;
                        }
                     else if (p_close<=CompraEm && p_close>=DefesaCompraEm)
                        {
                           // Deletar ordens de venda no servidor
                           func_delete_order(IDOrdem1);
                           IDOrdem1=0;
                           OrdensDeletadas=true;
                        }
                     else if (p_close>=VendaEm && p_close>=DefesaVendaEm)
                        {
                           SegundaOrdem=true;
                           func_send_order(ORDER_TYPE_SELL,Lot,DefesaVendaEm,DefesaCompraEm,3, TKPV);
                          
                           // Deletar ordens de compra no servidor
                           if(IDOrdem2!=0)
                              {
                                 func_delete_order(IDOrdem2);
                                 IDOrdem2=0;
                              }
                           OrdensDeletadas=true;
                         
                        }
                     else if (p_close<=CompraEm && p_close<=DefesaCompraEm)
                        {
                           SegundaOrdem=true;
                           // Deletar ordens de venda no servidor
                           if(IDOrdem1!=0)
                              {
                                 func_delete_order(IDOrdem1);
                                 IDOrdem1=0;
                              }
                           OrdensDeletadas=true;
                          
                        }
                  }
            }
           
           
      }
   else //Não estamos num novo dia
      {
         //Verificar preços e se houve realizado.
         //Caso chegou na 1a Ordem (qqr uma), deletar as ordens pendentes de signo invertido
         if (p_close >= VendaEm || p_close<=CompraEm)
            {
               PrimeiraOrdem=true;
               if (p_close>=VendaEm && p_close<=DefesaVendaEm)
                  {
                     // Deletar ordens de compra no servidor
                     func_delete_order(IDOrdem2);
                     IDOrdem2=0;
                     OrdensDeletadas=true;
                    
                  }
               else if (p_close<=CompraEm && p_close>=DefesaCompraEm)
                  {
                     // Deletar ordens de venda no servidor
                     func_delete_order(IDOrdem1);
                     IDOrdem1=0;
                     OrdensDeletadas=true;
                    
                  }
               else if (p_close>=VendaEm && p_close>=DefesaVendaEm)
                  {
                     SegundaOrdem=true;
                     func_send_order(ORDER_TYPE_SELL,Lot,DefesaVendaEm,DefesaCompraEm,3, TKPV);
                    
                     // Deletar ordens de compra no servidor
                     if(IDOrdem2!=0)
                        {
                           func_delete_order(IDOrdem2);
                           IDOrdem2=0;
                        }
                     OrdensDeletadas=true;
                    
                   }
               else if (p_close<=CompraEm && p_close<=DefesaCompraEm)
                  {
                     SegundaOrdem=true;
                     // Deletar ordens de venda no servidor
                     if(IDOrdem1!=0)
                        {
                           func_delete_order(IDOrdem1);
                           IDOrdem1=0;
                        }
                     OrdensDeletadas=true;
                    
                  }
            }
      
      }
      return;
     
  }
 
//------------------------------------------------------------------------------------------------------

//+------------------------------------------------------------------+
//| Função Enviar Ordem                                              |
//+------------------------------------------------------------------+

void func_send_order(ENUM_ORDER_TYPE type_order, //Tipo de ordem a colocar
                     double volume, double price_ask, double price_bid, int OrderNumber, double OTP) // Lote do volume da operação
     {
      MqlTradeRequest mrequest;  // To be used for sending our trade requests
      MqlTradeResult mresult;    // To be used to get our trade results
      MqlRates mrate[];          // To be used to store the prices, volumes and spread of each bar
      ZeroMemory(mrequest);      // Initialization of mrequest structure
      
            mrequest.action = TRADE_ACTION_PENDING;                               // pending order execution
            mrequest.symbol = _Symbol;                                            // currency pair
            mrequest.volume = volume;                                             // number of lots to trade
            mrequest.magic = EA_Magic;                                            // Order Magic Number
            mrequest.type = type_order;                                           // Type Order
            mrequest.type_filling = ORDER_FILLING_FOK;                            // Order execution type
            mrequest.deviation=100;
            mrequest.expiration=ORDER_TIME_DAY;                                   // Ordem vence no fim do dia
           
            if (type_order==ORDER_TYPE_BUY) 
               {
                  mrequest.price = NormalizeDouble(price_ask,_Digits);           // latest ask price
                  //mrequest.sl = NormalizeDouble(price_ask - STP*_Point,_Digits); // Stop Loss
                  mrequest.tp = NormalizeDouble(price_ask + OTP,_Digits); // Take Profit
               }
            if (type_order==ORDER_TYPE_SELL)
               {
                  mrequest.price = NormalizeDouble(price_bid,_Digits);            // latest Bid price
                  //mrequest.sl = NormalizeDouble(price_bid + STP*_Point,_Digits);  // Stop Loss
                  mrequest.tp = NormalizeDouble(price_bid - OTP,_Digits);  // Take Profit
               }                                                                  // Deviation from current price
//--- send order
            OrderSend(mrequest,mresult);
           
//--- get the result code
            if(mresult.retcode==10009 || mresult.retcode==10008) //Request is completed or order placed
              {
               Alert("Uma ordem foi colocada com sucesso no Ticket#:",mresult.order,"!!");
               switch (OrderNumber)
                  {
                     case 1:
                        IDOrdem1=mresult.order;
                        break;
                     case 2:
                        IDOrdem2=mresult.order;
                        break;
                     case 3:
                        IDOrdem3=mresult.order;
                        break;
                     case 4:
                        IDOrdem4=mresult.order;
                        break;
                  }
              }
            else
              {
               Alert("A ordem não pode ser colocada - Erro:",GetLastError());
               ResetLastError();          
               return;
              }
    
     }
//--------------------------------------------------------------------------------------------------------------    

void func_delete_order(const ulong ticket)
  {
      MqlTradeRequest mrequest;  // To be used for sending our trade requests
      MqlTradeResult mresult;    // To be used to get our trade results
      MqlRates mrate[];          // To be used to store the prices, volumes and spread of each bar
      ZeroMemory(mrequest);      // Initialization of mrequest structure

//--- setting request
   mrequest.action    =TRADE_ACTION_REMOVE;
   mrequest.magic     =EA_Magic;
   mrequest.order     =ticket;
//--- action and return the result
   OrderSend(mrequest,mresult);

//--- get the result code
            if(mresult.retcode==10009 || mresult.retcode==10008) //Request is completed or order placed
              {
               Alert("Uma ordem foi cancelada com sucesso no Ticket#:",mresult.order,"!!");
              }
            else
              {
               Alert("A ordem não pode ser cancelada - Erro:",GetLastError());
               ResetLastError();          
               return;
              }
  
  }

//--------------------------------------------------------------------------------------------------------------    

//--- Verifica se já estamos num novo dia
bool NewDay ( datetime aTimeCur, datetime aTimePre, int aVariant = 1 )
  {
   switch (aVariant)
     {
      case  1 :
          return (NewDay1 (aTimeCur, aTimePre));
         break ;
      case  2 :
          return (NewDay2 (aTimeCur, aTimePre));
         break ;
     }
   return ( false );
  }

//--------------------------------------------------------------------------------------------------------------    

//--- Verifica se estamos num novo dia    
bool NewDay1 ( datetime aTimeCur, datetime aTimePre)
  {
   return ((aTimeCur/86400)!=(aTimePre/86400));
  } 

//--------------------------------------------------------------------------------------------------------------    
 
//--- Verifica o dia da semana
bool NewDay2 ( datetime aTimeCur, datetime aTimePre)
  {
   MqlDateTime STM;
// --- Novo dia
   if (NewDay1 (aTimeCur, aTimePre))
     {
      TimeToStruct (aTimeCur, STM);
      switch (STM.day_of_week)
        {
         case  6 : // sábado
            return ( false );
            break ;
         case  0 : // domingo
            return ( true );
            break ;
         case  1 : // segunda-feira
            TimeToStruct (aTimePre, STM);
            if (STM.day_of_week!= 0 )
              { // Precedido por qualquer dia da semana que não seja domingo
               return ( true );
              }
            else
              {
               return ( false );
              }
            break ;
         default : // qualquer outro dia da semana
            return ( true );
        }
     }
   return ( false );
  }

//--------------------------------------------------------------------------------------------------------------    


 
//+------------------------------------------------------------------+

 
Juan Pablo Silenzi de Stagni:

Valeu, vou verificar os artigos!

Romeu Bertho:

Boa noite Juan,

isso acontece quando você tenta acessar uma posição do array que não existe. Pode ser que a causa esteja na manipulação incorreta da função CopyClose ou CopyRates, que por algum motivo não está preenchendo o seu array.

Eu separei dois artigos que podem ser úteis para você:

https://www.mql5.com/pt/articles/567 - Arrays

https://www.mql5.com/pt/articles/496 - Exemplo com a função CopyClose

Fique a vontade em postar o pedaço do código onde aconteceu o erro, desse modo facilita a identificação do erro pela comunidade.

Um abraço,

Romeu. 

Oi Romeu,
Fiz algumas modificações no código, mas continua dando o erro. Ele nem fala qual array é a que dá a falha.
Olha meu código, vê se descobre o problema por favor.
Abs
Arquivos anexados:
Marquito1.mq5  40 kb
 

Boa noite Juan,

estou com um tempo meio curto, mas dando uma olhada rápida eu descobri algumas coisinhas:

 Deixe as seguintes variáveis desse modo:

datetime          New_Day[];
bool              IsNewDay=false;
static datetime   Old_Time_M1;                  
datetime          New_Time[];

As funções Copy**** cuidam automaticamente do tamanho do array

 tente rodar novamente e se acontecer novamente o problema, cole o log aqui também. É a primeira vez que eu vejo um array out of range sem a linha do código, rs. Acredito que com essas modificações esse erro não apareça mais.

Um abraço,

Romeu. 

 
Olá @Juan Pablo Silenzi de Stagni,

Observei que seu código na parte que pega o fechamento anterior não tem verificação de erros:
// Pegar o fechamento do dia anterior

ArrayResize(CloseVal,1);           // --> isto não é necessário, CopyClose já ajusta o tamanho do array
ArraySetAsSeries(CloseVal,true);
CopyClose(_Symbol,PERIOD_D1,0,1,CloseVal);

double FechamentoDiaAnterior = CloseVal[1];

Minha sugestão é fazer o seguinte (em todas as funções que retornam dados do sistema ou cotações), ou algo parecido:
ArraySetAsSeries(CloseVal,true);

if(CopyClose(_Symbol,PERIOD_D1,0,1,CloseVal) <= 0){
   printf("Erro código %i: ", GetLastError());
   return;
}

double FechamentoDiaAnterior = CloseVal[1];    

Sugiro também utilizar break points e usar o passo a passo para depurar detalhes como esse.
 

Valeu pelas dicas amigos!

Abs!

 

Também estou com um problema de array, estou com uma situação onde eu desejo utilizar um array dinamico, pois não sei qual vai ser o tamanho do mesmo, estou tentando definir o tamanho do array utilizando uma variável conforme abaixo, quando eu compilo ele diz da erro dizendo que o valor bars é inválido (bars tem o valor de 1767), se no lugar de bars eu colocar 1767 ele funciona conforme preciso, mas como se trata de um array que não sei o tamanho eu estou tentando colocar pela variável bars que atualiza conforme a janela. Por favor poderiam me dar um auxílio??


int bars=Bars(_Symbol,_Period);

double         CompraBuffer[bars];  // bars tem o valor de 1767

double         VendaBuffer[bars];

   for(int i=0;i<(bars-1);i++)

   {

   CompraBuffer[i]=maVal_9[i]-maVal_21[i];

   }

 

fala Balsante,

eu suponho que o erro cometido foi voce nao ter considerado que logo no inicio do loop, valores 0, 1, 2, 3 e mais alguns outros valores, vc nao descontou que o calculo da media nos arrays que estao dentro do loop deve ser feito tambem, e estes calculos vao tentar buscar valores que nao existem, pois teriam que estar antes da posicao 0 no loop.

Vou tentar explicar melhor,... se a quantidade de barras for por exemplo 100 no total e vc quer usar um loop que dentro dele utilize media_movel das 10 ultimas barras, entao vc tem que comecar o loop a partir da posicao 10, para que nesse ponto vc tenha uma base de dados 10 barras antes para que a media possa ser calculada, ou seja, o loop tem que ir de 10 ate 100.


acho que o ponto eh este.

boa sorte.

Andre LC

 

Olá @balsante

boa tarde, use o ArrayResize  para definir o tamanho do array.

   double CompraBuffer[],VendaBuffer[];
   
   int bars=Bars(_Symbol,_Period);

   ArrayResize(CompraBuffer,bars);
   ArrayResize(VendaBuffer,bars);

   for(int i=0;i<bars;i++)
     {
      if(maVla_9[i]!=EMPTY_VALUE && maVal_21[i]!=EMPTY_VALUE)
         CompraBuffer[i]=maVal_9[i]-maVal_21[i];
     }
Razão: