Разработка Pivot Mean Oscillator: новый осциллятор на кумулятивном скользящем среднем

Marco Calabrese | 11 ноября, 2019

Содержимое


Введение: зачем нужен еще один осциллятор?

Осцилляторы представляют собой подкласс индикаторов, значения которых колеблются в некотором диапазоне выше и ниже некой средней линии. Осцилляторы широко используются в техническом анализе, торговые сигналы по ним формируются, к примеру, при пересечении средней линии или определенного порогового значения. Популярные осцилляторы: MACD, RSI, CCI и др., каждый из них обладает особыми характеристиками, например, пытается анализировать скорость изменения цены (также известную как импульс) или определять основной тренд.

В целом осцилляторы, формула которых вычисляет расхождение цен между двумя моментами, показывают опережающее поведение цены (например, RSI, CCI), а осцилляторы, основанные на средних, показывают запаздывающие значения. В то же время MACD обладает как опережающими, так и запаздывающими характеристиками, поскольку он вычисляет разницу между двумя скользящими средними. Полученная разница отображается в виде гистограммы, на которой легко определить пересечения средней линии и расхождения.

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

В этой статье мы рассмотрим осциллятор Pivot Mean Oscillator, который стал результатом попытки внести новый функционал в широкую панораму осцилляторов. Функции эти связаны с использованием индикатора Cumulative Moving Average (CMA).


О кумулятивном скользящем среднем CMA

Скользящее среднее (MA), также простое скользящее среднее, рассчитывается как среднее последних n значений в таймсерии. При появлении нового значения, самое старой исключается из расчета по принципу FIFO (первым пришел — первым ушел). Уровни скользящего среднего на финансовом рынке могут служить поддержкой при падающем движении или сопротивлением на растущем рынке.

Скользящее среднее концептуально работает с буфером фиксированного размера, из которого удаляются значения (соответственно, фрагменты информации) старше последнего доступного элемента. Если разрешить такому буферу неограниченно увеличиваться, благодаря чему в расчете могут участвовать все данные до текущей базовой точки, получится кумулятивный индикатор CMA.

К счастью, на практике нам не нужно выделять бесконечную память для хранения каждого отдельного элемента данных. Фактически, среднее CMA можно рассчитать по нескольким переменным (в зависимости от того, используется ли рекурсивная формула, подробности см. на рисунке ниже). 

Таблица 1

Таблица 1: Две формулы расчета CMA.


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

Кумулятивное среднее CMA является основным ингредиентом осциллятора PMO, представленного ниже.


Определения PM и осциллятора PMO

PMO строится на основе индекса нормализации, который мы назовем Pivot Mean (PM). Значение его вычисляется как соотношение между последним значением и CMA.

Pivot Mean позволяет быстро получить численное понимание расстояния между ценой и CMA. Другими словами, PM можно рассматривать как некий спред. Например, значение PM 1.0035 означает, что текущее значение на 0.35% выше CMA. Если PM = 1, текущее значение совпадает с кумулятивным скользящим средним.

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

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

Таблица 2

Таблица 2: Формулы PM и PMO.


Хотя есть сходства, представленная здесь формула PMO отличается от MACD. Обычно индикатор MACD рассчитывается по ценам, в то время как в основе PMO лежат значения PM. Кроме того, MACD использует экспоненциальные скользящие, а здесь мы пока остановимся на простых MA, оставив более сложные варианты PMO для будущих разработок.


Разработка и код

Судя по формуле PMO, входных параметров немного: 

//--- входные параметры
input datetime startingTime;
input int      MA_close=3;
input int      MA_open=21;

Используются три буфера:

//--- индикаторные буферы
double   PMOBuffer[];
double   closeBuffer[];
double   openBuffer[];  

Что касается глобальных переменных, нам нужен счетчик и две переменные для хранения сумм цен открытия и закрытия, используемых для расчета PMO. Также мы добавили пару вспомогательных переменных, которые позволяют отслеживать первый индекс во всех буферах, начиная со времени начала расчетов.

//----глобальные переменные---
int counter=1;
double sum_close=0;
double sum_open=0;
bool first_val_checked;
int first_valid_index;

