Похоже, iCustom() таки ошибается

 

Эта тема поднималась здесь несколько раз, но я не нашел ни окончательного
решения, ни признания уважаемых разработчиков, что ошибка вообще существует.

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

Я подготовил несложный пример. Индикатор ^iTest рисует зеленую линию по лоям баров.
Эксперт ^eaTest опрашивает индикатор через функцию iCustom и рисует полученные
значения красными точками. Если прогнать эксперт в тестере (на любых
валютах и таймфреймах), а потом в тестере сказать "Открыть график", то
на графике будет видна как "родная" зеленая линия, так нарисованные
экспертом точки. Казалось бы, точки должны лечь точно на линию.
У меня они не не только не ложатся точно, но как бы рассеяны случайным образом.
Может ли кто-нибудь объяснить, что неправильно в моем коде?
Коды индикатора, эксперта, а также демонстрация их совместной работы
прилагаются. Заранее спасибо за комментарии.

//+--------------------------------------------------------------------+
//| Индикатор                                               ^iTest.mq4 |
//+--------------------------------------------------------------------+
 
#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 DarkGreen
 
double gdaBuffer[ ];
int    gnPos;
               
int init( ){
   SetIndexBuffer( 0, gdaBuffer );
   SetIndexStyle( 0, DRAW_LINE );
   
   gnPos = Bars - 2;
   return(0);
}
 
int start( ){
   double dIndicatorValue;
 
   if( gnPos < 2 ){  // При каждом вызове индикатора будем обсчитывать как минимум 2 последних бара
      gnPos = 2;    
   }   
   
   while( gnPos >= 0 ){
      dIndicatorValue = Low[ gnPos ];
      gdaBuffer[ gnPos ] = dIndicatorValue;
      gnPos--;
   }
   
   return(0);
}

//+------------------------------------------------------------------+
//| Советник                                          ^eaTest.mq4    |
//| Для проверки вызова внешнего индикатора через ф-ю iCustom( )     |
//+------------------------------------------------------------------+
 
double gdIndicatorValue;        
 
void start( ){
   if( Bars < 100 ) return;
   gdIndicatorValue = iCustom( NULL, 0, "^iTest", 0, 0 );
   PlotIndicatorValue ( );
}
 
void PlotIndicatorValue( ){
   string sObj;
   sObj = DoubleToStr( Bars, 0);
   ObjectCreate( 
      sObj, 
      OBJ_ARROW, 
      0,
      Time[ 0 ],
      gdIndicatorValue
   );
   ObjectSet( sObj, OBJPROP_ARROWCODE, 159); // Жирная точка
   ObjectSet( sObj, OBJPROP_COLOR, OrangeRed);  
}
 
А теперь прогоните слегка измененного эксперта
//+------------------------------------------------------------------+
//|                                                         Bred.mq4 |
//|                                                             Rosh |
//|                                    'Похоже, iCustom() таки ошибается' |
//+------------------------------------------------------------------+
#property copyright "serpa"
#property link      "'Похоже, iCustom() таки ошибается'"
 
double gdIndicatorValue;        
//+------------------------------------------------------------------+
//| рисование                                                        |
//+------------------------------------------------------------------+
 
void PlotIndicatorValue( )
  {
   string sObj;
   sObj = DoubleToStr( Bars, 0);
   ObjectCreate(sObj,OBJ_ARROW,0,Time[0],gdIndicatorValue);
   ObjectSet( sObj, OBJPROP_ARROWCODE, 159); // Жирная точка
   ObjectSet( sObj, OBJPROP_COLOR, OrangeRed);  
  }
 
//+------------------------------------------------------------------+
//| Советник                                          ^eaTest.mq4    |
//| Для проверки вызова внешнего индикатора через ф-ю iCustom( )     |
//+------------------------------------------------------------------+
 
void start( )
  {
   if( Bars < 100 ) return;
   gdIndicatorValue = iCustom( NULL, 0, "^iTest", 0, 0 );
   if (Open[0]!=gdIndicatorValue) PlotIndicatorValue ();
  }
//--------------------------------------------------------------------

и подумайте - что изменилось?

Скажите, судя по выложенному коду - Вы даете понять , что являетесь программистом (стилистика написания указывает на знакомство с программированием,но при этом код грязен)? Если это так (то есть Вы являетесь программистом) - то откуда такие детские ошибки в понимании алгоритма? Даже в незнакомом языке можно разобраться при желании (логика от языка не зависит). Если не программист , и код не Ваш - почему бы Вам не спросить у того, кто написал этот код? Ведь профессионал написал бы так, чтобы вопросов не возникало. Есть желании разобраться - читаем статьи на сайте, на данный момент они покрывают 99% вопросов.
Приложенный Вами алгоритм работает именно так, как и должен работать, чтобы поставить в тупик новичка при моделировании по Open Prices.
 
