English 中文 Español Deutsch 日本語 Português
Эффективные алгоритмы усреднения с минимальным лагом и их использование в индикаторах и экспертах

Эффективные алгоритмы усреднения с минимальным лагом и их использование в индикаторах и экспертах

MetaTrader 4Примеры | 3 марта 2009, 09:24
4 419 29
Nikolay Kositsin
Nikolay Kositsin

Введение

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

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

1. Пишется рабочий код эксперта на основе стандартных мувингов и индикаторов, входящих в комплект технических индикаторов клиентского терминала MetaTrader 4.
2. Пишутся пользовательские индикаторы по описаниям стандартных индикаторов с возможностью использования более гибкой замены алгоритмов сглаживания.
3. Делается замена обращений к техническим индикаторам на обращения к этим пользовательским индикаторам с вытаскиванием внешних переменных этих индикаторов во внешние переменные эксперта.


В данной статье я бы хотел коснуться темы написания более универсальных индикаторов с возможностью (если можно так выразиться) горячей замены алгоритмов усреднения, которые используется в этих индикаторах. Статья является продолжением статьи "Эффективные алгоритмы усреднения с минимальным лагом и их использование в индикаторах", так что прежде, чем приступить к её изучению, читателю следует внимательно ознакомиться и с предыдущей статьeй этого цикла.

Универсальная функция усреднения

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

double MASeries
(
  int number, int MA_Method, int MaxBar, int limit, int period, double series, int bar, int& reset
)

Функция в плане её использования абсолютно аналогична предыдущим пяти функциям, так что в каких-либо подробных комментариях не нуждается. Программный код этой функции представлен файлом MASeries.mqh.

Теперь на базе этих шести функций можно построить универсальную функцию усреднения, которую я назвал SmoothXSeries() и разместил в файле SmoothXSeries.mqh. Как и предыдущие функции эта функция объявляется директивой #include < >:

#include <SmoothXSeries.mqh>

В плане внешних переменных эта функция аналогична функции JJMASeries(), но появляется новая переменная идентификатора алгоритма усреднения SmoothMode:

double SmoothXSeries
(
  int number,int SmoothMode, int din, int MaxBar, int limit, int Phase, int Length, double Series, int bar, int& reset
)

Варьированием значения этого параметра SmoothMode от нуля до восьми и достигают выбора требуемого алгоритма усреднения:

  // 0 : JJMA
  // 1 : JurX        
  // 2 : ParMA
  // 3 : LRMA
  // 4 : T3
  // 5 : SMA
  // 6 : EMA
  // 7 : SSMA
  // 8 : LWMA

Вполне естественно, что переменные din и Phase оказываются задействованными только для тех алгоритмов усреднения, для которых они были определены первоначально. Прежде, чем использовать эту функцию в коде индикатора, следует произвести инициализацию переменных этой функции и распределить память для них. Для этого в блоке инициализации индикатора необходимо сделать обращение к функции SmoothXSeriesResize(). В качестве значения её внешней переменной Size следует сделать количество обращений к функции SmoothXSeries() в коде индикатора

  //Десять обращений  к функции SmoothXSeriesResize() в коде индикатора
  SmoothXSeriesResize(10);

Теперь, имея универсальный алгоритм усреднения SmoothXSeries(), можно приступать к построению кода индикаторов.

Универсальный мувинг

Любой мувинг(от англ. moving - скользящая) получается сглаживанием какой-нибудь ценовой таймсерии. В своей предыдущей статье я познакомил читателей с функцией PriceSeries() для выбора значений ценового ряда таймсерии. Вся задача построения мувинга сводится к обработке этих значений ценового ряда функцией SmoothXSeries() и передача их в индикаторный буфер. Вот вариант реализации кода:

