Функция Bars() возвращает не корректное количество баров

 

В настройках терминала у меня ограничение баров в окне равное 10 000 т.е. 10 тысяч баров.

Эта функция по-разному ведёт себя в индикатора и в скриптах.

Например, вот скрипт:

//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//|                                                                                                                                                                 experience.mq5 |
//|                                                                                                                                                                            hoz |
//|                                                                                                                                                                                |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

//==================================================================================================================================================================================
// Возвращает количество баров в окне торгового инструмента активного окна на заданном таймфрейме. =================================================================================
int barsTotal(ENUM_TIMEFRAMES tf = PERIOD_CURRENT) {    // ТФ, количество баров которого требуется получить
//---
  return Bars(_Symbol, tf);
}
//==================================================================================================================================================================================
// Возвращает значение времени открытия бара торгового инструмента активного окна, находящегося на shift баров от 0-го бара в историю. =============================================
datetime barOpenTime(int shift,                                // Индекс бара, время открытия которого требуется определить
                     ENUM_TIMEFRAMES tf = PERIOD_CURRENT) {    // ТФ, на котором будет происходить поиск открытия баров функцией CopyTime()
//---
  datetime barOpenTime[1];    // Массив, в котором находятся цены открытия баров активного окна
//---
  return ((CopyTime(_Symbol, tf, shift, 1, barOpenTime) != -1) ? barOpenTime[0] : WRONG_VALUE);
}
//==================================================================================================================================================================================
// Возвращает индекс бара торгового инструмента активного окна по его времени открытия на заданном таймфрейме. =====================================================================
int barShift(datetime initialBarTime,                  // Время открытия бара, индекс коорого требуется найти
             ENUM_TIMEFRAMES tf = PERIOD_CURRENT) {    // ТФ, на котором будет происходить поиск открытия баров функцией CopyTime()
//----
  datetime barsOpenTime[],                     // Массив, в котором находится времени открытия баров открытого окна за указанный интервал времени
           lastBarTime = barOpenTime(0, tf);    // Время до которого будет происходить поиск времени открытия баров функцией CopyTime()

  if (CopyTime(_Symbol, tf, initialBarTime, lastBarTime, barsOpenTime) == -1)
    return -1;
//---
  return (ArraySize(barsOpenTime) > 1) ? (ArraySize(barsOpenTime)) : 0;
}
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//|                                                                                Script program start function                                                                   |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
void OnStart() {
//---
  int firstBarIndexCurTF = barsTotal(PERIOD_CURRENT) - 1;
  Print(__FUNCTION__, " :: firstBarIndexCurTF = ", firstBarIndexCurTF);
  datetime firstBarTimeCurTF = barOpenTime(firstBarIndexCurTF);
  Print(__FUNCTION__, " :: firstBarTimeCurTF = ", TimeToString(firstBarTimeCurTF, TIME_DATE|TIME_MINUTES));
  
  int barIndexOtherTF = barShift(firstBarTimeCurTF, PERIOD_H1);
  Print(__FUNCTION__, " :: barIndexOtherTF = ", barIndexOtherTF);
  datetime barTimeOtherTF = barOpenTime(barIndexOtherTF, PERIOD_H1);
  Print(__FUNCTION__, " :: barTimeOtherTF = ", TimeToString(barTimeOtherTF, TIME_DATE|TIME_MINUTES));
}

Если его накинуть на график в журнале увидим:

2018.10.12 21:18:16.123 experience (AUDJPY,M15) OnStart :: firstBarIndexCurTF = 9999
2018.10.12 21:18:16.123 experience (AUDJPY,M15) OnStart :: firstBarTimeCurTF = 2018.05.21 17:30
2018.10.12 21:18:16.123 experience (AUDJPY,M15) OnStart :: barIndexOtherTF = 2500
2018.10.12 21:18:16.123 experience (AUDJPY,M15) OnStart :: barTimeOtherTF = 2018.05.21 17:00

Мы видим, что в окне терминала имееся 9999 баров. Всё верно. Дата первого бара, который имеется на открытом графике совпадает с реальной датой, если промотать график в самое начало и поглядеть. Здесь всё в порядке. Этот тестовый скрипт я написал, что бы проверить свои мысли и логику своего кода.

