Индикатор не работает на старших тайм фреймах

 

Столкнулся с одной особенностью в MQL5. Собрался написать индикатор, который показывает старший тайм фрейм младшем или на текущем. Но когда в настройках я ставлю, к примеру, тайм фрейм H4, который старше текущего, Н1, то поведение программы не поддается объяснению. Ничего не работает. Я уже не знаю, баг это или я что-то не так делаю. Но, вроде, всё сделал правильно. Вот тестовый индикатор, который я написал для демонстрации данной проблемы:

#property indicator_chart_window

#property indicator_plots 0

input ENUM_TIMEFRAMES timeframe = PERIOD_H4;

int handle = 0;
ENUM_TIMEFRAMES _timeframe;

int trix_total = 0;
double trix_data[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit(){
  if(timeframe == PERIOD_CURRENT) 
    _timeframe = Period();
  else
    _timeframe = timeframe;
  
  
  if(_timeframe < Period()){
    _timeframe = Period();
  }
  
  handle = iTriX(Symbol(), _timeframe, 21, PRICE_CLOSE);
  return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
  IndicatorRelease(handle);
}

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[]
){
  if(_timeframe > Period()){
    int bars = (int)SeriesInfoInteger(_Symbol, _timeframe, SERIES_BARS_COUNT);
    if(prev_calculated <= 0){
      trix_total = CopyBuffer(handle, 0, 0, bars, trix_data);
      Print("TriX Timeframe: ", EnumToString(_timeframe));
      Print("bars: ", bars);
      Print("trix_total: ", trix_total);
      ResetLastError();
      Print("TriX BarsCalculated(): ", BarsCalculated(handle));
      Print("TriX handle : ", handle);
      Print("Error: ", GetLastError());
      Print("TriX Data =>");
      for(int i = trix_total-1; i >= 0; i--){
        Print("trix_data[",i,"]: ", trix_data[i]);
      }
      Print("<=");
    }
  }
  else{
    if(prev_calculated <= 0){
      Print("TriX Timeframe: ", EnumToString(_Period));
      trix_total = CopyBuffer(handle, 0, 0, rates_total, trix_data);
      Print("rates_total: ", rates_total);
      Print("trix_total: ", trix_total);
      ResetLastError();
      Print("TriX BarsCalculated(): ", BarsCalculated(handle));
      Print("TriX handle : ", handle);
      Print("Error: ", GetLastError());
      Print("TriX Data =>");
      for(int i = trix_total-1; i >= 0; i--){
        Print("trix_data[",i,"]: ", trix_data[i]);
      }
      Print("<=");
    }
  } 
  return(rates_total);
}
//+------------------------------------------------------------------+



Что на тестере, что во время отладки выдаёт следующее:

GE    0    22:39:38.593    indicators_test (EURUSD,H1)    2015.01.01 00:00:00   TriX Timeframe: PERIOD_H4
DK    0    22:39:38.593    indicators_test (EURUSD,H1)    2015.01.01 00:00:00   bars: 1551
PN    0    22:39:38.593    indicators_test (EURUSD,H1)    2015.01.01 00:00:00   trix_total: -1
RK    0    22:39:38.593    indicators_test (EURUSD,H1)    2015.01.01 00:00:00   TriX BarsCalculated(): -1
MG    0    22:39:38.593    indicators_test (EURUSD,H1)    2015.01.01 00:00:00   TriX handle : 10
NR    0    22:39:38.593    indicators_test (EURUSD,H1)    2015.01.01 00:00:00   Error: 4806
EI    0    22:39:38.593    indicators_test (EURUSD,H1)    2015.01.01 00:00:00   TriX Data =>
MJ    0    22:39:38.593    indicators_test (EURUSD,H1)    2015.01.01 00:00:00   <=

На старшем тайм фрейме:

KO    0    22:44:30.087    indicators_test (EURUSD,H1)    TriX Timeframe: PERIOD_H1
QG    0    22:44:30.087    indicators_test (EURUSD,H1)    rates_total: 100001
IR    0    22:44:30.087    indicators_test (EURUSD,H1)    trix_total: 100001
OK    0    22:44:30.087    indicators_test (EURUSD,H1)    TriX BarsCalculated(): 100001
EO    0    22:44:30.087    indicators_test (EURUSD,H1)    TriX handle : 10
IH    0    22:44:30.087    indicators_test (EURUSD,H1)    Error: 0
CR    0    22:44:30.087    indicators_test (EURUSD,H1)    TriX Data =>
QI    0    22:44:30.087    indicators_test (EURUSD,H1)    trix_data[100000]: -2.994367113683099e-06
KN    0    22:44:30.087    indicators_test (EURUSD,H1)    trix_data[99999]: -1.21283412451281e-07
KR    0    22:44:30.087    indicators_test (EURUSD,H1)    trix_data[99998]: 1.693938427483382e-06
CI    0    22:44:30.087    indicators_test (EURUSD,H1)    trix_data[99997]: 3.6130008542793e-06
ML    0    22:44:30.088    indicators_test (EURUSD,H1)    trix_data[99996]: 8.8225364385018e-06
IR    0    22:44:30.088    indicators_test (EURUSD,H1)    trix_data[99995]: 1.620381104119475e-05

При чем, данная проблема возникает не только с TriX, но и с другими индикаторами. Логи тестов прилагаю.

 

Вы забыли хендл на корректность. Вдруг на загаданном таймфрейме индикатор не создался.

Пример правильного создания и проверки (для индикатора iIchimoku и текущего символа и текущего таймфрейма):

//--- create handle of the indicator iIchimoku
   handle_iIchimoku=iIchimoku(Symbol(),Period(),9,26,52);
//--- if the handle is not created 
   if(handle_iIchimoku==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code 
      PrintFormat("Failed to create handle of the iIchimoku indicator for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early 
      return(INIT_FAILED);
     }
 
Vladimir Karputov:

Вы забыли хендл на корректность. Вдруг на загаданном таймфрейме индикатор не создался.

Пример правильного создания и проверки (для индикатора iIchimoku и текущего символа и текущего таймфрейма):

В других моих индикаторах, выполненных в виде классов, встроена эта проверка. Без неё такой индикатор не запустится. Но дело не в ней. У меня были случаи частичного копирования данных, с BarsCalculated(handle): -1 и Error: 4806 (при этом индикаторы еще  показывали что-то) но к сожалению сейчас я не могу привести такой пример. В разных билдах и ситуациях индикаторы вели себя по-разному.

Получается, бары в истории на выбранном ТФ всегда есть:

int bars = (int)SeriesInfoInteger(_Symbol, _timeframe, SERIES_BARS_COUNT);

DK    0    22:39:38.593    indicators_test (EURUSD,H1)    2015.01.01 00:00:00   bars: 1551

Но trix_total = -1, после вызова CopyBuffer

trix_total = CopyBuffer(handle, 0, 0, rates_total, trix_data);
Также,
BarsCalculated(handle)
возвращает -1. Но handle всегда 10. Так что он как раз таки является вполне корректным. Во всех случаях сам индикатор у меня создавался, а вот с копированием данных на старших ТФ возникают проблемы.
 
Mihail Matkovskij:

В других моих индикаторах, выполненных в виде классов, встроена эта проверка. Без неё такой индикатор не запустится. Но дело не в ней. У меня были случаи частичного копирования данных, с BarsCalculated(handle): -1 и Error: 4806 (при этом индикаторы еще  показывали что-то) но к сожалению сейчас я не могу привести такой пример. В разных билдах и ситуациях индикаторы вели себя по-разному.

Получается, бары в истории на выбранном ТФ всегда есть:

DK    0    22:39:38.593    indicators_test (EURUSD,H1)    2015.01.01 00:00:00   bars: 1551

Но trix_total = -1, после вызова CopyBuffer

Также,
возвращает -1. Но handle всегда 10. Так что он как раз таки является вполне корректным. Во всех случаях сам индикатор у меня создавался, а вот с копированием данными на старших ТФ возникают проблемы.

Вам не сложно будет прикрепить к сообщению файл индикатора? (Вашего, а не Trix)

 
Vladimir Karputov:

Вам не сложно будет прикрепить к сообщению файл индикатора? (Вашего, а не Trix)

К сожалению, выложить исходники на всеобщее обозрение не могу. Могу в данный пример подставить любой индикатор и он не будет работать на старших ТФ.
 
Mihail Matkovskij:
К сожалению, выложить исходники на всеобщее обозрение не могу. Могу в данный пример подставить любой индикатор и он не будет работать на старших ТФ.

Я имел в виду - Вы ывложили порнтянку в первом сообщении, так почему бы и не прекрепить файл? Тем кто хочет помочь, в таком случае будет легче.

Вы делали в своём коде CopyBuffer только ОДИН раз, когда prev_calculated==0 и затем выходили из цикла и возвращали return(rates_total);. А нужно было делать несколько попыток, пока индикатор iTrix не построится на чужом таймфрейме. И вот, пока он не построился, нужно было возвращать    return(0):

//+------------------------------------------------------------------+
//|                                                         Test.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                                           http://wmua.ru/slesar/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "http://wmua.ru/slesar/"
#property version   "1.00"
#property indicator_chart_window

#property indicator_plots 0
//--- input parameters
input ENUM_TIMEFRAMES timeframe=PERIOD_H4;

int handle=0;
ENUM_TIMEFRAMES _timeframe;

int trix_total=0;
double trix_data[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   if(timeframe==PERIOD_CURRENT)
      _timeframe=Period();
   else
      _timeframe=timeframe;

   if(_timeframe<Period())
      _timeframe=Period();
//--- create handle of the indicator iTriX
   handle=iTriX(Symbol(),_timeframe,21,PRICE_CLOSE);
//--- if the handle is not created 
   if(handle==INVALID_HANDLE)
     {
      //--- tell about the failure and output the error code 
      PrintFormat("Failed to create handle of the handle indicator for the symbol %s/%s, error code %d",
                  Symbol(),
                  EnumToString(Period()),
                  GetLastError());
      //--- the indicator is stopped early 
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   IndicatorRelease(handle);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[]
                )
  {
   if(_timeframe>Period())
     {
      int bars=(int)SeriesInfoInteger(_Symbol,_timeframe,SERIES_BARS_COUNT);
      if(prev_calculated==0)
        {
         static int counter=0;
         counter++;
         trix_total=CopyBuffer(handle,0,0,bars,trix_data);
         Print("TriX Timeframe: ",EnumToString(_timeframe));
         Print("bars: ",bars);
         Print("trix_total: ",trix_total);
         ResetLastError();
         Print("TriX BarsCalculated(): ",BarsCalculated(handle));
         Print("TriX handle : ",handle);
         Print("Error: ",GetLastError());
         Print("TriX Data =>");
         //for(int i=trix_total-1; i>=0; i--)
         //  {
         //   Print("trix_data[",i,"]: ",trix_data[i]);
         //  }
         Print("<=");
         if(trix_total==-1)
           {
            Print("counter ",counter);
            return(0);
           }
        }
     }
   else
     {
      if(prev_calculated==0)
        {
         Print("TriX Timeframe: ",EnumToString(_Period));
         trix_total=CopyBuffer(handle,0,0,rates_total,trix_data);
         Print("rates_total: ",rates_total);
         Print("trix_total: ",trix_total);
         ResetLastError();
         Print("TriX BarsCalculated(): ",BarsCalculated(handle));
         Print("TriX handle : ",handle);
         Print("Error: ",GetLastError());
         Print("TriX Data =>");
         for(int i=trix_total-1; i>=0; i--)
           {
            Print("trix_data[",i,"]: ",trix_data[i]);
           }
         Print("<=");
        }
     }
   return(rates_total);
  }
//+------------------------------------------------------------------+

При таком подходе можно хорошо видеть за сколько заходов в OnCalculate на чужом таймфрейме успевает построится индикатор iTrix

Файлы:
Test.mq5  4 kb
 
Vladimir Karputov:

Я имел в виду - Вы ывложили порнтянку в первом сообщении, так почему бы и не прекрепить файл? Тем кто хочет помочь, в таком случае будет легче.

Вы делали в своём коде CopyBuffer только ОДИН раз, когда prev_calculated==0 и затем выходили из цикла и возвращали return(rates_total);. А нужно было делать несколько попыток, пока индикатор iTrix не построится на чужом таймфрейме. И вот, пока он не построился, нужно было возвращать    return(0):

При таком подходе можно хорошо видеть за сколько заходов в OnCalculate на чужом таймфрейме успевает построится индикатор iTrix

Просто огромное спасибо Вам Владимир! Теперь, всё работает как надо. Пойду писать индикаторы :)
 
Mihail Matkovskij:
Просто огромное спасибо Вам Владимир! Теперь, всё работает как надо. Пойду писать индикаторы :)

Трям :)

 
Таймфрейм загружается, но только после прихода очередного тика. Если тиков нет, то приходится выбирать в меню пункт "Обновить" график. Не заставлять же пользователя обновлять график, когда нет котировок, в выходные и праздники. Как лучше сделать автоматическое обновление? Подумал, может быть, с помощью таймера. Но прицеплять каждый раз таймер к индикатору и переписывать постоянно один и тот же код не очень удобно. Может быть существует другой, лучший, способ?
 

При старте ставим флаг расчет=ложь, включаем таймер.
В таймере проверяем BarsCalculated , если всё рассчиталось, то перестраиваем индикатор заново и отключаем таймер.

В OnCalculate, ничего не делаем пока флаг расчет=ложь, кроме комментария "Calculation..."

 
Taras Slobodyanik:

если всё рассчиталось, то перестраиваем индикатор заново и отключаем таймер.

Что Вы имеете в виду под перестраиванием?

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