Rosh писал (а):
А теперь прогоните слегка измененного эксперта [...]
Спасибо. Я был неправ, и Вы показали в чем именно. Я вообще-то проверял гипотезу, что тестер рисует Open'ы, но выбрал неудачный
символ для "жирной точки" (159) - он рисуется пипсов на 5 от своей ценовой координаты, что и сбило меня с толку.
Я действительно новичок в этой области. А код я написал таким, чтобы профессионал быстро понял в чем дело
и либо согласился со мной, либо указал на мою ошибку. И как мне кажется, с этой задачей мой код справился.
 
ИМХО, все-таки ошибается - см. комментарий в левом верхнем углу:





Эксперт (слегка переделанный Moving Average) и индикатор - в аттаче.
Заметил, что проблема еще усугубляется, если вызываются значения "дальних" буферов iCustom (1, 2, ..., 7).
Сборка терминала: 4.201 от 26.12.2006.
Файлы:
hlr.zip  3 kb
 
Довольно давно обнаружил эту феньку, лень все было проверить и сообщить, т.к. обходится легко, путем встраивания индикатора в тело эксперта. Забавно, что если в том же визуальном режиме запустить "пустой" эксперт и прицепить к графику тот же самый индикатор с добавленной строкой Comment(...), то подобный прикол не наблюдается.

"Пустой" эксперт:

//+------------------------------------------------------------------+
//|                                                  Stub_Expert.mq4 |
//|                      Copyright © 2006, MetaQuotes Software Corp. |
//|                                        https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2006, MetaQuotes Software Corp."
#property link      "https://www.metaquotes.net/"
 
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
  {
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
  {
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
  {
//----
   
//----
   return(0);
  }
//+------------------------------------------------------------------+
 
Причем здесь Comment() ?
 
В общем-то ни при чем - просто для вывода на экран значений индикатора:
Comment("hlr_cur = ", hlr_cur, "; hlr_prv = ", hlr_prv);
Ее надо вписать в индикатор в цикл по барам, чтобы убедиться в корректности расчетов.
 
Может я чего-то не понял, но я не вижу доказательств.

Доказательства должны быть явно указаны попунктно, но никак не оставлены на самостоятельное додумывание. Моя попытка самостоятельного додумывания провалилась.
 
Comment() в индикаторе на графике и в окне визуального тестирования при вызове из эксперта (то есть , индикатор вызывается из эксперта) - разные вещи. Если Вы имели это ввиду - делайте поиск по форуму, обсуждалось.
То есть, мне нужно знать - смотреть код индикатора и советника, или не надо.
 
Раскройте архив, прогоните в визуальном режиме, и будут вам доказательства. Эксперт сам себе делает скриншоты. Я такое с кастом-индикатором, вызываемым извне, наблюдаю примерно с появления 200-й сборки. Обходный путь см. выше.
<То есть, мне нужно знать - смотреть код индикатора и советника, или не надо.>
Жесть! Миль пардон, ежели потревожил не по делу.
 
alexjou">SetIndexEmptyValue() в Ваш код, и теперь все нормально.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
 {
  //
  if (HLR_Range <= 1) { HLR_Range = 1; } 
 //---- indicators
  IndicatorShortName("Hi-Lo Range Oscillator (" + 
                      DoubleToStr(HLR_Range, 0) + ")"); 
  SetLevelStyle(STYLE_DASHDOT, 1, DodgerBlue); 
  SetIndexStyle(0, DRAW_LINE); 
  SetIndexLabel(0, "HLR"); 
  SetIndexBuffer(0, HLR_Buffer); 
  SetIndexDrawBegin(0, HLR_Range); 
  SetIndexEmptyValue(0,0.0);
 //----
  return(0);
 }
Это число 2 147 483 647 можно получить, если возвести двойку в степень 31, и от полученного результат отнять единицу. Сделайте поиск по обоим форумам по этому числу и увидите некоторые новые для себя сведения.
Для того, чтобы полностью контролировать работу алгоритма, старайтесь никогда не полагаться на значения по умолчанию, инициализируйте переменные/массивы самостоятельно.

Как видите, вызовы пользовательских индикаторов через iCustom() работают правильно, но если бы Вы прямо написали о проблеме, а не только выкладывали скриншоты для угадывания Вашего вопроса, то ответ получили бы быстрее.
Причина обращения: