CopyBuffer - Странное поведение или я что-то упускаю.

 
Индикатор, над которым я работаю, считывает символы из файла. При первой загрузке, когда символом является USDJPY, компилятор изначально возвращает ошибку (-1), и следующие результаты являются нормальными, правильными (2). При замене USDJPY на Symbol() компилятор не выдает абсолютно никаких ошибок. Любое объяснение, пожалуйста. Как исправить ошибку? Заранее благодарен.
//+------------------------------------------------------------------+
//|                                         Example - CopyBuffer.mq5 |
//|                                                          *********|
//|                                             *********************** |
//+------------------------------------------------------------------+
#property copyright "Max Primus"
#property link     ***********************
#property version   "1.00"
#property indicator_chart_window
#property indicator_plots 0

int      ma_handle = INVALID_HANDLE;
double   ma_buffer[];
string   symbol = "USDJPY";
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
      ma_handle = iMA(symbol,PERIOD_CURRENT,20,0,MODE_SMA,PRICE_CLOSE);
   if(ma_handle==INVALID_HANDLE){
      Print(__FUNCTION__," Error handle ma",GetLastError());
      return INVALID_HANDLE;
      }       
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
      int res = CopyBuffer(ma_handle,0,0,2,ma_buffer);
      Print("res=",res);

//--- return value of prev_calculated for next call
   return(rates_total);
  }
 
Max Primus:
При первой загрузке, когда символом является USDJPY, компилятор изначально возвращает ошибку (-1)

А точно ошибку выдает компилятор? Что такое загрузка? Наверное, запуск индикатора. После запуска компилятор уже не выдает никаких ошибок, т. к. программа успешно скомпилирована и запущена.

Видимо, речь идет об ошибке времени исполнения. То есть CopyBuffer() возвращает значение -1. Для такого случая в справке есть специальное описание:

When requesting data from the indicator, if requested timeseries are not yet built or they need to be downloaded from the server, the function will immediately return -1, but the process of downloading/building will be initiated.

Поэтому после получения такого значения достаточно прекратить обработку текущей итерации и ждать следующей итерации, к приходу которой данные таймсерии будут получены с большой вероятностью. Если не будут получены, ждем дальше.
 
Я очень внимательно прочитал документацию, и я знаком с этим пунктом. И если я вас правильно понимаю, это нормально, первый старт -1, а последующие 2. То есть это норма и все нормально. В этом случае мне приходится считать чеки и игнорировать первую. Это решаемо, но это не объясняет, почему он возвращает ошибку, когда валюта в формате "USDJPY", а когда это тип Symbol(), первый запуск в порядке!? Спасибо за быстрый ответ Ihor.
 
Max Primus #:
Я очень внимательно прочитал документацию, и я знаком с этим пунктом. И если я вас правильно понимаю, это нормально, первый старт -1, а последующие 2.
      int res = CopyBuffer(ma_handle,0,0,2,ma_buffer);
      int error = GetLastError();
      if (res < 0 || error != 0) {
         Print("Error: ", error);
         // 4806  Запрошенные данные не найдены
         // 4401  Запрашиваемая история не найдена
         return 0;
      }
      Print("res=",res);
 
Max Primus #:
Я очень внимательно прочитал документацию, и я знаком с этим пунктом. И если я вас правильно понимаю, это нормально, первый старт -1, а последующие 2. То есть это норма и все нормально. В этом случае мне приходится считать чеки и игнорировать первую. Это решаемо, но это не объясняет, почему он возвращает ошибку, когда валюта в формате "USDJPY", а когда это тип Symbol(), первый запуск в порядке!? Спасибо за быстрый ответ Ihor.

В качестве догадки предположу - потому что вызов Symbol() дергает ядро терминала на обновление таймсерий, и к моменту вызова CopyBuffer они уже готовы (но в принципе, время на синхронизацию может быть разным, и не факт что всегда на первом же вызове CopyBuffer() после Symbol() данные будут готовы), а вызов CopyBuffer("константная строка") - это первый запрос к указанной таймсерии и она только начинает строиться. Разумеется, предполагается, что другие MQL-программы не запросили тот же символ раньше - тогда по идее тайм серии уже должны быть готовы.

 
Max Primus #:
Я очень внимательно прочитал документацию, и я знаком с этим пунктом. И если я вас правильно понимаю, это нормально, первый старт -1, а последующие 2. То есть это норма и все нормально. В этом случае мне приходится считать чеки и игнорировать первую. Это решаемо, но это не объясняет, почему он возвращает ошибку, когда валюта в формате "USDJPY", а когда это тип Symbol(), первый запуск в порядке!? Спасибо за быстрый ответ Ihor.

На графике какого символа запускаете индикатор?

 
Alexey Viktorov #:

На графике какого символа запускаете индикатор?

На случайном символе. Первая проверка возвращает -1, а последующие — количество скопированных переменных.
 
Max Primus #:
На случайном символе. Первая проверка возвращает -1, а последующие — количество скопированных переменных.

В этом весь ответ… Symbol() возвращает имя текущего инструмента графика по которому загружена вся история. А когда пишете любой другой инструмент, то сначала история должна подгрузиться. А пока её нет, то и лезет ошибка.

 
Alexey Viktorov #:

В этом весь ответ… Symbol() возвращает имя текущего инструмента графика по которому загружена вся история. А когда пишете любой другой инструмент, то сначала история должна подгрузиться. А пока её нет, то и лезет ошибка.

Это утверждение выглядит логичным. Однако это означает, что проверка CopyBuffer() является избыточной для всех активов, кроме того, что находится на текущем графикe !?
      int res = CopyBuffer(ma_handle,0,0,2,ma_buffer);
   if(ChartSymbol(0) == symbol && res < 0){
      Print(__FUNCTION__," failed to copy array members, error ",GetLastError());
      return false;
      }
 
Max Primus #:
Это утверждение выглядит логичным. Однако это означает, что проверка CopyBuffer() является избыточной для всех активов, кроме того, что находится на текущем графикe !?

Или я совершенно не понял сказанного, или совсем наоборот. Для текущего символа ошибки очень редки, а вот для любого другого очень часто. Вообще рекомендуется запрашивать свойства «не родного» символа каждые пару минут. Так сказать дёргать кота за причинное место… Ну а если обращение идёт чаще, то специально дёргать нет необходимости, просто при запуске если данные не получены вернуть 0 и пусть пересчитывается сначала…

 
Сегодня я обнаружил следующее и это все объясняет, надеюсь.

--->>

Alain Verleyen 2019.09.17 06:37   EN
Luca:

Hi Alain, 

I could make a post with all the articles I browsed about my search on "4806 error" and "Requested data not found" and still not an answer, lot of unanswered and unresolved issues and posts just abandoned because people gave up.

But if you could point me in the right direction that would be appreciated. Thanks

Yeah. You didn't search very well in this case.

You have 2 main issues :

1° You initialize the indicator (create the handle) and on the next statement you call CopyBuffer(), that will never work as the indicator need some time to be launched and calculated. You NEED to declare in OnInit(). (Strictly speaking it's not mandatory but it's way simpler when you don't know and understand all the process very clearly).

For multi-symbols (and/or multi-timeframes), you can ALWAYS get an error 4806 at some point because MT5 doesn't wait the data to be calculated, so it happens that the data are not ready on other symbols/timeframes. You have to deal with it, the simpler is just return and wait next tick.


Благодаря!