- Основные характеристики индикаторов
- Главное событие индикаторов: OnCalculate
- Два типа индикаторов: для главного и отдельного окна
- Настройка количества буферов и графических построений
- Назначение массива в качестве буфера: SetIndexBuffer
- Настройка графических построений: PlotIndexSetInteger
- Правила сопоставления буферов и диаграмм
- Применение директив для настройки графических построений
- Установка названий для графических построений
- Визуализация пропусков данных (пустых элементов)
- Индикаторы с собственным подокном: размер и уровни
- Общие свойства индикаторов: заголовок и точность значений
- Поэлементное раскрашивание диаграмм
- Пропуск отрисовки на начальных барах
- Ожидание данных и управление видимостью (DRAW_NONE)
- Мультивалютные и мультитаймфреймовые индикаторы
- Отслеживание формирования баров
- Тестирование индикаторов
- Ограничения и преимущества индикаторов
- Создание заготовки индикатора в Мастере MQL
Отслеживание формирования баров
Рассмотренный в предыдущем разделе индикатор IndUnityPercent.mq5 пересчитывается на последнем баре на каждом тике, так как использует цены Close. Некоторые индикаторы и эксперты специально разрабатываются в более экономичном стиле — с однократным расчетом на каждом баре. Например, мы могли бы считать формулу Unity по ценам открытия, и тогда разумно пропускать тики. Способов определения появления нового бара можно придумать несколько:
- Запоминать время текущего 0-го бара (через параметр time функции OnCalculate — time[0] или в общем случае iTime(symbol, period, 0)) и ждать, когда оно изменится;
- Запоминать количество баров rates_total (или iBars(symbol, period)) и реагировать на увеличение на 1 (изменение на другое количество в ту или иную сторону подозрительно и может свидетельствовать о модификации истории);
- Ждать бара с тиковым объемом равным 1 (первый тик на баре).
Однако при мультивалютной природе индикатора само понятие формирования нового бара становится не таким однозначным.
На каждом символе очередной бар появляется по приходу собственных тиков, и их время обычно не совпадает. В этом случае разработчик индикатора должен определить протокол действий: стоит ли дожидаться появления баров с одинаковым временем на всех символах или пересчитывать индикатор на последних барах несколько раз — после появления нового бара на любом из символов.
В данном разделе мы представим простой класс MultiSymbolMonitor (см. файл MultiSymbolMonitor.mqh) для отслеживания формирования новых баров по заданном списку символов.
В конструктор класса можно передать требуемый таймфрейм. По умолчанию контролируется таймфрейм текущего графика, на котором запущена программа.
class MultiSymbolMonitor
|
Для хранения списка контролируемых символов воспользуемся вспомогательным классом MapArray из предыдущего раздела. В этот массив будем записывать пары [имя символа;временная метка последнего бара], то есть шаблонных типов <string,datetime>. Для заполнения массива предусмотрен метод attach.
protected:
|
Для заданного массива класс умеет обновлять и проверять метки времени в методе check, вызывая функцию iTime в цикле по символам.
ulong check(const bool refresh = false)
|
Вызывающий код должен вызывать check по своему усмотрению — как правило, по приходу тиков или по таймеру. Строго говоря, оба эти варианта не обеспечивают моментальной реакции на появление тиков (и новых баров) на других инструментах: ведь событие OnCalculate появляется только на тиках рабочего символа графика и если между ними произошел тик какого-то другого символа, мы об этом не узнаем вплоть до следующего "своего" тика.
Оперативный мониторинг тиков с нескольких инструментов мы рассмотрим в главе про интерактивные события на графиках (см. индикатор-шпион EventTickSpy.mq5 в разделе Генерация пользовательских событий).
Сейчас же ограничимся проверками баров с доступной точностью и вернемся к рассмотрению метода check.
Каждый момент времени характеризуется собственным состоянием набора временных меток по всем символам в массиве. Например, в 12:00 может сформироваться новый бар только по самому ликвидному инструменту, а для нескольких других инструментов тики появятся через несколько миллисекунд или даже секунд. В этот промежуток в массиве обновится один элемент, а остальные будут старыми. Затем постепенно все символы получат бары 12:00.
Для всех символов, по которым время открытия последнего бара не равно сохраненному, метод взводит бит под номером символа, формируя таким образом битовую маску с изменениями. В списке должно быть не более 64 символов.
Если возвращаемое значение равно нулю — изменений не зафиксировано.
Параметр refresh задает, будет ли метод check просто фиксировать изменения (false) или произведет обновление состояния в соответствии с текущей рыночной ситуацией (true).
Метод describe позволяет по битовой маске получить список изменившихся символов.
string describe(ulong flags = 0)
|
Наконец, метод inSync пригодится для определения того, имеют ли все символы в массиве одинаковое время последнего бара. Его имеет смысл применять только для корзины валют с одинаковыми торговыми сессиями.
bool inSync() const
|
С помощью описанного класса реализуем простой мультивалютный индикатор IndMultiSymbolMonitor.mq5, единственная задача которого будет в детектировании новых баров по списку символов.
Поскольку никакой отрисовки для индикатора не предусмотрено, количество буферов и диаграмм равно 0.
#property indicator_chart_window
|
Список инструментов задается в соответствующей входной переменной и затем преобразуется в массив, регистрируемый в объекте monitor.
input string Instruments = "EURUSD,GBPUSD,USDCHF,USDJPY,AUDUSD,USDCAD,NZDUSD";
|
Обрабочик OnCalculate вызывает монитор на тиках и выводит изменения состояния в журнал.
int OnCalculate(const int rates_total,
|
Чтобы проверить данный индикатор нам потребовалось бы провести за терминалом много времени онлайн. Однако MetaTrader 5 позволяет сделать это намного проще — с помощью тестера. Сделаем это в следующем разделе.