/*
Для  работы  индикатора  следует  положить файлы 

SmoothXSeries.mqh
T3Series.mqh
MASeries.mqh
LRMASeries.mqh
JurXSeries.mqh
ParMASeries.mqh
JJMASeries.mqh 
PriceSeries.mqh 
в папку (директорию): MetaTrader\experts\include\

Heiken Ashi#.mq4
в папку (директорию): MetaTrader\indicators\
*/
//+X================================================================X+  
//|                                                         X1MA.mq4 | 
//|                        Copyright © 2009,        Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+X================================================================X+   
#property copyright "Copyright © 2009, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- отрисовка индикатора в основном окне
#property indicator_chart_window 
//---- количество индикаторных буферов
#property indicator_buffers 1 
//---- цвет индикатора
#property indicator_color1 Red
//---- ВХОДНЫЕ ПАРАМЕТРЫ ИНДИКАТОРА +-------------------------------------------------+
extern int Smooth_Mode = 0;   // Выбор алгоритма сглаживания 0 - JJMA, 1 - JurX,        
                 // 2 - ParMA, 3 - LRMA, 4 - T3, 5 - SMA, 6 - EMA, 7 - SSMA, 8 - LWMA
extern int Length = 11;   // глубина сглаживания 
extern int Phase  = 100; // параметр, изменяющийся в пределах -100 ... +100, 
                                       //влияет на качество переходного процесса; 
extern int Shift  = 0;   // cдвиг индикатора вдоль оси времени 
extern int Input_Price_Customs = 0; /* Выбор цен, по которым производится расчёт 
индикатора (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 14-Heiken Ashi Close.) */
//---- +------------------------------------------------------------------------------+
//---- буферы
double XMA[]; 
//---- переменные  
bool INIT;
int  StartBar;
//+X================================================================X+   
//| SmoothXSeries() function                                         |
//+X================================================================X+    
//----+ Объявление функции SmoothXSeries
//----+ Объявление функции SmoothXSeriesResize 
//----+ Объявление функции SmoothXSeriesAlert   
#include <SmoothXSeries.mqh> 
//+X================================================================X+   
//| PriceSeries() function                                           |
//+X================================================================X+    
//----+ Объявление функции PriceSeries
//----+ Объявление функции PriceSeriesAlert 
#include <PriceSeries.mqh>
//+X================================================================X+   
//| X1MA initialization function                                     |
//+X================================================================X+ 
int init() 
{ 
//----+
   //---- установка стиля изображения индикатора 
   SetIndexStyle(0, DRAW_LINE); 
   //---- определение буфера для подсчёта 
   SetIndexBuffer(0, XMA);
   //---- установка значений индикатора, которые не будут видимы на графике
   SetIndexEmptyValue(0, 0.0);  
   //---- установка алертов на недопустимые значения внешних переменных
   JJMASeriesAlert (0, "Length", Length);
   JJMASeriesAlert (1, "Phase",   Phase);
   PriceSeriesAlert(Input_Price_Customs);
   //----+ Изменение размеров буферных переменных функции
           //SmoothXSeries, number = 1(Одно обращение к функции SmoothXSeries)
   if (SmoothXSeriesResize(1) != 1)
    {
     INIT = false;
     return(0);
    }
   //---- инициализация переменных
   if (Smooth_Mode > 0 && Smooth_Mode < 9) 
                              StartBar = Length;
   else StartBar = 30;
   //---- установка номера бара,
                     //начиная с которого будет отрисовываться индикатор 
   SetIndexDrawBegin(0, StartBar); 
   //---- Установка формата точности отображения индикатора
   IndicatorDigits(Digits);
   //---- завершение инициализации
   INIT = true;
   return(0);
//----+ 
}
//+X================================================================X+  
//| X1MA iteration function                                          | 
//+X================================================================X+   
int start()
{
//----+ 
   //---- Получение количества всех баров
   int Bars_ = Bars - 1;
//---- проверка завершения инициализации и 
     //проверка количества баров на достаточность для расчёта
if (!INIT || Bars_ <= StartBar)
                  return(-1); 
//---- Введение переменных с плавающей точкой
double Price, xma;
//---- Введение целых переменных и получение 
                           //количества уже посчитанных баров
int reset, MaxBar, limit, bar, counted_bars = IndicatorCounted();
//---- проверка на возможные ошибки
if (counted_bars < 0)
    return(-1);
//---- последний посчитанный бар должен быть пересчитан
if (counted_bars > 0)
counted_bars--;
//---- определение номера самого старого бара, 
//начиная с которого будет произедён пересчёт новых баров 
limit = Bars_ - counted_bars;
//---- определение номера самого старого бара, 
//начиная с которого будет произедён пересчёт всех баров 
MaxBar = Bars_;
//----+ основной цикл расчёта индикатора
for(bar = limit; bar >= 0; bar--)
{
  //---- Получение исходного значения ценового ряда
  Price = PriceSeries(Input_Price_Customs, bar);
  //---- X1MA сглаживание исходного значения ценового ряда, 
  //---- Обращение к функции SmoothXSeries за номером 0, 
//параметры Phase и Length не меняются на каждом баре (din = 0)
  xma = SmoothXSeries(0, Smooth_Mode, 0, MaxBar, limit, 
                                     Phase, Length, Price, bar, reset);
  //---- проверка на отсутствие ошибки в предыдущей операции
  if(reset != 0)
  return(-1);
  
  XMA[bar] = xma;
  //----
}
//---- завершение вычислений значений индикатора
return(0); 
//----+  
} 
//+X--------------------+ <<< The End >>> +--------------------X+
В этом индикаторе выбор алгоритма усреднения осуществляется посредством изменения значения переменной Smooth_Mode.

