English 中文 Español Deutsch 日本語 Português
Индикатор CCI. Три шага трансформации

Индикатор CCI. Три шага трансформации

MetaTrader 5Индикаторы | 28 июля 2022, 11:56
2 000 2
Aleksej Poljakov
Aleksej Poljakov

В предыдущей статье мы рассмотрели возможные изменения в классическом индикаторе Commodity Channel Index. Эти изменения касались способов расчета, но не затрагивали сути этого индикатора. В этой статье мы рассмотрим преобразования этого индикатора с несколько иной точки зрения. Мы попробуем внести изменения в логику его расчетов. И посмотрим как эти изменения отразятся на показаниях индикатора. И, конечно же, постараемся проверить обоснованность сделанных изменений.


Шаг первый

Напомню, что индикатор CCI основывается на простых и интуитивно понятных расчетах. Сначала рассчитывается разность между текущей ценой и средним значением. После чего эта разность делится на стандартное отклонение. То есть, мы сравниваем во сколько раз больше (или меньше) разность между ценой и выборочной средней по сравнению с выборочным стандартным отклонением.

Всё просто и понятно. Но здесь скрывается и один недостаток, который может привести к неверным решениям. Возьмем для примера две последовательности: 2, 1, 1 и 21, 11, 1. Если перевести эти последовательности на язык трейдинга, то первая — это флет, а вторая — явный и сильный тренд.

Давайте спросим себя: какая из этих двух последовательностей даст значение CCI больше? Попытайтесь дать ответ, опираясь на свою интуицию. Попробуйте и обосновать свой ответ. А я пока произведу необходимые расчеты.

Первая последовательность

Вторая последовательность

Как мы видим, обе последовательности дали одинаковый итог. Основная причина такого результата заключается в том, что мы используем деление на стандартное отклонение. Для первой последовательности разность между текущим значением и средней небольшая. Но также мало и стандартное отклонение. Для второй последовательности разность увеличилась, но также возросло и стандартное отклонение. Именно по этой причине две непохожие последовательности привели к одинаковому результату.

Если мы спросим любого трейдера о его требованиях к техническому индикатору, то он сам (или придется подвести его к этому ответу) скажет: уникальная ситуация должна вести к уникальному значению индикатора. Можно ли выполнить такое пожелание, если речь идет о CCI? Ответ – да, можно. Только для этого нам нужно отказаться от деления и заменить его умножением. Тогда формула индикатора будет выглядеть так:

При таком изменении индикатор должен хорошо выделять трендовые движения цены, когда и разность, и стандартное отклонение будут большими. Но такой подход имеет свои особенности. Мы не можем (даже приблизительно) оценить диапазон значений индикатора и его уровни. Этот недостаток мы можем преодолеть достаточно просто. Пусть сам индикатор считает какие значения он принимает и как часто. Собрав такие данные, мы сможем задать уровень индикатора. Показания индикатора, ненамного отклоняющиеся от нуля, будут встречаться чаще. Большие значения будут встречаться реже. Разграничивая значения индикатора по частоте их появления, мы и сможем задать уровни индикатора. Примем во внимание, что статистики для положительных и отрицательных значений индикатора могут различаться друг от друга. Поэтому будем собирать данные для положительного и отрицательного уровня раздельно.

Само значение уровней удобнее всего задавать в процентах. Например, если уровень будет равен 70, то именно такая доля значений индикатора будет лежать между уровнем и нулевой линией. И только 30% значений будут выходить за пределы уровней вверх или вниз.

Для расчета уровней мы поступим следующим образом. Создадим два массива в которых мы будем сохранять значения индикатора (положительные и отрицательные значения отдельно друг от друга).

int array_dn[],         //массив для хранения положительных значений
    array_up[],         //массив для хранения отрицательных значений
    size_dn=0,size_up=0;//размеры массивов

Установим размеры этих массивов.

ArrayResize(array_up,size_up,rates_total);
ArrayResize(array_dn,size_dn,rates_total);

По мере поступления исторических данных записываем полученные результаты. Обратите внимание, что в массив для отрицательных значений мы записываем все-таки положительные числа. Это делается для удобства последующей обработки.

