вызов iCustom разрешен только в Oninit?

 

код индикатора:

 

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1


int handlefrominit;
bool flagerror = false;
int OnInit(){
   handlefrominit = iCustom(Symbol(), PERIOD_CURRENT, "examples\\ATR", 14 );
   return(0);
}
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[])  {
   double buf[1];
   int handle;
   if( flagerror )return(rates_total);
   handle = handlefrominit;
   //handle = iCustom(Symbol(), PERIOD_CURRENT, "examples\\ATR", 14 );
   if( handle == INVALID_HANDLE ){
     Print("invalid handle ");
     flagerror = true;
     return(rates_total);
   }
   int res = CopyBuffer( handle, 0, 0, 1, buf );
   if( res == -1 ){
     Print("error get data from custom indicator ", _LastError, " rates_total=", rates_total );
     flagerror = true;
   }else{
     Print("data from indicator= ", buf[0], " rates_total=", rates_total );
   }
   return(rates_total);
  }
//+------------------------------------------------------------------+

 

 лог:


2010.02.14 11:11:40 testinit (GBPUSD,H4) data from indicator= 0.006287142857142831 rates_total= 8223
2010.02.14 11:11:40 testinit (GBPUSD,H4) data from indicator= 0.006287142857142831 rates_total= 8223

причем видно по логу, что OnCalculate вызывается дважды, хотя в данный момент котировки стоят 

 

если iCustom перенести в OnCalculate:

 

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1


int handlefrominit;
bool flagerror = false;
int OnInit(){
   //handlefrominit = iCustom(Symbol(), PERIOD_CURRENT, "examples\\ATR", 14 );
   return(0);
}
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[])  {
   double buf[1];
   int handle;
   if( flagerror )return(rates_total);
   handle = handlefrominit;
   handle = iCustom(Symbol(), PERIOD_CURRENT, "examples\\ATR", 14 );
   if( handle == INVALID_HANDLE ){
     Print("invalid handle ");
     flagerror = true;
     return(rates_total);
   }
   int res = CopyBuffer( handle, 0, 0, 1, buf );
   if( res == -1 ){
     Print("error get data from custom indicator ", _LastError, " rates_total=", rates_total );
     flagerror = true;
   }else{
     Print("data from indicator= ", buf[0], " rates_total=", rates_total );
   }
   return(rates_total);
  }
//+------------------------------------------------------------------+

 лог:

2010.02.14 11:15:15 testinit (GBPUSD,H4) error get data from custom indicator 4806 rates_total= 8223

 

Прежде чем запрашивать значения индикатора, необходимо получить количество баров, на которых он рассчитан. Для этого служит функция BarsCalculated():

Возвращает количество рассчитанных данных для запрашиваемого индикатора.

int  BarsCalculated(
   int       indicator_handle,     // handle индикатора
   );

Параметры

indicator_handle

[in]  Хэндл индикатора, полученный соответствующей индикаторной функцией.

Возвращаемое значение

Возвращает количество рассчитанных данных в индикаторном буфере или -1 в случае ошибки (данные еще не рассчитаны).

Примечание

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

Попробуйте код:

//+------------------------------------------------------------------+
//|                                                 Test_iCustom.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
#property indicator_style1 DRAW_LINE
#property indicator_color1  DodgerBlue
#property indicator_label1  "test"

