Отличие работы прорисовки нескольких линий индикатора в МТ4 и в МТ5 - страница 6

 
Eugeni Neumoin:

Полагаю, все проблемы из-за (цитата из описания языка со страницы по доступу к таймсериям): "...Это связано с тем, что в целях экономии ресурсов в MetaTrader 5 не хранится полная копия требуемых данных для mql5-программы, а дается прямой доступ к базе данных терминала...".

Добились экономии ресурсов, но потеряли в эффективности. Фактически потеря ресурса времени.

Почему нужны котировки по всем таймфреймам?

Если мы вручную привязываем к барам, допустим, вилы Эндрюса. В МТ5 грамотно решено с ручной привязкой. Вилы по времени привязываются точно к тому моменту, когда был макимум или минимум бара. И при переключении на младший тф вилы всегда оказываются привязанными к максимуму или минимуму баров.

А вот при программном выведении на график вил Эндрюса такого не происходит. Необходимо в программе находить точное время максимумов и минимумов. Иначе при переходе на младшие тф вилы будут привязаны к точкам, находящимся в воздухе.

Пример для вывода вил на месячном тф по паре EURUSD:

//+------------------------------------------------------------------+
//|                                                      AP_test.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+

bool yes;

int OnInit()
  {
//--- indicator buffers mapping
   yes=true;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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 (yes)
     {
      datetime t_1 = D'31.03.1995 00:00';
      datetime t_2 = D'01.10.2000 00:00';
      datetime t_3 = D'01.07.2008 00:00';
      double   a,b,c;
      int      shift;
      string   nameObj="AP_test";

/*
      double   arr[];
      shift=iBarShift(_Symbol,PERIOD_MN1,t_1,false);
      CopyHigh(_Symbol,PERIOD_MN1,shift,1,arr);
      a=arr[0];
      shift=iBarShift(_Symbol,PERIOD_MN1,t_2,false);
      CopyLow(_Symbol,PERIOD_MN1,shift,1,arr);
      b=arr[0];
      shift=iBarShift(_Symbol,PERIOD_MN1,t_3,false);
      CopyHigh(_Symbol,PERIOD_MN1,shift,1,arr);
      c=arr[0];
*/
      shift=iBarShift(_Symbol,PERIOD_MN1,t_1,false);
      a=iHigh(_Symbol,PERIOD_MN1,shift);
      shift=iBarShift(_Symbol,PERIOD_MN1,t_2,false);
      b=iLow(_Symbol,PERIOD_MN1,shift);
      shift=iBarShift(_Symbol,PERIOD_MN1,t_3,false);
      c=iHigh(_Symbol,PERIOD_MN1,shift);
   
      ObjectCreate(0,nameObj,OBJ_PITCHFORK,0,t_1,a,t_2,b,t_3,c);
      ObjectSetInteger(0,nameObj,OBJPROP_STYLE,0);
      ObjectSetInteger(0,nameObj,OBJPROP_WIDTH,0);
      ObjectSetInteger(0,nameObj,OBJPROP_COLOR,clrRed);
      ObjectSetInteger(0,nameObj,OBJPROP_RAY_RIGHT,true);
      ObjectSetInteger(0,nameObj,OBJPROP_LEVELS,0); 
      ObjectSetInteger(0,nameObj,OBJPROP_SELECTABLE,true); 
//   ObjectSetInteger(0,nameObj,OBJPROP_SELECTED,true); 
      
      ChartRedraw();

      yes=false;
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

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

Для всех этих целей и необходим быстрый доступ ко всем таймсериям всех таймфреймов.

Это первое.

Второе. То, что говорят будто котировки с сервера приходят в виде упакованных минутных таймсерий, является неправдой. Если посмотреть размер HCC файлов по всей доступной истории по паре EURUSD с сервера Метаквотес, то до 1998 года включительно размер файлов не превышает 79 кб. И при выводе этой пары на график на месячном, недельном и дневном тф размер графика меняется. А вот при дальнейшем уменьшении тф вплоть до  двухчасового тф график не изменяется.

Начиная с 1999 года размер HCC файлов превышает 17 000 кб. И здесь уже необходимо программно проверять, с какого тф приходят упакованные котировки. Есть сомнения, что на каком-то участке также упакованные котировки взяты не с минутного тф.

Следовательно до 1998 года с сервера приходят упакованные не минутки, а дневки. И все графические построения до 1999 года будут корректными только на тф не ниже дневок. На более мелких тф в этом промежутке все графические построения некорректные. 

Использование аналитических объектов - Графики котировок, технический и фундаментальный анализ - MetaTrader 5
Использование аналитических объектов - Графики котировок, технический и фундаментальный анализ - MetaTrader 5
  • www.metatrader5.com
Определение трендов, построение каналов, выявление циклов и уровней поддержки/сопротивления — все эти и многие другие задачи решаются при помощи аналитических объектов. Всего в торговой платформе доступно 46 таких инструментов. Среди них имеются геометрические фигуры, различные каналы, инструменты Ганна, Фибоначчи, Эллиотта и многое другое. В...
 

Пройдемся далее по вилам Эндрюса в МТ5.

С какой целью созданы в вилах уровни так, как они выводятся, для меня уже много лет загадка.

Вот пример вывода уровня 0.618:

Вилы из МТ5

Развитие ценового движения происходит от третьей точки привязки вил внутрь канала вил. С какой целью рисуется уровень выше третьей точки привязки для меня загадка. Сделано как-то бестолково. Да и нижний уровень также получается бесполезным.

Но вот если строить уровни от третьей точки внутрь вил таким образом, что расстояние от третьей точки привязки до второй точки привязки брать за 100%, то все кардинально меняется. Линии начинают работать. Они приобретают смысл:

Полный комплект вил из ZUP

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

Единственное объяснение может быть следующим. При построении какой-то медианы на рынке, к которой цены подходят с двух сторон и отскакивают от медианы. В этом случае необходимо брать какую-то базу, относительно которой строить уровни в разные стороны. Но это уже не на 100% вилы Эндрюса будут. Это будет какой-то другой графический инструмент.

 
Rashid Umarov:

Как я это вижу: Для начала можно сделать вывод в лог информацию о том, что таймфрейм синхронизирован - при переключении.  То что описано в Организация доступа к данным, но под свои задачи.

Когда будет сделано решение "я на 100% знаю, что таймфрейм синхронизирован и готов к использованию", то будет ясно в какой момент можно что-то требовать от объектов на этом таймфрейме.

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

Поставил программу test на тф D1 по EURUSD. Выгрузил из памяти терминал. Удалил историю по всем символам. Вновь запустил терминал.

Результат:

2019.06.27 18:44:08.639 test (EURUSD,D1) 29 open time=2019.06.27 18:44:08

2019.06.27 19:11:30.707 test (EURUSD,D1) 73 end time=2019.06.27 19:11:30


Примерно 27 минут загружалось и формировались таймсерии.

Текст программы:

//+------------------------------------------------------------------+
//|                                                         test.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window

bool set_tf_load=true;
bool end_set_time=true;

string TF_txt[21]={"m1","m2","m3","m4","m5","m6","m10","m12","m15","m20","m30","H1","H2","H3","H4","H6","H8","H12","D1","W1","MN1"};
ENUM_TIMEFRAMES etf[21]={PERIOD_M1,PERIOD_M2,PERIOD_M3,PERIOD_M4,PERIOD_M5,PERIOD_M6,PERIOD_M10,PERIOD_M12,PERIOD_M15,PERIOD_M20,PERIOD_M30,PERIOD_H1,PERIOD_H2,PERIOD_H3,PERIOD_H4,PERIOD_H6,PERIOD_H8,PERIOD_H12,PERIOD_D1,PERIOD_W1,PERIOD_MN1};

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   EventSetMillisecondTimer(50);
   end_set_time=true;

Print("");
Print(__LINE__," open time=",TimeLocal());
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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[])
  {
//---
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   set_tf_load=true;

   CheckLoadHistory();

   if (set_tf_load && end_set_time) {Print(__LINE__," end time=",TimeLocal()); end_set_time=false;}
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+ 
//|                                                                  | 
//+------------------------------------------------------------------+ 
void CheckLoadHistory() 
  { 
   datetime start_date;
   datetime first_date=0; 
   datetime times[100]; 
//--- check symbol & period 

   ENUM_TIMEFRAMES period;

//--- max bars in chart from terminal options 
   int max_bars=TerminalInfoInteger(TERMINAL_MAXBARS); 
//--- load symbol history info 
   datetime first_server_date=0; 
   while(!SeriesInfoInteger(_Symbol,PERIOD_M1,SERIES_SERVER_FIRSTDATE,first_server_date) && !IsStopped()) 
      Sleep(5); 
      
   start_date=first_server_date;

   for (int i=20;i>=0;i--)
     {
      period=etf[i];
      if (period==Period()) continue;
//--- load data step by step 
      int fail_cnt=0; 
      while(!IsStopped()) 
        { 
         //--- wait for timeseries build 
         while(!SeriesInfoInteger(_Symbol,period,SERIES_SYNCHRONIZED) && !IsStopped()) 
            Sleep(5); 
         //--- ask for built bars 
         int bars=Bars(_Symbol,period); 
         if(bars>0) 
           { 
            if(bars>=max_bars)  {break;}
            //--- ask for first date 
            if(SeriesInfoInteger(_Symbol,period,SERIES_FIRSTDATE,first_date)) 
               if(first_date>0 && first_date<=start_date) {set_tf_load=true; break;} 
           } 

         //--- copying of next part forces data loading 
         int copied=CopyTime(_Symbol,period,bars,100,times); 
         if(copied>0) 
           { 
            //--- check for data 
            if(times[0]<=start_date)  break; 
            if(bars+copied>=max_bars) break; 
            fail_cnt=0; 
           } 
         else 
           { 
            //--- no more than 100 failed attempts 
            fail_cnt++; 
            if(fail_cnt>=100) {set_tf_load=false; break;}
            Sleep(10); 
           } 
        } 

      datetime t=iTime(_Symbol,period,max_bars-1);
      if (t>0 && t>start_date) start_date=t;
     }
//--- stopped 
   if (IsStopped()) set_tf_load=false; 
  } 
//+----

Грустно как-то. Чтобы все корректно работало, необходимо вначале подождать 27 минут загрузки данных.

Из описания языка MQL5 цитата: "...При доступе к ценовым данным или к значениям индикаторов из mql5-программ следует помнить, что не гарантируется их доступность в определенный момент времени, либо с определенного момента времени. Это связано с тем, что в целях экономии ресурсов в MetaTrader 5 не хранится полная копия требуемых данных для mql5-программы, а дается прямой доступ к базе данных терминала..."

Где-то еще про экономию ресурсов в описании встречал текст.

Классная экономия получилась. В МТ4 без такой экономии все работает быстро, всегда есть доступ к данным.

Буду думать, как оптимизировать процесс. 

 

Справедливости ради добавлю, в МТ4 такой тест не проводил. То есть не удалял истории по все символам.

Но там нет такого, что приходится смотреть на экран с надписью ОЖИДАНИЕ ОБНОВЛЕНИЯ. Там все сразу строится на доступной истории. А в МТ5 попробовал строить на доступной истории. Результат - чуть ранее выкладывал картинку с артефактами... и некоторые другие ляпы выскакивают.

 

Наверное, надо загружать историю текущего тф. Определять время самого первого бара загруженной истории. И загружать по всем тф историю в глубину не далее времени самого первого бара текущего тф. Но при каждом новом вызове функции загрузки истории добавлять сколько возможно истории на месячном тф. Когда есть полная история на месячном тф, все остальные тф загружаются относительно быстро. Если имеется только история по месячному тф, полная загрузка по всем тф происходит где-то за 3-4 минуты. 

Пока видится такой оптимизационный цикл.

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