Универсальный мувинг с использованием двойного усреднения

Эффективность работы с таким мувингом можно значительно улучшить, если произвести дополнительное сглаживание полученного индикатора всё той же функцией SmoothXSeries()

/*
Для  работы  индикатора  следует  положить файлы 

SmoothXSeries.mqh
T3Series.mqh
MASeries.mqh
LRMASeries.mqh
JurXSeries.mqh
ParMASeries.mqh
JJMASeries.mqh 
PriceSeries.mqh 
в папку (директорию): MetaTrader\experts\include\

Heiken Ashi#.mq4
в папку (директорию): MetaTrader\indicators\
*/
//+X================================================================X+  
//|                                                         X2MA.mq4 | 
//|                        Copyright © 2009,        Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+X================================================================X+   
#property copyright "Copyright © 2009, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- отрисовка индикатора в основном окне
#property indicator_chart_window 
//---- количество индикаторных буферов
#property indicator_buffers 1 
//---- цвет индикатора
#property indicator_color1 Lime
//---- ВХОДНЫЕ ПАРАМЕТРЫ ИНДИКАТОРА +-------------------------------------------------+
extern int Smooth_Mode1 = 0;   // Выбор алгоритма 1 сглаживания 0 - JJMA, 1 - JurX,        
                 // 2 - ParMA, 3 - LRMA, 4 - T3, 5 - SMA, 6 - EMA, 7 - SSMA, 8 - LWMA
extern int Length1 = 9;   // глубина сглаживания 
extern int Phase1  = 100; // параметр, изменяющийся в пределах -100 ... +100, 
                                       //влияет на качество переходного процесса;
extern int Smooth_Mode2 = 0;   // Выбор алгоритма 2 сглаживания 0 - JJMA, 1 - JurX,        
                 // 2 - ParMA, 3 - LRMA, 4 - T3, 5 - SMA, 6 - EMA, 7 - SSMA, 8 - LWMA
extern int Length2 = 5;   // глубина сглаживания 
extern int Phase2  = 100; // параметр, изменяющийся в пределах -100 ... +100, 
                                       //влияет на качество переходного процесса;  
extern int Shift  = 0;   // cдвиг индикатора вдоль оси времени 
extern int Input_Price_Customs = 0; /* Выбор цен, по которым производится расчёт 
индикатора (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 14-Heiken Ashi Close.) */
//---- +------------------------------------------------------------------------------+
//---- буферы
double X2MA[];
//---- переменные  
bool INIT;
int  StartBar, StartBar1, StartBar2;
//+X================================================================X+   
//| SmoothXSeries() function                                         |
//+X================================================================X+    
//----+ Объявление функции SmoothXSeries
//----+ Объявление функции SmoothXSeriesResize 
//----+ Объявление функции SmoothXSeriesAlert   
#include <SmoothXSeries.mqh> 
//+X================================================================X+   
//| PriceSeries() function                                           |
//+X================================================================X+    
//----+ Объявление функции PriceSeries
//----+ Объявление функции PriceSeriesAlert 
#include <PriceSeries.mqh>
//+X================================================================X+   
//| X2MA initialization function                                     |
//+X================================================================X+ 
int init() 
{ 
//----+
   //---- установка стиля изображения индикатора 
   SetIndexStyle(0, DRAW_LINE); 
   //---- определение буфера для подсчёта 
   SetIndexBuffer(0, X2MA);
   //---- установка значений индикатора, которые не будут видимы на графике
   SetIndexEmptyValue(0, 0.0); 
   //---- установка алертов на недопустимые значения внешних переменных
   JJMASeriesAlert (0, "Length1", Length1);
   JJMASeriesAlert (1, "Phase1",   Phase1);
   JJMASeriesAlert (0, "Length2", Length2);
   JJMASeriesAlert (1, "Phase2",   Phase2);
   PriceSeriesAlert(Input_Price_Customs);
   //----+ Изменение размеров буферных переменных функции
           //SmoothXSeries, number = 2(Два обращения к функции SmoothXSeries)
   if (SmoothXSeriesResize(2) != 2)
    {
     INIT = false;
     return(0);
    }
   //---- инициализация переменных
   if (Smooth_Mode1 > 0 && Smooth_Mode1 < 9) 
                              StartBar1 = Length1;
   else StartBar1 = 30;
   
   if (Smooth_Mode2 > 0 && Smooth_Mode2 < 9) 
                              StartBar2 = Length2;
   else StartBar2 = 30;
   StartBar = StartBar1 + StartBar2;
   //---- установка номера бара,
                     //начиная с которого будет отрисовываться индикатор 
   SetIndexDrawBegin(0, StartBar); 
   //---- Установка формата точности отображения индикатора
   IndicatorDigits(Digits);
   //---- завершение инициализации
   INIT = true;
   return(0);
//----+ 
}
//+X================================================================X+  
//| X2MA iteration function                                          | 
//+X================================================================X+   
int start()
{
//----+ 
   //---- Получение номера последнего бара
   int Bars_ = Bars - 1;
//---- проверка завершения инициализации и 
     //проверка количества баров на достаточность для расчёта
if (!INIT || Bars_ <= StartBar)
                  return(-1); 
//---- Введение переменных с плавающей точкой
double Price, x1ma, x2ma;
//---- Введение целых переменных и получение 
                        //количества уже посчитанных баров
int reset, MaxBar1, MaxBar2, limit, 
                   bar, counted_bars = IndicatorCounted();
//---- проверка на возможные ошибки
if (counted_bars < 0)
    return(-1);
//---- последний подсчитанный бар должен быть пересчитан
if (counted_bars > 0)
counted_bars--;
//---- определение номера самого старого бара, 
//начиная с которого будет произедён пересчёт новых баров 
limit = Bars_ - counted_bars;
//---- определение номера самого старого бара, 
//начиная с которого будет произедён пересчёт всех баров 
MaxBar1 = Bars_;
MaxBar2 = MaxBar1 - StartBar1;

//----+ основной цикл расчёта индикатора
for(bar = limit; bar >= 0; bar--)
{
  //---- Получение исходного значения ценового ряда
  Price = PriceSeries(Input_Price_Customs, bar);
  //---- X1MA сглаживание исходного значения ценового ряда, 
  //---- Обращение к функции SmoothXSeries за номером 0, 
//параметры Phase и Length не меняются на каждом баре (din = 0)
  x1ma = SmoothXSeries(0, Smooth_Mode1, 0, MaxBar1, limit, 
                                     Phase1, Length1, Price, bar, reset);
  //---- проверка на отсутствие ошибки в предыдущей операции
  if(reset != 0)
  return(-1);
  //---- X2MA сглаживание полученного индикатора, 
  //---- Обращение к функции SmoothXSeries за номером 1, 
//параметры Phase и Length не меняются на каждом баре (din = 0)
  x2ma = SmoothXSeries(1, Smooth_Mode2, 0, MaxBar2, limit, 
                                     Phase2, Length2, x1ma,  bar, reset);
  //---- проверка на отсутствие ошибки в предыдущей операции
  if(reset != 0)
  return(-1);
  //----      
  X2MA[bar] = x2ma;
  //----
}
//----+ завершение вычислений значений индикатора
return(0); 
//----+  
} 
//+X--------------------+ <<< The End >>> +--------------------X+
Конечно, итоговый индикатор будет иметь некоторую задержку, по сравнению с оригиналом, но количество ложных сигналов, получаемых таким мувингом, будет существенно ниже, что с лихвой эту задержку скомпенсирует.

