Полная загрузка истории графика перед выполнением функций индикатора

 

Прошу поделиться готовым решением.

Пример: мне надо рисовать вертикальную линию в 12:00, я меняю инструмент на текущем графике (через Enter ввожу например), терминал загружает последние бары, включая бар со временем открытия 12:00, но вертикальная линия не рисуется.

 
Botan626:

Прошу поделиться готовым решением.

Пример: мне надо рисовать вертикальную линию в 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);
  }
//+------------------------------------------------------------------+
Файлы:
 
При помощи ChartNavigate() можно подгрузить историю. 
 
Dmitry Fedoseev #:
При помощи ChartNavigate() можно подгрузить историю. 

Каким образом? А не будет проблемы в том случае, например, когда история загружается долго?

 
Botan626 #:

Проблема в том, что написано в названии темы, код для рисования вертикальной линии у меня есть.

Явного способа определения окончания подкачки в 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() использовать между вызовами.

В индикаторе - таймер. 

 
Ihor Herasko #:

К примеру, я использую такой способ

В это случае 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 не будут равны часы открытия, не производить расчёты в индикаторе. Плохой способ?

 
Ihor Herasko #:

Правда, это для случаев с другим ТФ, отличным от текущего. Для текущего ТФ нужно будет поисследовать, вернет ли функция когда-нибудь 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", даже когда график загружал историю.

 
Dmitry Fedoseev #:

Если количество баров не меняется - значит закончили.

Как понять, что кол-во баров больше не будет меняться?  Таймер на сколько выставлять?

Сам способ интересный, может быть есть готовый код?

 
Botan626 #:

Как понять, что кол-во баров больше не будет меняться?  Таймер на сколько выставлять?

Сам способ интересный, может быть есть готовый код?

Понять никак, но предположить можно. Например, если в течении секунды вызываете ChartNavigate(), но количество баров не меняется. 

Сами решите для себя, какая задержка будет казаться приемлемой. 

Эксперимент можно провести - вызвать один раз  ChartNavigate() и следить за тем, как количество баров меняется. 

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