- Описание ресурсов с помощью директивы #resource
- Разделяемое использование ресурсов разных MQL-программ
- Ресурсные переменные
- Подключение пользовательских индикаторов как ресурсов
- Динамическое создание ресурсов: ResourceCreate
- Удаление динамических ресурсов: ResourceFree
- Чтение и модификация данных ресурса: ResourceReadImage
- Сохранение изображений в файл: ResourceSave
- Шрифты и вывод текста в графические ресурсы
- Прикладное применение графических ресурсов в трейдинге
Прикладное применение графических ресурсов в трейдинге
Чтобы у вас не создалось впечатление, что ресурсы подходят только для украшений, покажем, как на их основе можно разработать инструмент, полезный для трейдеров. Заодно ликвидируем еще одно упущение: до сих пор мы использовали ресурсы только внутри объектов OBJ_BITMAP_LABEL, которые позиционируются в экранных координатах. Однако графические ресурсы могут быть встроены и в объекты OBJ_BITMAP с привязкой к координатам котировок: ценам и времени.
Ранее в книге был описан индикатор IndDeltaVolume.mq5, рассчитывающий дельту объемов (тиковых или реальных) для каждого бара. Кроме такого представления дельты объемов существует и еще одно, не менее популярное у пользователей, — так называемый профиль рынка. Это распределение объемов в разрезе ценовых уровней. Подобную гистограмму можно строить для всего окна целиком, на заданную глубину (например, внутри дня) или для отдельно взятого бара.
Именно последний вариант мы и реализуем в виде нового индикатора DeltaVolumeProfile.mq5. Основные технические тонкости запроса истории тиков мы уже рассмотрели в рамках вышеупомянутого индикатора, поэтому сконцентрируемся теперь, в основном, на графической составляющей.
Флаг ShowSplittedDelta во входной переменной будет управлять тем, как отображать объемы: в разбивке на покупки/продажи или в свернутом виде.
input bool ShowSplittedDelta = true; |
В индикаторе не будет буферов. Рассчитывать и показывать гистограмму для конкретного бара он будет по запросу пользователя, а конкретно - по щелчку мыши на этом баре. Таким образом, на первый план выходит обработчик OnChartEvent. В нем мы получаем экранные координаты, пересчитываем их в цену и время, и вызываем некую вспомогательную функцию RequestData, запускающую расчет.
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
Для её наполнения нам потребуется класс DeltaVolumeProfile, который построен по подобию класса CalcDeltaVolume из IndDeltaVolume.mq5.
В новом классе описаны переменные, учитывающие способ подсчета объемов (tickType), тип цены, по которой строится график (barType), режим из входной переменной ShowSplittedDelta (будет помещен в переменную-член delta), а также префикс для генерируемых объектов на графике.
class DeltaVolumeProfile
|
Напомним, что TickType можно менять на значение TRADE_TICKS только для торговых инструментов, по которым доступны реальные объемы. По умолчанию включен режим INFO_TICKS, работоспособный на всех инструментах.
Запрос тиков для конкретного бара делает метод createProfileBar.
int createProfileBar(const int i)
|
Непосредственный анализ тиков и подсчет объемов выполняется в защищенном методе calcProfile. В нем мы прежде всего узнаем диапазон цен бара и его размер в пикселях.
void calcProfile(const int b, const datetime time, const MqlTick &ticks[])
|
Руководствуясь этой информацией, создаем объект OBJ_BITMAP, выделяем массив для изображения и создаем ресурс. Фон всей картинки — пустой (прозрачный). Каждый объект привязывается верхней средней точкой к цене High своего бара и имеет ширину одного бара.
uint data[];
|
Далее следует подсчет объемов в тиках переданного массива. Количество ценовых уровней равно высоте бара в пикселях (h). Обычно оно меньше, чем диапазон цены в пунктах, и потому пиксели выступают, своего рода, корзинами для подсчета статистики. Если на мелком таймфрейме диапазон пунктов окажется меньше размера в пикселях, гистограмма получится визуально разреженной. Объемы покупок и продаж аккумулируются отдельно в массивах plus и minus.
long plus[], minus[], max = 0;
|
Для нормирования гистограммы попутно находим максимальное значение.
if(delta)
|
Наконец, полученная статистика выводится в графический буфер data и отправляется в ресурс. Объемы покупки выводятся синим цветом, продажи — красным, а если включен нетто-режим, то сумма — зеленым.
for(int i = 0; i < h; i++)
|
Теперь мы можем вернуться к функции RequestData: её задача — вызвать метод createProfileBar и обработать ошибки (если они возникли).
void RequestData(const int b, const datetime time, const int count = 0)
|
Единственная стратегия обработки ошибок заключается в том, чтобы попробовать запросить тики еще раз, потому что они могли не успеть загрузиться. Для этой цели функция посылает графику пользовательское сообщение TRY_AGAIN и сама же обрабатывает его.
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
Мы повторяем этот процесс не более 5 раз, потому что история тиков может иметь ограниченную глубину, и нагружать компьютер зря не имеет смысла.
Дополнительно класс DeltaVolumeProfile снабжен механизмом для обработки сообщения CHARTEVENT_CHART_CHANGE, чтобы перерисовать уже имеющиеся объекты в случае изменения размеров или масштаба графика. Подробности можно выяснить в исходном коде.
Результат работы индикатора показан на следующем изображении.
Отображение побаровых гистограмм раздельных объемов в графических ресурсах
Учтите, что сразу после нанесения индикатора гистограммы не отображаются: вам следует щелкнуть на баре, чтобы для него рассчиталась гистограмма.