Расширение стандартной библиотеки MQL5 и повторное использование кода

23 сентября 2013, 17:19
Jordi Bassaganas
18
3 950

Введение

Стандартная библиотека MQL5 – это объектно-ориентированный фреймворк, состоящий из набора готовых к использованию классов, облегчающих труд разработчика. Однако она не может удовлетворить все требования абсолютно всех разработчиков в мире, поэтому если вы хотите иметь в своем распоряжении больше пользовательских элементов, вам необходимо расширить ее. В статье описывается интеграция обычного индикатора ZigZag в стандартную библиотеку. В ходе работы мы будем опираться на принципы разработки, применяемые в компании MetaQuotes.

Говоря кратко, MQL5 API предлагает вам надежность, гибкость, простоту обслуживания, а также возможность повторного использования кода. Если вы собираетесь совершенствовать ваши навыки в языке MQL5 и разрабатывать сложные приложения, например, мультивалютные советники, вам прежде всего необходимо освоить стандартную библиотеку, чтобы обеспечить своим программам успешную жизнь.

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

Рис 1. Правильные многогранники – совершенные объекты. Они хорошо демонстрируют идею разработки приложений по четкому плану

Рис. 1. Правильные многогранники – совершенные объекты. Они хорошо демонстрируют идею разработки приложений по четкому плану

1. Загрузка индикатора ZigZag

Начнем с загрузки стандартного инидкатора ZigZag, доступного в Code Base, прямо в терминале MetaTrader 5. При этом будут созданы файлы Indicators\zigzag.mq5 и Indicators\zigzag.ex5.

Рис. 2. Загрузка стандартного индикатора ZigZag в терминале MetaTrader 5

Рис. 2. Загрузка стандартного индикатора ZigZag в терминале MetaTrader 5

Ниже приведены строки коды из Indicators\zigzag.mq5, содержащие входные параметры индикатора, глобальные переменные и обработчик OnInit(). Я привожу эту часть только потому, что весь файл состоит из 298 строк кода. Это сделано исключительно ради удобства и понимания более глобальной картины, о которой мы поговорим ниже.

//+------------------------------------------------------------------+
//|                                                       ZigZag.mq5 |
//|                        Copyright 2009, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "2009, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots   1
//---- plot Zigzag
#property indicator_label1  "Zigzag"
#property indicator_type1   DRAW_SECTION
#property indicator_color1  Red
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- input parameters
input int      ExtDepth=12;
input int      ExtDeviation=5;
input int      ExtBackstep=3;
//--- indicator buffers
double         ZigzagBuffer[];      // main buffer
double         HighMapBuffer[];     // highs
double         LowMapBuffer[];      // lows
int            level=3;             // recounting depth
double         deviation;           // deviation in points
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,ZigzagBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,HighMapBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,LowMapBuffer,INDICATOR_CALCULATIONS);

//--- set short name and digits   
   PlotIndexSetString(0,PLOT_LABEL,"ZigZag("+(string)ExtDepth+","+(string)ExtDeviation+","+(string)ExtBackstep+")");
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//--- set empty value
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
//--- to use in cycle
   deviation=ExtDeviation*_Point;
//---
   return(INIT_SUCCEEDED);
  }


2. Краткий обзор: от общего к частному

Мы попробуем применить нисходящий анализ при рассмотрении нашего нового объектно-ориентированного индикатора ZigZag, который мы хотим интегрировать в стандартную библиотеку MQL5. Это означает, что сначала мы должны рассмотреть всю систему, а затем проанализировать ее составные части. Так почему бы нам не написать пару тестовых советников, чтобы увидеть глобальную картину? Итак, давайте напишем процедурного советника и его объектно-ориентированную версию.


2.1. Стандартный индикатор ZigZag

Среднестатистический MQL5-разработчик скорее всего включит индикатор ZigZag в свой советник следующим образом:

