Dirección de indexación en los arrays y series temporales

Por defecto todas los arrays y búfers de indicadores tienen la dirección de indexación de izquierda a derecha. El índice del primer elemento siempre es igual a cero. De esta manera, el primer elemento de un array o búfer de indicador con el índice 0 por defecto se encuentra en el extremo izquierdo y el último elemento se encuentra en el extremo derecho.

Un búfer de indicador es un array dinámico del tipo double, cuyo tamaño es gestionado por el terminal de cliente para que éste siempre corresponda a la cantidad de barras sobre las cuales se calcula el indicador. Un array dinámico habitual del tipo double se asigna como un búfer de indicador a través de la función SetIndexBuffer(). Para los buffers de indicadores no hace falta establecer el tamaño mediante la función ArrayResize(), esto será hecho por el sistema de ejecución del mismo terminal.

Las series temporales son arrays con la indexación inversa. Es decir, el primer elemento de una serie temporal se encuentra en el extremo derecho y el último se encuentra en el izquierdo. Las series temporales están destinadas para almacenar los datos históricos de precios de los instrumentos financieros y contienen obligatoriamente la información sobre la hora, entonces se puede decir que en una serie temporal los datos más recientes se encuentran en el extremo derecho y los más antiguos en el extremo izquierdo.

Por tanto, en una serie temporal el elemento con el índice cero contiene la información sobre la última cotización de un instrumento. Si una serie temporal representa datos del período de tiempo diario, en la posición cero se contienen datos sobre el día en curso no finalizado, y en la posición con el índice uno se almacenan los datos del día de ayer.

Cambio de dirección de indexación

La función ArraySetAsSeries() permite cambiar el modo de acceso a los elementos de un array dinámico, pero el orden físico de almacenamiento de datos en la memoria del ordenador no sufre cambio alguno. Esta función simplemente cambia el modo de direccionamiento hacia los elementos de un array, por eso cuando copiamos un array dentro del otro a través de la función ArrayCopy(), el contenido del array-receptor no va a depender de la dirección de indexación en el array fuente.

No se puede cambiar la dirección de indexación para los arrays distribuidos estáticamente. Incluso si un array ha sido pasado como un parámetro a una función, dentro de esta función los intentos de cambiar la dirección de indexación no tendrán efecto alguno.

Para los búfers de indicadores, igual que para los arrays habituales, también se permite establecer la dirección de indexación al revés, como en las series temporales. Es decir, en este caso la referencia hacia la posición cero en el búfer de indicador va a significar la referencia hacia el último valor en el búfer de indicador correspondiente, y esto va a corresponder al valor del indicador en la última barra. Pero como ya se ha mencionado antes, la ubicación física de datos en el búfer de indicador se queda sin cambiar.

Recepción de datos de precios en los indicadores

Cada indicador personalizado obligatoriamente ha de contener la función OnCalculate(). A esta función se le pasan los datos de precios necesarios para calcular los valores en los búfers de indicadores. A través de la función ArrayGetAsSeries() se puede averiguar la dirección de indexación en estos arrays pasados.

Los arrays pasados a la función reflejan los datos de precios, es decir, estos arrays tienen los indicios de las series temporales y la función ArrayIsSeries() devolverá true a la hora de comprobar estos arrays. Pero a pesar de eso, en cualquier caso hay que comprobar la dirección de indexación sólo a través de la función ArrayGetAsSeries().

Para no depender de los valores por defecto, hay que llamar incondicionalmente a la función ArraySetAsSeries() para los arrays con los que se prevé trabajar y establecer la dirección de indexación necesaria.

Recepción de datos de precios y valores de indicadores

Por defecto en los Asesores Expertos, indicadores y scripts todos los arrays tienen la dirección de indexación de izquierda a derecha. En caso de necesidad, en cualquier programa mql5 se puede solicitar los valores de las series temporales referente a cualquier símbolo y período de tiempo, además, los valores de indicadores calculados sobre cualquier símbolo y período de tiempo.

Para conseguir estos datos se usan las funciones Copy...():

  • CopyBuffer — copia los valores de un búfer de indicador a un array del tipo double;
  • CopyRates — copia el historial de precios a una matriz de estructuras MqlRates;
  • CopyTime — copia los valores Time a un array del tipo datetime;
  • CopyOpen — copia los valores Open a un array del tipo double;
  • CopyHigh — copia los valores High a un array del tipo double;
  • CopyLow — copia los valores Low a un array del tipo double;
  • CopyClose — copia los valores Close a un array del tipo double;
  • CopyTickVolume — copia los volúmenes de tick a un array del tipo long;
  • CopyRealVolume — copia los volúmenes bursátiles a un array del tipo long;
  • CopySpread — copia el historial de spreads a un array del tipo int;

 

Todas estas funciones trabajan de una manera igual, y por eso será suficiente estudiar el mecanismo de obtención de datos en el ejemplo de CopyBuffer(). Se supone que todos los datos solicitados tienen la dirección de indexación igual que en las series temporales, y en la posición con el índice 0 (cero) se almacenan los datos de la barra actual no finalizada. Para conseguir acceder a estos datos necesitamos copiar el volumen de datos que hace falta a un array-receptor, por ejemplo al array buffer.

copyBuffer

Durante el copiado es necesario indicar la posición de inicio en el array fuente a partir de la cual los datos empiezan a copiarse al array de destino. En caso del éxito la cantidad de elementos especificada será copiada desde el array de origen (en este caso se trata del búfer de indicador) al array-receptor. El copiado siempre se realiza tal como se muestra en el dibujo, independientemente de la dirección de indexación establecida en el array-receptor.

Si se supone procesar los datos de precios en un ciclo con el gran número de iteraciones, entonces se recomienda comprobar el hecho de la finalización forzosa del programa utilizando la función IsStopped():

int copied=CopyBuffer(ma_handle,// manejador del indicador
                      0,        // índice del búfer de indicador
                      0,        // posición de inicio para el copiado
                      number,   // número de valores a copiar 
                      Buffer    // array-receptor de valores
                      );
if(copied<0) return;
int k=0;
while(k<copied && !IsStopped())
  {
   //--- obtenemos el valor para el índice k
   double value=Buffer[k];
   // ... 
   // trabajo con el valor value
   k++;
  }

Ejemplo:

input int per=10; // período del exponente
int ma_handle;    // manejador del indicador
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ma_handle=iMA(_Symbol,0,per,0,MODE_EMA,PRICE_CLOSE);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double ema[10];
   int copied=CopyBuffer(ma_handle,// manejador del indicador
                         0,        // índice del búfer de indicador
                         0,        // posición de inicio para el copiado
                         10,       // número de valores a copiar
                         ema       // array-receptor de valores
                         );
   if(copied<0) return;
// .... código que sigue
  }

Véase también

Organización de acceso a los datos