Не получается брать данные индикатора со старшего ТФ

 

Уже четвёртый день в индикаторе пытаюсь получить данные стандартного индикатора АО со старшего таймфрейма, и всё никак...

В цикле считываю данные АО, но именно в цикле исторических данных нет. На текущем баре данные есть. В чём подвох? Что делаю не так?

//+------------------------------------------------------------------+
//|                                                       MTF AO.mq5 |
//|              Copyright 2017, Artem A. Trishkin, Skype artmedia70 |
//|                       https://login.mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70"
#property link      "https://login.mql5.com/ru/users/artmedia70"
#property version   "1.00"

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1
//--- plot AO
#property indicator_label1  "AO MTF"
#property indicator_type1   DRAW_SECTION
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1

//--- indicator buffers
double         BufferAO[];
//+------------------------------------------------------------------+
//|  Enums                                                           |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|  Input Variables                                                 |
//+------------------------------------------------------------------+
sinput   ENUM_TIMEFRAMES   PeriodForWork  =  PERIOD_M5;  // Таймфрейм, на котором искать дивергенции
//+------------------------------------------------------------------+
//|  Global Variables                                                |
//+------------------------------------------------------------------+
string            Prefix, symbol;
int               handle_ao;                 // Хэндл AO
int               size_ao=0;                 // Количество скопированных данных AO
double            array_ao[];                // Массив данных АО
ENUM_TIMEFRAMES   periodForWork;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,BufferAO);
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0);
   ArrayInitialize(BufferAO,0);
   
   //--- проверка рабочего периода и его смена, если выбран рабочий период меньше текущего
   periodForWork=PeriodForWork;
   if(Period()>periodForWork && PeriodForWork!=PERIOD_CURRENT) {
      Alert("Выбран не корректный период: ",GetNameTF(PeriodForWork),"\nМеняю рабочий период на ",GetNameTF(Period()));
      periodForWork=PERIOD_CURRENT;//GetTFasEnum(Period());
      }

   //--- имена
   symbol=Symbol();                                                        // Symbol()
   Prefix="MTFdiv";                                                        // Префикс имён объектов
   IndicatorSetString(INDICATOR_SHORTNAME,Prefix);                         // Короткое имя индикатора
   
   //--- хэндл AO
   handle_ao=iAO(symbol,periodForWork);
   if(handle_ao==INVALID_HANDLE) {
      Print("Не удалось создать хэндл AO");
      return(INIT_FAILED);
      }
   int count=(int)SeriesInfoInteger(symbol,periodForWork,SERIES_BARS_COUNT);
   size_ao=CopyBuffer(handle_ao,0,0,count,array_ao);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function                       |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- delete graphics
   ObjectsDeleteAll(0,Prefix);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
   ArraySetAsSeries(BufferAO,true);
   ArraySetAsSeries(array_ao,true);
   //---
   ArraySetAsSeries(open,true);
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(low,true);
   ArraySetAsSeries(close,true);
   
   int count=(int)SeriesInfoInteger(symbol,periodForWork,SERIES_BARS_COUNT);
   //---
   if(rates_total<1) return(0);
   //---
   int limit=rates_total-prev_calculated;
   if(limit>1) {
      limit=rates_total-1;
      ArrayInitialize(BufferAO,0);
      }
   
   int periodSeconds=PeriodSeconds(periodForWork); // Количество секунд в рабочем периоде
   static datetime lastTime=0;
   int bar_first=TerminalInfoInteger(TERMINAL_MAXBARS);
   //--- основной цикл индикатора
   for(int i=limit; i>=0; i--) {
      //--- Пропускаем отсутствующие бары
      if(i>bar_first) continue;
      
      //--- Получаем данные АО
      ResetLastError();
      size_ao=CopyBuffer(handle_ao,0,0,count,array_ao);
      if(size_ao<0) Print("Ошибка копирования данных AO ",GetLastError());
      
      //--- время открытия бара на рабочем периоде, соответствующее времени бара i на текущем периоде
      datetime timePeriod=GetTimeOpen(symbol,periodForWork,i);
      //--- если нашли открытие нового бара на рабочем таймфрейме (текущее время больше прошлого)
      if(timePeriod>0 && timePeriod>lastTime) { 
         //---
         datetime time_work=GetTimeOpen(symbol,periodForWork,i);                 // время открытия i на рабочем таймфрейме
         int bar_work_to_current=GetBarShift(symbol,PERIOD_CURRENT,time_work);   // бар открытия времени time_work на текущем периоде графика
         double ao_work=GetDataAO(time_work);                                    // значение АО на баре i
         //---
         if(i<5) {
            Print("Work period: ",GetNameTF(periodForWork),
                  ",i=",i,", bar_work_to_current=",bar_work_to_current,
                  ", time_work=",TimeToString(time_work,TIME_MINUTES),
                  ", ao_work=",DoubleToString(ao_work,Digits())
                 );
            }
         BufferAO[bar_work_to_current]=ao_work;
         //--- конец обработки текущего бара
         lastTime=timePeriod; // запомним прошлое время для дальнейшего сравнения с временем следующего бара
         }
      //--- конец цикла индикатора
      }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Functions                                                        |