Для расчета двух скользящих средних в составе PMO нужна функция, реализующая скользящие средние. При этом следует избегать расчетов в самом начале буферов в непосредственной близости от времени начала. В этом случае будет недостаточно элементов для расчета средних. Однако из-за особенностей определения PM, можно установить значение, предшествующее началу расчета, равным единице, что позволяет рассчитывать скользящие средние без задержек. Поэтому вспомогательная функция выглядит следующим образом:

double simpleMA(const int pos, const int avg_positions, const double &data[],int arr_tail_pos){
   double _local_sum = 0;
   for(int i=pos+avg_positions-1; i >= pos;i--){
      if(i > arr_tail_pos){
         _local_sum += 1;  // если запрошенные данные превышают установленный лимит буфера, установить значение в 1
      }else{
         _local_sum += data[i];
      }
           
   }
   return _local_sum/avg_positions; 
}

Теперь посмотрим на код программы:

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//---
   ArraySetAsSeries(PMOBuffer,true);
   ArraySetAsSeries(closeBuffer,true);
   ArraySetAsSeries(openBuffer,true);
   ArraySetAsSeries(open,true);
   ArraySetAsSeries(high,true);
   ArraySetAsSeries(time,true);
   
   
   
//--- возвращаемое значение prev_calculated для следующего вызова
   int total = rates_total - prev_calculated;
   double _tmp_sum_close,_tmp_sum_open;
    if(total > 0){
     
      for(int i=total-1;i>=0;i--){  
         if(time[i] >= startingTime){
            if(first_val_checked == false){
               first_val_checked = true;
               first_valid_index = i;
            }
            
            sum_close += close[i];
            sum_open += open[i];
            
            closeBuffer[i] = close[i] *counter / sum_close;
            openBuffer[i] = open[i]*counter / sum_open;
            
            PMOBuffer[i] = simpleMA(i,MA_close,closeBuffer,first_valid_index)-simpleMA(i,MA_open,openBuffer,first_valid_index);
 
            counter++;         
         }   
         else{
            PMOBuffer[i] = 0;
         }    
         
       
      }
 
   }else{
      _tmp_sum_close = sum_close +close[0];
      _tmp_sum_open = sum_open + open[0];
      closeBuffer[0] = close[0] *counter / _tmp_sum_close;
     
      openBuffer[0] = open[0] *counter / _tmp_sum_open;
  
      PMOBuffer[0] = simpleMA(0,MA_close,closeBuffer,first_valid_index)-simpleMA(0,MA_open,openBuffer,first_valid_index);
   }
   return(rates_total);
  }
//+------------------------------------------------------------------+


Эксперименты на EURUSD

Ниже представлены результаты и комментарии работы PMO на графике EURUSD. Нас интересуют два основных момента:

  1. Аспекты торговли с использованием индикатора PMO
  2. Анализ значения PMO

Аспекты торговли

Как видно на рисунке ниже, осциллятор PMO очень сильно похож на RSI: сигналы этих индикаторов почти совпадают. Однако есть и различия. В непосредственной близости от сильного роста 12 сентября 2019 (которые связано с официальными релизами от европейского центробанка), внимательный читатель может заметить техническую фигуру Меррила "M" на индикаторе PMO, в которой левое плечо выше правого, что прямо противоположно происходящему с сигналом RSI и базовой ценой EURUSD. Это связано с тем ростом котировок 12 сентября, при этом кумулятивная средняя оказалась выше значения следующего дня. Такие показатели осциллятора можно использовать для открытия короткой позиции после второй вершины.

Благодаря сходству с RSI развороты вокруг пиков и впадин можно трактовать как условия перекупленности и перепроданности и, следовательно, как ранний сигнал, который можно использовать в торговой стратегии. Хотя PMO не имеет привязки как у RSI, прямое пересечение нулевой линии можно рассматривать как дальнейшее подтверждение тренда. Как говорилось во введении, одновременное использование нескольких сигналов может помочь получить хорошие результаты при торговле.


Рис 1