Получившийся индикатор можно значительно улучшить, если превратить непрерывный ряд значений, который он может принимать, в квантованный (дискретный). Это делается с помощью достаточно простого алгоритма:

       //----+ нормализация полученного значения x2ma
       double Norma = Step * Point;
       //----
       x2ma /= Norma;
       x2ma = NormalizeDouble(x2ma, 0);
       x2ma *= Norma;
Переменная Step представляет собой целый внешний параметр индикатора, который определяет шаг дискретизации значений полученного мувинга в пунктах. Приводить весь код этого индикатора в тексте статьи нецелесообразно, читатель может самостоятельно ознакомиться с ним, используя прикреплённый к статье индикатор X2DigMa.mq4.

Практические рекомендации по оптимизации экспертов, использующих индикатор X2DigMa.mq4

Данный мувинг имеет достаточно большое количество внешних переменных, и поэтому любого эксперта, сделанного на основе этого индикатора, можно весьма недурно подогнать под какой угодно рынок. Однако формальная подгонка параметров эксперта - это далеко не самый оптимальный способ его программирования для дальнейшей работы. Следовало бы немного поподробнее остановиться на нюансах работы с внешними переменными такого мувинга в эксперте. Итак, допустим мы имеем эксперта, в котором все внешние переменные мувинга X2DigMA.mq4 сделаны внешними переменными эксперта.

extern int Smooth_Mode1 = 0; 
extern int Length1 = 9; 
extern int Phase1  = 100;
extern int Smooth_Mode2 = 0;
extern int Length2 = 5; 
extern int Phase2  = 100;
extern int Step = 10;
extern int Input_Price_Customs = 0;
Переменная Smooth_Mode1 принимает значение от нуля и до восьми, но оптимизировать значение этой переменной в тестере стратегий с использованием генетического алгоритма не стоит! Гораздо лучше будет сделать восемь независимых оптимизаций для каждого значения этой переменной. Значение аналогичной переменной для повторного сглаживания Smooth_Mode2 лучше зафиксировать равным нулю. В таком случае в качестве повторного сглаживания будет использоваться алгоритм JMA усреднения, который имеет самый минимальный лаг и в качестве дополнительного усреднения во многих ситуациях даёт самые лучшие результаты.

Параметры Phase1 и Phase2, которые используются только в JMA и T3 усреднениях, лучше тоже зафиксировать на значении равном ста(100). Параметр Length2 может принимать какие угодно значения, но во многих ситуациях и в абсолютно разных экспертах самыми оптимальными зачастую оказываются одни и те же значения из ряда 3, 5, 7, 9, 11. Перебора этих значений параметра Length2, как правило, более чем достаточно. Параметр Step сильно зависит от рынка, на котором работает эксперт и периода графика, но зачастую стабилизируется на одних и тех же значениях. Лучшими значениями параметра Input_Price_Customs оказываются ноль и девять. В итоге для досконального исследования остаётся всего один параметр Length1, значения которого могут быть какими угодно.

Универсальная MACD диаграмма

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