//+------------------------------------------------------------------+
double GetDataAO(int shift) {
   double array[1];
   if(CopyBuffer(handle_ao,0,shift,1,array)==1) return(array[0]);
   return(0);
}
//+------------------------------------------------------------------+
double GetDataAO(datetime shift) {
   double array[1];
   if(CopyBuffer(handle_ao,0,shift,1,array)==1) return(array[0]);
   return(0);
}
//+------------------------------------------------------------------+
datetime GetTimeOpen(string symbol_name, ENUM_TIMEFRAMES timeframe, int index) {
   datetime array[1]={-1};
   ResetLastError();
   if(CopyTime(symbol_name,timeframe,index,1,array)==1) return(array[0]);
   Print(__FUNCTION__," > Ошибка получения времени бара ",index,"(",GetNameTF(timeframe),"): ",GetLastError());
   return(-1);
}
//+------------------------------------------------------------------+
int GetBarShift(const string symbol_name, const ENUM_TIMEFRAMES timeframe, const datetime time) {
   int res=-1;
   datetime last_bar;
   if(SeriesInfoInteger(symbol_name,timeframe,SERIES_LASTBAR_DATE,last_bar)) {
      if(time>last_bar) res=0;
      else {
         const int shift=Bars(symbol_name,timeframe,time,last_bar);
         if(shift>0) res=shift-1;
         }
      }
   return(res);
}
//+------------------------------------------------------------------+
string GetNameTF(int timeframe=PERIOD_CURRENT) {
   if(timeframe==PERIOD_CURRENT) timeframe=Period();
   switch(timeframe) {
      //--- MQL4
      case 1: return("M1");
      case 5: return("M5");
      case 15: return("M15");
      case 30: return("M30");
      case 60: return("H1");
      case 240: return("H4");
      case 1440: return("D1");
      case 10080: return("W1");
      case 43200: return("MN");
      //--- MQL5
      case 2: return("M2");
      case 3: return("M3");
      case 4: return("M4");      
      case 6: return("M6");
      case 10: return("M10");
      case 12: return("M12");
      case 16385: return("H1");
      case 16386: return("H2");
      case 16387: return("H3");
      case 16388: return("H4");
      case 16390: return("H6");
      case 16392: return("H8");
      case 16396: return("H12");
      case 16408: return("D1");
      case 32769: return("W1");
      case 49153: return("MN");      
      default: return("UnknownPeriod");
   }
}
//+------------------------------------------------------------------+

Файлы:
iMTF_AO.mq5  19 kb
 

Данные с тф М5 появляются только реалтайм на М1. При запуске история не рисуется...

 
Встречался с такой проблемой при написании мультитаймфреймовых индикаторов года 2 назад - не погруженная история для валютной пары по другим TF.
Решалось костылями, какими именно - сейчас буду искать.
 

У пользователя был индикатор измеряющий "силу" рынка.
Индикатор работал по текущему ТФ и валютной паре.

Задача была - показать результаты из 8 популярных валют на одном чарте с возможностью выбора независимого TФ для отображения.
На каком бы пользователь ТФ не был - должно показывать результат с установленного в параметры.

Проблему по прогрузке трафика с других валют по нужному ТФ решал следующим костылем:

   for (int i = ArraySize(symbols_load) - 1; i >= 0; --i){
      int counter = 0;
      int max_count = 10;
      while(counter < max_count){
         RefreshRates();
         double tmp_arr[];
         int res = CopyClose(symbols_load[i] + Suffix, int(TF), 0, 3, tmp_arr);
         if (res == 3)
            break;
         RefreshRates();
         ++counter;
      }
   }

