Direção de Indexação em Arrays, Buffers e Séries Temporais

A indexação padrão de todos os arrays e buffers de indicador é da esquerda para direita. O índice do primeiro elemento é sempre igual a zero. Assim, o primeiro elemento de um array ou buffer de indicador com índice 0 está por padrão na posição mais a esquerda, enquanto o último elemento está na posição mais a direita.

Um buffer de indicador é um array dinâmico de tipo double, cujo tamanho é gerenciado pelos terminais clientes, de modo que ele sempre corresponde ao número de barras do indicador sobre o qual está calculando. Um array dinâmico usual de tipo double é atribuído como um buffer de indicador usando a função SetIndexBuffer(). Buffers de indicador não requerem que seus tamanhos sejam definidos usando a função ArrayResize() - isso será feito pelo sistema de execução do terminal.

Séries de tempo são array com indexação reversa, isto é, o primeiro elemento de uma série de tempo está na posição mais a direita, e o último elemento está na posição mais a esquerda. Em uma série de tempo sendo usada para armazenar dados de preços históricos e que contém informações de hora, os dados mais recentes são colocados na posição mais a direita da série de tempo, enquanto que os dados mais antigos na posição mais a esquerda.

Assim o elemento da série de tempo com índice 0 contém a informação sobre a última cotação de um ativo. Se uma série de tempo contém dados sobre uma janela de tempo diária, os dados correntes do dia ainda não terminado ficam localizados na posição zero, e na posição com índice 1 contém os dados de ontem.

Alterando a Direção de Indexação

A função ArraySetAsSeries() permite alterar o método de acessar elementos de um array dinâmico; no entanto, a ordem física de armazenamento de dados na memória do computador não é alterada. Esta função simplesmente altera o método de endereçar elementos de um array, assim quando copiar um array em um outro usando a função ArrayCopy(), o conteúdo do array recipiente não dependerá da direção de indexação no array fonte.

A direção de indexação não pode ser alterada para arrays alocados estaticamente. Mesmo se um array for passado como um parâmetro para uma função, tentar alterar a direção de indexação dentro desta função não produzirá nenhum efeito.

Para buffers de indicador, assim como para arrays comuns, a direção de indexação pode ser definida no sentido contrário (como em séries de tempo), isto é, uma referência à posição zero no buffer de indicador retornará o último valor no correspondente buffer de indicador e isso não corresponderá ao valor do indicador na barra mais recente. Contudo, a localização física das barras do indicador não será alterada.

Recebendo Dados de Preço em Indicadores

Cada indicador customizado deve necessariamente conter a função OnCalculate(), cujos dados de preço requeridos para calcular valores em buffers de indicadores são passados. A direção de indexação nestes arrays passados pode ser descoberta usando a função ArrayGetAsSeries().

Arrays passados para a função refletem dados de preço, isto é, estes arrays têm o sinal de uma série de preço e a função ArrayIsSeries() retornará true ao verificar estes arrays. Contudo, de qualquer forma a direção de indexação deve ser verificada somente pela função ArrayGetAsSeries().

A fim de não ficar dependente de valores default, a função ArraySetAsSeries() deve ser incondicionalmente chamada para os arrays com os quais você vai trabalhar, e definir a direção requerida.

Recebendo Dados de Preço e Valores de Indicador

A direção de indexação padrão de todos os arrays em Expert Advisores, indicadores e scripts é da esquerda para direita. Se necessário, em qualquer programa mql5 você pode solicitar valores de séries de tempo de qualquer ativo e janela de tempo, bem como valores de indicadores calculados sobre qualquer ativo e janela de tempo.

Use as funções Copy...() para este propósito:

  • CopyBuffer — copiar valores de um buffer de indicador para um array de tipo double;
  • CopyRates — copiar histórico de preços para um array de estruturas MqlRates;
  • CopyTime — copiar valores de Hora para um array de tipo datetime;
  • CopyOpen — copiar valores de Abertura para um array de tipo double;
  • CopyHigh — copiar valores de Máximo para um array de tipo double;
  • CopyLow — copiar valores de Mínimo para um array de tipo double;
  • CopyClose — copiar valores de Fechamento para um array de tipo double;
  • CopyTickVolume — copiar volumes de tick para um array de tipo long;
  • CopyRealVolume — copiar volumes de capital (equity) para um array de tipo long;
  • CopySpread — copiar o histórico de spreads para um array de tipo int;

 

Todas estas funções trabalham de forma similar. Vamos considerar o mecanismo de obtenção de dados no exemplo de CopyBuffer(). É implícito que a direção de indexação dos dados requeridos é de série de tempo, e a posição com índice 0 (zero) armazena dados da barra corrente ainda incompleta. A fim de obter acesso a estes dados nós precisamos copiar o volume necessário de dados em um array recipiente, por exemplo, em um array de buffer.

copyBuffer

Para copiar nós precisamos especificar a posição de início no array fonte, início a partir do qual dados serão copiados para o array recipiente. Em caso de sucesso, o número especificado de elementos serão copiados para o array recipiente do array fonte (do buffer de indicador neste caso). Independentemente do valor de indexação definido no array recipiente, a cópia é sempre realizada como exibida na figura abaixo.

Se é esperado que um grande número de iterações seja tratado por um loop, é recomendável que se verifique a ocorrência de uma finalização de programa forçada usando a função IsStopped().

int copied=CopyBuffer(ma_handle,// manipulador do indicador
                      0,        // O índice do buffer do indicador
                      0,        // Posição início para copiar
                      number,   // Número de valores para copiar
                      Buffer    // O array que recebe os valores
                      );
if(copied<0) return;
int k=0;
while(k<copied && !IsStopped())
  {
   //--- Obtém o valor para o índice k
   double value=Buffer[k];
   // ... 
   // trabalha com o valor
   k++;
  }

Exemplo:

input int per=10; // período do expoente
int ma_handle;    // manipulador do indicador
//+------------------------------------------------------------------+
//| Função de inicialização do Expert                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ma_handle=iMA(_Symbol,0,per,0,MODE_EMA,PRICE_CLOSE);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Função tick (ponto) de um Expert                                 |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double ema[10];
   int copied=CopyBuffer(ma_handle,// manipulador do indicador
                         0,        // índice do buffer do indicador
                         0,        // posição de ínicio da cópia
                         10,       // número de valores para copiar
                         ema       // array que recebe os valores
                         );
   if(copied<0) return;
// .... outro código
  }

Também Veja

Organizando Acesso aos Dados