//+----------------------------------------------------------------------+
//|                                            ExpertOriginalZigZag.mq5  |
//|                   Copyright © 2013, Laplacianlab - Jordi Bassagañas  | 
//+----------------------------------------------------------------------+
//--- свойства торгового советника
#property copyright     "Copyright © 2013, Laplacianlab - Jordi Bassagañas"
#property link          "https://www.mql5.com/ru/articles"
#property version       "1.00"
#property description   "Этот тестовый торговый советник создан исключительно для демонстрации использования стандартного индикатора ZigZag."
//--- входные данные торгового советника
input ENUM_TIMEFRAMES   EAPeriod=PERIOD_H1;
input string            CurrencyPair="EURUSD";
//--- глобальные переменные
int      zigZagHandle;
double   zigZagBuffer[];
double   zigZagHigh[];
double   zigZagLow[];
//+------------------------------------------------------------------+
//| Функция инициализации советника                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   zigZagHandle=iCustom(CurrencyPair,EAPeriod,"zigzag",12,5,3);
   ArraySetAsSeries(zigZagBuffer,true);
   ArraySetAsSeries(zigZagHigh,true);
   ArraySetAsSeries(zigZagLow,true);  
   return(0);
  }
//+------------------------------------------------------------------+
//| Функция деинициализации советника                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   IndicatorRelease(zigZagHandle);
   ArrayFree(zigZagBuffer);
   ArrayFree(zigZagHigh);
   ArrayFree(zigZagLow);
  }
//+------------------------------------------------------------------+
//| Тиковая функция советника                                        |
//+------------------------------------------------------------------+
void OnTick()
  {
   //--- обновляем данные   
   if(CopyBuffer(zigZagHandle,0,0,2,zigZagBuffer)<0)
   {
      Print("Невозможно скопировать буфер 0 индикатора ZigZag!");
      return;
   }
   if(CopyBuffer(zigZagHandle,1,0,2,zigZagHigh)<0)
   {
      Print("Невозможно скопировать буфер 1 индикатора ZigZag!");
      return;
   }
   if(CopyBuffer(zigZagHandle,2,0,2,zigZagLow)<0)
   {
      Print("Невозможно скопировать буфер 2 индикатора ZigZag!");
      return;
   }
   //--- вывод значений
   if(zigZagBuffer[0]!=0) Print("zigZagBuffer[0]: ", zigZagBuffer[0]);
   if(zigZagHigh[0]!=0) Print("zigZagHigh[0]: ", zigZagHigh[0]);
   if(zigZagLow[0]!=0) Print("zigZagLow[0]: ", zigZagLow[0]);
  }
//+------------------------------------------------------------------+


2.2. Индикатор ZigZag в составе стандартной библиотеки

В то же время, опытный MQL5-разработчик наверняка решит работать с индикатором ZigZag так же, как он работает с индикаторами в составе стандартной библиотеки, а именно:

//+----------------------------------------------------------------------+
//|                                                  ExpertOOZigZag.mq5  |
//|                   Copyright © 2013, Laplacianlab - Jordi Bassagañas  | 
//+----------------------------------------------------------------------+
#include <..\Include\Indicators\Custom\Trend.mqh>
//--- свойства торгового советника
#property copyright     "Copyright © 2013, Laplacianlab - Jordi Bassagañas"
#property link          "https://www.mql5.com/ru/articles"
#property version       "1.00"
#property description   "Этот тестовый торговый советник создан исключительно для демонстрации "
#property description   "использования объектно-ориентированной версии стандартного индикатора ZigZag."
//--- входные данные торгового советника
input ENUM_TIMEFRAMES   EAPeriod=PERIOD_H1;
input string            CurrencyPair="EURUSD";
//--- глобальные переменные
CiZigZag *ciZigZag;
//+------------------------------------------------------------------+
//| Функция инициализации советника                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
   ciZigZag=new CiZigZag;
   ciZigZag.Create(CurrencyPair,EAPeriod,12,5,3);
   return(0);
  }
//+------------------------------------------------------------------+
//| Функция деинициализации советника                                |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   delete(ciZigZag);
  }
//+------------------------------------------------------------------+
//| Тиковая функция советника                                        |
//+------------------------------------------------------------------+
void OnTick()
  {   
   //--- обновляем данные
   ciZigZag.Refresh();
   //--- вывод значений
   if(ciZigZag.ZigZag(0)!=0) Print("OO ZigZag buffer: ", ciZigZag.ZigZag(0));
   if(ciZigZag.High(0)!=0) Print("OO ZigZag high: ", ciZigZag.High(0));
   if(ciZigZag.Low(0)!=0) Print("OO ZigZag low: ",ciZigZag.Low(0));
  }