int handle;
bool flagerror=false;
double buf[1];
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnInit()
  {
//handlefrominit = iCustom(Symbol(), PERIOD_CURRENT, "examples\\ATR", 14 );
   SetIndexBuffer(0,buf,INDICATOR_DATA);
//return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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[])
  {
   if(flagerror)return(rates_total);

   handle = iCustom(Symbol(), PERIOD_CURRENT, "examples\\ATR", 14 );
   if(handle==INVALID_HANDLE)
     {
      Print("invalid handle ");
      flagerror=true;
      return(rates_total);
     }
   ResetLastError();
   while(BarsCalculated(handle)<=0)
     {
      // значения индикатора еще не рассчитаны, зайдем в следующий раз
      return(0);
     }
   int res=CopyBuffer(handle,0,0,1,buf);
   if(res==-1)
     {
      Print("error get data from custom indicator ",_LastError," rates_total=",rates_total);
      flagerror=true;
        }else{
      Print("data from indicator= ",buf[0]," rates_total=",rates_total);
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+

Так как котировки в выходные не идут, то для того, чтобы вызвать OnCalculate() второй раз, вызовите команду "Обновить"


 
Но вообще говоря, всегда создавайте хендлы индикаторов в функции OnInit(), это более правильный подход.
Документация по MQL5: Доступ к таймсериям и индикаторам / IndicatorCreate
Документация по MQL5: Доступ к таймсериям и индикаторам / IndicatorCreate
  • www.mql5.com
Доступ к таймсериям и индикаторам / IndicatorCreate - Документация по MQL5
 
Rosh писал(а)  :
Но вообще говоря, всегда создавайте хендлы индикаторов в функции OnInit(), это более правильный подход.

здесь утрированный пример,  планировалось хендлы получать в конструктарах объектов, а сами экземпляры могут объявлятся где угодно: и внутри oncalculte, и в теле глобального модуля. также необязательно, что подобное будет использовать именно в индикаторе, это может быть и в скрипте. я мт4 спойкойно использовал конструкции типа:

 

bool flagfirst = true;
  for( int ii = 0; ii < ArraySize(toolscot); ii++ ){

    
    int isymb = findterminalsymbol(toolscot[ii]);
    string sym = toolssymbol[isymb]; 
    if( sym == "USDRUB" )continue; //рубли не учитываем
    ArrayInitialize(cntballs, 0);
    ArrayInitialize(cntsuc, 0);
    for( int i = 150; i > 0; i-- ){
      int ball = iCustom(sym, PERIOD_W1, "cotballsandsignals", 1, i );  
      int signal = iCustom(sym, PERIOD_W1, "cotballsandsignals", 2, i );  
      double dir = iClose(sym, PERIOD_W1, i )-iOpen(sym, PERIOD_W1, i); 
ну и далее ...

 

может стоит внести в справку по icustom информацию о том, что наличие корректного хендла не гарантирует наличия рассчитанных данных? 

в описании barcalculated есть фраза:

"Функция полезна в тех случаях, когда необходимо получить данные индикатора сразу после его создания (получения хендла индикатора)." , что значит сразу? получается, что при вызове из Oninit - "не сразу", из какой то другой функции - "сразу". или все-таки не гарантируется, что даже и при получении хендла через oninit в oncalculate будем иметь рассчитанные данные? если так, то нужно всегда до получения данных из кастомных индикаторов делать проверку на их наличие, как вприведенном выше примере? может проще все-таки средствами платформы гарантированно готовить рассчитанные данние внутри первого вызова copybuffer, зачем на пользователя возлагать множество подобных проверок внутри кода? все таки это прикладная платформа, она должна сама заботится о наличии подобных данных.

 

gdtt писал(а)  :

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

А ведь правда.

 
gdtt:


"Функция полезна в тех случаях, когда необходимо получить данные индикатора сразу после его создания (получения хендла индикатора)." , что значит сразу? получается, что при вызове из Oninit - "не сразу", из какой то другой функции - "сразу".


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

Если вызов iCustom производится в OnCalculate(), то исполнительная система просто не успеет рассчитать данные сразу же после создания хендла индикатора. Это потребует хоть и очень малого времени, но потребует.

Документация по MQL5: Доступ к таймсериям и индикаторам / IndicatorCreate
Документация по MQL5: Доступ к таймсериям и индикаторам / IndicatorCreate
  • www.mql5.com
Доступ к таймсериям и индикаторам / IndicatorCreate - Документация по MQL5
 
avatara:

А ведь правда.

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

Rosh писал(а)  :
Никакая мощная система не исключает необходимости проверок. Эти проверки можно спрятать внутри исполняющей системы и отдавать данные только после полного расчета (со всеми тормозами, если код индикатора написан криво), либо дать возможность программисту самостоятельно контролировать готовность затребованных данных.

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

Спасибо за пояснения.
 
Rosh:

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

Если вызов iCustom производится в OnCalculate(), то исполнительная система просто не успеет рассчитать данные сразу же после создания хендла индикатора. Это потребует хоть и очень малого времени, но потребует.

 

 

Вы уж извините, что я упорствую в своих заблуждениях. Но и Вы поймите (как знать, может мы и сможем повлиять на Вас) - мне нужен инструмент, которым было бы комфортно пользоваться. Если встает вопрос выбора - написать много строк, и это будет работать быстро, или мало, но, возможно, медленно, я выбираю второй( какая разница - будет график выводится за 0.00001 или 0.0001 секунды?), т.к. такой код легче сопровождать и в нем меньше невыявленных ошибок, компьютеры с течением времени работают быстрее, а не медленнее, лучче купить новую производительную железку, чем писать горы строк. Ну если написанный код будет работать медленно (то о чем говорится выше), ну мы ж не совсем бараны, если нужно будет, то найдем в своих кодах и подправим узкие моменты.
 
gdtt:
Вы уж извините, что я упорствую в своих заблуждениях. Но и Вы поймите (как знать, может мы и сможем повлиять на Вас) - мне нужен инструмент, которым было бы комфортно пользоваться. Если встает вопрос выбора - написать много строк, и это будет работать быстро, или мало, но, возможно, медленно, я выбираю второй( какая разница - будет график выводится за 0.00001 или 0.0001 секунды?), т.к. такой код легче сопровождать и в нем меньше невыявленных ошибок, компьютеры с течением времени работают быстрее, а не медленнее, лучче купить новую производительную железку, чем писать горы строк. Ну если написанный код будет работать медленно (то о чем говорится выше), ну мы ж не совсем бараны, если нужно будет, то найдем в своих кодах и подправим узкие моменты.

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

К сожалению, CopyXXX функции внутри индикаторов не могут работать в синхронном режиме, так как это не просто затормозит расчет и отрисовку индикаторов, а фактически остановит терминал.

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

 
Renat:

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

К сожалению, CopyXXX функции внутри индикаторов не могут работать в синхронном режиме, так как это не просто затормозит расчет и отрисовку индикаторов, а фактически остановит терминал.

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

 

проясните пожалуйста:

 

#include <cot.mqh>
void OnStart() {
  int cothandlespeculants = iCustom( "EURUSD", PERIOD_W1, "cot", noncommercial, netlongs, COT );
  if( cothandlespeculants == INVALID_HANDLE ){
    Print("Ошибка создания индикатора ");
    return;
  }
  int n = 1;
  double netlongsspeculants[];
  int res = CopyBuffer( cothandlespeculants, 0, 0, n, netlongsspeculants );
  Print("res=", res, " barscalulated=", BarsCalculated(cothandlespeculants)  );
}

 гарантированно на выходе всегда получаю:

2010.02.26 14:33:47 tstcallcustom (GBPUSD,W1) res= -1  barscalulated= -1

если делать обвязку типа:

 

if( !waitforclaculcateindicator( cothandlespeculants ) ){
      Print("Таймаут ожидания расчета индикатора cot");
      return;
    }

 где

bool waitforclaculcateindicator( int handle ){
  int cnt;
  while( true ){
    int clc = BarsCalculated( handle );
    Print("bars calculated=", clc );
    if( clc <= 0 ){
      Sleep(500);
    }else break;
    cnt++;
    if( cnt > 500*40/1000 ){//таймаут 20 секунд
      //Print("time out calculating");
      return(false);
    }
  }
  return( true );
}

данные получить удается

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

Причина обращения: