Направление индексации в массивах, буферах и таймсериях

Все массивы и индикаторные буферы по умолчанию имеют направление индексации слева направо. Индекс первого элемента всегда равен нулю. Таким образом, самый первый элемент массива или индикаторного буфера с индексом 0 по умолчанию находится на крайней левой позиции, последний элемент находится на крайней правой позиции.

Индикаторный буфер представляет из себя динамический массив типа double, размером которого управляет клиентский терминал с тем, чтобы он всегда соответствовал количеству баров, на которых индикатор рассчитывается. Обычный динамический массив типа double назначается в качестве индикаторного буфера с помощью функции SetIndexBuffer(). Для индикаторных буферов не требуется задавать размер с помощью функции ArrayResize(), исполняющая система терминала сама позаботится об этом.

Таймсерии представляют из себя массивы с обратной индексацией, то есть самый первый элемент таймсерии находится на крайней правой позиции, а последний элемент таймсерии находится на крайней левой позиции. Так как таймсерии предназначены для хранения исторических ценовых данных по финансовым инструментам и обязательно содержат информацию о времени, то можно сказать, что самые свежие данные в таймсерии находятся в правой крайней позиции, а самые старые в крайней левой позиции.

Поэтому, элемент с индексом ноль в таймсерии содержит информацию о самой последней котировке по инструменту. Если таймсерия представляет данные по дневному таймфрейму, то на нулевой позиции содержатся данные текущего незавершенного дня, а на позиции с индексом один хранятся данные вчерашнего дня.

Изменение направления индексации

Функция ArraySetAsSeries() позволяет изменять способ доступа к элементам динамического массива, но при этом физически порядок хранения данных в памяти компьютера не изменяется. Эта функция просто изменяет способ адресации к элементам массива, поэтому при копировании одного массива в другой с помощью функции ArrayCopy() содержимое массива-приемника не будет зависеть от направления индексации в массиве-источнике.

Нельзя изменять направление индексации для статически распределенных массивов. Даже если массив был передан в качестве параметра в функцию, то и внутри этой функции попытки изменения направления индексации ни к чему не приведут.

Для индикаторных буферов, как и для обычных массивов, также разрешается устанавливать направление индексации задом наперед как в таймсерии, то есть, обращение к нулевой позиции в индикаторном буфере в этом случае будет означать обращение к самому последнему значению в соответствующем индикаторном буфере и это будет соответствовать значению индикатора на самом последнем баре. При этом физически размещение данных в индикаторном буфере останется неизменным, как уже упоминалось.

Получение ценовых данных в индикаторах

В каждом пользовательском индикаторе обязательно должна присутствовать функция OnCalculate(), которой передаются ценовые данные, необходимые для расчета значений в индикаторных буферах. Направление индексации в этих переданных массивах можно выяснить с помощью функции ArrayGetAsSeries().

Переданные в функцию массивы отражают ценовые данные, т.е. эти массивы имеют признак таймсерии и функция ArrayIsSeries() вернет true при проверке этих массивов. Но тем не менее, направление индексации необходимо в любом случае проверять только функцией ArrayGetAsSeries().

Чтобы не зависеть от умолчаний, необходимо безусловно вызывать функцию ArraySetAsSeries() для тех массивов, с которыми предполагается работать, и установить требуемое направление индексации.

Получение ценовых данных и значений индикаторов

В экспертах, индикаторах и скриптах все массивы по умолчанию имеют направление индексации слева направо. При необходимости в любой mql5-программе можно запросить значения таймсерий по любому символу и таймфрейму, а также значения индикаторов, рассчитанных на любом символе и таймфрейме.

Для получения таких данных служат функции Copy...():

  • CopyBuffer – копирование значений индикаторного буфера в массив типа double;
  • CopyRates – копирование ценовой истории в массив структур MqlRates;
  • CopyTime – копирование значений Time в массив типа datetime;
  • CopyOpen – копирование значений Open в массив типа double;
  • CopyHigh – копирование значений High в массив типа double;
  • CopyLow – копирование значений Low в массив типа double;
  • CopyClose – копирование значений Close в массив типа double;
  • CopyTickVolume – копирование тиковых объемов в массив типа long;
  • CopyRealVolume – копирование биржевых объемов в массив типа long;
  • CopySpread – копирование истории спредов в массив типа int;

 

Все эти функции работают одинаково, и поэтому достаточно рассмотреть механизм получения данных на примере CopyBuffer(). Подразумевается, что все запрашиваемые данные имеют направление индексации, как в таймсерии, при этом подразумевается, что в позиции с индексом 0 (ноль) хранятся данные текущего незавершенного бара. Чтобы получить доступ к этим данным, нам необходимо скопировать нужный нам объем данных в массив-приемник, например, в массив buffer.

copyBuffer

При копировании необходимо указать стартовую позицию в массиве-источнике, начиная с которой будут копироваться данные в массив-приемник. В случае успеха в массив-получатель будет скопировано указанное количество элементов из массива-источник, в данном случае из индикаторного буфера. При этом независимо от того, какое направление индексации установлено в массиве получателе, копирование всегда производится так, как указано на рисунке.

Если ценовые данные предполагается обрабатывать в цикле с большим количество итераций, то рекомендуется проверять факт принудительного завершения программы с помощью функции IsStopped():

int copied=CopyBuffer(ma_handle,// хэндл индикатора
                      0,        // индекс индикаторного буфера
                      0,        // стартовая позиция для копирования
                      number,   // количество значений для копирования 
                      Buffer    // массив-получатель значений
                      );
if(copied<0) return;
int k=0;
while(k<copied && !IsStopped())
  {
   //--- получаем значение для индекса k
   double value=Buffer[k];
   // ... 
   // работа со значением value
   k++;
  }

Пример:

input int per=10; // период экспоненты
int ma_handle;    // хэндл индикатора
//+------------------------------------------------------------------+
//| 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,// хэндл индикатора
                         0,        // индекс индикаторного буфера
                         0,        // стартовая позиция для копирования
                         10,       // количество значений для копирования 
                         ema       // массив-получатель значений
                         );
   if(copied<0) return;
// .... дальнейший код            
  }

Смотри также

Организация доступа к данным