//+------------------------------------------------------------------+

2.3. Вывод

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

  • ООП позволяет легко моделировать задачи.
  • ООП упрощает повторное использование кода, что в свою очередь благотворно влияет на цену, надежность, гибкость и удобство технического обслуживания.
  • Данная парадигма позволяет создавать абстрактные типы данных (АТД, Abstract Data Types). АТД – это абстрактная модель типов данных, присутствующих во всех языках программирования.

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

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


3. Интеграция нового объектно-ориентированного индикатора ZigZag в стандартную библиотеку MQL5

Как уже было сказано во Введении, в ходе работы мы будем опираться на объектно-ориентированный стиль компании MetaQuotes для создания набора классов, назначение которых – обладающих той же функциональностью, что и скачанный ранее индикатор ZigZag. Это довольно легко. Нам лишь необходимо взглянуть на файлы в папке Include\Indicators, а также изучить и понять некоторые идеи, лежащие в основе стандартной библиотеки MQL5. Если вы взглянете на содержимое файла Trend.mqh, вы увидите, что в нем много классов технических индикаторов: ADX, Bollinger Bands, SAR, скользящие средние и т.д. Все эти классы наследуются от CIndicator. Мы можем придерживаться указанной структуры. Другой способ решения задачи – расширение нового объектно-ориентированного индикатора с помощью класса CiCustom.

Начнем с создания новой папки Include\Indicators\Custom и нового файла Include\Indicators\Custom\Trend.mqh для создания наших собственных индикаторов, так же как это делает MetaQuotes в Include\Indicators\Trend.mqh. Итак, у нас уже есть расширенный файл Include\Indicators\Custom\Trend.mqh. Ниже рассматриваются некоторые технические аспекты его разработки.

//+------------------------------------------------------------------+
//|                              Include\Indicators\Custom\Trend.mqh |
//|                  Copyright 2013, Laplacianlab - Jordi Bassagañas |
//|                     https://www.mql5.com/ru/users/laplacianlab |
//+------------------------------------------------------------------+
#include <..\Include\Indicators\Indicator.mqh>
//+------------------------------------------------------------------+
//| Класс CiZigZag.                                                  |
//| Назначение: класс индикатора "ZigZag".                           |
//|          Выводится из класса CIndicator.                         |
//+------------------------------------------------------------------+
class CiZigZag : public CIndicator
  {
protected:
   int               m_depth;
   int               m_deviation;
   int               m_backstep;

public:
                     CiZigZag(void);
                    ~CiZigZag(void);
   //--- методы доступа к защищенным данным
   int               Depth(void)          const { return(m_depth);      }
   int               Deviation(void)      const { return(m_deviation);  }
   int               Backstep(void)       const { return(m_backstep);   }
   //--- метод создания
   bool              Create(const string symbol,const ENUM_TIMEFRAMES period,
                            const int depth,const int deviation_create,const int backstep);
   //--- методы доступа к данным индикатора
   double            ZigZag(const int index) const;
   double            High(const int index) const;
   double            Low(const int index) const;
   //--- метод идентификации
   virtual int       Type(void) const { return(IND_CUSTOM); }

protected:
   //--- методы настройки
   virtual bool      Initialize(const string symbol,const ENUM_TIMEFRAMES period,const int num_params,const MqlParam &params[]);
   bool              Initialize(const string symbol,const ENUM_TIMEFRAMES period,
                                const int depth,const int deviation_init,const int backstep);
  };
//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CiZigZag::CiZigZag(void) : m_depth(-1),
                         m_deviation(-1),
                         m_backstep(-1)
  {
  }
//+------------------------------------------------------------------+
//| Деструктор                                                       |
//+------------------------------------------------------------------+
CiZigZag::~CiZigZag(void)
  {
  }
