обновление раздаваемой панельки и продолжение рассуждений про GUI и его устройство
панелька получила некоторые обновления, визуально - теперь умеет подписывать вертикальные линии. Чуть (почти незаметно) подправлены подписи. Отметки позиций теперь учитывают своп и комиссии, раньше были просто на средне-взвешенной цене.
подобороты некоторые баги и конечно-же добавлены новые :-)
А теперь снова к GUI
В прошлый раз коснулись OnChartEvent (что в советниках ему лучше и не быть вовсе, чтобы не быть заспамленным) и отчасти синхронных функций (с которыми надо быть осторожным). Теперь посмотрим как советники взаимодействуют с ипостасью чарта в лице индикаторов.
Простецкий индикатор, который при старте говорит в котором треде он запущен, а далее печатает события которые получает. В расчётной части - в единственном буфере суммирует "сколько баров было рассчитано"
#property indicator_chart_window #property indicator_buffers 1 #property indicator_plots 1 #property indicator_label1 "FAKE" #property indicator_type1 DRAW_NONE #property indicator_color1 clrNONE #property indicator_style1 STYLE_SOLID #property indicator_width1 1 #include <WinAPI/processthreadsapi.mqh> double FAKE[]; long counter; int OnInit() { counter=0; uint threadid=GetCurrentThreadId(); PrintFormat("Indicator thread %d",threadid); SetIndexBuffer(0,FAKE,INDICATOR_DATA); return(INIT_SUCCEEDED); } 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[]) { ArraySetAsSeries(FAKE,true); for(int bar=prev_calculated;bar<rates_total;bar++) { int i= rates_total - bar - 1; FAKE[i]=(double)(counter++); } return(rates_total); } void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { PrintFormat("OnChartEvent id=%d (%s) lparam=%d dparam=%f sparam=%s", id,EnumToString((ENUM_CHART_EVENT)id),lparam,dparam,sparam); }
и столь же простой советник использующий индикатор - тоже печатает к которой нитке запущен и далее в таймере смотрит и говорит сколько баров было обсчитано
#include <WinAPI/processthreadsapi.mqh> int handle=INVALID_HANDLE; double lastValue=0; int OnInit() { uint threadid=GetCurrentThreadId(); PrintFormat("Expert thread %d",threadid); handle=iCustom(_Symbol,PERIOD_CURRENT,"/Indicators/PrintChartEvents"); if (handle==INVALID_HANDLE) { Alert(StringFormat("Unable to create indicator,err=%d",GetLastError())); return INIT_FAILED; } lastValue=0; EventSetTimer(60); return(INIT_SUCCEEDED); } void OnDeinit(const int reason) { if (handle!=INVALID_HANDLE) IndicatorRelease(handle); EventKillTimer(); } void OnTick() { } void OnTimer() { double data[2]; CopyBuffer(handle,0,0,2,data); if (data[1]!=lastValue) { lastValue=data[1]; PrintFormat("lastValue=%f",lastValue); } }
Запускаем советник, смотрим в журнал:
про это в документации сказано, но не всеми воспринимается: ВСЕ ИНДИКАТОРЫ ЗАПУСКАЮТСЯ В ТРЕДЕ ЧАРТА. А советник в отдельном. ВСЕ индикаторы разделяют один ресурс - тред чарта. Их OnCalculate() будут вызываться последовательно. Буферы индикатора разделяются между индикатором и советником.
Конечно разработчики терминала "костьми легли" на выстраивании приоритетов и разделении индикаторных буферов, но всё равно на CopyBuffer можно получить пенальти в виде непредвиденной задержки - если данные всё ещё не готовы в OnCalculate. Например вызван синхронный ObjectFind(), а в чарте много необработанных запросов. Или просто "долго рисуется". Это кстати веская причина по которой запрещён WebRequest в индикаторах.
Выход: минимизировать (а лучше вообще избегать) использование синхронных функций внутри OnCalculate индикаторов. Например не использовать их при открытии бара,ведь советники большую часть данных запрашивают именно в этот момент.
С событиями и индикаторами вроде почти всё, надводную часть айсберга почти изучили ;-) Остаётся всего 9/10
Прицеплена последняя версия панельки. Для демок без ограничений, для реала 2 месяца