Вот типа голая заготовка индикатора, который ничего не делает. Но там я получаю такие же данные как в скрипте т.е. первый бар открытого графика и его дату, а так же индекс бара с таймфрейа повыше (в данном случае H1) и время его открытия. Время в журнал принтую что бы убедится в корректности того, что я верно нашёл бар. Оказывается, что тот же код в индикаторе не работает, хоть ты стрельнись:

//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
//|                                                                                                                                                             invalidExample.mq5 |
//|                                                                                                                                                                            hoz |
//|                                                                                                                                                                                |
//+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
#property copyright "hoz"
#property link      ""
#property version   "1.00"
#property indicator_chart_window            // Индикатор отображается в окне графика
#property indicator_buffers 1               // Используется 3 буфера индикатора
#property indicator_plots   1               // Количество графических серий индикатора
//---- plot properties
#property indicator_type1  DRAW_SECTION     // Вид графического построения
#property indicator_color1 clrDodgerBlue    // Цвет отображения данных 1-го буфера
#property indicator_style1 STYLE_SOLID      // Стиль графической серии
#property indicator_width1 2                // Толщина линий 1-го буфера

double extremum_price_buffer[];            // Буфер, хранящий цены кривой Zig-Zag'а (непустые значения - экстремумы)
//==================================================================================================================================================================================
// Custom indicator initialization function. =======================================================================================================================================
int OnInit() {
//--- indicator buffers mapping
  SetIndexBuffer(0, extremum_price_buffer, INDICATOR_DATA);               // Первый буфер - экстремумы
  PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);                   // Установка пустого значения буфера extremum_price_buffer, по которому нет отрисовки
  ArraySetAsSeries(extremum_price_buffer, true);
//---
  return INIT_SUCCEEDED;
}
//==================================================================================================================================================================================
// 1.1 Возвращает количество баров в окне торгового инструмента активного окна на заданном таймфрейме. =============================================================================
int barsTotal(ENUM_TIMEFRAMES tf = PERIOD_CURRENT) {    // ТФ, количество баров которого требуется получить
//---
  return Bars(_Symbol, tf);
}
//==================================================================================================================================================================================
// Возвращает значение времени открытия бара торгового инструмента активного окна, находящегося на shift баров от 0-го бара в историю. =============================================
datetime barOpenTime(int shift,                                // Индекс бара, время открытия которого требуется определить
                     ENUM_TIMEFRAMES tf = PERIOD_CURRENT) {    // ТФ, на котором будет происходить поиск открытия баров функцией CopyTime()
//---
  datetime barOpenTime[1];    // Массив, в котором находятся цены открытия баров активного окна
//---
  return ((CopyTime(_Symbol, tf, shift, 1, barOpenTime) != -1) ? barOpenTime[0] : WRONG_VALUE);
}
//==================================================================================================================================================================================
// Возвращает индекс бара торгового инструмента активного окна по его времени открытия на заданном таймфрейме. =====================================================================
int barShift(datetime initialBarTime,                  // Время открытия бара, индекс коорого требуется найти
             ENUM_TIMEFRAMES tf = PERIOD_CURRENT) {    // ТФ, на котором будет происходить поиск открытия баров функцией CopyTime()
//----
  datetime barsOpenTime[],                     // Массив, в котором находится времени открытия баров открытого окна за указанный интервал времени
           lastBarTime = barOpenTime(0, tf);    // Время до которого будет происходить поиск времени открытия баров функцией CopyTime()

  if (CopyTime(_Symbol, tf, initialBarTime, lastBarTime, barsOpenTime) == -1)
    return -1;
//---
  return (ArraySize(barsOpenTime) > 1) ? (ArraySize(barsOpenTime)) : 0;
}
//==================================================================================================================================================================================
// Определение индекса бара, с которого необходимо производить перерасчет. =========================================================================================================
int recalcIndex(int barsTotal,        // Количество пришедших баров таймфрейма открытого графика
                int countedBars) {    // Количество уже обработанных баров таймфрейма открытого графика
//---
  int barsTotalOtherTF = barsTotal(PERIOD_H1);

  if (countedBars == 0) {
    ArrayInitialize(extremum_price_buffer, EMPTY_VALUE);
    int firstBarIndexCurTF = barsTotal - 1;
    Print(__FUNCTION__, " :: firstBarIndexCurTF = ", firstBarIndexCurTF);
    datetime firstBarTimeCurTF = barOpenTime(firstBarIndexCurTF);
    Print(__FUNCTION__, " :: firstBarTimeCurTF = ", TimeToString(firstBarTimeCurTF, TIME_DATE|TIME_MINUTES));

    int barIndexOtherTF = barShift(firstBarTimeCurTF, PERIOD_H1);
    Print(__FUNCTION__, " :: barIndexOtherTF = ", barIndexOtherTF);
    datetime barTimeOtherTF = barOpenTime(barIndexOtherTF, PERIOD_H1);
    Print(__FUNCTION__, " :: barTimeOtherTF = ", TimeToString(barTimeOtherTF, TIME_DATE|TIME_MINUTES));
    return barShift(barOpenTime(firstBarIndexCurTF), PERIOD_H1) - 2;
  }
//---
  return 1;
}
//==================================================================================================================================================================================
// 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[]) {
//---
  int limit = recalcIndex(rates_total, prev_calculated);    // Определим первый расчетный бар