if(cci>0)
  {
   ArrayResize(array_up,size_up+1);
   array_up[size_up]=(int)MathRound(cci/_Point);
   size_up++;
  }
if(cci<0)
  {
   ArrayResize(array_dn,size_dn+1);
   array_dn[size_dn]=(int)MathRound(-cci/_Point);
   size_dn++;
  }

Перед открытием нулевого бара сначала нужно отсортировать эти массивы. После чего найдем индексы элементов массивов. В этих ячейках и будут значения уровней. Для отрицательного уровня не забудем вернуть знак минус.

ArraySort(array_up);
IndicatorSetDouble(INDICATOR_LEVELVALUE,0,array_up[size_up*level/100]*_Point);
ArraySort(array_dn);
IndicatorSetDouble(INDICATOR_LEVELVALUE,1,-array_dn[size_dn*level/100]*_Point);

 

Ну, а теперь посмотрим на наш новый индикатор.


Как мы видим, все варианты расчетов дали похожую картинку. Основное отличие — численные значения уровней. Интересно, что уровни для положительных и отрицательных значений всех вариантов отличаются друг от друга. Это значит, что с точки зрения нашего индикатора движения цены вверх и вниз несимметричны и наше предположение об отдельном сборе статистики оказалось обоснованным.

Однако интереснее сравнить наш новый индикатор с классическим CCI. Тут мы можем встретить участки, на которых индикаторы выглядят довольно похоже.

 

Так и такие участки графика, где поведение индикаторов отличается друг от друга. Особенно сильно это различие становится заметным, если мы обратим внимание на места пересечений линии индикатора и его уровней.


Теперь давайте проверим наш новый индикатор в деле. Для этого напишем торговый советник, который будет торговать по его сигналам. Так как уровни индикатора могут меняться, то правила открытия позиций мы установим такими. Открытие позиции Buy будет происходить, если текущее значение индикатора находится ниже отрицательного уровня, а предыдущее значение индикатора — ниже текущего. Открытие позиции Sell будет происходить, если текущее значение индикатора находится выше положительного уровня, а предыдущее значение — выше текущего. Открытие позиции одного типа ведет к закрытию всех противоположных позиций.

Параметры тестирования: символ EURUSD, таймфрейм H1, интервал тестирования 2021.01.01 - 2021.12.31.

Основные результаты каждого теста приведены в таблице

TypeInd
Total Net Profit
Gross Profit
Gross Loss
Total Trades
Classical 248.21
1 361.74
-1 113.53
823
Square -304.83
2 993.08
-3 297.91
3581
Modern -567.15
2 540.88
-3 108.03
3251

Интересно, что классический способ расчета стандартного отклонения сразу дал положительный результат. А в двух последних вариантах значительно возросло количество трейдов. Это обстоятельство может указывать на необходимость увеличения уровней срабатывания индикатора. Тогда снизится количество трейдов, и, возможно, повысится их эффективность. Пример кривой баланса для классического варианта представлен на рисунке.


Шаг второй

До сих пор для расчета индикатора мы использовали стандартное отклонение. Применение стандартного отклонения для нормализации значений оправданно только, если распределение величин происходит по нормальному закону. В случае с индикатором CCI исходными данными являются разности между ценой и средней. Давайте посмотрим, как они распределяются в действительности.

Для того, чтобы подчеркнуть особенности получившегося результата, я уменьшил объем выборки и удалил нулевые значения из нее. Как мы видим, график получился довольно своеобразным, и на график нормального распределения не похож даже приблизительно.

Если разности распределены по какому-то своему эмпирическому закону, то мы можем позволить себе отказаться от использования стандартного отклонения. Тогда наш индикатор превратится в половинку CCI.

Давайте подумаем, к чему может привести такой шаг. Очевидно, что без сглаживания разброс значений индикатора будет довольно большим и он будет выглядеть несколько непривычно. Кроме того, большие движения цены могут повлиять на визуальное восприятие индикатора. Но эти недостатки не могут перевесить один большой соблазн.

При расчете значений индикатора CCI используется простая средняя. Формула, которая всем известна, но я её напомню:

Но что скрывается за этой формулой? Это может быть среднее арифметическое, математическое ожидание случайной величины, и прямоугольное окно. Давайте остановимся на последнем варианте. Почему именно прямоугольное окно? Есть же еще оконные функции, которые можно применить?

Мне известно около пятидесяти оконных функций с собственными названиями. Количество оконных функций без собственных имен гораздо больше.

Для эксперимента мы возьмем прямоугольное окно, треугольное и окно с плоской вершиной. Последняя оконная функция довольно необычна тем, что некоторые ее весовые коэффициенты принимают отрицательные значения. Также возьмем три несимметричных окна — с линейными весами, степенными и экспоненциальными. Средние с линейными и экспоненциальными весами доступны в торговой платформе MetaTrader в общем меню Moving Average.
Общий вид всех вариантов показан на рисунке (самый нижний индикатор — классический CCI).

Все варианты довольно похожи, но уровни у них могут отличаться довольно сильно. Это зависит от используемой оконной функции — некоторые из них запаздывают, и относительно большие значения индикатора могут встречаться чаще. Другие оконные функции следуют за ценой, и тогда чаще встречаются небольшие отклонения.

Ну и на всякий случай, добавим в индикатор два варианта сглаживания. Они не изменят сути расчетов, но могут сделать индикатор визуально привлекательнее.

 

Для проверки этого индикатора hCCI напишем еще одного торгового эксперта. Сигналы для открытия и закрытия позиций будут точно такими же, как и для предыдущего робота. Параметры тестирования и его интервал также совпадают с предыдущим случаем.

Основные результаты тестирования приведены в таблице.

