Скачать MetaTrader 5

CopyTime

Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий
Не знаешь язык собеседника? Функция автоматического перевода тебе поможет!
Prival
4550
Prival 2010.05.14 13:02 

Код

 

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//---- plot Line
#property indicator_label1  "Line"
#property indicator_type1   DRAW_LINE
#property indicator_color1  DarkBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2
//--- indicator buffers
double         LineBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,LineBuffer,INDICATOR_DATA);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate (const int rates_total,      // размер входных таймсерий
                 const int prev_calculated,  // обработано баров на предыдущем вызове
                 const datetime& time[],     // Time
                 const double& open[],       // Open
                 const double& high[],       // High
                 const double& low[],        // Low
                 const double& close[],      // Close
                 const long& tick_volume[],  // Tick Volume
                 const long& volume[],       // Real Volume
                 const int& spread[])        // Spread
  {
// ничего не считаем и ничего не рисуем на графике
   if(rates_total<0)                 return(0);           
// работаем только по закончившимся барам
   if(rates_total==prev_calculated)  return(rates_total);
   
   int start,j,copied_M5,copied_M15;
   datetime time_M5[1],time_M15[1]; 
   ArraySetAsSeries(time,true);

   for(int i=1;i>=0;i--)  {
   ResetLastError();
   copied_M5 =CopyTime(_Symbol,PERIOD_M5 ,time[i],1,time_M5 );
   copied_M15=CopyTime(_Symbol,PERIOD_M15,time[i],1,time_M15);
   if(copied_M5<1 || copied_M15<1) Print("************* ОШИБКА *****************");
   Print("i=",i," TF=",_Period," time[i]=",time[i], " copied=",copied_M5," time_M5=",time_M5[0]," copied=",copied_M15," time_M15=",time_M15[0]," ",_LastError);
   }
    
//--- return value of prev_calculated for next call
   return(rates_total);
  }
  1. Запускаем на M1. Ошибок нет.
  2. Запускаем на М5. С появлением нового бара идут ошибки. Иногда сразу при запуске
  3. Закомментируем строку. Ошибок нет.
   if(rates_total==prev_calculated)  return(rates_total);

 

