Проверка количества просчитанных баров: BarsCalculated

Когда мы создаем сторонний индикатор — с помощью вызова iCustom или других функций, с которыми мы познакомимся позднее в этой главе — ему требуется некоторое время на вычисления. Как мы знаем, основным мерилом готовности данных индикатора является количество просчитанных баров, которое он возвращает из своей функции OnCalculate. Имея дескриптор индикатора, мы можем узнать это количество.  

int BarsCalculated(int handle)

Функция возвращает количество баров, для которых рассчитаны данные в индикаторе, заданном дескриптором handle. В случае ошибки получим -1.

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

В индикаторе UseWPR2.mq5 попытаемся создать IndWPR, меняя период WPR во входном параметре.

input int WPRPeriod = 0;

По умолчанию он равен 0, что является некорректным значением. Оно предложено намеренно, чтобы продемонстрировать нештатную ситуацию. Напомним, что в исходном коде IndWPR.mq5 присутствуют проверки в OnInit и в OnCalculate.

// IndWPR.mq5
void OnInit()
{
   if(WPRPeriod < 1)
   {
      Alert(StringFormat("Incorrect Period value (%d). Should be 1 or larger",
         WPRPeriod));
   }
   ...
}
   
int OnCalculate(ON_CALCULATE_STD_FULL_PARAM_LIST)
{
   if(rates_total < WPRPeriod || WPRPeriod < 1return 0;
   ...
}

Таким образом, при нулевом периоде мы должны получить уведомление об ошибке и BarsCalculated должна всегда возвращать 0. После того как мы введем положительное значение для периода, вспомогательный индикатор должен начать рассчитываться нормально (и учитывая простоту расчета WPR — практически моментально), и BarsCalculated должна вернуть общее количество баров.

Теперь представим исходный код создания дескриптора в UseWPR2.mq5.

// UseWPR2.mq5
int handle// дескриптор в глобальной переменной
   
int OnInit()
{
   // передаем имя и параметр
   handle = PRTF(iCustom(_Symbol_Period"IndWPR"WPRPeriod));
   // следующая проверка здесь бесполезна, потому что нужно выждать,
   // когда индикатор будет загружен, запустится и рассчитается
   // (здесь только для демонстрации)
   PRTF(BarsCalculated(handle));
   // успешность инициализации зависит от дескриптора
   return handle == INVALID_HANDLE ? INIT_FAILED : INIT_SUCCEEDED;
}

В OnCalculate просто выведем в журнал значения BarsCalculated и rates_total.

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &data[])
{
   // ждем, когда подчиненный индикатор рассчитается на всех барах
   if(PRTF(BarsCalculated(handle)) != PRTF(rates_total))
   {
      return prev_calculated;
   }
   
   // ... здесь обычно идет дальнейшая работа с использованием handle
   
   return rates_total;
}

Откомпилируем и запустим UseWPR2 сперва с параметром 0, а затем с каким-либо допустимым значением, например, 21. Вот записи журнала для нулевого периода.

iCustom(_Symbol,_Period,IndWPR,WPRPeriod)=10 / ok
BarsCalculated(handle)=-1 / INDICATOR_DATA_NOT_FOUND(4806)
Alert: Incorrect Period value (0). Should be 1 or larger
BarsCalculated(handle)=0 / ok
rates_total=20000 / ok
...

Сразу после создания дескриптора данные еще недоступны, поэтому видна ошибка INDICATOR_DATA_NOT_FOUND(4806) и результат BarsCalculated равен -1. Далее следует уведомление о некорректном входном параметре, что подтверждает успешную загрузку и запуск индикатора IndWPR. В последующем мы получаем значение BarsCalculated, равное 0.

Чтобы индикатор рассчитался, введем корректный входной параметр. В данном случае, BarsCalculated равно rates_total.

iCustom(_Symbol,_Period,IndWPR,WPRPeriod)=10 / ok
BarsCalculated(handle)=-1 / INDICATOR_DATA_NOT_FOUND(4806)
BarsCalculated(handle)=20000 / ok
rates_total=20000 / ok
...

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