Прежде чем запрашивать значения индикатора, необходимо получить количество баров, на которых он рассчитан. Для этого служит функция BarsCalculated():
Возвращает количество рассчитанных данных для запрашиваемого индикатора.
int BarsCalculated( |
Параметры
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() второй раз, вызовите команду "Обновить"
- www.mql5.com
Но вообще говоря, всегда создавайте хендлы индикаторов в функции 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, зачем на пользователя возлагать множество подобных проверок внутри кода? все таки это прикладная платформа, она должна сама заботится о наличии подобных данных.
"Функция полезна в тех
случаях, когда необходимо получить данные индикатора сразу после его создания
(получения хендла индикатора)." , что значит сразу? получается, что при вызове из Oninit - "не сразу", из какой то другой функции - "сразу".
Если хендл индикатора создается в OnInit (мы говорим о создании хендла именно в индикаторе), то к моменту обращения за данными этого индикатора в функции OnCalculate() все расчеты с большой вероятностью уже будут завершены.
Если вызов iCustom производится в OnCalculate(), то исполнительная система просто не успеет рассчитать данные сразу же после создания хендла индикатора. Это потребует хоть и очень малого времени, но потребует.
- www.mql5.com
А ведь правда.
Rosh писал(а) # :
Никакая мощная система не исключает необходимости проверок. Эти проверки можно спрятать внутри исполняющей системы и отдавать данные только после полного расчета (со всеми тормозами, если код индикатора написан криво), либо дать возможность программисту самостоятельно контролировать готовность затребованных данных.
Если хендл индикатора создается в OnInit (мы говорим о создании хендла именно в индикаторе), то к моменту обращения за данными этого индикатора в функции OnCalculate() все расчеты с большой вероятностью уже будут завершены.
Если хендл индикатора создается в OnInit (мы говорим о создании хендла именно в индикаторе), то к моменту обращения за данными этого индикатора в функции OnCalculate() все расчеты с большой вероятностью уже будут завершены.
Если вызов iCustom производится в OnCalculate(), то исполнительная система просто не успеет рассчитать данные сразу же после создания хендла индикатора. Это потребует хоть и очень малого времени, но потребует.
Вы уж извините, что я упорствую в своих заблуждениях. Но и Вы поймите (как знать, может мы и сможем повлиять на Вас) - мне нужен инструмент, которым было бы комфортно пользоваться. Если встает вопрос выбора - написать много строк, и это будет работать быстро, или мало, но, возможно, медленно, я выбираю второй( какая разница - будет график выводится за 0.00001 или 0.0001 секунды?), т.к. такой код легче сопровождать и в нем меньше невыявленных ошибок, компьютеры с течением времени работают быстрее, а не медленнее, лучче купить новую производительную железку, чем писать горы строк. Ну если написанный код будет работать медленно (то о чем говорится выше), ну мы ж не совсем бараны, если нужно будет, то найдем в своих кодах и подправим узкие моменты.
Как раз в последнем билде мы изменили алгоритм работы CopyXXX функций для работы в синхронном режиме при вызовах из экспертов и скриптов (но не в индикаторах). То есть, теперь эти функции практически гарантированно отдают запрошенные данные без необходимости обвязки через ожидание.
К сожалению, CopyXXX функции внутри индикаторов не могут работать в синхронном режиме, так как это не просто затормозит расчет и отрисовку индикаторов, а фактически остановит терминал.
В этом случае при обращениях из индикаторов к другим таймсериям нужно использовать контроль доступности данных и самостоятельно пропускать расчет до тех пор, пока данные не будут доставлены.
Как раз в последнем билде мы изменили алгоритм работы 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 ); }
данные получить удается
подскажите, кто знает - есть ли на форуме поиск, вроде бы была ветка, посвященная закачиванию истории программно - не могу ее найти.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
код индикатора:
лог:
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:
лог:
2010.02.14 11:15:15 testinit (GBPUSD,H4) error get data from custom indicator 4806 rates_total= 8223