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

laplacianlab | 23 сентября, 2013

Введение

Стандартная библиотека 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 значительно упрощается по сравнению с его процедурным аналогом. Тем не менее, позвольте кратко перечислить преимущества при работе с объектно-ориентированной библиотекой:

Рис 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, представленных в начале данной статьи, в Тестере стратегий со следующим набором параметров:

Поскольку оба советника показывают одинаковые результаты, мы можем заключить, что интеграция нашего 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, пригоден к использованию.