функции ArraySetAsSeries изменили порядок доступа ко всем используемым массивам и здесь нам не нужно использовать индекс i-1, так как в текущем тике мы начинаем цикл с индекса 1.
Теперь, в функции OnChartEvent код сначала проверяет идентификатор события и если событие — это щелчок мыши на графическом объекте, код переходит к проверке, является ли этот объект графическим объектом индикатора.
Дальше код выделяет из имени объекта его порядковый номер, который соответствует индексу бара, и выводит значения буферов используемых индикаторов в диалоговое окно Alert отображения информации пользователю.
Параллельно информация выводится в окно Эксперты терминала.
Здесь было бы удобно вывести информацию в диалоговое окно MessageBox, которое позволяет взаимодействовать с пользователем, но его нельзя вызывать из пользовательских индикаторов, так как индикаторы выполняются в интерфейсном потоке и не должны его тормозить.
Объектно-ориентированный подход
В объектно-ориентированных языках все — это классы. В том числе и точка входа в приложение является классом, который содержит специфический метод — точку входа в приложение, или который расширяет специфический класс фреймворка или платформы.
С языком MQL5 это немного не так.
Создание программ на языке MQL5 связано с использованием набора функций обратного вызова, которые вызываются клиентским терминалом при наступлении тех или иных событий.
И код MQL5-приложения не является классом, а состоит из набора функций обратного вызова и вспомогательного пользовательского кода.
Так вот в части именно вспомогательного пользовательского кода разработчик и волен использовать либо процедурное программирование, либо объектно-ориентированное программирование.
В случае выбора процедурного программирования вспомогательный пользовательский код представляет собой набор пользовательских функций, при выборе объектно-ориентированного программирования вспомогательный пользовательский код представляет собой набор пользовательских классов, которые могут использовать стандартную MQL5-библиотеку классов.
Напомним базовые понятия объектно-ориентированного программирования.
Инкапсуляция — это когда код представлен классами, которые предоставляют открытые методы для доступа и изменения данных, таким образом защищая данные.
Расширяемость типов — это возможность добавлять пользовательские типы данных, что как раз основано на использовании классов, так как каждый новый пользовательский класс представляет новый тип данных.
Наследование — это возможность создавать новые классы на основе уже существующих классов, таким образом, повторно используя уже существующий проверенный и протестированный код. При этом в MQL5 нет множественного наследования.
Полиморфизм — это возможность иметь всем классам одной и той же иерархии наследования метод с одним именем, но разной реализацией.
Перегрузка — это создание методов класса, имеющих одно имя, но предназначенных для работы с разными типами данных, таким образом класс делается универсальным для разных типов данных.
В качестве примера использования объектно-ориентированного подхода рассмотрим создание нашего пользовательского индикатора Impulse keeper с применением классов.
В данном случае, использование класса CIndicator и его наследников CiMA и CiSAR, обеспечивающих доступ к индикаторам MA и PSAR, позволяет вообще обойтись без буферов индикатора Impulse keeper.
Так как они были нужны нам для копирования буферов индикаторов MA и PSAR, а классы CiMA и CiSAR предоставляют напрямую доступ к своим буферам.
Для использования класса CIndicator и его потомков, в код необходимо включить файл Trend.mqh:
Далее в коде индикатора Impulse keeper объявим экземпляры классов CiMA и CiSAR.
И в функции OnInit создадим индикаторы, используя метод Create класса CIndicator.
В функции OnCalculate после вычисления начальной позиции расчета индикатора установим размеры буферов индикаторов CiMA и CiSAR, используя метод BufferResize класса CIndicator.
Если это не сделать, размеры буферов используемых индикаторов будут по умолчанию иметь величину 100, и наш индикатор будет рассчитываться только до 100 бара.
Далее обновим данные используемых индикаторов и рассчитаем и отрисуем наш индикатор.
Чтобы быть последовательными в объектно-ориентированном подходе, весь код по расчету и отрисовке нашего индикатора можно выделить в отдельный пользовательский класс.
Благо мастер редактора MQL5 предоставляет возможность создания каркаса пользовательского класса как опция мастера Новый класс.
Назовем этот класс как IKSignal.
И здесь, в классе IKSignal мы объявляем закрытые поля класса, представляющие начальную позицию расчета индикатора и ценовую историю.
В конструкторе класса мы копируем его параметры в поля класса и меняем порядок доступа к полям-массивам.
Также в классе объявляется открытая функция draw, в которой фактически и будет производиться расчет и отрисовка индикатора.
В качестве параметров этой функции выступают экземпляры классов CiMA и CiSAR.
Тут мы просто переносим код из функции OnCalculate.
Теперь в коде основного файла нам не нужно включать файл Trend.mqh, так как мы уже сделали это в коде класса IKSignal, вместо этого нам нужно включить файл класса IKSignal.
Поместим файл класса IKSignal в каталог Include и включим его в основной файл индикатора:
Теперь функция OnCalculate примет следующий вид.
Здесь мы создаем экземпляр класса IKSignal с указанными в правильном порядке параметрами и применяем к нему функцию draw.
Как видно, код основного файла индикатора значительно упрощается.
При этом функциональность индикатора осталась той же самой.
Почему не работают индикаторы
Для торговли на Форекс предлагается огромное число самых разнообразных индикаторов, накладывая которые на график цены сразу же видно, что все они замечательно предсказывают движение цены и дают замечательные сигналы на продажу и покупку.
Почему же тогда начинающий трейдер, пользуясь индикаторами, сразу же уходит в минус?
Основные причины две.
Первая причина — это размер спреда. При увеличении спреда количество удачных сделок будет стремительно уменьшаться.
И вторая причина — это то, что в реале сделка не открывается на открытии того же бара, на котором индикатор дает сигнал, а открывается или закрывается позже.
В качестве примера рассмотрим индикатор Parabolic SAR.
Покупка — разворот, на анализируемом баре индикатор ниже цены, а на предыдущем — выше.
Продажа — разворот, на анализируемом баре индикатор выше цены, а на предыдущем — ниже.
Возьмем шаг индикатора 0.02, спред 0.0002 на паре EURUSD.
При условии открытия и закрытия позиции на открытии того же бара, на котором индикатор формирует сигнал, получаются следующие результаты:
Здесь для сделок на