Рис. 1: Сходства между PMO(3,21) и RSI(14).


Теперь мы можем набросать очень простой и упрощенный набор правил для торговли по осциллятору PMO. Более сложные стратегии оставим для разработчиков дальнейших советников на основе PMO.

  • Положительный разворот ниже нулевой линии служит ранним сигналом на покупку
  • Отрицательный разворот выше нулевой линии служит ранним сигналом на продажу
  • При пересечении нулевой линии снизу вверх рекомендуется покупать
  • При пересечении нулевой линии сверху вниз рекомендуется продавать

Чувствительность и быстрое реагирование на изменения в рыночных условиях является ключевым фактором для успешной торговли. При этом, при работе со скользящими средними, чем более сглаженный сигнал, тем выше задержка. При использовании PMO( m,n), m влияет на задержку в осцилляторе, а n — на задержку при пересечении средней линии. Конечно, самая быстрая реакция была бы у PMO(1,1), который рассчитывает разницу между двумя значениями Pivot Mean без какого-либо усреднения. Неплохим компромиссом будет PMO(1, n), при этом значение n небольшое (например, 5), что гарантирует быстрое реагирование и пересечение нуля без сильного запаздывания.


Анализ значений PMO

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

На рисунке ниже показаны результаты, полученные при запуске PMO(3,21) на графике EURUSD с периодом H1, за первые 8 месяцев 2019 года. Получается колоколообразное распределение значений PMO вокруг нуля. Небольшой левый перекос, вероятно, связан с нисходящими движениями по EURUSD в последние месяцы. Тем не менее, преобладание симметрии около нуля позволяет сделать вывод, что существует общий баланс между нисходящими и восходящими движениями.


Рис 2

Рис. 2: Колоколообразное распределение значений PMO(3,21). Это позволит нам предположить квазигауссовскую статистическую модель, которая может быть полезна для прогнозирования дальнейших движений.


Еще один момент, который следует принимать во внимание, — это взаимосвязь между PMO и скользящими средними, рассчитанными непосредственно по ценам закрытия и открытия, а не по значениям PM. На рисунке ниже видна сильная корреляция с R-квадратом, близким к единице. Это означает, что при работе со значениями PM не происходит искажения исходных данных. Более того, у работы со значениями PM есть преимущество, по сравнению с использованием данных из разных источников (например, других валютных пар). Это нормализация через расчет PM.

Рис 3

Рис. 3: Корреляция между PMO(3,21) и ненормализованной версией. Почти линейная форма показывает, что используемая в PMO нормализация не вносит существенных искажений в исходные сигналы по ценам открытия и закрытия. 


Заключение и дальнейшая работа


В статье я представил осциллятор Pivot Mean Oscillator (PMO) и реализацию торгового индикатора для платформ MetaTrader Cumulative Moving Average (кумулятивное скользящее среднее, CMA) на основе концепции Pivot Mean. Полученный осциллятор оказался схож с другими популярными индикаторами осцилляторного типа, такими как RSI и MACD. Некоторые особенности расчетов связаны с использованием кумулятивного скользящего среднего. Многое еще предстоит сделать с точки зрения дальнейшей разработки. Например, можно рассмотреть варианты, основанные на других типах средних значений. Также можно поработать над советниками, использующими данные, получаемые из статистического распределения значений PMO вокруг нулевой центральной линии.

Я призываю читателей дальше развивать эту тему и поэкспериментировать с использованием приложенных файлов.


Список файлов приложения

Файл описание
 PMO.mq4  Исходный MQL4-код осциллятора PMO, используемый в этой статье.
 PMO_logger.mq4  Исходный MQL4-код осциллятора PMO с функцией логирования для анализа данных. В нем реализованы два дополнительных входных параметра: data_logging (флаг логирования данных, true/false) и filename (string).
 PMO.mq5  Исходный MQL5-код осциллятора PMO.
 PMO_logger.mq5  Исходный MQL5-код осциллятора PMO с функцией логирования для анализа данных. В нем реализованы два дополнительных входных параметра: data_logging (флаг логирования данных, true/false) и filename (string).