Новый индикатор технического анализа Moving Mini-Max и его реализация в MQL5
Введение
Применение методов теоретической физики и современной математики к анализу ценовых рядов (Quantitative Finance) позволяет изучать модели ценообразования и динамику финансовых рынков.
Не так давно я наткнулся на статью, в которой описывался новый индикатор технического анализа, в основе которого лежат идеи из квантовой физики, примененные к финансам. Я заинтересовался им и решил рассказать о том, как реализовывать в MQL5 индикаторы, описанные в научных работах.
Оригинальная работа "Moving Mini-Max – a new indicator for technical analysis" [2] написана физиком З.К. Силагадзе, который работает в Институте Ядерной Физики им. Г.И. Будкера Сибирского Отделения РАН и Новосибирском Государственном Университете. Ссылки на эту статью и исходные коды на MQL5 вы найдете в конце статьи.
Индикатор
Никогда не думал, что буду писать эти строки, но здесь я займусь объяснением идеи туннельного эффекта. Полагаю, большинство читателей далеки от квантовой физики, я постараюсь вести изложение просто, надеюсь это не будет для вас сложным. Сначала определим кратко идею технического анализа финансовых временных рядов.
В основном нам нужно найти:
- ценовые уровни поддержки и сопротивления
- направление долгосрочного и краткосрочного трендов
- вершины и впадины трендов
Оригинальная идея индикатора "Moving Mini-Max" заключается в нахождении вершин и впадин графика, используя квантовую аналогию для альфа-частицы, пытающейся покинуть ядро. Это задача теории альфа-распада, разработанной Г. Гамовым [1].
Порой картинка стоит тысячи слов, поэтому лучше приведу ниже небольшой график.
Рисунок 1. Воображаемый квантовый мяч на графике валютной пары
Представьте себе мяч, брошенный с вершины холма (в нашем случае это максимум графика временного ряда). По классической механике он будет отражаться от препятствий и у него не будет возможности выбраться из локальной ямы, в которую он попадет. Но по квантовой механике в теории альфа-распада такой мяч может будет иметь очень маленькую, но ненулевую вероятность туннелирования (просачивания) сквозь барьеры к потенциальной яме и колебаться там.
Эта задача аналогична задаче о нахождении локального минимума на ценовом графике. В работе З.К. Силагадзе [2] предполагается, что для упрощения расчетов вместо решения реальной квантовомеханической задачи достаточно имитировать квантовое поведение. Здесь мы рассмотрим математические основы подхода, представленного в оригинальной статье [2] и затем приведем реализацию решения данной задачи на MQL5.
Пусть - временной ряд цен за некоторый период времени. Moving Mini-Max - это нелинейное преобразование временного ряда вида:
где и для определяются следующим образом:
Как видно, это рекуррентное соотношение, и каждый i-й элемент зависит от элемента i-1. Полученный преобразованием Moving Mini-Max удовлетворяет условию нормировки, сумма всех элементов равна единице:
Вероятности туннелирования квантового мяча называются вероятностями перехода, поскольку они имитируют вероятности перехода сквозь узкие барьеры ценового ряда, представляющие собой маленькие препятствия снизу.
где
Параметр m - это ширина окна сглаживания, этот параметр имеет смысл величины, обратной массе мяча, он позволяет управлять его "проникающей способностью". Можно убедиться в том, что при увеличении m график mini-max станет более гладким.
В дополнение к u(si) введем d(si), соответствующий локальным минимумам, отличие для штрихованных Q заключается в знаке минус выражения в аргументе функции exp():
Реализация
Ознакомившись с математическими основами, мы можем реализовать все это в MQL5. Лучше начать с последнего выражения. Если обратить внимание на переменные m и n, мы увидим что для построения индикатора требуется массив из n+2m элементов ценового ряда для одного mini-max окна длиной m баров. Переменная i пробегает значения от 1 до n , а k пробегает значения от 1 to m, поэтому для начала нам потребуется буфер размером n+2m.
Ценовые данные можно получить так:
double S[]; ArrayResize(S,n+2*m); CopyClose(Symbol(),0,0,n+2*m,S);
Здесь мы объявили массив чисел типа double, установили его размер n+2m и скопировали цены закрытия последних n+2m баров текущего символа, начиная с последнего бара графика.
Следующим шагом является вычисления значений Q. Согласно определению, для вычисления i-го элемента анализируемого ценового ряда нам требуется вычисление суммы m экспонент с аргументами ценового ряда.
Поэтому для расчета всех значений Q нам требуется реализовать цикл от 1 до n:
void calcQii() { int i,k; for(i=0; i<n; i++) { double sqiip1=0; double sqiim1=0; double dqiip1=0; double dqiim1=0; for(k=0; k<m; k++) { sqiip1 += MathExp(2*(S[m-1+i+k]-S[i])/(S[m-1+i+k]+S[i])); sqiim1 += MathExp(2*(S[m-1+i-k]-S[i])/(S[m-1+i-k]+S[i])); dqiip1 += MathExp(-2*(S[m-1+i+k]-S[i])/(S[m-1+i+k]+S[i])); dqiim1 += MathExp(-2*(S[m-1+i-k]-S[i])/(S[m-1+i-k]+S[i])); } sQiip1[i] = sqiip1; sQiim1[i] = sqiim1; dQiip1[i] = dqiip1; dQiim1[i] = dqiim1; } }
Как видите, функция calcQii вычисляет значения i элементов Q и Q` рассматриваемого ценового окна размером n. Массив S хранит значения цен, а sQiip1, sQiim1, dQiip1, dQiim1 используются при промежуточных расчетах величин Q и Q`.
Вероятности вычисляются при помощи переменных Q и Q`, поэтому мы можем сделать другую функцию с циклом от 1 до n при помощи массивов sQii и dQii:
void calcPii() { int i; for(i=0; i<n; i++) { sPiip1[i] = sQiip1[i] / (sQiip1[i] + sQiim1[i]); sPiim1[i] = sQiim1[i] / (sQiip1[i] + sQiim1[i]); dPiip1[i] = dQiip1[i] / (dQiip1[i] + dQiim1[i]); dPiim1[i] = dQiim1[i] / (dQiip1[i] + dQiim1[i]); } }
Осталось вычислить элементы uSi, а затем dSi и поместить результаты в массивы uSi and dSi:
void calcui() { int i; sui[0] = 1; dui[0] = 1; for(i=1; i<n; i++) { sui[i] = (sPiim1[i]/sPiip1[i])*sui[i-1]; dui[i] = (dPiim1[i]/dPiip1[i])*dui[i-1]; } double uSum = 0; double dSum = 0; ArrayInitialize(uSi, 0.0); ArrayInitialize(dSi, 0.0); for(i=0; i<n; i++) { uSum+=sui[i]; dSum+=dui[i]; } for(i=0; i<n; i++) { uSi[n-1-i] = sui[i] / uSum; dSi[n-1-i] = dui[i] / dSum; } }
Для проверки выполнения условия нормировки, добавим следующие строки:
double result=0; for(i=0; i<n; i++) { /* Print("i = "+i+" uSi = "+uSi[i]); */ result+=uSi[i]; } Print("Result = "+ DoubleToString(result));
После того, как с расчетами разобрались, нам требуется реализовать отображение результатов в окне индикатора. Для этого мы должны объявить как минимум два индикаторных буфера: один для uSi, второй для dSi и задать тип отображения индикатора как DRAW_LINE.
#property indicator_separate_window #property indicator_buffers 2 #property indicator_plots 2 #property indicator_type1 DRAW_LINE #property indicator_type2 DRAW_LINE #property indicator_color1 SeaGreen #property indicator_color2 BlueViolet
Затем при помощи функции SetIndexBuffer() мы связываем массивы uSi и dSi с отображаемыми индикаторными буферами (INDICATOR_DATA):
SetIndexBuffer(0,uSi,INDICATOR_DATA); SetIndexBuffer(1,dSi,INDICATOR_DATA); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); PlotIndexSetInteger(0,PLOT_SHIFT,-(m-1)); PlotIndexSetInteger(1,PLOT_SHIFT,-(m-1));
Рисунок 2. Индикатор Moving Mini-Max
Возможными приложениями индикатора, описанного в статье, является выявление уровней поддержки и сопротивления и распознавания индикаторных паттернов. Что касается линий поддержки и сопротивления, они формируются при пересечении индикаторов mini-max и их скользящих средних.
Если цена идет через локальный максимум и пересекает скользящую среднюю, мы имеем уровень сопротивления. После реализации данного подхода я заметил, что этот метод дает ряд ложных сигналов, тем не менее, приведу здесь этот код, который демонстрирует размещение этих линий на MQL5 при помощи библиотеки ChartObjectsLines.mqh:
void SR() { // отображаем линию сопротивления если произошло пересечение локальных максимумов (анализ uSi) со скользящей средней int i, cnt=0; int rCnt=CopyClose(Symbol(),0,0,n+2*m,S); for (i=n-2; i>=0; i--) if (uSi[i]<uSi_MA[i] && uSi[i+1]>=uSi_MA[i+1]) { Print("Resistance at " + i); CChartObjectHLine *line=new CChartObjectHLine(); line.Create(0, "MiniMaxResistanceLine:"+IntegerToString(cnt), 0, S[i]); line.Color(LightSkyBlue); line.Width(1); line.Background(true); line.Selectable(false); cnt++; } // отображаем линию поддержки если произошло пересечение локальных минимумов (анализ dSi) и пересекла скользящую среднюю for (i=n-2; i>=0; i--) if (dSi[i]<dSi_MA[i] && dSi[i+1]>=dSi_MA[i+1]) { Print("Support at " + i); CChartObjectHLine *line=new CChartObjectHLine(); line.Create(0, "MiniMaxSupportLine:"+IntegerToString(cnt), 0, S[i]); line.Color(Tomato); line.Width(1); line.Background(true); line.Selectable(false); cnt++; } }
Я заметил интересный факт: он вполне хорошо распознает локальные минимумы и максимумы краткосрочных трендов на заданном временном окне. Этого достаточно для вычисления раздвижки между минимальными и максимальными значениями и использования их для маркировки начала краткосрочного бычьего и медвежьего тренда.
Мы можем использовать этот момент наряду с другими индикаторами и системой управления капиталом для создания прибыльного советника. Для маркировки раздвижек в текущем временном окне мы можем использовать индикаторные буферы для отображения их стрелками каждый раз, когда разность между ними является наибольшей.
Для придания большей наглядности я решил использовать новую возможность MQL5 - построение разноцветных гистограмм. Восходящий и нисходящий тренд окрашиваются в различные цвета, а сигнал об изменении тренда отображается желтым цветом.
Для использования разноцветной гистограммы нам потребуется использование 2 буферов данных и один буфер для индексов цвета. Рассмотрим реализацию отображения. Всего у нас 5 буферов, три из них задаются для разноцветной гистограммы.
//+------------------------------------------------------------------+ //| MovingMiniMax.mq5 | //| Copyright 2011, Investeo.pl | //| http://Investeo.pl | //+------------------------------------------------------------------+ #property copyright "Copyright 2011, Investeo.pl" #property link "http://Investeo.pl" #property description "Moving Mini-Max indicator" #property description "proposed by Z.K. Silagadze" #property description "from Budker Institute of Nuclear Physics" #property description "and Novosibirsk State University" #property description "Original paper can be downloaded from:" #property description "http://arxiv.org/abs/0802.0984" #property version "0.6" #property indicator_separate_window #property indicator_buffers 5 #property indicator_plots 3 #property indicator_type1 DRAW_COLOR_HISTOGRAM2 #property indicator_type2 DRAW_ARROW #property indicator_type3 DRAW_ARROW #property indicator_color1 Chartreuse, OrangeRed, Yellow #property indicator_color2 RoyalBlue #property indicator_color3 RoyalBlue #property indicator_width1 5 #property indicator_width2 4 #property indicator_width3 4
Обратите внимание на то, что для построения гистограммы используются два буфера данных (INDICATOR_DATA) и один буфер цветовых индексов (INDICATOR_COLOR_INDEX). Буферы должны быть установлены в определенном порядке, сначала задаются буферы данных, затем определяется буфер индексов цвета.
SetIndexBuffer(0,uSi,INDICATOR_DATA); SetIndexBuffer(1,dSi,INDICATOR_DATA); SetIndexBuffer(2,trend,INDICATOR_COLOR_INDEX); SetIndexBuffer(3,upArrows,INDICATOR_DATA); SetIndexBuffer(4,dnArrows,INDICATOR_DATA); PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); PlotIndexSetDouble(1,PLOT_EMPTY_VALUE,0.0); PlotIndexSetDouble(2,PLOT_EMPTY_VALUE,0.0); PlotIndexSetInteger(1,PLOT_ARROW,234); PlotIndexSetInteger(2,PLOT_ARROW,233);
Буферы 0,1,2 используются для цветовой гистограммы, буферы 3 и 4 используются для отображения стрелок.
Алгоритм раскраски следующий:
if (upind<dnind) { for (i=0; i<upind; i++) trend[i]=0; for (i=upind; i<dnind; i++) trend[i]=1; for (i=dnind; i<n; i++) trend[i]=0 ; } else { for (i=0; i<dnind; i++) trend[i]=1; for (i=dnind; i<upind; i++) trend[i]=0; for (i=upind; i<n; i++) trend[i]=1; } trend[upind] = 2; trend[dnind] = 2;
Приведем скриншот полученного результата:
Рисунок 3. Окончательная версия индикатора Moving Mini-Max
Следует помнить о том, что значения маркировок восходящего и нисходящего трендов вычисляются на заданном временном окне, каждый раз при появлении нового бара. По этой причине индикатор называется moving mini-max. Несмотря на запаздывание в m баров, он дает удивительно хорошую картину тренда на текущем временном окне и интерпретацию "дыхания" рынка.
Я считаю, что торговля по этому индикатору может быть прибыльной.
Выводы
Я представил математические основы нового индикатора технического анализа и его реализацию на MQL5. Оригинальная статья З.К. Силагадзе доступна по адресу: http://arxiv.org/abs/0802.0984.
Исходный код индикатора можно скачать в приложении к статье.
В будущем я надеюсь представить более интересные технические индикаторы и их реализацию на MQL5.
Литература:
1. Г.А. Гамов Теория радоактивного распада (УФН, т. X, 1930).
2. Z.K. Silagadze. Moving Mini-Max -- a new indicator for technical analysis
Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/238
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Задумка понравилась, но что-то не так. Индикатор по реализации просто в рассматриваемом окне находит лок макс и мин. Гармоники вроде могут что-то сказать о фазе рынка (флет или тренд) но не явно. Нужно смотреть в динамике этот индикатор. Пока мне кажется, что он бесполезен.
Очень хорошо ловит точки разворота рынка. Жди сигнала он покажет приближение к уровням поддержки и сопротивления... только определи току входа и ты получил прибыль...
Ничего он не ловит, он рисует как Репин)