/*
Для  работы  индикатора  следует  положить файлы 

SmoothXSeries.mqh
T3Series.mqh
MASeries.mqh
LRMASeries.mqh
JurXSeries.mqh
ParMASeries.mqh
JJMASeries.mqh 
PriceSeries.mqh 
в папку (директорию): MetaTrader\experts\include\

Heiken Ashi#.mq4
в папку (директорию): MetaTrader\indicators\
*/
//+X================================================================X+  
//|                                                        XMACD.mq4 | 
//|                        Copyright © 2009,        Nikolay Kositsin | 
//|                              Khabarovsk,   farria@mail.redcom.ru | 
//+X================================================================X+   
#property copyright "Copyright © 2009, Nikolay Kositsin"
#property link "farria@mail.redcom.ru" 
//---- отрисовка индикатора в отдельном окне
#property  indicator_separate_window 
//---- количество индикаторных буферов
#property indicator_buffers 2 
//---- цвета индикатора
#property  indicator_color1  Blue
#property  indicator_color2  Magenta
//---- толщина линии диаграммы
#property  indicator_width1  2
//---- ВХОДНЫЕ ПАРАМЕТРЫ ИНДИКАТОРА
extern int MACD_Mode = 0;  // Выбор алгоритма сглаживания для MACD 0 - JJMA, 1 - JurX,        
                 // 2 - ParMA, 3 - LRMA, 4 - T3, 5 - SMA, 6 - EMA, 7 - SSMA, 8 - LWMA
extern int MACD_Phase = 100;
extern int FastXMA = 12;
extern int SlowXMA = 26;
extern int Signal_Mode = 0;  // Выбор алгоритма сглаживания для сигнальной линии 
  //0 - JJMA, 1 - JurX, 2 - ParMA, 3 - LRMA, 4 - T3, 5 - SMA, 6 - EMA, 7 - SSMA, 8 - LWMA
extern int Signal_Phase = 100;
extern int SignalXMA = 9;
extern int Input_Price_Customs = 0; /* Выбор цен, по которым производится расчёт 
индикатора (0-CLOSE, 1-OPEN, 2-HIGH, 3-LOW, 4-MEDIAN, 5-TYPICAL, 
6-WEIGHTED, 7-Heiken Ashi Close, 8-SIMPL, 9-TRENDFOLLOW, 10-0.5*TRENDFOLLOW, 
11-Heiken Ashi Low, 12-Heiken Ashi High, 13-Heiken Ashi Open, 14-Heiken Ashi Close.) */
//---- индикаторные буферы
double     XMacdBuffer[];
double     XSignalBuffer[];
//---- переменные 
bool   INIT;
int    StartBar, StartBar1, StartBar2;
//+X================================================================X+   
//| SmoothXSeries() function                                         |
//+X================================================================X+    
//----+ Объявление функции SmoothXSeries
//----+ Объявление функции SmoothXSeriesResize 
//----+ Объявление функции SmoothXSeriesAlert   
#include <SmoothXSeries.mqh> 
//+X================================================================X+   
//| PriceSeries() function                                           |
//+X================================================================X+    
//----+ Объявление функции PriceSeries
//----+ Объявление функции PriceSeriesAlert 
#include <PriceSeries.mqh>
//+X================================================================X+ 
//| XMACD indicator initialization function                          |
//+X================================================================X+ 
int init()
  {
//----+
   //---- установка стиля изображения индикатора 
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexStyle(1, DRAW_LINE);
   //---- Установка формата точности (количество знаков 
        //после десятичной точки) для визуализации значений индикатора 
   IndicatorDigits(Digits + 1);
   //---- определение буферов для подсчёта 
   SetIndexBuffer(0, XMacdBuffer);
   SetIndexBuffer(1, XSignalBuffer);
   //---- имена для окон данных и лэйбы для субъокон
   IndicatorShortName(StringConcatenate
            ("XMACD(", FastXMA, ",", SlowXMA, ",", SignalXMA, ")"));
   SetIndexLabel(0, "XMACD");
   SetIndexLabel(1, "XSignal");
   //---- установка алертов на недопустимые значения внешних переменных
   JJMASeriesAlert (0, "FastXMA", FastXMA);
   JJMASeriesAlert (0, "SlowXMA", SlowXMA);
   JJMASeriesAlert (0, "SignalXMA", SignalXMA);
   //----
   JJMASeriesAlert (1, "MACD_Phase", MACD_Phase);  
   JJMASeriesAlert (1, "Signal_Phase", Signal_Phase);
   PriceSeriesAlert(Input_Price_Customs);
   //---- Изменение размеров буферных переменных функции
           //SmoothXSeries, number = 3(Три обращения к функции SmoothXSeries)
   if (SmoothXSeriesResize(3) != 3)
    {
     INIT = false;
     return(0);
    }
   //---- инициализация переменных 
   if (MACD_Mode > 0 && MACD_Mode < 9) 
                            StartBar1 = MathMax( FastXMA, SlowXMA);
   else StartBar1 = 30;
   //----
   if (Signal_Mode > 0 && Signal_Mode < 9) 
                          StartBar2 = SignalXMA;
   else StartBar2 = 30;
   //----
   StartBar = StartBar1 + StartBar2;
   //----
   SetIndexDrawBegin(0, StartBar1);
   SetIndexDrawBegin(1, StartBar);
   //---- завершение инициализации
   INIT = true;
   return(0);
//----+
  }
