Прошу поделиться готовым решением.
Пример: мне надо рисовать вертикальную линию в 12:00,
Вертикальная линия отображается при помощи следующего кода (пример из справки):
bool VLineCreate(const long chart_ID=0, // ID графика const string name="VLine", // имя линии const int sub_window=0, // номер подокна datetime time=0, // время линии const color clr=clrRed, // цвет линии const ENUM_LINE_STYLE style=STYLE_SOLID, // стиль линии const int width=1, // толщина линии const bool back=false, // на заднем плане const bool selection=true, // выделить для перемещений const bool hidden=true, // скрыт в списке объектов const long z_order=0) // приоритет на нажатие мышью { //--- если время линии не задано, то проводим ее через последний бар if(!time) time=TimeCurrent(); //--- сбросим значение ошибки ResetLastError(); //--- создадим вертикальную линию if(!ObjectCreate(chart_ID,name,OBJ_VLINE,sub_window,time,0)) { Print(__FUNCTION__, ": не удалось создать вертикальную линию! Код ошибки = ",GetLastError()); return(false); } //--- установим цвет линии ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr); //--- установим стиль отображения линии ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style); //--- установим толщину линии ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,width); //--- отобразим на переднем (false) или заднем (true) плане ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back); //--- включим (true) или отключим (false) режим перемещения линии мышью //--- при создании графического объекта функцией ObjectCreate, по умолчанию объект //--- нельзя выделить и перемещать. Внутри же этого метода параметр selection //--- по умолчанию равен true, что позволяет выделять и перемещать этот объект ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection); ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection); //--- скроем (true) или отобразим (false) имя графического объекта в списке объектов ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden); //--- установим приоритет на получение события нажатия мыши на графике ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order); //--- успешное выполнение return(true); }
я меняю инструмент на текущем графике (через Enter ввожу например), терминал загружает последние бары, включая бар со временем открытия 12:00, но вертикальная линия не рисуется.
Вот тут не понятно: нужно, чтобы теперь не стало вертикальной линии или проблема в том, что линия исчезает? Если второе, то покажите тот код, к которому приводит подобное поведение.
@Ihor Herasko, благодарю за ответ.
Проблема в том, что написано в названии темы, код для рисования вертикальной линии у меня есть.
Более подробно: я переключаю таймфреймы и инструменты на графике с помощью кнопок на экране (см. прикреплённый файл), после переключения терминал загружает отсутствующую историю и если новые бары имеют время открытия такое-же, какое задано для рисования вертикальных линий, верт. линии не рисуются. Получается, мне необходимо дождаться загрузки всей истории, и только после этого рисовать вертикальные линии. Вот это у меня не получается.
Я пробовал это Download history in MQL4 EA и это Загрузка графика перед стартом индикатора, но так и не понял, как это применять.
#property strict #property indicator_chart_window #property indicator_buffers 1 #define HR0100 (PERIOD_H1*60) #define HR2400 (PERIOD_D1*60) #define SYMBOL string //int TimeOfDay(datetime when=0){ if(when == 0) when = TimeCurrent(); // return( int(when % HR2400 ));} //datetime DateOfDay(datetime when=0){ if(when == 0) when = TimeCurrent(); // return( when - TimeOfDay(when));} sinput string times01 = "9 12"; //Vertical Line 01 Hour Times sinput string TFs01 = "M1 M5 M15 M30 H1"; //Vertical Line 01 Visibility Timeframes sinput int days01 = 5; //Vertical Line 01 Number of Days sinput color line01color = clrLightSeaGreen; //Vertical Line 01 Color sinput ENUM_LINE_STYLE line01style = STYLE_DOT; //Vertical Line 01 Style sinput int line01width = 1; //Vertical Line 01 Width string hours01[], obj, currentperiod; //+------------------------------------------------------------------+ int OnInit() { obj = "VLs "; currentperiod=StringSubstr(EnumToString((ENUM_TIMEFRAMES)_Period),7); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(reason==1 || reason==2 || reason==3 || reason==4 || reason==5 || reason==6 || reason==7 || reason==8 || reason==9){ ObjectsDeleteAll(0,obj,0,OBJ_VLINE); ChartRedraw(0); //ObjectsDeleteAll(0,0,OBJ_VLINE); ChartRedraw(0); ArrayFree(hours01);} } //+------------------------------------------------------------------+ bool download_history(ENUM_TIMEFRAMES period){ return download_history(_Symbol, period);} //+------------------------------------------------------------------+ bool download_history(SYMBOL symbol, ENUM_TIMEFRAMES period) { if(period == PERIOD_CURRENT) period = (ENUM_TIMEFRAMES)_Period; ResetLastError(); datetime other = iTime(symbol, period, 0); if(_LastError == 0 && other != 0) return true; if(_LastError != ERR_HISTORY_WILL_UPDATED && _LastError != ERR_NO_HISTORY_DATA) PrintFormat("iTime(%s,%i) Failed: %i", symbol, period, _LastError); return false; } //+------------------------------------------------------------------+ bool IsTFDataReady(ENUM_TIMEFRAMES eTF) { ResetLastError(); iTime(_Symbol,eTF,1); return GetLastError()==ERR_NO_ERROR; } //+------------------------------------------------------------------+ 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[]) { //ObjectCreate(0,"VLine",OBJ_VLINE,0,iTime(NULL,0,0)-iTime(NULL,0,0)%HR2400+12*HR0100,0); //if(!download_history(PERIOD_CURRENT) && !download_history(PERIOD_D1)) return prev_calculated; //if(IsTFDataReady(PERIOD_CURRENT)&&IsTFDataReady(PERIOD_D1)) if(TFs01!="" && times01!=""){ string TFs=TFs01; StringTrimLeft(TFs); StringTrimRight(TFs); StringToUpper(TFs); string sep=" "; ushort u_sep=StringGetCharacter(sep,0); StringSplit(times01,u_sep,hours01); if(StringFind(TFs,currentperiod,0)!=-1){ for(int i=0; i<ArraySize(hours01); i++){ int c=0; datetime plottime=0; for(int l=0; l<days01; l++){ datetime plotday=iTime(_Symbol,0,0)-iTime(_Symbol,0,0)%HR2400-(l+c)*PeriodSeconds(PERIOD_D1); MqlDateTime plotdaystruct; TimeToStruct(plotday,plotdaystruct); if((ENUM_DAY_OF_WEEK)plotdaystruct.day_of_week==0) {plotday -= 2*PeriodSeconds(PERIOD_D1); c+=2;} if((ENUM_DAY_OF_WEEK)plotdaystruct.day_of_week==6) {plotday -= PeriodSeconds(PERIOD_D1); c+=1;} if(iTime(_Symbol,0,iBarShift(_Symbol,0,plotday+(int)hours01[i]*HR0100,true))-(plotday+(int)hours01[i]*HR0100) != 0){ if(i<ArraySize(hours01)-1 && iTime(_Symbol,0,iBarShift(_Symbol,0,plotday+(int)hours01[i]*HR0100,false)-1)-iTime(_Symbol,0,iBarShift(_Symbol,0,plotday+(int)hours01[i+1]*HR0100,false))==0) break; plottime=iTime(_Symbol,0,iBarShift(_Symbol,0,plotday+(int)hours01[i]*HR0100,false)-1);} if(iTime(_Symbol,0,iBarShift(_Symbol,0,plotday+(int)hours01[i]*HR0100,true))-(plotday+(int)hours01[i]*HR0100) == 0) plottime=iTime(_Symbol,0,iBarShift(_Symbol,0,plotday+(int)hours01[i]*HR0100,false)); ObjectCreate(0,obj+StringFormat("%02s",hours01[i])+" "+StringFormat("%02s",(string)(l+1)),OBJ_VLINE,0,plottime,0); ObjectSet(obj+StringFormat("%02s",hours01[i])+" "+StringFormat("%02s",(string)(l+1)),OBJPROP_COLOR,line01color); ObjectSet(obj+StringFormat("%02s",hours01[i])+" "+StringFormat("%02s",(string)(l+1)),OBJPROP_STYLE,line01style); ObjectSet(obj+StringFormat("%02s",hours01[i])+" "+StringFormat("%02s",(string)(l+1)),OBJPROP_WIDTH,line01width); ObjectSet(obj+StringFormat("%02s",hours01[i])+" "+StringFormat("%02s",(string)(l+1)),OBJPROP_BACK,true); ObjectSet(obj+StringFormat("%02s",hours01[i])+" "+StringFormat("%02s",(string)(l+1)),OBJPROP_SELECTABLE,false); ObjectSet(obj+StringFormat("%02s",hours01[i])+" "+StringFormat("%02s",(string)(l+1)),OBJPROP_HIDDEN,true);}}}} return(rates_total); } //+------------------------------------------------------------------+
Проблема в том, что написано в названии темы, код для рисования вертикальной линии у меня есть.
Явного способа определения окончания подкачки в MQL4 нет. Есть лишь косвенные способы. К примеру, я использую такой способ:
bool IsTFDataReady(int tf) { ResetLastError(); iTime(NULL, tf, 1); return GetLastError() == ERR_NO_ERROR; }
Правда, это для случаев с другим ТФ, отличным от текущего. Для текущего ТФ нужно будет поисследовать, вернет ли функция когда-нибудь false.
Другим способом контроля видится сравнение количества баров при каждом событии Calculate. До тех пор, пока количество баров прирастает на 2 бара и больше, не производим запуск расчетной части индикатора. Что-то вроде такого:
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[]) { static int nPrevBars = 0; if (rates_total - 2 >= nPrevBars) { nPrevBars = rates_total; return 0; } // Расчетная часть индикатора }
Только это, к сожалению, тоже не 100%-ый способ.
Несколько раз вызвать функцию. Параметры - так, чтобы за пределы начала графика прокрутить, тогда будет подкачка.
Если количество баров не меняется - значит закончили.
В эксперта можно Sleep() использовать между вызовами.
В индикаторе - таймер.
В это случае OnCalculate должен быть таким:
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(IsTFDataReady(PERIOD_CURRENT)) { // Расчетная часть индикатора } return(rates_total); }
? Что-то ещё добавлять надо?
А если такой способ: сравнивать время открытия последнего бара с текущим временем сервера TimeCurrent, и пока, например, на H1 не будут равны часы открытия, не производить расчёты в индикаторе. Плохой способ?
Правда, это для случаев с другим ТФ, отличным от текущего. Для текущего ТФ нужно будет поисследовать, вернет ли функция когда-нибудь false.
Скорее всего нет, я добавил вывод последней ошибки
bool IsTFDataReady(ENUM_TIMEFRAMES eTF) { ResetLastError(); iTime(_Symbol,eTF,1); PrintFormat("iTime(%s,%i) LastError: %i", _Symbol, _Period, _LastError); return GetLastError()==ERR_NO_ERROR; }
терминал выводит только 0 ошибку "2022.05.30 20:58:31.507 Vertical Lines 02 USDNOK,H1: iTime(USDNOK,60) LastError: 0", даже когда график загружал историю.
Как понять, что кол-во баров больше не будет меняться? Таймер на сколько выставлять?
Сам способ интересный, может быть есть готовый код?
Как понять, что кол-во баров больше не будет меняться? Таймер на сколько выставлять?
Сам способ интересный, может быть есть готовый код?
Понять никак, но предположить можно. Например, если в течении секунды вызываете ChartNavigate(), но количество баров не меняется.
Сами решите для себя, какая задержка будет казаться приемлемой.
Эксперимент можно провести - вызвать один раз ChartNavigate() и следить за тем, как количество баров меняется.

- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Прошу поделиться готовым решением.
Пример: мне надо рисовать вертикальную линию в 12:00, я меняю инструмент на текущем графике (через Enter ввожу например), терминал загружает последние бары, включая бар со временем открытия 12:00, но вертикальная линия не рисуется.