Скачать MetaTrader 5

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

3 марта 2009, 09:24
Nikolay Kositsin
28
1 777

Введение

В механических торговых системах, построенных на базе индикаторов, в основе которых лежат какие-либо алгоритмы усреднения, их создатели редко когда используют больше одного какого-нибудь алгоритма усреднения. Во многих случаях, если алгоритм эксперта построен на основе обычных мувингов и индикаторов, входящих в стандартный набор индикаторов терминала 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)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (28)
Henry_White
Henry_White | 26 июн 2009 в 23:45
GODZILLA:

Моя функция работает с любыми числами в том числе и с отрицательными! А вот на скурпулёзное изучение вашей идеи у меня уйдёт много времени, которого у меня по вполне понятным причинам нету абсолютно! Два вопроса:

1. Ваш ценовой ряд уже лежит в индикаторном буфере?

2. на каждом пересчёте пересчитывается только значение с последнего бара или все значения?

2. Сначала отвечу на второй вопрос... Я пока делаю расчет ТОЛЬКО на момент расчета своей статистики. Расчитываются бары от 700 до 1. Нулевой пока не считаю. С этим бы разобраться...

1. Я не совсем понял вопрос... Под "уже" Вы имеете ввиду какой момент? Давайте я просто прокомментирую эти три строки: 

      for(i=0; i<Bars_for_Stats+100; i++) CalcData(i);                             // Расчет данных где Bars_for_Stats - целое число, допустим 700
      StatInit(Bars_for_Stats, 0, 3);                                              // Расчет статистических коэф-ов 
      for(i=Bars_for_Stats; i>0; i--) GetSignal(i);                                // Собственно расчет данных для индикаторов с обработкой JJMASeries

1-я: заполнение промежуточных (не индикаторных) массивов, на основе текущего ВР
2-я: вычисление стат. величин для последующей нормализации (значащей роли не играет)
3-я: собственно заполнение индикаторных буферов. Сложные и громоздкие расчеты этих величин я не привожу, так как они отношения к делу не имеют, но они имеют, безусловно, прямую временную корреляцию с ценовыми рядами. Реальные значения этих расчетов я показал на графике (красный) и попытку сгладить эти значения через JJMASeries(сиреневый). Для того, чтобы его "увидеть" мне пришлось его поднять на 20 единиц.

По поводу отрицательных величин я, похоже, погорячился... Действительно, если опустить график на нулевой уровень, то JJMASeries рисует верхушки выше "1" и ниже "-1". Между этими значениями пусто. Если поднять график - картина как на скриншоте. Глубина JMA сглаживания равна 36. Фаза 100.
В общем, есть еще много непонятного. Буду разбираться дальше. Если есть возможность помочь - буду признателен.

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[]. Вот вариант обращения к функции:

Henry_White
Henry_White | 30 июн 2009 в 10:08

Николай,

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

MQL4 Comments
MQL4 Comments | 6 ноя 2011 в 10:28

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

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

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

Каналы. Продвинутые модели. Волны Вульфа Каналы. Продвинутые модели. Волны Вульфа

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

Рецепты нейросетей Рецепты нейросетей

Статья для начинающих кулинаров в приготовлении "слоёных" пирогов

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.