//--- return value of prev_calculated for next call
  return rates_total;
}

В журнале вижу какую-то чушь т.е не то, что вижу после отработки скрипта:

2018.10.12 21:24:42.515 invalidExample (AUDJPY,M15)     recalcIndex :: firstBarIndexCurTF = 24853
2018.10.12 21:24:42.515 invalidExample (AUDJPY,M15)     recalcIndex :: firstBarTimeCurTF = 2017.10.12 00:00
2018.10.12 21:24:42.515 invalidExample (AUDJPY,M15)     recalcIndex :: barIndexOtherTF = 6214
2018.10.12 21:24:42.515 invalidExample (AUDJPY,M15)     recalcIndex :: barTimeOtherTF = 2017.10.11 23:00

Возникает вопрос. С чего вдруг скрипт возвращает значение первого бара в истории меньше выставленного мной ограничения в 10тыс баров т.е. 9999, а индикатор возвращает, в данном случае 24853?

 
Я так думаю, какое значение в rates_total то и истинное. Если возможно, забудьте про Bars.
 
Unicornis:
Я так думаю, какое значение в rates_total то и истинное. Если возможно, забудьте про Bars.

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

 

Кстати, специально сегодня посмотрел в недосправку по этому поводу. Написано:

Параметр "Max bars in chart"

Параметр "Max bars in charts" ограничивает доступное для графиков, индикаторов и mql5-программ количество баров в формате HC. Это ограничение действует для данных всех таймфреймов, и предназначено в первую очередь для экономии ресурсов.

Устанавливая большие значения данного параметра, следует помнить, что при наличии достаточно глубокой истории ценовых данных для младших таймфреймов расход памяти на хранение таймсерий и буферов индикаторов может составить сотни мегабайт и достигнуть ограничения оперативной памяти для программы клиентского терминала (2Гб для 32-битных приложений MS Windows).

Изменение параметра "Max bars in charts" вступает в силу после перезапуска клиентского терминала. Само по себе изменение данного параметра не вызывает ни автоматического обращения к серверу за дополнительными данными, ни формирования дополнительных баров таймсерий. Запрос дополнительных ценовых данных у сервера и обновление таймсерий с учетом нового ограничения произойдет либо в случае прокрутки графика в область недостающих данных, либо в случае запроса недостающих данных из mql5-программы.

Объем запрашиваемых у сервера данных соответствует требуемому количеству баров данного таймфрейма с учетом значения параметра "Max bars in charts". Ограничение, задаваемое параметром, не является жестким, и в некоторых случаях количество доступных баров по таймфрейму может быть незначительно больше текущего значения параметра.


У меня в терминале стоит ограничение 10 тыс.

Получая количество баров с другого ТФ, который выше относительно того, на котором работает индикатор, возвращается баров в разы больше. Логично предположить, что это утверждение не работает. Справку писать 1 человек, а другой не в курсах об этом. Хренво только, что я сразу об этом не знал. Помучился, с надежой что выйдет всё красиво. Пришёл к выводу, что так как хочу не выйдет по причине не возможности ограничить количество баров нативно. Проще деревянным способом взять данные для написания МТФ индикатора из такого же индикатора, который работает на 1 ТФ и когда получаешь данные выбрать ТФ другой. Деревянно, но работать будет.

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