В принципе же ничего не поменялось. Хочется сделать индикатор легче – запрашивать нужные данные не каждый тик, а с появлением  нового бара. Но в этом случае идет ошибка ((

 

Что делать ?

Также остался без ответа вот этот вопрос https://www.mql5.com/ru/forum/821/page2

Погружаемся в особенности индикаторов MetaTrader 5
Погружаемся в особенности индикаторов MetaTrader 5
  • www.mql5.com
Погружаемся в особенности индикаторов MetaTrader 5.
Rashid Umarov
Админ
11841
Rashid Umarov 2010.05.14 13:19  
Prival писал(а)  :

Код

  1. Запускаем на M1. Ошибок нет.
  2. Запускаем на М5. С появлением нового бара идут ошибки. Иногда сразу при запуске
Вы смотрели раздел Организация доступа к данным? Запрашиваемые данные могут перестраиваться в момент обращения, в таком случае фунция Copy...() может возвращать -1. Почему Вы не запрашиваете код ошибки в таких случаях? Есть же функция GetLastError().

Prival
4550
Prival 2010.05.14 13:44  

Конечно же запрашиваю. 4401 Запрашиваемая история не найдена.

Бьюсь уже дня три с этим кодом. Никак его до ума не могу довести. Если я правильно понимаю. Он перестает работать  из-за"....Для экономии ресурсов данные по таймфрейму загружаются и хранятся в оперативной памяти только по необходимости, при длительном отсутствии обращений к данным происходит выгрузка их из оперативной памяти с сохранением в файл."

вот код.

//| возвращает true если новый бар, иначе false                      |
//+------------------------------------------------------------------+
bool isNewBar_i(datetime date, ENUM_TIMEFRAMES timeFrame)
  {
//----
   static datetime old_Times[21];// массив для хранения старых значений времени
   bool res=false;               // переменная результата анализа  
   int  pos;                     // номер ячейки массива old_Times[]     
   datetime new_Time[1];         // время нового бара

   switch(timeFrame)
     {
      case PERIOD_M1:  pos= 0; break;
      case PERIOD_M2:  pos= 1; break;
      case PERIOD_M3:  pos= 2; break;
      case PERIOD_M4:  pos= 3; break;
      case PERIOD_M5:  pos= 4; break;
      case PERIOD_M6:  pos= 5; break;
      case PERIOD_M10: pos= 6; break;
      case PERIOD_M12: pos= 7; break;
      case PERIOD_M15: pos= 8; break;
      case PERIOD_M20: pos= 9; break;
      case PERIOD_M30: pos=10; break;
      case PERIOD_H1:  pos=11; break;
      case PERIOD_H2:  pos=12; break;
      case PERIOD_H3:  pos=13; break;
      case PERIOD_H4:  pos=14; break;
      case PERIOD_H6:  pos=15; break;
      case PERIOD_H8:  pos=16; break;
      case PERIOD_H12: pos=17; break;
      case PERIOD_D1:  pos=18; break;
      case PERIOD_W1:  pos=19; break;
      case PERIOD_MN1: pos=20; break;
     }
   // скопируем время запрашиваемого по времени бара в ячейку new_Time[0]   
   int copied=CopyTime(_Symbol,timeFrame,date,1,new_Time);
   //Print("isNewBars ",_Symbol," timeFrame=",timeFrame," date=",date," copied=",copied," pos=",pos," new=",new_Time[0]," old=",old_Times[pos] );
   if(copied>0) // все ок. данные скопированы
      {
      if(old_Times[pos]!=new_Time[0])       // если старое время бара не равно новому
         {
         if(old_Times[pos]!=0) res=true;    // если это не первый запуск, то истина = новый бар
         old_Times[pos]=new_Time[0];        // запоминаем время бара
         }  
      }
//---- 
   return(res);
  }
  

 В справке даны рекомендации

"Для экспертов и пользовательских индикаторов лучше использовать событийную модель обработки. Если при обработке события OnTick() или OnCalculate() не удалось получить все необходимые данные требуемой таймсерии, то следует выйти из обработчика события, рассчитывая на появление доступа к данным при следующем вызове обработчика." 

как мне выйти в этой функции из обработчика события  OnCalculate() непонимаю. Sleep тоже нельзя.

 

Aleksey Sergan
23886
Aleksey Sergan 2010.05.14 14:10  

так ошибка не выдается

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_plots   1
//---- plot Line
#property indicator_label1  "Line"
#property indicator_type1   DRAW_LINE
#property indicator_color1  DarkBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2
//--- indicator buffers
double         LineBuffer[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,LineBuffer,INDICATOR_DATA);
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate (const int rates_total,      // размер входных таймсерий
                 const int prev_calculated,  // обработано баров на предыдущем вызове
                 const datetime& time[],     // Time
                 const double& open[],       // Open
                 const double& high[],       // High
                 const double& low[],        // Low
                 const double& close[],      // Close
                 const long& tick_volume[],  // Tick Volume
                 const long& volume[],       // Real Volume
                 const int& spread[])        // Spread
  {
// ничего не считаем и ничего не рисуем на графике
   if(rates_total<0)                 return(0);           
// работаем только по закончившимся барам
   if(rates_total==prev_calculated)  return(rates_total);
   
   int start,j,copied_M5,copied_M15;
   datetime time_M5[1],time_M15[1]; 
   ArraySetAsSeries(time,true);
   bool notsinh = false;
   for(int i=1;i>=0;i--)  {
     ResetLastError();
     copied_M5 =CopyTime(_Symbol,PERIOD_M5 ,time[i],1,time_M5 );  
     copied_M15=CopyTime(_Symbol,PERIOD_M15,time[i],1,time_M15);
     if( copied_M5<1 || copied_M15 <1 )return(prev_calculated); 
     if(copied_M5<1 || copied_M15<1) Print("************* ОШИБКА *****************");
     Print("i=",i," TF=",_Period," time[i]=",time[i], " copied=",copied_M5," time_M5=",time_M5[0]," copied=",copied_M15," time_M15=",time_M15[0]," ",_LastError);
   }
    
//--- return value of prev_calculated for next call
   return(rates_total);
  }

а на новом баре м5 выдается то что ожидается:

2010.05.14 18:09:59 test (EURUSD,M5) i= 0  TF= 5  time[i]= 2010.05.14 12:10:00  copied= 1  time_M5= 2010.05.14 12:10:00  copied= 1  time_M15= 2010.05.14 12:00:00   0
2010.05.14 18:09:59 test (EURUSD,M5) i= 1  TF= 5  time[i]= 2010.05.14 12:05:00  copied= 1  time_M5= 2010.05.14 12:05:00  copied= 1  time_M15= 2010.05.14 12:00:00   0

 

а такая конструкция почемуто не дала результата:

   for(int i=1;i>=0;i--)  {
     ResetLastError();
     if( !SeriesInfoInteger( _Symbol, PERIOD_M5,SERIES_SYNCRONIZED) || !SeriesInfoInteger( _Symbol, PERIOD_M15,SERIES_SYNCRONIZED))notsinh=true;   
     copied_M5 =CopyTime(_Symbol,PERIOD_M5 ,time[i],1,time_M5 );  
     copied_M15=CopyTime(_Symbol,PERIOD_M15,time[i],1,time_M15);
     if( notsinh )return(prev_calculated); 
     if(copied_M5<1 || copied_M15<1) Print("************* ОШИБКА *****************");
     Print("i=",i," TF=",_Period," time[i]=",time[i], " copied=",copied_M5," time_M5=",time_M5[0]," copied=",copied_M15," time_M15=",time_M15[0]," ",_LastError);
   }
вродем бы сделл проверку насинхронизацияю истории, а по факту - все равно не копирует выдает ***ошибка***

 


 

Rashid Umarov
Админ
11841
Rashid Umarov 2010.05.14 15:21  
gdtt:

так ошибка не выдается

     if( copied_M5<1 || copied_M15 <1 )return(prev_calculated); 
     if(copied_M5<1 || copied_M15<1) Print("************* ОШИБКА *****************");
Конечно не выдаст, выполнение будет прервано еще на первой проверке.
Rashid Umarov
Админ
11841
Rashid Umarov 2010.05.14 17:01  
Prival:

 В справке даны рекомендации

"Для экспертов и пользовательских индикаторов лучше использовать событийную модель обработки. Если при обработке события OnTick() или OnCalculate() не удалось получить все необходимые данные требуемой таймсерии, то следует выйти из обработчика события, рассчитывая на появление доступа к данным при следующем вызове обработчика." 

как мне выйти в этой функции из обработчика события  OnCalculate() непонимаю. Sleep тоже нельзя.

Выход простой - Оператор возврата return.

У Вас в коде другая проблема, есть строка

// работаем только по закончившимся барам
   if(rates_total==prev_calculated)  return(rates_total);

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

Приходит тик на новом часовом баре, индикатор пытается запросить данные с 5-минутного и 15-минутного таймфрейма, но они не готовы. Они будут готовы через какое-то очень малое время, если индикатор запросит их на следующем тике. Но на следующем тике их никто  уже не запрашивает, индикатор отваливается на целый час.

Rashid Umarov
Админ
11841
Rashid Umarov 2010.05.14 17:22  

Т.к. обработка происходит редко, то даже загруженная история сбрасывается на диск при отсутствии других потребителей:

// работаем только по закончившимся барам
   if(rates_total==prev_calculated) return(rates_total);


Prival
4550
Prival 2010.05.14 21:46  
Rosh писал(а)  :

Т.к. обработка происходит редко, то даже загруженная история сбрасывается на диск при отсутствии других потребителей:

Видно придется показать весь код сразу (сыройон очень).  Хотелось бы прежде чем выложить его в общий доступ сделать его правильным, что бы все там было красиво и по уму.

Задача заменить стандартную сетку на более информационную. Я подобное делал для МТ4. Вот рисунок с поясняющими надписями. Код индикатора прилагаю

// цвет вертикальных линий

color new_hour=DimGray;   // новый час

color new_day =Blue;          // новый день

color new_week=DeepPink;   // новая неделя

color new_mon =Yellow;        // новый месяц

 

// цвет горизонтальных линий

color new_Hfigure=RoyalBlue;  // новая фигура

color new_Hline=DimGray;      // новая линия

 

изменяя их в коде программе Вы можете настроить цветовую схему под себя.

 

//--- input parameters

input int   Step=250;         // шаг сетки в пунктах по вертикали

input int   Figure=1000;       // уровень фигуры

 

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

  1. Сделать расчеты максимально экономными. Если индикатор висит  на М15  его нет смысла рассчитывать чаще. Исключения - изменилось видимое количество баров и (или) размеры окна и (или) обрыв связи (перерисовка линии ближайшего  часа).
  • Строка 96  for(int i=start;i>=0;i--). Рассчитываем каждый тик. И описанной выше в этой ветке проблемы нет. При i>0 получаем экономию расчетов, т.к. работаем по завершенному бару, но при приходе нового бара линия (вертикальная) часто не рисуется.
  • Хотелось бы иметь функцию isNewBar_i  в которой решена эта проблема. Задача этой функции вернуть да или нет для нового бара. Применение  оператора возврата return с другой логикой усложняет программу и делает эту функцию не универсальной, что очень бы хотелось, т.к. она может пригодиться и при написании советников.
  1. При изменении видимого количества баров и(или) размеров окна. Для отработки приходиться ждать прихода нового тика. Вот тут (https://www.mql5.com/ru/articles/39) Алексей предложил метод как «обмануть» терминал. Но пока не разбирался, буду думать, тестировать.
  2. При первом запуске (иногда) вертикальные линии не прорисовываются. Приходиться переключать TF для повторной инициализации

 

З.Ы.

  1. Rosh обращаюсь к Вам, я понимаю, что подготовка к чемпионату это важнее. Но может потом, позже, Вы покажете как эффективно и красиво написать isNewBar. Ведь это Ваша функция, написанная для MQL4, я именно её брал в качестве образца. И если бы Вы меня носом в хелп не ткнули,  так бы и не понял, почему же она не работает.
  2. Разработчики выгрузкой данных решили проблемы терминала, но решили её скинув на плечи программистов АТС, страшно подумать сколько АТС разобьется об этот подводный камень на чемпионате, ведь в тестере эта ошибка не проявиться.

Файлы:
setka_0.mq5 12 kb
Dmitry Voronkov
5769
Dmitry Voronkov 2010.05.14 22:15  
Prival:

Видно придется показать весь код сразу (сыройон очень).  Хотелось бы прежде чем выложить его в общий доступ сделать его правильным, что бы все там было красиво и по уму.

Что могу посоветовать, на вскидку, вертикальные линии сделай припомощи гистограммы, это заметно разгрузит терминал, и может быть решит твою проблему с открытием нового бара.

и вообще попробуй все что можно перевести в буфера, замерно ускоряет обработку 

Prival
4550
Prival 2010.05.14 22:43  
vdv2001 писал(а)  :

Что могу посоветовать, на вскидку, вертикальные линии сделай припомощи гистограммы, это заметно разгрузит терминал, и может быть решит твою проблему с открытием нового бара.

и вообще попробуй все что можно перевести в буфера, замерно ускоряет обработку 

делал это самый первый вариант. именно гистограма. там нет вот такого

ObjectSetInteger(0, nm, OBJPROP_BACK, true); // рисовать как фон

из-за это покажу на рисунке

 

это для вертикальных линий.

для горизонтальных.  Заранее неизвестно сколько их будет видно. (неизвестно количество буферов). Можно конечто все задействовать, но тогда индикатор явно становиться тяжолым

Prival
4550
Prival 2010.05.14 22:57  

Я вижу два выхода. Раз разработчики свалили эту проблему на нас.

1. Дать нам функцию, которая запрещала бы терминалу выгружать определенные данные. Мне например для реализации этого кода нужны то всего  значения баров old_Time[21] и new_Time[21].

2. дать возможность завершить OnCalculate в любом месте программы, естественно корректно. 

А лучше оба метода сразу. Будет поле для маневра.  


12
Авторизуйтесь или зарегистрируйтесь, чтобы добавить комментарий