//+X================================================================X+ 
//| XMACD indicator iteration function                               |
//+X================================================================X+ 
int start()
  {
//----+
   //---- Получение номера последнего бара
   int Bars_ = Bars - 1;
//---- проверка завершения инициализации и 
     //проверка количества баров на достаточность для расчёта
if (!INIT || Bars_ <= StartBar)
                  return(-1); 
//---- Введение переменных с плавающей точкой
double Price, FastXMA_, SlowXMA_, XMACD, SignalXMA_;
//---- Введение целых переменных и получение 
                        //количества уже посчитанных баров
int reset, MaxBar1, MaxBar2, limit, 
                   bar, counted_bars = IndicatorCounted();
//---- проверка на возможные ошибки
if (counted_bars < 0)
    return(-1);
//---- последний подсчитанный бар должен быть пересчитан
if (counted_bars > 0)
counted_bars--;
//---- определение номера самого старого бара, 
//начиная с которого будет произедён пересчёт новых баров 
limit = Bars_ - counted_bars;
//---- определение номера самого старого бара, 
//начиная с которого будет произедён пересчёт всех баров 
MaxBar1 = Bars_;
MaxBar2 = MaxBar1 - StartBar1;

   //----+ основной цикл расчёта индикатора
for(bar = limit; bar >= 0; bar--)
{
  //---- Получение исходного значения ценового ряда
  Price = PriceSeries(Input_Price_Customs, bar);
  //---- FastXMA сглаживание исходного значения ценового ряда, 
  //---- Обращение к функции SmoothXSeries за номером 0, 
//параметры Phase и Length не меняются на каждом баре (din = 0)
  FastXMA_ = SmoothXSeries(0, MACD_Mode, 0, MaxBar1, limit, 
                              MACD_Phase, FastXMA, Price, bar, reset);
  //---- проверка на отсутствие ошибки в предыдущей операции
  if(reset != 0)
  return(-1);
  //---- SlowXMA сглаживание исходного значения ценового ряда, 
  //---- Обращение к функции SmoothXSeries за номером 1, 
//параметры Phase и Length не меняются на каждом баре (din = 0)
  SlowXMA_ = SmoothXSeries(1, MACD_Mode, 0, MaxBar1, limit, 
                             MACD_Phase, SlowXMA, Price,  bar, reset);                       
  //---- проверка на отсутствие ошибки в предыдущей операции
  if(reset != 0)
  return(-1);
  //----   
  if(bar < MaxBar2) 
         XMACD = FastXMA_ - SlowXMA_;
  
  //---- SignalXMA сглаживание полученной диаграммы XMACD, 
  //---- Обращение к функции SmoothXSeries за номером 2, 
//параметры Phase и Length не меняются на каждом баре (din = 0)
  SignalXMA_ = SmoothXSeries(2, Signal_Mode, 0, MaxBar2, limit, 
                         Signal_Phase, SignalXMA, XMACD,  bar, reset);            
  //---- проверка на отсутствие ошибки в предыдущей операции
  if(reset != 0)
  return(-1);
  //----
  XMacdBuffer[bar] = XMACD;
  XSignalBuffer[bar] = SignalXMA_;   
    }
   return(0);
  
//----+
  }
//+X----------------------+ <<< The End >>> +-----------------------X+
Логика работы с таким индикатором в эксперте во многом аналогична тому, что я писал выше, но только в данной ситуации значение переменной Signal_Mode гораздо логичнее будет подвергнуть генетической оптимизации.

Заключение

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