Window
Total Net Profit
Gross Profit
Gross Loss
Total Trades
Rectangular
224.57
1 745.03
-1 520.46
726
Triangular
94.17
1 532.10
-1 437.93
696
FlatTop
236.54
1 354.67
-1 118.13
643
LWMA
243.62
1 444.48
-1 200.86
639
Power
44.57
1 175.79
-1 131.22
561
Exponential
-317.41
725.11
-1 042.52
359

    Из всех оконных функций только экспоненциальное окно дало отрицательный результат. Это не значит, что оно не годится для трейдинга. Это значит, что его параметры нуждаются в более точной настройке. Также нуждаются в доработке и правила закрытия позиций. (Впрочем, это касается всех вариантов данного эксперта). На рисунке приведена кривая баланса советника с оконной функцией LWMA.



    Шаг третий

    До сих пор мы рассматривали индикатор CCI в виде осциллятора. Но было бы интересно переместить его на основной график и посмотреть, как он будет отображаться на нем. Давайте рассмотрим, как мы можем этого добиться.

    В основе большинства осцилляторов лежит простой принцип — подавление основного сигнала для выделения малозаметных движений цены. Таким образом, для переноса индикатора на основной график нам нужно добавить к его значению опорный сигнал. В случае CCI в качестве сигнала могут использоваться текущая цена или средняя. Тогда формулы расчета значения индикатора будут такими:

     

    Оба варианта неустойчивы. Их значения могут сильно отклоняться от линии цены. Но этот недостаток компенсируется тем, что оба индикатора могут хорошо выделять трендовые движения цены.


     


    Заключение

    Представленные индикаторы развивают принципы, заложенные в классический индикатор CCI. Несомненным достоинством новых индикаторов является возможность их настройки по выбору трейдера.

    Параметры индикаторов:

    Индикатор pCCI

     

    • TypeInd – задает способ расчета значений индикатора;
    • iPeriod – период индикатора, минимальное значение 2;
    • iLevel – значение уровней индикатора, допустимое значение 1 – 99.

       Индикатор hCCI

    • Window – тип используемой оконной функции;
    • Smoothing – используемое сглаживание;
    • iPeriod – период индикатора, минимальное значение 2;
    • iLevel – значение уровней индикатора, допустимое значение 1 – 99.

      Индикатор lCCI

    • Window – тип используемой оконной функции;
    • Direct – тип опорного сигнала;
    • iPeriod – период индикатора, минимальное значение 2.

      Скрипт Difference Distribution

    • Length – период скользящей средней;
    • Level – максимальное значение выборки;
    • ViewDuration – продолжительность отображения;
    • ScreenShot – если параметр включен, то график сохраняется в папке Files.

    Торговый эксперт EA pCCI

    Все его параметры совпадают с параметрами индикатора pCCI.  Сигналы на открытие и закрытие позиций происходят при открытии нового бара.

      Торговый эксперт EA hCCI

      Его главные настройки соответствуют настройкам индикатора hCCI. 

      Прикрепленные файлы |
      pCCI.mq5 (5.11 KB)
      hCCI.mq5 (4.68 KB)
      lCCI.mq5 (6.77 KB)
      EA_pCCI.mq5 (8.8 KB)
      EA_hCCI.mq5 (8.6 KB)
      pCCI.mq4 (6.51 KB)
      hCCI.mq4 (5.69 KB)
      lCCI.mq4 (4.39 KB)
      EA_pCCI.mq4 (7.64 KB)
      EA_hCCI.mq4 (7.44 KB)
      Последние комментарии | Перейти к обсуждению на форуме трейдеров (2)
      Verner999
      Verner999 | 11 сент. 2022 в 22:48

      Большое спасибо за интересное исследование!

      Меня беспокоит один момент. Возможно, я неправильно интерпретировал код индикаторов (я, к сожалению, не очень силён в программировании), но, насколько я понял, автоматический расчёт уровней индикаторов осуществляется на основании всей истории. То есть, если я смотрю прошлое поведение индикатора, то я буду видеть уровни, рассчитанные на основе всех данных, включая те, которых на тот момент ещё не существовало. Это так, или я, всё-таки, неправильно интерпретировал код?

      Aleksej Poljakov
      Aleksej Poljakov | 12 сент. 2022 в 05:49
      Verner999 #:

      Большое спасибо за интересное исследование!

      Меня беспокоит один момент. Возможно, я неправильно интерпретировал код индикаторов (я, к сожалению, не очень силён в программировании), но, насколько я понял, автоматический расчёт уровней индикаторов осуществляется на основании всей истории. То есть, если я смотрю прошлое поведение индикатора, то я буду видеть уровни, рассчитанные на основе всех данных, включая те, которых на тот момент ещё не существовало. Это так, или я, всё-таки, неправильно интерпретировал код?

      Всё верно, уровни рассчитываются на всей истории. Но их значения будут действительны и для прошлого. Когда статистика по уровням только начинает собираться, значения уровней еще могут меняться. Но после первой тысячи баров они встанут на месте. Проще всего - запустить тестирование в МТ4 (там небольшая предыстория). В начале уровни будут плавать, а потом - встанут намертво.

      DoEasy. Элементы управления (Часть 13): Оптимизация взаимодействия WinForms-объектов с мышкой, начало разработки WinForms-объекта TabControl DoEasy. Элементы управления (Часть 13): Оптимизация взаимодействия WinForms-объектов с мышкой, начало разработки WinForms-объекта TabControl
      В статье исправим и оптимизируем обработку внешнего вида WinForms-объектов после увода курсора мышки с объекта и начнём разработку WinForms-объекта TabControl.
      Нейросети — это просто (Часть 22): Обучение без учителя рекуррентных моделей Нейросети — это просто (Часть 22): Обучение без учителя рекуррентных моделей
      Мы продолжаем рассмотрение алгоритмов обучения без учителя. И сейчас я предлагаю обсудить особенности использования автоэнкодеров для обучения рекуррентных моделей.
      Разработка торговой системы на основе индикатора MFI Разработка торговой системы на основе индикатора MFI
      Это новая статья из серии, в которой мы учимся создавать торговые системы на основе популярных технических индикаторов. На этот раз она посвящена Индексу денежного потока MFI. Мы подробно изучим этот индикатор и разработаем простые торговые системы на MQL5 для исполнения в MetaTrader 5.
      Разработка торгового советника с нуля (Часть 21): Новая система ордеров (IV) Разработка торгового советника с нуля (Часть 21): Новая система ордеров (IV)
      Наконец-то визуальная система заработает... хотя пока не до конца. Здесь мы закончим вносить основные изменения, которых будет не мало, но они все необходимы, и вся работа будет достаточно интересной.