Универсальный тренд с графическим интерфейсом
Содержание
- Введение
- Типы индикаторов
- Отображение тренда
- Используемые индикаторы
- Внешние параметры
- Создание индикатора
- Создание графического интерфейса
- Добавление графического интерфейса к индикатору
- Заключение
- Приложение
Введение
В двух предыдущих статьях этой серии была описана разработка универсального осциллятора с графическим интерфейсом и затем — универсального канала на его основе.
Универсальный трендовый индикатор тоже может быть создан на основе универсального осциллятора. Чтобы не повторяться, используем при этом несколько иной подход. Возможно, кому-то он понравится больше.
В универсальном осцилляторе и универсальном канале все объекты элементов управления создавались в классе формы при помощи автоматических указателей, а при помощи дополнительного класса выполнялось управление их видимостью и позицией. Теперь же будет создан универсальный составной элемент управления по принципам, описанным в серии статей "Пользовательские графические элементы управления" (статья 1, статья 2, статья 3). Однако созданы будут только методы, необходимые для решения задачи данной конкретной статьи.
Типы индикаторов
Не будем ограничиваться индикаторами, которые традиционно относятся к трендовым. Любой индикатор зависящий от направления движения цены (хоть скользящая средняя, хоть осциллятор RSI) можно применять как для определения момента входа, так и для определения тренда. Например, если цена выше скользящей средней, то можно считать, что присутствует восходящий тренд, и наоборот (рис. 1).
Рис. 1. Использование скользящей средней и цены для определения тренда. Синими стрелками вверх показаны интервалы, когда
можно покупать (цена выше средней), красными стрелками вниз — интервалы, когда можно продавать (цена ниже средней).
Точно так же можно использовать наклон средней: наклон вверх — восходящий тренд, наклон вниз — нисходящий (рис. 2).
Рис. 2. Использование наклона скользящей средней для определения тренда. Синими стрелками вверх показаны интервалы, когда
можно покупать (средняя направлена вверх), красными стрелками вниз — интервалы, когда можно продавать (средняя направлена вниз)
Если определять бар, на котором цена пересекла среднюю (на одном баре цена закрытия была ниже средней, на следующем выше), то в этом случае средняя используется для определения момента входа. В этом случае торговый сигнал существует в течение одного бара (рис. 3).
Рис. 3. Использование скользящей средней и цены для определения моментов входа. Синими стрелками вверх показаны бары
покупки (на одном баре цена была ниже средней, на следующем стала выше средней), красными стрелками вниз показаны
бары продажи (на одном баре цена была выше средней, на следующем стала ниже средней)
Так же можно использовать наклон средней: бары, на которых средняя меняет направление, являются барами входа (рис. 4).
Рис. 4. Использование наклона скользящей средней для определения моментов входа. Синими стрелками вверх показаны бары
покупки (нижние экстремумы средней), красными стрелками вниз — бары продажи (верхние экстремумы)
В данной статье нас будут интересовать варианты определения тренда (как на рис. 1 и рис. 2). Варианты определения баров входа я привел для сравнения и полноты понимания.
По осцилляторам обычно определяется момент входа, чаще всего по пересечению уровня, например RSI (рис. 5). Осциллятор стохастик для определения момента входа можно использовать как минимум двумя способами: по пересечению уровня и по пересечению главной и сигнальной линий.
Рис. 5. Определение баров входа по индикатору RSI. Синими стрелками показаны бары покупки (пересечение уровня
70 вверх), красными стрелками — бары продажи (пересечение уровня 30 вниз)
Рассмотрим, как можно использовать осцилляторы для определения тренда. Для стохастика ответ очевиден: по положению главной и сигнальной линий, когда главная линия выше сигнальной, то можно покупать, а когда главная ниже сигнальной — можно продавать (рис. 6).
Рис. 6. Определение главной и сигнальной линий осциллятора стохастик для определения тренда. Синими стрелками обозначен
тренд вверх (главная линия выше сигнальной), красными — тренд вниз (главная линия ниже сигнальной)
Аналогично можно использовать и уровни: если осциллятор выше какого-то уровня — можно покупать, если ниже — можно продавать (рис. 7).
Рис. 7. Использование осциллятора RSI и уровней для определения тренда. Синими стрелками обозначен тренд вверх
(RSI выше 60), красными стрелками обозначен тренд вниз (RSI ниже 40)
Отображение тренда
Определимся с наиболее удобным способом отображения тренда. Первая возникающая идея — это цветная линия, меняющая свой цвет в зависимости от тренда. Рассмотрим определение тренда по осциллятору RSI и уровням 60 и 40. Если линия RSI выше уровня 60, то можно покупать, а если ниже 40 — можно продавать (рис. 7). Получается, что когда линия RSI находится между уровнями 40 и 60, то нельзя ни покупать ни продавать. Теперь поменяем уровни местами: уровень покупки равен 40 (при значениях больше 40 можно покупать), уровень продажи 60 (при значениях меньше 60 можно продавать). В этом случае между уровнями 40 и 60 можно и покупать, и продавать (рис. 8).
Рис. 8. Использование осциллятора RSI и уровней для определения тренда. При значении уровня покупки 40, а уровня продажи 60
существуют участки, когда можно и покупать, и продавать (существуют одновременно и синяя, и красная стрелки).
Из этого следует, что тренд надо отображать двумя независимыми рядами данных. Будем использовать два индикаторных буфера: один смещенный чуть выше, другой — чуть ниже (чтобы иметь возможность отображать два буфера одновременно). Поскольку буферы будут отображаться прерывисто, лучше использовать гистограммы или значки. Выберем значки. Тогда, кроме разного цвета для разных буферов, можно использовать разные значки. Как будет выглядеть индикатор, показано на рис 9.
Рис. 9. Удобный способ отображения тренда
Такой способ отображения тренда позволяет расширить количество используемых индикаторов. К примеру, можно ввести индикаторы, не зависящие от направления, а только разрешающие/запрещающие торговлю на различных интервалах. Например, можно использовать индикатор ATR или STD. Если его значение выше определенного порога, то отображаются обе стрелки (и вверх, и вниз). Таким образом, универсальный индикатор становится еще более универсальным.
Используемые индикаторы
Прежде чем приступить к созданию универсального трендового индикатора, определимся с полным перечнем индикаторов, по которым будем определять тренд. Таким образом мы выясним необходимый набор внешних параметров (количество и типы переменных). Конечно, все возможные варианты вряд ли получится сразу вместить в индикатор — их слишком много. Только одну скользящую среднюю можно использовать как минимум двумя способами. А ведь еще можно использовать две скользящих средних. Поэтому надо изначально обеспечить максимально легкую возможность доработки индикатора.
Некоторые варианты использования индикаторов могут быть идентичными, хотя это может выглядеть не настолько очевидным. Например, использование для определения тренда двух скользящих средних (быстрой и медленной) делает ненужным вариант определения тренда по цене и средней. Если для быстрой средней установить период, равный 1, она будет соответствовать цене. Поэтому каждый индикатор нужно рассматривать отдельно. Более того, необходимо непосредственно рассмотреть каждый из вариантов применения каждого индикатора.
Индикатор не имеет параметров, является идентичным индикатору OsMA при определенных параметрах, поэтому использоваться не будет.
iAD (Accumulation/Distribution)
Очень специфический индикатор. Диапазон значений индикатора не определен, линия его сильно изломанная, а это не подходит для определения тренда без соответствующей обработки (например, сглаживания). Использоваться не будет.
iADX (Average Directional Index)
Вариант 1. Положение линий PDI и MDI. PDI выше MDI — тренд вверх, PDI ниже MDI — тренд вниз.
Параметры:
- int adx_period.
Вариант 2. Не зависящий от направления. Положение линии ADX относительно определенного уровня. ADX выше уровня — разрешена покупка и продажа. Кроме параметра индикатора, потребуется дополнительный параметр для уровня.
Параметры:
- int adx_period — период;
- double level — уровень.
iADXWilder (Average Directional Index by Welles Wilder)
Все так же, как у индикатора ADX.
Индикатор представляет собой три скользящих средних различного периода и с различным смещением. Способов применения этого индикатора можно придумать очень много, ограничимся одним вариантом.
Вариант 1. Быстрая линия (губы) выше средней (зубы), средняя выше медленной (челюсти) — тренд вверх, при обратном расположении линий — тренд вниз.
Параметры:
- int jaw_period — период челюстей;
- int jaw_shift — смещение челюстей;
- int teeth_period — период зубов;
- int teeth_shift — смещение зубов;
- int lips_period — период для губ;
- int lips_shift — смещение губ;
- ENUM_MA_METHOD ma_method — тип сглаживания;
- ENUM_APPLIED_PRICE applied_price — тип цены.
iAMA (Adaptive Moving Average)
Индикатор представляет собой скользящую среднюю. Будем использовать по два варианта применения всех средних.
Вариант 1. Наклон линии. Кроме стандартных параметров индикатора, потребуется параметр, определяющий смещение второй точки индикатора, относительно которой проверяется наклон.
Параметры:
- int ama_period — период AMA;
- int fast_ma_period — период быстрой скользящей;
- int slow_ma_period — период медленной скользящей;
- int ama_shift — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price — тип цены;
- int shift2 — смещение точки, относительно которой проверяется наклон.
Вариант 2. Две линии: быстрая и медленная. Быстрая линия выше медленной — тренд вверх, быстрая ниже медленной — тренд вниз. Потребуется два идентичных комплекта стандартных параметров.
Параметры:
- int ama_period1 — период AMA;
- int fast_ma_period1 — период быстрой скользящей;
- int slow_ma_period1 — период медленной скользящей;
- int ama_shift1 — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price1 — тип цены;
- int ama_period2 — период AMA;
- int fast_ma_period2 — период быстрой скользящей;
- int slow_ma_period2 — период медленной скользящей;
- int ama_shift2 — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price2 — тип цены.
Примечание: переменные с числом 1 в конце используются для быстрой линии, с числом 2 — для медленной.
Индикатор не имеет параметров, является идентичным индикатору MACD при определенных параметрах, поэтому использоваться не будет.
Индикатор не зависит от направления, будет использоваться один вариант.
Вариант 1: не зависящий от направления. Положение линии ATR относительно уровня. ATR выше уровня — разрешена покупка и продажа. Кроме параметра индикатора, потребуется дополнительный параметр для уровня.
Параметры:
- int ma_period — период;
- double level — уровень.
iBearsPower (Bears Power) и iBullsPower (Bulls Power)
Индикаторы BearsPower и BullsPower несимметричны, то есть, должны использоваться в паре: один — для сигналов покупки, второй — для сигналов продажи. Для определения тренда вверх будем использовать BullsPower, для определения тренда вниз — BearsPower. Будеv использовать два варианта: по положению индикатора относительно уровня и по наклону.
Вариант 1. Если BullsPower выше заданного уровня — разрешены покупки, если BearsPower ниже отрицательного значения этого же уровня — разрешены продажи. Кроме стандартных параметров, потребуется дополнительный параметр для уровня.
Параметры:
- int ma_period — период;
- double level — уровень.
Вариант 2. Направление индикатора. Для этого варианта потребуется дополнительный параметр, определяющий смещение второй точки, относительно которой определяется наклон.
Параметры:
- int ma_period — период;
- int shift2 — смещение второй точки.
Индикатор представляет собой канал.
Вариант 1. Если цена пересекает верхнюю границу вверх — начинается восходящий тренд; при пересечении ценой центральной линии вниз тренд отменяется. Аналогично индикатор работает и в другую сторону для нижней линии и тренда вниз.
Параметры:
- int bands_period — период для расчета средней линии;
- int bands_shift — смещение индикатора по горизонтали;
- double — количество стандартных отклонений;
- ENUM_APPLIED_PRICE applied_price — тип цены.
iCCI (Commodity Channel Index)
Индикатор представляет собой осциллятор в подокне. Линия индикатора довольно изломанная даже при больших периодах, поэтому вариант с наклоном не будет использоваться.
Вариант 1. Положение относительно уровня. Если индикатор выше уровня — тренд вверх, если ниже отрицательного значения этого же уровня — тренд вниз.
Параметры:
- int ma_period — период усреднения;
- ENUM_APPLIED_PRICE applied_price — тип цены или handle;
- double level — уровень.
Применение индикатора подобно применению индикатора CCI.
Вариант 1. Положение относительно уровня. Если индикатор выше уровня — тренд вверх, если ниже отрицательного значения этого же уровня — тренд вниз.
Параметры:
- int fast_ma_period — быстрый период;
- int ow_ma_period — медленный период;
- ENUM_MA_METHOD ma_method — тип сглаживания;
- ENUM_APPLIED_VOLUME applied_volume — используемый объем;
- double level — уровень.
iDEMA (Double Exponential Moving Average)
Индикатор представляет собой скользящую среднюю и применяется так же, как и рассмотренный ранее индикатор AMA.
Вариант 1. Наклон линии.
Параметры:
- int ma_period — период усреднения;
- ENUM_APPLIED_PRICE applied_price — тип цены;
- int ma_shift — смещение индикатора по горизонтали;
- int shift2 — смещение точки, относительно которой проверяется наклон.
Вариант 2. Две линии: быстрая и медленная.
Параметры:
- int ma_period1 — период усреднения;
- ENUM_APPLIED_PRICE applied_price1 — тип цены;
- int ma_shift1 — смещение индикатора по горизонтали;
- int ma_period2 — период усреднения;
- ENUM_APPLIED_PRICE applied_price2 — тип цены;
- int ma_shift2 — смещение индикатора по горизонтали.
Примечание: переменные с числом 1 в конце используются для быстрой линии, с числом 2 — для медленной.
Индикатор представляет собой осциллятор в подокне, изменяющийся в диапазоне от 0 до 1. Нейтральный уровень индикатора — уровень 0.5. Линия индикатора изломанная, не подойдет для варианта с наклоном.
Вариант 1. Положение относительно уровня. Уровень для продажи будет задаваться через параметры, а уровень для покупки будет вычисляться симметрично относительно уровня 0.5.
Параметры:
- int ma_period — период усреднения;
- double level — уровень продажи.
Индикатор представляет собой канал, подобно полосам Боллинджера, но применяется более просто.
Вариант 1. Если цена выше верхней границы канала, покупка разрешена, если ниже нижней границы — разрешена продажа.
Параметры:
- int ma_period — период для расчета средней линии;
- int ma_shift — смещение индикатора по горизонтали;
- ENUM_MA_METHOD ma_method — тип сглаживания;
- ENUM_APPLIED_PRICE applied_price — тип цены или;
- double deviation — отклонение границ от средней линии.
Индикатор представляет собой осциллятор в подокне, изменяющийся вокруг уровня 0. Применение подобно применению индикатора CCI.
Вариант 1. Положение относительно уровня.
Параметры:
- int ma_period — период усреднения;
- ENUM_MA_METHOD ma_method — тип сглаживания;
- ENUM_APPLIED_VOLUME applied_volume — тип объема для расчета;
- double level — уровень.
Параметров индикатор не имеет.
Вариант 1. Определение происходит по типу последнего фрактала. Если последний фрактал сверху, разрешаются продажи, если снизу — разрешаются покупки.
iFrAMA (Fractal Adaptive Moving Average)
Индикатор представляет собой скользящую среднюю, применяется так же, как AMA.
Вариант 1. Наклон линии.
Параметры:
- int ma_period — период усреднения;
- int ma_shift — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price — тип цены;
- int shift2 — смещение точки, относительно которой проверяется наклон.
Вариант 2. Две линии: быстрая и медленная.
Параметры:
- int ma_period1 — период усреднения;
- int ma_shift1 — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price1 — тип цены;
- int ma_period2 — период усреднения;
- int ma_shift2 — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price2 — тип цены.
Примечание: переменные с числом 1 в конце используются для быстрой линии, с числом 2 — для медленной.
Этот индикатор рассчитывается на основе индикатора Alligator. Всю информацию, которую он дает, можно получить непосредственно от индикатора Alligator, поэтому использовать его мы не будем.
iIchimoku (Ichimoku Kinko Hyo)
У этого индикатора интерес могут представлять пара линий: тенкан — киджун и облако. В облаке можно выделить две линии, меняющие свое положение (то одна сверху, то другая). Получается два варианта использования индикатора.
Вариант 1. Положение линий тенкан и киджун. Если линия текан (красная) выше линии киджун (синяя) — тренд вверх, если тенкан ниже киджун — тренд вниз.
Параметры:
- int tenkan_sen — период Tenkan-sen;
- int kijun_sen — период Kijun-sen;
- int senkou_span_b — период Senkou Span B.
Вариант 2. По направлению облака. Облако определяется двумя линиями: SpanA и SpanB. Если линия SpanA выше линии SpanB — тренд вверх, если наоборот — тренд вниз.
Параметры:
- int tenkan_sen — период Tenkan-sen;
- int kijun_sen — период Kijun-sen;
- int senkou_span_b — период Senkou Span B.
Этот индикатор мы использовать не будем в силу его высокой специфичности.
Индикатор представляет собой осциллятор в подокне. Линия индикатора очень изломанная, для определения тренда по наклону не подходит. Остается вариант по уровню.
Вариант 1. Уровень. Нейтральный уровнь: 100. Кроме стандартных параметров индикатора, потребуется параметр для уровня продажи, уровень покупки будет вычисляться симметрично, относительно уровня 100.
Параметры:
- int mom_period — период усреднения;
- ENUM_APPLIED_PRICE applied_price — тип цены или handle;
- double level — уровень продажи.
Индикатор представляет собой осциллятор в подокне, изменяющийся от 0 до 100. Нейтральный уровень: 50. Линия изломанная, для определения тренда по направлению линии не подходит.
Вариант 1. По уровню. Кроме стандартных параметров, потребуется параметр для определения уровня продажи, уровень покупки будет рассчитываться симметрично относительно уровня 50. Если линия индикатора выше уровня покупки — тренд вверх, если ниже уровня продажи — тренд вниз.
Параметры:
- int ma_period — период усреднения;
- ENUM_APPLIED_VOLUME applied_volume — тип объема для расчета;
- double level — уровень продажи.
Это обычная скользящая средняя.
Вариант 1. Наклон линии.
Параметры:
- int ma_period — период усреднения;
- int ma_shift — смещение индикатора по горизонтали;
- ENUM_MA_METHOD ma_method — тип сглаживания;
- ENUM_APPLIED_PRICE applied_price — тип цены;
- int shift2 — смещение точки, относительно которой проверяется наклон.
Вариант 2. Две линии: быстрая и медленная.
Параметры:
- int ma_period1 — период усреднения;
- int ma_shift1 — смещение индикатора по горизонтали;
- ENUM_MA_METHOD ma_method1 — тип сглаживания;
- ENUM_APPLIED_PRICE applied_price1 — тип цены;
- int ma_period2 — период усреднения;
- int ma_shift2 — смещение индикатора по горизонтали;
- ENUM_MA_METHOD ma_method2 — тип сглаживания;
- ENUM_APPLIED_PRICE applied_price2 — тип цены.
Примечание: переменные с числом 1 в конце используются для быстрой линии, с числом 2 — для медленной.
iOsMA (Moving Average of Oscillator (MACD histogram)
Осциллятор OsMA представляет собой гистограмму в подокне. Может быть два варианта: по уровню и по направлению.
Вариант 1. По уровню. Если гистограмма выше уровня — разрешены покупки, если ниже отрицательного значения того же уровня — разрешены продажи.
Параметры:
- int fast_ema_period — период быстрой средней;
- int slow_ema_period — период медленной средней;
- int signal_period — период усреднения разности;
- ENUM_APPLIED_PRICE applied_price — тип цены или handle;
- double level — уровень.
Вариант 2. По направлению. Если гистограмма направлена вверх — разрешены покупки, если вниз — продажи. Потребуется дополнительный параметр для смещения второй точки, относительно которой проверяется направление.
Параметры:
- int fast_ema_period — период быстрой средней;
- int slow_ema_period — период медленной средней;
- int signal_period — период усреднения разности;
- ENUM_APPLIED_PRICE applied_price — тип цены или handle;
- int shift2 — смещение второй точки для определения направления.
iMACD (Moving Averages Convergence-Divergence)
Индикатор MACD отображает в подокне гистограмму и сигнальную линию. Индикатор можно использовать тремя различными способами: по уровню гистограммы, по ее направлению и по ее положению относительно сигнальной линии. Однако последнее является частным случаем проверки индикатора OsMA по уровню (при значении уровня 0), поэтому не будет использоваться.
Вариант 1. По уровню. Если гистограмма выше уровня — разрешены покупки, если ниже отрицательного значения того же уровня — разрешены продажи.
Параметры:
- int fast_ema_period — период быстрой средней;
- int slow_ema_period — период медленной средней;
- int signal_period — период усреднения разности;
- ENUM_APPLIED_PRICE applied_price — тип цены или handle;
- double level — уровень.
Вариант 2. По направлению. Если гистограмма направлена вверх — покупки, если вниз — продажи. Потребуется дополнительный параметр для смещения второй точки, относительно которой проверяется направление.
Параметры:
- int fast_ema_period — период быстрой средней;
- int slow_ema_period — период медленной средней;
- int signal_period — период усреднения разности;
- ENUM_APPLIED_PRICE applied_price — тип цены или handle;
- int shift2 — смещение второй точки для определения направления.
Этот индикатор, как и индикатор AD, не имеет определенного диапазона значений и сильно изломан. Не будет использоваться.
iSAR (Parabolic Stop And Reverse System)
Индикатор отображается на графике цены, рисует одну линию из точек. В зависимости от направления движения цены, линия располагается то сверху, то снизу цены.
Вариант 1. Положение относительно цены. Цена выше линии индикатора — тренд вверх, цена ниже линии индикатора — тренд вниз.
Параметры:
- double step — шаг изменения цены — коэффициент ускорения;
- double maximum — максимальный шаг.
iRSI (Relative Strength Index)
Осциллятор в подокне. Один вариант применения, подобный применению индикатора MFI.
Вариант 1. По уровню.
Параметры:
- int ma_period — период усреднения;
- ENUM_APPLIED_PRICE price — тип цены;
- double level — уровень продажи.
Осциллятор в подокне с сигнальной линией. Значение меняется вокруг нуля.
Вариант 1. По уровню. Выше уровня — покупки, ниже отрицательного значения уровня — продажи.
Параметры:
- int ma_period — период усреднения;
- double level — уровень.
Вариант 2. Главная и сигнальная линии.
Параметры:
- int ma_period — период усреднения.
Индикатор, не зависящий от направления. Подобен индикатору ATR.
Вариант 1. По уровню.
Параметры:
- int ma_period — период усреднения;
- int ma_shift — смещение индикатора по горизонтали;
- ENUM_MA_METHOD ma_method — тип сглаживания;
- ENUM_APPLIED_PRICE applied_price — тип цены;
- double level — уровень.
iStochastic (Stochastic Oscillator)
Осциллятор в подокне с главной и сигнальной линиями.
Вариант 1. Наклон главной линии.
Параметры:
- int Kperiod — K-период;
- int Dperiod — D-период;
- int slowing — окончательное сглаживание;
- ENUM_MA_METHOD ma_method — тип сглаживания;
- ENUM_STO_PRICE price_field — цена;
- int shift2 — смещение второй точки для определения наклона.
Вариант 2. По уровню. Значение индикатора меняется от 0 до 100, нейтральный уровень 50. Требуется дополнительный параметр для уровня продажи, уровень покупки будет вычисляться.
Параметры:
- int Kperiod — K-период;
- int Dperiod — D-период;
- int slowing — окончательное сглаживание;
- ENUM_MA_METHOD ma_method — тип сглаживания;
- ENUM_STO_PRICE price_field — цена;
- double level — уровень.
Вариант 3. Положение главной и сигнальной линий.
Параметры:
- int Kperiod — K-период;
- int Dperiod — D-период;
- int slowing — окончательное сглаживание;
- ENUM_MA_METHOD ma_method — тип сглаживания;
- ENUM_STO_PRICE price_field — цена.
iTEMA (Triple Exponential Moving Average)
Еще одна скользящая средняя.
Вариант 1. Наклон линии.
Параметры:
- int ma_period — период усреднения;
- int ma_shift — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price — тип цены;
- int shift2 — смещение точки, относительно которой проверяется наклон.
Вариант 2. Две линии: быстрая и медленная.
Параметры:
- int ma_period1 — период усреднения;
- int ma_shift1 — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price1 — тип цены;
- int ma_period2 — период усреднения;
- int ma_shift2 — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price2 — тип цены.
Примечание. Переменные с числом 1 в конце используются для быстрой линии, с числом 2 — для медленной.
iTriX (Triple Exponential Moving Averages Oscillator)
Осциллятор в подокне. Один вариант — наклон линии, и для разнообразия в качестве второго попробуем вариант с двумя линиями: быстрой и медленной
Вариант 1. Наклон линии.
Параметры:
- int ma_period — период усреднения;
- int ma_shift — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price — тип цены;
- int shift2 — смещение точки, относительно которой проверяется наклон.
Примечание: функция iTriX не имеет параметра ma_shift, но индикатор все равно можно смещать. В любом случае смещение будет выполняться не через параметр shift (он будет устанавливаться равным 0 для всех индикаторов), а через вычисление индекса бара.
Вариант 2. Две линии: быстрая и медленная.
Параметры:
- int ma_period1 — период усреднения;
- int ma_shift1 — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price1 — тип цены;
- int ma_period2 — период усреднения;
- int ma_shift2 — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price2 — тип цены.
Примечание. Переменные с числом 1 в конце используются для быстрой линии, с числом 2 — для медленной.
iWPR (Williams' Percent Range)
Индикатор идентичен главной линии стохастика при замедлении 1, но с перевернутой шкалой. Использоваться не будет.
iVIDyA (Variable Index Dynamic Average)
Еще одна скользящая средняя.
Вариант 1. Наклон линии.
Вариант 2. Две линии: быстрая и медленная.Параметры:
- int cmo_period — период CMO
- ema_period — период сглаживания
- ma_shift — смещение индикатора по горизонтали
- ENUM_APPLIED_PRICE applied_price — тип цены
- int shift2 — смещение точки, относительно которой проверяется наклон.
Параметры:
- int ma_period1 — период усреднения;
- int ma_shift1 — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price1 — тип цены;
- int ma_period2 — период усреднения;
- int ma_shift2 — смещение индикатора по горизонтали;
- ENUM_APPLIED_PRICE applied_price2 — тип цены.
Примечание: переменные с числом 1 в конце используются для быстрой линии, с числом 2 — для медленной.
Показания индикатора не зависят от направления движения цены. Индикатор может использоваться подобно индикатору ATR или STD.
Вариант 1. Уровень. При значении ндикатора выше уровня разрешаются покупки и продажи.
Параметры:
- ENUM_APPLIED_VOLUME applied_volume — тип объема;
- double level — уровень.
Определившись с индикаторами и способами их использования, напишем перечисление всех их типов. В папке Includes создадим папку UniTrend, в ней создадим файл UniTrendDefines.mqh с перечислением:
enum EType{
Type_ADX_PDIMDI, // положение линий PDI и MDI индикатора ADX
Type_ADX_Level, // положение линий ADX относительно уровня
Type_ADXW_PDIMDI, // положение линий PDI и MDI индикатора ADX Wilder
Type_ADXW_Level, // положение линий ADX относительно уровня у индикатора ADX Wilder
Type_Alligator, // Аллигатор
Type_AMA_Dir, // направление АМА
Type_AMA_2MA, // две АМА
Type_ATR_Level, // ATR
Type_BuBe_Level, // Bulls/Bears Power и уровень
Type_BuBe_Dir, // направление Bulls/Bears Power
Type_Bands, // полосы Боллинджера
Type_CCI_Level, // CCI и уровень
Type_Chaikin_Level, // осциллятор Чайкина и уровень
Type_DEMA_Dir, // направление DEMA
Type_DEMA_2MA, // две DEMA
Type_DeMarker_Level, // Демаркер и уровень
Type_Envelopes, // Конверт
Type_Force_Level, // осциллятор Force и уровень
Type_Fractals, // фракталы
Type_FrAMA_Dir, // направление FrAMA
Type_FrAMA_2MA, // две FrAMA
Type_Ichimoku_TK, // Ишимоку: Тенкан и Киджун
Type_Ichimoku_SASB, // Ишимоку: облако
Type_Momentum_Level, // Моментум и уровень
Type_MFI_Level, // MFI и уровень
Type_MA_Dir, // направление МА
Type_MA_2MA, // две MA
Type_OsMA_Dir, // направление OsMA
Type_OsMA_Level, // OsMA и уровень
Type_MACD_Dir, // направление MACD
Type_MACD_Level, // MACD и уровень
Type_SAR, // SAR
Type_RSI_Level, // RSI и уровень
Type_RVI_Level, // RVI и уровень
Type_RVI_MS, // главная и сигнальная линии RVI
Type_STD_Level, // стандартная девиация и уровень
Type_Sto_Dir, // направление стохастика
Type_Sto_Level, // стохастик и уровень
Type_Sto_MS, // главная и сигнальная линии стохастика
Type_TEMA_Dir, // направление TEMA
Type_TEMA_2MA, // две TEMA
Type_TriX_Dir, // направление TriX
Type_TriX_2MA, // две TriX
Type_VIDyA_Dir, // направление VIDyA
Type_VIDyA_2MA, // две VIDyA
Type_Volumes // объем
Внешние параметры
Проанализировав приведенные выше описания индикаторов, можно определить необходимый набор внешних параметров. В таблице 1 приведены все необходимые параметры и их типы. В основном будут задействованы переменные с префиксом "f_" (от анг. fast — быстрый). Для вариантов с быстрой и медленной скользящими средними используется вторая группа параметров с префиксом "s_" (от анг. slow — медленный).
Таблица 1. Внешние параметры и их типы
Тип | Имя |
---|---|
int | f_period1 |
int | f_shift1 |
int | f_period2 |
int | f_shift2 |
int | f_period3 |
int | f_shift3 |
ENUM_MA_METHOD | f_method |
ENUM_APPLIED_PRICE | f_price |
ENUM_APPLIED_VOLUME | f_volume |
ENUM_STO_PRICE | f_sto_price |
double | f_level |
int | f_dot2shift |
double | f_step |
double | f_maximum |
int | s_period1 |
int | s_shift1 |
int | s_period2 |
int | s_shift2 |
int | s_period3 |
int |
s_shift3 |
ENUM_MA_METHOD | s_method |
ENUM_APPLIED_PRICE | s_price |
int | mult |
int | level_digits |
int | sar_step_digits |
int | sar_maximum_digits |
Кроме параметров, перечисленных в описаниях индикаторов, в нижней части таблицы находится несколько дополнительных параметров:
- mult — коэффициент умножения параметров, измеряющихся в пунктах, в зависимости от количества знаков у котировок. Значения некоторых индикаторов, например MACD и OsMA имеют размерность цены, поэтому задавать их уровень будет удобней в пунктах. Соответственно будет удобно корректировать значения параметров в зависимости от количества знаков в котировках.
- level_digits — количество знаков после запятой у параметра уровня. В графическом интерфейсе для установки значения уровня используется элемент управления CSpinBox (поле ввода с кнопками "+" и "-"), поэтому было бы удобно для разных индикаторов устанавливать различное минимальное изменение (величина, на которую меняется значение при нажатии на кнопку "+" или "-").
- sar_step_digits — количество знаков после запятой для параметра step индикатора SAR.
- sar_maximum_digits — количество знаков после запятой для параметра maximum индикатора SAR.
#define ADXW_LEVEL_DIGITS 0 // для индикатора ADX Wilder
#define ATR_LEVEL_DIGITS 1 // для индикатора ATR
#define BUBE_LEVELS_DIGITS 1 // для индикаторов Bulls/Bears Power
#define CCI_LEVEL_DIGITS 0 // для индикатора CCI
#define CHAIKIN_LEVEL_DIGITS 0 // для осциллятора Чайкина
#define DEMARKER_LEVEL_DIGITS 2 // для индикатора Demarker
#define FORCE_LEVEL_DIGITS 3 // для индикатора Force
#define MOMENTUM_LEVEL_DIGITS 2 // для индикатора Momentum
#define MFI_LEVEL_DIGITS 0 // для индикатора
#define OSMA_LEVBEL_DIGITS 2 // для индикатора OsMA
#define MACD_LEVEL_DIGITS 2 // для индикатора MACD
#define RSI_LEVEL_DIGITS 0 // для индикатора RSI
#define RVI_LEVEL_DIGITS 2 // для индикатора RVI
#define STD_LEVEL_DIGITS 1 // для индикатора STD
#define STO_LEVEL_DIGITS 0 // для индикатора Stochastic
#define BANDS_LEVEL_DIGITS 1 // для полос Боллинджера
#define ENVELOPES_LEVEL_DIGITS 2 // для индикатора Envelopes
#define SAR_STEP_DIGITS 3 // для индикатора SAR (параметр step)
#define SAR_MAXIMUM_DIGITS 2 // для индикатора SAR (параметр maximum)
На основании таблицы 1 создадим структуру:
int f_period1;
int f_shift1;
int f_period2;
int f_shift2;
int f_period3;
int f_shift3;
long f_method;
long f_price;
long f_volume;
long f_sto_price;
double f_level;
int f_dot2shift;
double f_step;
double f_maximum;
int s_period1;
int s_shift1;
int s_period2;
int s_shift2;
int s_period3;
int s_shift3;
long s_method;
long s_price;
int mult;
int level_digits;
int sar_step_digits;
int sar_maximum_digits;
};
Объединение параметров в структуру позволит отделить их от остального кода, что будет очень удобным в случае доработки индикатора при добавлении новых типов определения тренда, если имеющихся параметров будет недостаточно. Также это значительно упростит передачу параметров в функции и методы классов.
Поскольку создаваемый в статье индикатор будет отображать тренд в виде рядов значков (это одинаково для всех индикаторов), не составит труда добавить в индикатор функцию уведомления о начале тренда. Кого-то может интересовать уведомление только сформировавшегося тренда (показания на сформированном баре), а кого-то — первый момент появления нового тренда (на формирующемся баре). Поэтому напишем перечисления для выбора типа уведомления:
Alerts_off=0, // уведомление отключено
Alerts_Bar0=1, // уведомление по формирующемуся бару
Alerts_Bar1=2 // уведомление по сформированному бару
};
Создание индикатора
Создание классов для универсальных индикаторов подробно рассматривалось в статьях "Универсальный осциллятор с графическим интерфейсом" и "Универсальный канал с графическим интерфейсом". Рассмотрим особенности их создания применительно к данному случаю.
Все перечисленные выше способы определения тренда делятся на две категории: с одним или с двумя индикаторами. У одной группы после загрузки индикатора надо проверить один хэндл, а у второй — два. Значит, у базового класса будут два дочерних класса с различными способами проверки хэндлов. В свою очередь, эти дочерние классы будет иметь свои дочерние классы, в которых будет определяться тренд.
Базовый класс:
protected:
int m_handle1;
int m_handle2;
string m_name;
string m_help;
int m_ci;
double m_b1[1];
double m_b2[1];
double m_b3[1];
double m_b4[1];
int m_shift;
int m_shift1;
int m_shift2;
int m_shift3;
int m_dot2shift;
double m_level;
public:
void CUniTrend(){
m_handle1=INVALID_HANDLE;
m_handle2=INVALID_HANDLE;
}
void ~CUniTrend(){
if(m_handle1!=INVALID_HANDLE){
IndicatorRelease(m_handle1);
}
if(m_handle2!=INVALID_HANDLE){
IndicatorRelease(m_handle2);
}
}
virtual int Calculate( const int rates_total,
const int prev_calculated,
double & upBuffer[],
double & dnBuffer[]
){
return(rates_total);
}
virtual bool Calculated(){
return(false);
}
virtual bool CheckHandles(){
return(true);
}
string Name(){
return(m_name);
}
string Help(){
return(m_help);
}
};
В секции protected объявлены различные вспомогательные переменные, которые пригодятся в дочерних классах. В конструкторе инициализируются переменные для хэндлов индикаторов, в деструкторе производится освобождение хэндлов. Остальные методы виртуальны.
Дочерний класс для варианта с одним индикатором:
public:
bool Calculated(){
if(BarsCalculated(m_handle1)>0){
return(true);
}
else{
return(false);
}
}
bool CheckHandles(){
return(m_handle1!=INVALID_HANDLE);
}
};
В классе два реальных метода: CheckHandle() — чтобы проверить, удалось ли загрузить индикатор, и Calculated() — что бы узнать, просчитан ли индикатор полностью и можно ли обновлять содержимое буферов, отображающих тренд.
Дочерний класс для варианта с двумя индикаторами:
public:
bool Calculated(){
if(BarsCalculated(m_handle1)>0 && BarsCalculated(m_handle2)>0){
return(true);
}
else{
return(false);
}
}
bool CheckHandles(){
return(m_handle1!=INVALID_HANDLE && m_handle2!=INVALID_HANDLE);
}
};
Все классы с различными вариантами определения тренда будут являться дочерними по отношению к классу CUniTrend1 или CUniTrend2. Рассмотрим один дочерний класс:
private:
public:
void CUniTrend_ADX_PDIMDI( bool use_default,
bool keep_previous,
SExtParams & par){
// установка параметров по умолчанию
if(use_default){
if(keep_previous){
if(par.f_period1==PARAMETER_EMPTY)par.f_period1=14;
}
else{
par.f_period1=14;
}
}
// загрузка индикатора
m_handle1=iADX(Symbol(),Period(),par.f_period1);
// формирование имени индикатора и строки с подсказкой по параметрам
m_name=StringFormat( "iADX_PDIMDI(%i)",
par.f_period1
);
m_help=StringFormat( "adx_period - f_period1(%i)",
par.f_period1
);
}
int Calculate( const int rates_total,
const int prev_calculated,
double & upBuffer[],
double & dnBuffer[]
){
int start;
if(prev_calculated==0){
start=1;
}
else{
start=prev_calculated-1;
}
for(int i=start;i<rates_total;i++){
upBuffer[i]=EMPTY_VALUE;
dnBuffer[i]=EMPTY_VALUE;
m_ci=rates_total-i-1;
if(CopyBuffer(m_handle1,PLUSDI_LINE,m_ci,1,m_b1)==-1){
return(0);
}
if(CopyBuffer(m_handle1,MINUSDI_LINE,m_ci,1,m_b2)==-1){
return(0);
}
if(m_b1[0]>m_b2[0]){
upBuffer[i]=1;
}
else if(m_b1[0]<m_b2[0]){
dnBuffer[i]=-1;
}
}
return(rates_total);
}
};
Основные важные места в конструкторе класса прокомментированы, а метод Calculate() является аналогом стандартной функции OnCalculate() индикатора, создание кода для этой функции аналогично созданию кода индикатора.
В приложении к статье все классы индикаторов располагаются в файле Include/UniTrend/UniTrendIndicators.mqh.
Теперь, имея вся классы, можно создать простой индикатор для определения тренда, так же, как мы делали в статьях про универсальный осциллятор и универсальный канал. Готовый индикатор без графического интерфейса можно найти в приложении в файле Indicators/iUniTrend.mq5.
Создание графического интерфейса
Все классы графического интерфейса располагаются в файлах UniTrendForm.mqh и UniTrendControl.mqh. В файле UniTrendForm.mqh располагается класс формы, а в файле UniTrendControl.mqh — классы универсального элемента управления для ввода параметров индикаторов. Рассматривать подробно создание класса формы нет смысла, это уже рассматривалось в статьях по созданию универсального осциллятора и универсального канала и подробно рассмотрено в статье "Пользовательские графические элементы управления. Часть 3. Формы". Рассмотрим создание универсального элемента управления.
Основу универсального элемента управления составляет базовый класс CUniTrendControl. В разделе public класса располагаются только виртуальные методы, в секции protected располагается несколько вспомогательных методов по работе с выпадающими списками: методы для заполнения списков вариантами и методы для установки спискам выбранных пунктов. Ниже приведен код базового класса с комментариями:
protected:
/* функция расчета минимального изменения значения по
количеству знаков после запятой для параметра уровня
*/
double SolveChange(int d){
return(NormalizeDouble(1.0/pow(10,d),d));
}
// заполнения списка вариантами ENUM_MA_METHOD
void AddVariantsMethod(CComBox & cb){
for(int i=0;i<ArraySize(e_method);i++){
cb.AddItem(EnumToString((ENUM_MA_METHOD)e_method[i]));
}
}
// заполнения списка вариантами ENUM_APPLIED_PRICE
void AddVariantsPrice(CComBox & cb){
for(int i=0;i<ArraySize(e_price);i++){
cb.AddItem(EnumToString((ENUM_APPLIED_PRICE)e_price[i]));
}
}
// заполнения списка вариантами ENUM_APPLIED_VOLUME
void AddVariantsVolume(CComBox & cb){
for(int i=0;i<ArraySize(e_volume);i++){
cb.AddItem(EnumToString((ENUM_APPLIED_VOLUME)e_volume[i]));
}
}
// заполнения списка вариантами ENUM_STO_PRICE
void AddVariantsStoPrice(CComBox & cb){
for(int i=0;i<ArraySize(e_sto_price);i++){
cb.AddItem(EnumToString((ENUM_STO_PRICE)e_sto_price[i]));
}
}
// получения индекса значения для ENUM_MA_METHOD
int MethodIndex(long val){
for(int i=ArraySize(e_method)-1;i>=0;i--){
if(e_method[i]==val){
return(i);
}
}
return(-1);
}
// получения индекса значения для ENUM_APPLIED_PRICE
int PriceIndex(long val){
for(int i=ArraySize(e_price)-1;i>=0;i--){
if(e_price[i]==val){
return(i);
}
}
return(-1);
}
// получения индекса значения для ENUM_APPLIED_VOLUME
int VolumeIndex(long val){
for(int i=ArraySize(e_volume)-1;i>=0;i--){
if(e_volume[i]==val){
return(i);
}
}
return(-1);
}
// получения индекса значения для ENUM_STO_PRICE
int StoPriceIndex(long val){
for(int i=ArraySize(e_sto_price)-1;i>=0;i--){
if(e_sto_price[i]==val){
return(i);
}
}
return(-1);
}
public:
// инициализации элементов управления
virtual void Init(SExtParams & par){}
// установка значений
virtual void SetValues(SExtParams & par){}
// получения значений
virtual void GetValues(SExtParams & par){}
// отображение элементов управления
virtual void Show(int x,int y){}
// скрытие элементов управления
virtual void Hide(){}
// количество элементов управления для расчета высоты формы
virtual int ControlsCount(){
return(0);
}
// отработка событий
virtual int Event(int id,long lparam,double dparam,string sparam){
return(0);
}
};
Рассмотрим один дочерний класс для варианта определения тренда по линии ADX и уровню (два элемента управления):
private:
// указатели на простые элементы управления
CSpinInputBox m_f_period1;
CSpinInputBox m_f_level;
public:
// инициализация элементов управления
void Init(SExtParams & par){
m_f_period1.Init("f_period1",SPIN_BOX_WIDTH,1," adx_period");
m_f_period1.SetMinValue(1);
m_f_period1.SetReadOnly(false);
m_f_level.Init("f_level",COMBO_BOX_WIDTH,this.SolveChange(par.level_digits)," level");
m_f_level.SetMinValue(0);
m_f_level.SetReadOnly(false);
}
// установка значений
void SetValues(SExtParams & par){
m_f_period1.SetValue(par.f_period1);
m_f_level.SetValue(par.f_level);
}
// получения значений
void GetValues(SExtParams & par){
par.f_period1=(int)m_f_period1.Value();
par.f_level=m_f_level.Value();
}
// отображение элементов управления
void Show(int x,int y){
m_f_period1.Show(x,y);
y+=20;
m_f_level.Show(x,y);
}
// скрытие элементов управления
void Hide(){
m_f_period1.Hide();
m_f_level.Hide();
}
// количество элементов управления для рсчета высоты формы
int ControlsCount(){
return(2);
}
// отработка событий элементов управления
int Event(int id,long lparam,double dparam,string sparam){
int e1=m_f_period1.Event(id,lparam,dparam,sparam);
int e2=m_f_level.Event(id,lparam,dparam,sparam);
if(e1!=0 || e2!=0){
return(1);
}
return(0);
}
};
В методы SetValues() и GetValues() передается переменная типа SExtParams, в каждом дочернем классе используются только необходимые ему поля структуры. Элементу управления для уровня необходимо устанавливать величину минимального изменения, это делается при инициализации элемента управления, поэтому в метод Init() тоже передается структура с параметрами. В общем и целом, создание дочерних классов соответствует всем принципам создания элементов управления, описанным в статье "Пользовательские графические элементы управления. Часть 1. Создание простого элемента управления", разве что здесь создаются не все методы, а только необходимые.
Добавление графического интерфейса к индикатору
Этот этап создания индикатора во многом подобен соответствующему этапу при создании универсального трендового индикатора и при создании универсального канала. Рассмотрим только отличия.
Ранее, при работе индикатора в режиме использования значений по умолчанию (UseDefault=true), все параметры инициализироваоись значениями -1. Теперь такой вариант не подходит, потому что параметр уровня для некоторых индикаторов может быть отрицательным. Поэтому инициализация переменных выполняется значением константы PARAMETER_EMPTY, объявленной в файле UniTrendDefines.mqh. Константа имеет значение INT_MAX (значение, сильно выходящее за пределы реальных значений уровней).
Еще одно небольшое отличие в функции OnTimer() — для проверки, посчитан ли индикатор, вызывается метод Calculated(), потому что для некоторых вариантов тренда надо проверить один индикатор, а для некоторых — два. Это может быть известно только внутри класса индикатора.
В результате получаем еще один универсальный и очень удобный индикатор (рис. 10).
Рис. 10. Универсальный трендовый индикатор с графическим интерфейсом
Обратите внимание: кроме отображения имени выбранного варианта в списке на форме, тип используемого индикатора отображается и в подокне индикатора в левом верхнем углу. Отображается не только тип, но и значения всех параметров (в скобках). Если значение уровня задается в пунктах, то записывается выражение расчета фактического значения уровня (рис. 11).
Рис. 11. Отображение параметра, задаваемого в пунктах
Готовый индикатор можно найти в приложении, имя файла — Indicators/iUniTrendGUI.mq5.
Заключение
Всего в индикатор вошло 46 различных вариантов определения тренда. Графический интерфейс, позволяющий быстро менять параметры индикаторов и их типы, позволяет удобно исследовать историю. Наличие функции уведомления делает индикатор полезным и для реального практического применения.
Новый подход в создании графического интерфейса имеет как свои преимущества, так и свои недостатки. Из недостатков можно отметить больший объем кода и, соответственно, больший объем работы. В отличие от классов, управляющих видимостью элементов управления (как у универсального осциллятора и универсального канала), здесь для каждого варианта определения тренда создавался практически полноценный элемент управления. Однако более четкая отделенность и независимость кода составного элемента управления от кода формы значительно упростило его разработку, а также упрощает дальнейшее расширение индикатора, если в этом будет необходимость.
Приложение
В приложении к статье находится архив со всеми необходимыми файлами. Все файлы разложены по папкам так, как они должны быть размещены в терминале.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Добрый день.
Расположил все папки и индикаторы по своим местам. Но в проводнике терминала отображается только индикатор iUniTrend. Индикатор iUniTrendGUI не отображается в проводнике, хотя находится в папке индикаторов. Соответственно на графике не отображается графический интерфейс, т.к. я не могу накинуть на него iUniTrendGUI. Поясните пожалуйста в чем причина и как это исправить.
Спасибо.
Откройте iUniTrendGUI в редакторе, попробуйте откомпилировать - узнаете, может быть какого файла не хватает или не туда скопировали, а может откомпилируется и заработает.
Откройте iUniTrendGUI в редакторе, попробуйте откомпилировать - узнаете, может быть какого файла не хватает или не туда скопировали, а может откомпилируется и заработает.
При компиляции 200 ошибок.
В файле iUniTrend не работает звуковой аллерт.
При компиляции 200 ошибок.
В файле iUniTrend не работает звуковой аллерт.
200 ошибок - какой-то файл забыли, скорее всего библиотеку графических элементов, наверно статью не читали. Это все-таки статья, а не маркет и не кодабаза.
С алертом - да, затупил. Надо сделать исправление в функции OnCalculate(). Строку:
Заменить следующей строкой:
int rv=Indicator.Calculate(rates_total,prev_calculated,up,dn);
Еще в самый конец добавить:
return(rv);
Библиотека. Ее положить в папку MQL5/Include папке данных терминала. Папка данных терминала открывается через Главное меню - Файл - Открыть каталог данных.
Индикатор с исправленным алертом