//+------------------------------------------------------------------+
//| Создаем индикатор "Zig Zag"                                      |
//+------------------------------------------------------------------+
bool CiZigZag::Create(const string symbol,const ENUM_TIMEFRAMES period,
                      const int depth,const int deviation_create,const int backstep)
  {
//--- проверяем историю
   if(!SetSymbolPeriod(symbol,period))
      return(false);
//--- создаем
   m_handle=iCustom(symbol,period,"zigzag",depth,deviation_create,backstep);
//--- проверяем результат
   if(m_handle==INVALID_HANDLE)
      return(false);
//--- индикатор успешно создан
   if(!Initialize(symbol,period,depth,deviation_create,backstep))
     {
      //--- ошибка инициализации
      IndicatorRelease(m_handle);
      m_handle=INVALID_HANDLE;
      return(false);
     }
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Инициализируем индикатор с универсальными параметрами            |
//+------------------------------------------------------------------+
bool CiZigZag::Initialize(const string symbol,const ENUM_TIMEFRAMES period,const int num_params,const MqlParam &params[])
  {
   return(Initialize(symbol,period,(int)params[0].integer_value,(int)params[1].integer_value,(int)params[2].integer_value));
  }
//+------------------------------------------------------------------+
//| Инициализируем индикатор со специальными параметрами             |
//+------------------------------------------------------------------+
bool CiZigZag::Initialize(const string symbol,const ENUM_TIMEFRAMES period,
                        const int depth,const int deviation_init,const int backstep)
  {
   if(CreateBuffers(symbol,period,3))
     {
      //--- строка состояния отрисовки
      m_name  ="ZigZag";
      m_status="("+symbol+","+PeriodDescription()+","+
               IntegerToString(depth)+","+IntegerToString(deviation_init)+","+
               IntegerToString(backstep)+") H="+IntegerToString(m_handle);
      //--- сохраняем настройки
      m_depth=depth;
      m_deviation=deviation_init;
      m_backstep=backstep;       
      //--- создаем буферы
      ((CIndicatorBuffer*)At(0)).Name("ZIGZAG");
      ((CIndicatorBuffer*)At(1)).Name("HIGH");
      ((CIndicatorBuffer*)At(2)).Name("LOW");
      //--- ok
      return(true);
     }
//--- ошибка
   return(false);
  }
//+------------------------------------------------------------------+
//| Доступ к буферу ZigZag индикатора "Zig Zag"                      |
//+------------------------------------------------------------------+
double CiZigZag::ZigZag(const int index) const
  {
   CIndicatorBuffer *buffer=At(0);
//--- проверяем
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }
//+------------------------------------------------------------------+
//| Доступ к буферу High индикатора "Zig Zag"                        |
//+------------------------------------------------------------------+
double CiZigZag::High(const int index) const
  {
   CIndicatorBuffer *buffer=At(1);
//--- проверяем
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }
//+------------------------------------------------------------------+
//| Доступ к буферу Low индикатора "Zig Zag"                         |
//+------------------------------------------------------------------+
double CiZigZag::Low(const int index) const
  {
   CIndicatorBuffer *buffer=At(2);
//--- проверяем
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }
//+------------------------------------------------------------------+


3.1. Инкапсуляция

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

У CiZigZag имеются собственные защищенные свойства:

protected:
   int               m_depth;
   int               m_deviation;
   int               m_backstep;

Соответственно, CiZigZag обладает открытым интерфейсом для доступа к указанным свойствам за пределами объекта типа CiZigZag:

public:
   //--- методы доступа к защищенным данным
   int               Depth(void)          const { return(m_depth);      }
   int               Deviation(void)      const { return(m_deviation);  }
   int               Backstep(void)       const { return(m_backstep);   }

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


3.2. Доступ к данным ZigZag

Как видно из первой части этой статьи, файл с исходным кодом zigzag.mq5 создает три буфера:

//--- отображение индикаторных буферов
   SetIndexBuffer(0,ZigzagBuffer,INDICATOR_DATA);
   SetIndexBuffer(1,HighMapBuffer,INDICATOR_CALCULATIONS);
   SetIndexBuffer(2,LowMapBuffer,INDICATOR_CALCULATIONS);

С помощью инкапсуляции методы CiZigZagZigZag(const int index), High(const int index) и Low(const int index) – возвращают индикаторные буферы, созданные ранее в методе инициализации. Необходимо отметить, что основой этих трех методов является класс CIndicatorBuffer определена в файле MQL5 Include\Indicators\Indicator.mqh. Таким образом, мы уже с головой ушли в MQL5 API!

В качестве примера ниже приведен код для доступа к буферу High типа CiZigZag:

//+------------------------------------------------------------------+
//| Доступ к буферу High индикатора "Zig Zag"                        |
//+------------------------------------------------------------------+
double CiZigZag::High(const int index) const
  {
   CIndicatorBuffer *buffer=At(1);
//--- проверяем
   if(buffer==NULL)
      return(EMPTY_VALUE);
//---
   return(buffer.At(index));
  }


3.3.
Полиморфизм, перегрузка методов и виртуальные функции

В предыдущем разделе мы кратко рассмотрели тему инкапсуляции, которая является одной из наиболее важных особенностей объектно-ориентированного программирования. Классы, содержащиеся в Include\Indicators\Indicator.mqh и в файле Include\Indicators\Custom\Trend.mqh имеют дело с двумя другими аспектами ООП – полиморфизмом и перегрузкой методов.

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

Ограничимся этим кратким вступлением. Рамки статьи не позволяют подробнее рассмотреть эти темы. Эту задачу я оставляю вам в качестве упражнения. Пожалуйста, ознакомьтесь с разделами "Полиморфизм" и "Перегрузка" в Справочнике MQL5. В любом случае, как мы видим, стандартная библиотека использует все возможности ООП. Соответственно, чем лучше мы их знаем, тем лучше мы сможем расширить API под свои нужды.

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

Вот почему мы реализуем метод инициализации CiZigZag таким образом:

//+------------------------------------------------------------------+
//| Инициализация индикатора с универсальными параметрами            |
//+------------------------------------------------------------------+
bool CiZigZag::Initialize(const string symbol,const ENUM_TIMEFRAMES period,const int num_params,const MqlParam &params[])
  {
   return(Initialize(symbol,period,(int)params[0].integer_value,(int)params[1].integer_value,(int)params[2].integer_value));
  }
//+------------------------------------------------------------------+
//| Инициализация индикатора со специальными параметрами             |
//+------------------------------------------------------------------+
bool CiZigZag::Initialize(const string symbol,const ENUM_TIMEFRAMES period,
                        const int depth,const int deviation_init,const int backstep)
  {
   if(CreateBuffers(symbol,period,3))
     {
      //--- строка состояния отрисовки
      m_name  ="ZigZag";
      m_status="("+symbol+","+PeriodDescription()+","+
               IntegerToString(depth)+","+IntegerToString(deviation_init)+","+
               IntegerToString(backstep)+") H="+IntegerToString(m_handle);
      //--- сохраняем настройки
      m_depth=depth;
      m_deviation=deviation_init;
      m_backstep=backstep;       
      //--- создаем буферы
      ((CIndicatorBuffer*)At(0)).Name("ZIGZAG");
      ((CIndicatorBuffer*)At(1)).Name("HIGH");
      ((CIndicatorBuffer*)At(2)).Name("LOW");
      //--- ok
      return(true);
     }
//--- ошибка
   return(false);
  }

4. Тестируем новый объектно-ориентированный ZigZag, уже доступный в стандартной библиотеке

Разумеется, вы должны прежде всего убедиться в том, что разработанные вами расширения работают именно так, как вы и планировали. Я рекомендую провести полное тестирование ваших пользовательских компонентов. Для упрощения понимания мы проведем простой тест трех основных методов CiZigZag: ZigZag(const int index), High(const int index) и Low(const int index).

Мы выведем значения, рассчитанные этими тремя методами на каждом тике советника, и сравним результаты процедурного советника ExpertOriginalZigZag.ex5 и объектно-ориентированного советника ExpertOOZigZag.ex5. Если результаты совпадают, мы можем заключить, что наше новое расширение в порядке и мы можем использовать наш объектно-ориентированный ZigZag, интегрированный в MQL5 API.

Рис. 4. Сравниваем результаты советников ExpertOriginalZigZag.ex5 и ExpertOOZigZag.ex5

Рис. 4. Сравниваем результаты советников ExpertOriginalZigZag.ex5 и ExpertOOZigZag.ex5

Итак, прогоним оба советника, ExpertOriginalZigZag.ex5 и ExpertOOZigZag.ex5, представленных в начале данной статьи, в Тестере стратегий со следующим набором параметров:

  • Пара: EURUSD, H1
  • Дата: Выбор периода, с 2013.08.01 по 2013.08.15
  • Режим торговли: Обычный, OHLC на М1
  • Начальный депозит: 10000 USD, 1:100
  • Оптимизация: Отключена

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

Логи советника ExpertOriginalZigZag.ex5:

DE      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:50:40   zigZagBuffer[0]: 1.32657
ML      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:50:40   zigZagLow[0]: 1.32657
FL      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:50:59   zigZagBuffer[0]: 1.32657
GE      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:50:59   zigZagLow[0]: 1.32657
KS      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:00   zigZagBuffer[0]: 1.32657
FR      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:00   zigZagLow[0]: 1.32657
GK      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:20   zigZagBuffer[0]: 1.32653
RJ      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:20   zigZagLow[0]: 1.32653
OR      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:40   zigZagBuffer[0]: 1.32653
FS      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:40   zigZagLow[0]: 1.32653
QJ      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:59   zigZagBuffer[0]: 1.32653
PH      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:51:59   zigZagLow[0]: 1.32653
JQ      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:52:00   zigZagBuffer[0]: 1.32653
KP      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:52:00   zigZagLow[0]: 1.32653
RH      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:52:20   zigZagBuffer[0]: 1.32653
GI      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:52:20   zigZagLow[0]: 1.32653
GP      0       18:45:39        ExpertOriginalZigZag (EURUSD,H1)        2013.08.01 08:52:40   zigZagBuffer[0]: 1.32614
// и так далее...

Логи советника ExpertOOZigZag.ex5:

RP      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:50:40   OO ZigZag buffer(0): 1.32657
HQ      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:50:40   OO ZigZag low(0): 1.32657
DI      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:50:59   OO ZigZag buffer(0): 1.32657
RH      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:50:59   OO ZigZag low(0): 1.32657
QR      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:00   OO ZigZag buffer(0): 1.32657
GS      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:00   OO ZigZag low(0): 1.32657
IK      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:20   OO ZigZag buffer(0): 1.32653
GJ      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:20   OO ZigZag low(0): 1.32653
EL      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:40   OO ZigZag buffer(0): 1.32653
OD      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:40   OO ZigZag low(0): 1.32653
OE      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:59   OO ZigZag buffer(0): 1.32653
IO      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:51:59   OO ZigZag low(0): 1.32653
DN      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:52:00   OO ZigZag buffer(0): 1.32653
RF      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:52:00   OO ZigZag low(0): 1.32653
PP      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:52:20   OO ZigZag buffer(0): 1.32653
RQ      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:52:20   OO ZigZag low(0): 1.32653
MI      0       18:48:02        ExpertOOZigZag (EURUSD,H1)      2013.08.01 08:52:40   OO ZigZag buffer(0): 1.32614
// и так далее...

Вывод

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

Сначала мы воспользовались преимуществом повторного использования кода, скачав индикатор ZigZag из Code Base. Загрузив индикатор в терминал MetaTrader 5, мы использовали нисходящий анализ, чтобы начать разработку нашего нового объектно-ориентированного индикатора ZigZag. Мы окинули взглядом всю систему и приступили к подробному анализу. На первом этапе разработки мы сравнили тестовый советник, использующий процедурный индикатор ZigZag, с его объектно-ориентированным аналогом.

Мы добавили в индикатор ZigZag объектно-ориентированный класс, созданный в соответствии с принципами разработки компании MetaQuotes, которые использовались при создании стандартной библиотеки. И наконец, мы провели несколько простых тестов и пришли к выводу, что наш новый CiZigZag, уже интегрированный в MQL5 API, пригоден к использованию.


Перевод с английского произведен MetaQuotes Software Corp.
Оригинальная статья: https://www.mql5.com/en/articles/741

Прикрепленные файлы |
expertoozigzag.mq5 (2.11 KB)
trend.mqh (6.36 KB)
zigzag.mq5 (9.34 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (18)
Tango_X
Tango_X | 17 июл 2017 в 21:09
Rashid Umarov:

Базовый класс CIndicator имеет метод GetData, с помощью которого можно получить данные из индикаторного буфера.

Получает данные из буфера индикатора по стартовой позиции и количеству

int  GetData(
   const int      start_pos,      // позиция
   const int      count,          // количество
   const int      buffer_num,     // номер буфера
   double&        buffer[]        // массив
   ) const



После этого задавайте для вашего массива нужное направление индексации  с помощью ArraySetAsSeries

Я Вас правильно понял???

CiZigZag *Zig;
double ArrZig[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   Zig=new CiZigZag;
   Zig.Create(CurrencyPair,EAPeriod,12,5,3);

   SetIndexBuffer(0,ArrZig,INDICATOR_CALCULATIONS);
   ArraySetAsSeries(ArrZig,false);

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   delete(Zig);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
//---
   int limit;
   if(prev_calculated==0) limit=0;
   else
      limit=prev_calculated-1;

   Zig.Refresh();
   Zig.GetData(0,rates_total-1,0,ArrZig);

   for(int i=limit;i<rates_total-1 && !IsStopped();i++)
     {

      //if (Zig.ZigZag(i)!=0) Print(Zig.ZigZag(i)," ",time[i]);  
      if(ArrZig[i]!=0) Print(ArrZig[i]," ",time[i]);
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
Получается что надо на каждом тике нужно копировать всю историю?
Rashid Umarov
Rashid Umarov | 18 июл 2017 в 09:26
Tango_X:

Я Вас правильно понял???

Получается что надо на каждом тике нужно копировать всю историю?

1. Можно на открытие нового бара

2. А зачем все значения индикатора получать каждый раз, и при этом еще заботиться о направлении индексации? какая вообще задача стоит?

TheXpert
TheXpert | 18 июл 2017 в 10:08

Зачем оборачивать простой индикатор в класс если он используется потом или на графике или через iCustom?

Второе решение лучше, потому что является объектно-ориентированным

ООП ради ООП, ну ок.

Tango_X
Tango_X | 18 июл 2017 в 11:28
Rashid Umarov:

1. Можно на открытие нового бара

2. А зачем все значения индикатора получать каждый раз, и при этом еще заботиться о направлении индексации? какая вообще задача стоит?


Проблему решил по условиям цикла, теперь все работает как хотелось. спасибо!

Tango_X
Tango_X | 18 июл 2017 в 11:31
Комбинатор:

Зачем оборачивать простой индикатор в класс если он используется потом или на графике или через iCustom?

ООП ради ООП, ну ок.


Все верно))

Очень удобно, всем советую
Как заработать на сервисах MetaTrader AppStore и Trading Signals, не являясь продавцом и поставщиком Как заработать на сервисах MetaTrader AppStore и Trading Signals, не являясь продавцом и поставщиком

Начать зарабатывать на MQL5.com, не будучи при этом продавцом программ на Маркете или поставщиком доходных сигналов, можно прямо сейчас. Выбирайте продукты по ключевым для вас критериям и ссылайтесь на них на различных интернет-ресурсах. Зацепите потенциального покупателя - и деньги ваши!

Создание новостного торгового советника Создание новостного торгового советника

Представляю вашему вниманию продолжение статьи "Приобщаемся к объектно-ориентированному программированию в MQL5". Напомню, в статье рассматривалось создание с нуля простого объектно-ориентированного советника, а также были даны некоторые советы по ООП. На этот раз я представлю вам технические основы для создания торгового советника, торгующего на новостях. В своей серии статей я хочу поделиться своими идеями в области ООП, а также раскрыть новую тему – работу с файловой системой.

Рецепты MQL5 - Сохраняем результаты оптимизации торгового эксперта по указанным критериям Рецепты MQL5 - Сохраняем результаты оптимизации торгового эксперта по указанным критериям

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

Итоги MetaTrader AppStore за 3 квартал 2013 года Итоги MetaTrader AppStore за 3 квартал 2013 года

Подошел к концу очередной квартал этого года, и мы решили подвести его итоги для MetaTrader AppStore - магазина торговых роботов и технических индикаторов для платформ MetaTrader. Всего к концу отчетного квартала более 500 разработчиков разместили в Маркете свыше 1 200 продуктов для MetaTrader 4 и MetaTrader 5.