где:

symbols_load - список валют необходимых прогрузить
Suffix - возможная приставка к названию валютных пар
TF - необходимый таймфрейм

 
Artyom Trishkin:

Данные с тф М5 появляются только реалтайм на М1. При запуске история не рисуется...

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

Как-то так:

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1

#property indicator_label1  "AO"
#property indicator_type1   DRAW_SECTION
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1


//+------------------------------------------------------------------+
//| inputs
//+------------------------------------------------------------------+
input ENUM_TIMEFRAMES TimeFrame_ = PERIOD_D1;


//+------------------------------------------------------------------+
//| defines
//+------------------------------------------------------------------+
#define _PrintLastError_(info,r) { Print((info != "" ? info+" " : ""),__FUNCTION__,":",__LINE__,":Error#",_LastError); r; }


//+------------------------------------------------------------------+
//| global vars
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES _MTF;
datetime        _MTF_TimeBuf[];

int    _AO_Handle = INVALID_HANDLE;
double _AO_Buf[];

int    _LastRatesTotal;
int    _LastPrevCalculated;
double _PriceBuf[];

datetime _Time[];


//+------------------------------------------------------------------+
//| ind buf's
//+------------------------------------------------------------------+
double _Main_VBuf[];


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
{
   _MTF = TimeFrame_;
   
   if (PeriodSeconds(_MTF) < PeriodSeconds(_Period)) _MTF = _Period;
   
   if ((_AO_Handle = iAO(_Symbol, _MTF)) == INVALID_HANDLE) _PrintLastError_("", return INIT_FAILED)
   
   GetTimes(_MTF_TimeBuf, _MTF);
   
   EventSetTimer(1);

//---
   SetIndexBuffer(0, _Main_VBuf);
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0);
   