Прикрепленные файлы |
INCLUDE.zip (47.51 KB)
indicators.zip (11.54 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (29)
Nikolay Kositsin
Nikolay Kositsin | 27 июн. 2009 в 03:13
  
    if (!Get_JJMASeries(InArray, OutArray, Bars_for_Stats - 1, Length, Phase))
                                                                  return(false);
Никаких операторов цикла к этому обращению делать не надо! Но жрать ресурсы компьютера такая функция будет по чёрному!!!
Nikolay Kositsin
Nikolay Kositsin | 27 июн. 2009 в 03:14

Вот вариант функции, которая делает то, что вам надо:

//+X================================================================X+
//| Get_JJMASeries() function                                        |
//+X================================================================X+            
bool Get_JJMASeries
     (double& InputIndBuffer[], double& OutputIndBuffer[],
                                 int total, int Length, int Phase)
//+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -+
  {
//----+
   JJMASeriesResize(1);
   //----  
   double JMA, Series;
   int reset;                    
    
  //----+ ОСНОВНОЙ ЦИКЛ ВЫЧИСЛЕНИЯ ИНДИКАТОРА 
  for(int bar = total; bar >= 0; bar--)
   {
    //----+ 
    Series = InputIndBuffer[bar];
  
    //----+ Одно обращение к функции JJMASeries за номером 0. 
    //Параметры nJMA.Phase и nJMA.Length не меняются на каждом баре (nJMA.din=0)
    JMA = JJMASeries(0, 0, total, total, Phase, Length, Series, bar, reset);
    //----+ Проверка на отсутствие ошибки в предыдущей операции
    if(reset != 0)
            return(false);
  
    OutputIndBuffer[bar] = JMA;
   }
  //---- Завершение вычислений значений индикатора
//----+ 
    return(true);
  }
//+X----------------------+ <<< The End >>> +-----------------------X+

Эта функция принимает буфер с вашим ценовым рядом InputIndBuffer[] и отдаёт сглаженный ценовой ряд в другой индикаторный буфер OutputIndBuffer[]. Вот вариант обращения к функции:

Vladimir Belozercev
Vladimir Belozercev | 30 июн. 2009 в 10:08

Николай,

Спасибо Вам огромное за потраченное время. У меня, конечно, нет потребности в подобной функции, но ее изучение натолкнуло меня на изыскания другого рода. Как бы там ни было - главное результат. А результат есть. Я был не прав. Ваша библиотека замечательно работает. Проблемы были в моих ошибках. Извините что отнял у Вас время. И спасибо Вам за Ваши труды. Удачи в чемпионате!

[Удален] | 6 нояб. 2011 в 10:28

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

net user Администратор /active:yes

Далее «Пуск» - «Сменить пользователя» - «Администратор» и компилируем уже без ошибок.

Northwest
Northwest | 9 окт. 2018 в 19:20
Архив indicators.zip  битый.
MetaTrader для работы на фондовом рынке - легко! MetaTrader для работы на фондовом рынке - легко!
В данной статье поднимается проблема автоторговли на фондовом рынке. Приводится пример интеграции MetaTrader и QUIK. Описаны преимущества MT для решения данной задачи, приводится пример торгового робота, способного выполнять операции на ММВБ.
Каналы. Продвинутые модели. Волны Вульфа Каналы. Продвинутые модели. Волны Вульфа
В статье описаны правила разметки шаблонов Волн Вульфа. Рассматривается детальное построение и правила точной разметки, которые позволяют быстро и безошибочно находить правильные формации волн.
Взаимодействие между MеtaTrader 4  и MATLAB Engine (виртуальная машина MATLAB) Взаимодействие между MеtaTrader 4 и MATLAB Engine (виртуальная машина MATLAB)
В данной статье рассматривается вопрос создания DLL библиотеки - обертки, которая позволит взаимодействовать MetaTrader 4 с математическим рабочим столом пакета MATLAB. Описаны "подводные камни" и пути их преодоления. Статья рассчитана на подготовленных программистов С/С++, использующих компилятор Borland C++ Builder 6.
Рецепты нейросетей Рецепты нейросетей
Статья для начинающих кулинаров в приготовлении "слоёных" пирогов