//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   IndicatorRelease(_AO_Handle);
   EventKillTimer();
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTimer()
{
   if (_LastPrevCalculated <= 0)
   {
      OnCalculate (_LastRatesTotal,
                   _LastPrevCalculated,
                   0,
                   _PriceBuf);
   }
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnCalculate (const int rates_total,      // размер массива price[] 
                 const int prev_calculated,  // обработано баров на предыдущем вызове 
                 const int begin,            // откуда начинаются значимые данные 
                 const double& price[])       // массив для расчета 
{
   ResetLastError();
   
//---
   if (prev_calculated <= 0)
   {
      ArrayInitialize(_Main_VBuf, 0);
   }
       
//---   
   if (ArrayCopy(_PriceBuf, price, 0, 0, rates_total) != rates_total) _PrintLastError_("ArrayCopy", return _LastPrevCalculated = 0)

   _LastRatesTotal = rates_total;
   
//---
   if (rates_total != prev_calculated)
   {
      if (!GetTimes(_Time, _Period)) _PrintLastError_("", return _LastPrevCalculated = 0)
      if (!GetTimes(_MTF_TimeBuf, _MTF)) _PrintLastError_("", return _LastPrevCalculated = 0)
   }
   
   if (!GetAO())
   { 
      if (_LastError == ERR_INDICATOR_DATA_NOT_FOUND) return _LastPrevCalculated = 0;
      
      _PrintLastError_("", return _LastPrevCalculated = 0)
   }
   
//---   
   const int MTF_BarsCount = ArraySize(_MTF_TimeBuf);
   const int Limit = fmax(prev_calculated, (int)ceil((double)PeriodSeconds(_MTF)/(double)PeriodSeconds(_Period)));
   
   for (int i=rates_total-1, tf_time_i=MTF_BarsCount-1; i>=Limit; --i)
   {
      if (_Time[i] >= _MTF_TimeBuf[tf_time_i])
      {
         _Main_VBuf[i] = _AO_Buf[tf_time_i];
      }
      else
      { 
         --tf_time_i;
         
         if (tf_time_i < 0) return _LastPrevCalculated = 0;
      }
   }  
   
//---   
   return _LastPrevCalculated = rates_total;
}     


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool GetTimes(datetime & buf[],ENUM_TIMEFRAMES tf)
{
   int BarsCount = Bars(_Symbol, tf);
   
   if (CopyTime(_Symbol, tf, 0, BarsCount, buf) != BarsCount) _PrintLastError_("CopyTime", return false)
   
   return true;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool GetAO()
{
   int BarsCount = Bars(_Symbol, _MTF);
   
   if (CopyBuffer(_AO_Handle, 0, 0, BarsCount, _AO_Buf) != BarsCount)
   { 
      if (_LastError == ERR_INDICATOR_DATA_NOT_FOUND) _PrintLastError_("AO is not built yet. Wait...", return false)
      
      _PrintLastError_("CopyBuffer", return false)
   }
   
   return true;
}
 
Sergey Dzyublik:
Встречался с такой проблемой при написании мультитаймфреймовых индикаторов года 2 назад - не погруженная история для валютной пары по другим TF.
Решалось костылями, какими именно - сейчас буду искать.

Неоднократно уже обсуждалось.

1. В OnInit запросить все символы-периоды, которые предполагается использовать

2. Запустить 1-минутный таймер

3. В OnTimer запрашивать все нужные символы-периоды. Без дальнейшего использования, типа CopyRates(symbol,period,0,1,rates_array). Только спрашивать (на всякий случай), синхронизировано или нет

4. В OnCalculate спокойно запрашивать и использовать через минуту-полторы после первого запуска.

 

Добавил модификацию:

#property version "1.1"

//+-------------------------------- Versions History --------------------------------+
//|
//| 
//| v.1.1
//| - добавлена проверка на синхронизированность данных по старшему ТФ.
//|
//|
//+-------------------------------- Versions History --------------------------------+

#property indicator_separate_window
#property indicator_buffers 1
#property indicator_plots   1

#property indicator_label1  "AO"
#property indicator_type1   DRAW_SECTION
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1


//+------------------------------------------------------------------+
//| inputs
//+------------------------------------------------------------------+
input ENUM_TIMEFRAMES TimeFrame_ = PERIOD_D1;


//+------------------------------------------------------------------+
//| defines
//+------------------------------------------------------------------+
#define _PrintLastError_(info,r) { Print((info != "" ? info+" " : ""),__FUNCTION__,":",__LINE__,":Error#",_LastError); r; }


//+------------------------------------------------------------------+
//| global vars
//+------------------------------------------------------------------+
bool            _IsMTF;
ENUM_TIMEFRAMES _MTF;
datetime        _MTF_TimeBuf[];
datetime        _MTF_FirstDate;

int    _AO_Handle = INVALID_HANDLE;
double _AO_Buf[];

int    _LastRatesTotal;
int    _LastPrevCalculated;
double _PriceBuf[];

datetime _Time[];


//+------------------------------------------------------------------+
//| ind buf's
//+------------------------------------------------------------------+
double _Main_VBuf[];


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
{
   _MTF = TimeFrame_;
   
   if (PeriodSeconds(_MTF) < PeriodSeconds(_Period)) _MTF = _Period;
   if (PeriodSeconds(_MTF) > PeriodSeconds(_Period)) _IsMTF = true;
   
   if ((_AO_Handle = iAO(_Symbol, _MTF)) == INVALID_HANDLE) _PrintLastError_("", return INIT_FAILED)
   
   GetTimes(_MTF_TimeBuf, _MTF);
   
   EventSetTimer(1);

//---
   SetIndexBuffer(0, _Main_VBuf);
   PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0);
   
//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   IndicatorRelease(_AO_Handle);
   EventKillTimer();
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTimer()
{
//---MTF control
   if (_LastPrevCalculated > 0)
   {
      if (SymbolIsSynchronized(_Symbol)) 
      {
         datetime MTF_FirstDate = (datetime)SeriesInfoInteger(_Symbol, _MTF, SERIES_FIRSTDATE);
         
         if (_MTF_FirstDate != MTF_FirstDate)
         {
            _MTF_FirstDate = MTF_FirstDate;
            _LastPrevCalculated = 0;
         }
      }
      else _LastPrevCalculated = 0;
   }
   
   if (_LastPrevCalculated <= 0)
   {
      OnCalculate (_LastRatesTotal,
                   _LastPrevCalculated,
                   0,
                   _PriceBuf);
   }
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnCalculate (const int rates_total,      // размер массива price[] 
                 const int prev_calculated,  // обработано баров на предыдущем вызове 
                 const int begin,            // откуда начинаются значимые данные 
                 const double& price[])       // массив для расчета 
{
   ResetLastError();
   
//---
   if (prev_calculated <= 0)
   {
      ArrayInitialize(_Main_VBuf, 0);
   }
       
//---   
   if (ArrayCopy(_PriceBuf, price, 0, 0, rates_total) != rates_total) _PrintLastError_("ArrayCopy", return _LastPrevCalculated = 0)

   _LastRatesTotal = rates_total;
   
//---
   if (rates_total != prev_calculated)
   {
      if (!GetTimes(_Time, _Period)) _PrintLastError_("", return _LastPrevCalculated = 0)
      if (!GetTimes(_MTF_TimeBuf, _MTF)) _PrintLastError_("", return _LastPrevCalculated = 0)
   }
   
   if (!GetAO())
   { 
      if (_LastError == ERR_INDICATOR_DATA_NOT_FOUND) return _LastPrevCalculated = 0;
      
      _PrintLastError_("", return _LastPrevCalculated = 0)
   }
   
//---   
   const int MTF_BarsCount = ArraySize(_MTF_TimeBuf);
   const int Limit = fmax(prev_calculated, (int)ceil((double)PeriodSeconds(_MTF)/(double)PeriodSeconds(_Period)));
   
   for (int i=rates_total-1, tf_time_i=MTF_BarsCount-1; i>=Limit; --i)
   {
      if (_Time[i] >= _MTF_TimeBuf[tf_time_i])
      {
         _Main_VBuf[i] = _AO_Buf[tf_time_i];
      }
      else
      { 
         --tf_time_i;
         
         if (tf_time_i < 0) return _LastPrevCalculated = 0;
      }
   }  
   
//---   
   return _LastPrevCalculated = rates_total;
}     


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool GetTimes(datetime & buf[],ENUM_TIMEFRAMES tf)
{
   int BarsCount = Bars(_Symbol, tf);
   
   if (CopyTime(_Symbol, tf, 0, BarsCount, buf) != BarsCount) _PrintLastError_("CopyTime", return false)
   
   return true;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool GetAO()
{
   int BarsCount = Bars(_Symbol, _MTF);
   
   if (CopyBuffer(_AO_Handle, 0, 0, BarsCount, _AO_Buf) != BarsCount)
   { 
      if (_LastError == ERR_INDICATOR_DATA_NOT_FOUND) _PrintLastError_("AO is not built yet. Wait...", return false)
      
      _PrintLastError_("CopyBuffer", return false)
   }
   
   return true;
}
 
Slawa:

Неоднократно уже обсуждалось.

1. В OnInit запросить все символы-периоды, которые предполагается использовать

2. Запустить 1-минутный таймер

3. В OnTimer запрашивать все нужные символы-периоды. Без дальнейшего использования, типа CopyRates(symbol,period,0,1,rates_array). Только спрашивать (на всякий случай), синхронизировано или нет

4. В OnCalculate спокойно запрашивать и использовать через минуту-полторы после первого запуска.

Секунду-полторы?

Официальный костыль!

 
fxsaber:

Секунду-полторы?

Официальный костыль!


нее... периоды строятся долго минуту точно моргать может...
 

Уже четвёртый день в индикаторе пытаюсь получить данные стандартного индикатора АО со старшего таймфрейма, и всё никак...

я вам писал в другой ветке, используйте BarsCalculated - пока не будет больше нуля не запускаем основной цикл расчета (OnCalculate)

https://www.mql5.com/ru/forum/170952/page32#comment_4864720
Особенности языка mql5, тонкости и приёмы работы
Особенности языка mql5, тонкости и приёмы работы
  • www.mql5.com
В данной теме будут обсуждаться недокументированные приёмы работы с языком mql5, примеры решения тех, или иных задач...
 
Slawa:

Неоднократно уже обсуждалось.

1. В OnInit запросить все символы-периоды, которые предполагается использовать

2. Запустить 1-минутный таймер

3. В OnTimer запрашивать все нужные символы-периоды. Без дальнейшего использования, типа CopyRates(symbol,period,0,1,rates_array). Только спрашивать (на всякий случай), синхронизировано или нет

4. В OnCalculate спокойно запрашивать и использовать через минуту-полторы после первого запуска.

Спасибо за информацию.

Предположим мы на М5.
На М5 приходит новый бар, идет обработка OnCalculate (используется iCustom по другим валютам и с другим TF - M1).
Только затем срабатывает наш минутный таймер.

Вопрос: для МТ4 в OnCalculate будет ли обработка iCustom видить приход нового бара для М1 по всем используемым валютным парам?
Ведь наш таймер отрабатывает уже после OnCalculate.
Причина обращения: