Работа с таймсериями в библиотеке DoEasy (Часть 54): Классы-наследники абстрактного базового индикатора

Artyom Trishkin | 9 октября, 2020

Содержание


Концепция

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


Доработка классов библиотеки

Как обычно, начнём с добавления необходимых текстовых сообщений библиотеки.

В файле \MQL5\Include\DoEasy\Data.mqh впишем индексы новых сообщений:

//--- CIndicatorDE
   MSG_LIB_TEXT_IND_TEXT_STATUS,                      // Статус индикатора
   MSG_LIB_TEXT_IND_TEXT_STATUS_STANDART,             // Стандартный индикатор
   MSG_LIB_TEXT_IND_TEXT_STATUS_CUSTOM,               // Пользовательский индикатор
   
   MSG_LIB_TEXT_IND_TEXT_TYPE,                        // Тип индикатора
   MSG_LIB_TEXT_IND_TEXT_TIMEFRAME,                   // Таймфрейм индикатора
   MSG_LIB_TEXT_IND_TEXT_HANDLE,                      // Хэндл индикатора

   MSG_LIB_TEXT_IND_TEXT_GROUP,                       // Группа индикатора
   MSG_LIB_TEXT_IND_TEXT_GROUP_TREND,                 // Трендовый индикатор
   MSG_LIB_TEXT_IND_TEXT_GROUP_OSCILLATOR,            // Осциллятор
   MSG_LIB_TEXT_IND_TEXT_GROUP_VOLUMES,               // Объёмы
   MSG_LIB_TEXT_IND_TEXT_GROUP_ARROWS,                // Стрелочный индикатор
   
   MSG_LIB_TEXT_IND_TEXT_EMPTY_VALUE,                 // Пустое значение для построения, для которого нет отрисовки
   MSG_LIB_TEXT_IND_TEXT_SYMBOL,                      // Символ индикатора
   MSG_LIB_TEXT_IND_TEXT_NAME,                        // Имя индикатора
   MSG_LIB_TEXT_IND_TEXT_SHORTNAME,                   // Короткое имя индикатора
   
//--- CIndicatorsCollection
   MSG_LIB_SYS_FAILED_ADD_IND_TO_LIST,                // Ошибка. Не удалось добавить объект-индикатор в список
   
  };
//+------------------------------------------------------------------+

и далее впишем новые сообщения, соответствующие вновь добавленным индексам:

   {"Статус индикатора","Indicator status"},
   {"Стандартный индикатор","Standard indicator"},
   {"Пользовательский индикатор","Custom indicator"},
   {"Тип индикатора","Indicator type"},
   {"Таймфрейм индикатора","Indicator timeframe"},
   {"Хэндл индикатора","Indicator handle"},
   {"Группа индикатора","Indicator group"},
   {"Трендовый индикатор","Trend indicator"},
   {"Осциллятор","Solid lineOscillator"},
   {"Объёмы","Volumes"},
   {"Стрелочный индикатор","Arrow indicator"},
   {"Пустое значение для построения, для которого нет отрисовки","Empty value for plotting, for which there is no drawing"},
   {"Символ индикатора","Indicator symbol"},
   {"Имя индикатора","Indicator name"},
   {"Короткое имя индикатора","Indicator shortname"},
   
   {"Ошибка. Не удалось добавить объект-индикатор в список","Error. Failed to add indicator object to list"},
   
  };
//+---------------------------------------------------------------------+

При создании класса объекта абстрактного индикатора в прошлой статье мы не вписали одно из целочисленных свойств объекта — тип стандартного индикатора. Этот тип будет соответствовать типам перечисления ENUM_INDICATOR, и нужен будет для поиска конкретного индикатора.
Если мы хотим найти все индикаторы MACD, хранящиеся в коллекции, то первым делом мы должны получить список всех индикаторов MACD, находящихся в коллекции. Для этого нам необходимо отфильтровать полный список коллекции индикаторов по типу IND_MACD, а уже потом в полученном списке, в котором будут лежать только IND_MACD, делать выбор по другим искомым свойствам.

Допишем новое свойство объекта-индикатора в файл \MQL5\Include\DoEasy\Defines.mqh:

//+------------------------------------------------------------------+
//| Целочисленные свойства индикатора                                |
//+------------------------------------------------------------------+
enum ENUM_INDICATOR_PROP_INTEGER
  {
   INDICATOR_PROP_STATUS = 0,                               // Статус индикатора (из перечисления ENUM_INDICATOR_STATUS)
   INDICATOR_PROP_TYPE,                                     // Тип индикатора (из перечисления ENUM_INDICATOR)
   INDICATOR_PROP_TIMEFRAME,                                // Таймфрейм индикатора
   INDICATOR_PROP_HANDLE,                                   // Хэндл индикатора
   INDICATOR_PROP_GROUP,                                    // Группа индикатора
  }; 
#define INDICATOR_PROP_INTEGER_TOTAL (5)                    // Общее количество целочисленных свойств индикатора
#define INDICATOR_PROP_INTEGER_SKIP  (0)                    // Количество неиспользуемых в сортировке свойств индикатора
//+------------------------------------------------------------------+

и увеличим количество целочисленных свойств с 4 до 5.

При добавлении нового свойства объекту нам нужно задать возможность поиска и сортировки объектов по этому свойству.
Добавим новый критерий сортировки в перечисление:

//+------------------------------------------------------------------+
//| Возможные критерии сортировки индикаторов                            |
//+------------------------------------------------------------------+
#define FIRST_INDICATOR_DBL_PROP          (INDICATOR_PROP_INTEGER_TOTAL-INDICATOR_PROP_INTEGER_SKIP)
#define FIRST_INDICATOR_STR_PROP          (INDICATOR_PROP_INTEGER_TOTAL-INDICATOR_PROP_INTEGER_SKIP+INDICATOR_PROP_DOUBLE_TOTAL-INDICATOR_PROP_DOUBLE_SKIP)
enum ENUM_SORT_INDICATOR_MODE
  {
//--- Сортировка по целочисленным свойствам
   SORT_BY_INDICATOR_INDEX_STATUS = 0,                      // Сортировать по статусу индикатора
   SORT_BY_INDICATOR_TYPE,                                  // Сортировать по типу индикатора
   SORT_BY_INDICATOR_TIMEFRAME,                             // Сортировать по таймфрейму индикатора
   SORT_BY_INDICATOR_HANDLE,                                // Сортировать по хэндлу индикатора
   SORT_BY_INDICATOR_GROUP,                                 // Сортировать по группе индикатора
//--- Сортировка по вещественным свойствам
   SORT_BY_INDICATOR_EMPTY_VALUE = FIRST_INDICATOR_DBL_PROP,// Сортировать по пустому значению для построения, для которого нет отрисовки
//--- Сортировка по строковым свойствам
   SORT_BY_INDICATOR_SYMBOL = FIRST_INDICATOR_STR_PROP,     // Сортировать по символу индикатора
   SORT_BY_INDICATOR_NAME,                                  // Сортировать по имени индикатора
   SORT_BY_INDICATOR_SHORTNAME,                             // Сортировать по короткому имени индикатора
  };
//+------------------------------------------------------------------+

Доработаем класс объекта абстрактного индикатора в файле \MQL5\Include\DoEasy\Objects\Indicators\IndicatorDE.mqh.

Перенесём массив структур параметров индикатора из приватной секции класса в защищённую (этот массив теперь станет доступен классам-наследникам), а в приватной секции объявим переменную для хранения описания типа индикатора:

//+------------------------------------------------------------------+
//| Класс абстрактного индикатора                                    |
//+------------------------------------------------------------------+
class CIndicatorDE : public CBaseObj
  {
protected:
   MqlParam          m_mql_param[];                                              // Массив параметров индикатора
private:
   long              m_long_prop[INDICATOR_PROP_INTEGER_TOTAL];                  // Целочисленные свойства
   double            m_double_prop[INDICATOR_PROP_DOUBLE_TOTAL];                 // Вещественные свойства
   string            m_string_prop[INDICATOR_PROP_STRING_TOTAL];                 // Строковые свойства
   string            m_ind_type;                                                 // Описание типа индикатора
   

В публичную секцию класса впишем два метода — для возврата типа индикатора и для возврата описания типа индикатора:

public:  
//--- Конструктор по умолчанию
                     CIndicatorDE(void){;}
//--- Деструктор
                    ~CIndicatorDE(void);
                     
//--- Устанавливает (1) целочисленное, (2) вещественное и (3) строковое свойство буфера
   void              SetProperty(ENUM_INDICATOR_PROP_INTEGER property,long value)   { this.m_long_prop[property]=value;                                        }
   void              SetProperty(ENUM_INDICATOR_PROP_DOUBLE property,double value)  { this.m_double_prop[this.IndexProp(property)]=value;                      }
   void              SetProperty(ENUM_INDICATOR_PROP_STRING property,string value)  { this.m_string_prop[this.IndexProp(property)]=value;                      }
//--- Возвращает из массива свойств (1) целочисленное, (2) вещественное и (3) строковое свойство буфера
   long              GetProperty(ENUM_INDICATOR_PROP_INTEGER property)        const { return this.m_long_prop[property];                                       }
   double            GetProperty(ENUM_INDICATOR_PROP_DOUBLE property)         const { return this.m_double_prop[this.IndexProp(property)];                     }
   string            GetProperty(ENUM_INDICATOR_PROP_STRING property)         const { return this.m_string_prop[this.IndexProp(property)];                     }
//--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства буфера
   string            GetPropertyDescription(ENUM_INDICATOR_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_INDICATOR_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_INDICATOR_PROP_STRING property);
//--- Возвращает флаг поддержания буфером данного свойства
   virtual bool      SupportProperty(ENUM_INDICATOR_PROP_INTEGER property)          { return true;       }
   virtual bool      SupportProperty(ENUM_INDICATOR_PROP_DOUBLE property)           { return true;       }
   virtual bool      SupportProperty(ENUM_INDICATOR_PROP_STRING property)           { return true;       }

//--- Сравнивает объекты CIndicatorDE между собой по всем возможным свойствам (для сортировки списков по указанному свойству объекта-индикатора)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Сравнивает объекты CIndicatorDE между собой по всем свойствам (для поиска равных объектов-индикаторов)
   bool              IsEqual(CIndicatorDE* compared_obj) const;
                     
//--- Устанавливает (1) группу, (2) пустое значение буферов, (3) имя, (4) короткое имя индикатора
   void              SetGroup(const ENUM_INDICATOR_GROUP group)      { this.SetProperty(INDICATOR_PROP_GROUP,group);                         }
   void              SetEmptyValue(const double value)               { this.SetProperty(INDICATOR_PROP_EMPTY_VALUE,value);                   }
   void              SetName(const string name)                      { this.SetProperty(INDICATOR_PROP_NAME,name);                           }
   void              SetShortName(const string shortname)            { this.SetProperty(INDICATOR_PROP_SHORTNAME,shortname);                 }
   
//--- Возвращает (1) статус, (2) группу, (3) таймфрейм, (4) хэндл, (5) пустое значение буферов, (6) имя, (7) короткое имя, (8) символ, (9) тип индикатора
   ENUM_INDICATOR_STATUS Status(void)                          const { return (ENUM_INDICATOR_STATUS)this.GetProperty(INDICATOR_PROP_STATUS);}
   ENUM_INDICATOR_GROUP  Group(void)                           const { return (ENUM_INDICATOR_GROUP)this.GetProperty(INDICATOR_PROP_GROUP);  }
   ENUM_TIMEFRAMES   Timeframe(void)                           const { return (ENUM_TIMEFRAMES)this.GetProperty(INDICATOR_PROP_TIMEFRAME);   }
   ENUM_INDICATOR    TypeIndicator(void)                       const { return (ENUM_INDICATOR)this.GetProperty(INDICATOR_PROP_TYPE);         }
   int               Handle(void)                              const { return (int)this.GetProperty(INDICATOR_PROP_HANDLE);                  }
   double            EmptyValue(void)                          const { return this.GetProperty(INDICATOR_PROP_EMPTY_VALUE);                  }
   string            Name(void)                                const { return this.GetProperty(INDICATOR_PROP_NAME);                         }
   string            ShortName(void)                           const { return this.GetProperty(INDICATOR_PROP_SHORTNAME);                    }
   string            Symbol(void)                              const { return this.GetProperty(INDICATOR_PROP_SYMBOL);                       }
   
//--- Возвращает описание (1) типа, (2) статуса, (3) группы, (4) таймфрейма, (5) пустого значения индикатора
   string            GetTypeDescription(void)                  const { return m_ind_type;                                                    }
   string            GetStatusDescription(void)                const;
   string            GetGroupDescription(void)                 const;
   string            GetTimeframeDescription(void)             const;
   string            GetEmptyValueDescription(void)            const;
   
//--- Выводит в журнал описание свойств объекта-индикатора (full_prop=true - все свойства, false - только поддерживаемые)
   void              Print(const bool full_prop=false);
//--- Выводит в журнал краткое описание объекта-индикатора (реализация в наследниках)
   virtual void      PrintShort(void) {;}

  };
//+------------------------------------------------------------------+

В закрытом параметрическом конструкторе извлечём подстроку из входного параметра типа индикатора, чтобы оставить только само наименование индикатора (например, из IND_MACD останется только MACD, что и будет описанием типа индикатора), а сам тип индикатора запишем в свойства объекта:

//+------------------------------------------------------------------+
//| Закрытый параметрический конструктор                             |
//+------------------------------------------------------------------+
CIndicatorDE::CIndicatorDE(ENUM_INDICATOR ind_type,
                           string symbol,
                           ENUM_TIMEFRAMES timeframe,
                           ENUM_INDICATOR_STATUS status,
                           ENUM_INDICATOR_GROUP group,
                           string name,
                           string shortname,
                           MqlParam &mql_params[])
  {
//--- Устанавливаем идентификатор коллекции объекту
   this.m_type=COLLECTION_INDICATORS_ID;
//--- Записываем описание типа индикатора
   this.m_ind_type=::StringSubstr(::EnumToString(ind_type),4);
//--- Если размер переданного в конструктор массива параметров больше нуля, то
//--- заполняем массив параметров объекта данными из переданного в конструктор массива
   int count=::ArrayResize(m_mql_param,::ArraySize(mql_params));
   for(int i=0;i<count;i++)
     {
      this.m_mql_param[i].type=mql_params[i].type;
      this.m_mql_param[i].double_value=mql_params[i].double_value;
      this.m_mql_param[i].integer_value=mql_params[i].integer_value;
      this.m_mql_param[i].string_value=mql_params[i].string_value;
     }
//--- Создаём хэндл индикатора
   int handle=::IndicatorCreate(symbol,timeframe,ind_type,count,this.m_mql_param);
   
//--- Сохранение целочисленных свойств
   this.m_long_prop[INDICATOR_PROP_STATUS]                     = status;
   this.m_long_prop[INDICATOR_PROP_TYPE]                       = ind_type;
   this.m_long_prop[INDICATOR_PROP_GROUP]                      = group;
   this.m_long_prop[INDICATOR_PROP_TIMEFRAME]                  = timeframe;
   this.m_long_prop[INDICATOR_PROP_HANDLE]                     = handle;
   
//--- Сохранение вещественных свойств
   this.m_double_prop[this.IndexProp(INDICATOR_PROP_EMPTY_VALUE)]=EMPTY_VALUE;
//--- Сохранение строковых свойств
   this.m_string_prop[this.IndexProp(INDICATOR_PROP_SYMBOL)]   = (symbol==NULL || symbol=="" ? ::Symbol() : symbol);
   this.m_string_prop[this.IndexProp(INDICATOR_PROP_NAME)]     = name;
   this.m_string_prop[this.IndexProp(INDICATOR_PROP_SHORTNAME)]= shortname;
  }
//+------------------------------------------------------------------+

В методе, возвращающем описание целочисленного свойства индикатора, добавим блок кода для возврата описания типа индикатора:

//+------------------------------------------------------------------+
//| Возвращает описание целочисленного свойства индикатора           |
//+------------------------------------------------------------------+
string CIndicatorDE::GetPropertyDescription(ENUM_INDICATOR_PROP_INTEGER property)
  {
   return
     (
      property==INDICATOR_PROP_STATUS        ?  CMessage::Text(MSG_LIB_TEXT_IND_TEXT_STATUS)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetStatusDescription()
         )  :
      property==INDICATOR_PROP_TYPE        ?  CMessage::Text(MSG_LIB_TEXT_IND_TEXT_TYPE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetTypeDescription()
         )  :
      property==INDICATOR_PROP_GROUP          ?  CMessage::Text(MSG_LIB_TEXT_IND_TEXT_GROUP)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetGroupDescription()
         )  :
      property==INDICATOR_PROP_TIMEFRAME     ?  CMessage::Text(MSG_LIB_TEXT_IND_TEXT_TIMEFRAME)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+this.GetTimeframeDescription()
         )  :
      property==INDICATOR_PROP_HANDLE        ?  CMessage::Text(MSG_LIB_TEXT_IND_TEXT_HANDLE)+
         (!this.SupportProperty(property) ?  ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) :
          ": "+(string)this.GetProperty(property)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

Классы объектов индикаторов

Теперь нам предстоит создать объекты-наследники базового абстрактного индикатора, которые будут уточнять всю информацию по создаваемому объекту-индикатору, и именно эти классы и будут служить для создания индикаторов разных типов и получению данных от них.

В каталоге \MQL5\Include\DoEasy\Objects\Indicators\ создадим новую папку Standart, а в ней новый файл IndAC.mqh класса CIndAC стандартного индикатора Accelerator Oscillator, унаследованного от базового класса абстрактного индикатора, файл которого подключен к листингу этого класса.
Так как класс будет небольшим, то сразу же посмотрим его полный листинг:

//+------------------------------------------------------------------+
//|                                                        IndAC.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "..\\IndicatorDE.mqh"
//+------------------------------------------------------------------+
//| Стандартный индикатор Accelerator Oscillator                     |
//+------------------------------------------------------------------+
class CIndAC : public CIndicatorDE
  {
private:

public:
   //--- Конструктор
                     CIndAC(const string symbol,const ENUM_TIMEFRAMES timeframe,MqlParam &mql_param[]) : 
                        CIndicatorDE(IND_AC,symbol,timeframe,
                                     INDICATOR_STATUS_STANDART,
                                     INDICATOR_GROUP_OSCILLATOR,
                                     "Accelerator Oscillator",
                                     "AC("+symbol+","+TimeframeDescription(timeframe)+")",mql_param) {}
   //--- Поддерживаемые свойства индикатора (1) вещественные, (2) целочисленные
   virtual bool      SupportProperty(ENUM_INDICATOR_PROP_DOUBLE property);
   virtual bool      SupportProperty(ENUM_INDICATOR_PROP_INTEGER property);
   
//--- Выводит в журнал краткое описание объекта-индикатора
   virtual void      PrintShort(void);
  };
//+------------------------------------------------------------------+
//| Возвращает истину, если индикатор поддерживает переданное        |
//| целочисленное свойство, возвращает ложь в противном случае       |
//+------------------------------------------------------------------+
bool CIndAC::SupportProperty(ENUM_INDICATOR_PROP_INTEGER property)
  {
   return true;
  }
//+------------------------------------------------------------------+
//| Возвращает истину, если индикатор поддерживает переданное        |
//| вещественное свойство, возвращает ложь в противном случае        |
//+------------------------------------------------------------------+
bool CIndAC::SupportProperty(ENUM_INDICATOR_PROP_DOUBLE property)
  {
   return true;
  }
//+------------------------------------------------------------------+
//| Выводит в журнал краткое описание объекта-индикатора             |
//+------------------------------------------------------------------+
void CIndAC::PrintShort(void)
  {
   ::Print(GetStatusDescription()," ",this.Name()," ",this.Symbol()," ",TimeframeDescription(this.Timeframe()));
  }
//+------------------------------------------------------------------+

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

   //--- Конструктор
                     CIndAC(const string symbol,const ENUM_TIMEFRAMES timeframe,MqlParam &mql_param[]) : 
                        CIndicatorDE(IND_AC,symbol,timeframe,
                                     INDICATOR_STATUS_STANDART,
                                     INDICATOR_GROUP_OSCILLATOR,
                                     "Accelerator Oscillator",
                                     "AC("+symbol+","+TimeframeDescription(timeframe)+")",mql_param) {}

Во входных параметрах класса мы передаём наименование символа, таймфрейма и уже заполненную структуру параметров индикатора (в данном примере — Accelerator Oscillator).
В списке инициализации передаём в закрытый параметрический конструктор родительского класса (по порядку):

Все остальные методы уже нам знакомы по предыдущим создаваемым нами объектам библиотеки, и выполняют точно такие же задачи.
Методы, возвращающие флаг поддержания объектом целочисленных и вещественных свойств, возвращают true — все свойства поддерживаются объектами-индикаторами.
Метод, возвращающий краткое описание индикатора возвращает строку такого типа:

Standard indicator Accelerator Oscillator EURUSD H4

Во всех остальных файлах подобных классов объектов-индикаторов отличие будет только в конструкторе класса — будут передаваться соответствующие индикатору параметры в конструктор родительского класса.

Например, для индикатора Accumulation/Distribution конструктор класса будет выглядеть так:

   //--- Конструктор
                     CIndAD(const string symbol,const ENUM_TIMEFRAMES timeframe,MqlParam &mql_param[]) :
                        CIndicatorDE(IND_AD,symbol,timeframe,
                                     INDICATOR_STATUS_STANDART,
                                     INDICATOR_GROUP_VOLUMES,
                                     "Accumulation/Distribution",
                                     "AD("+symbol+","+TimeframeDescription(timeframe)+")",mql_param) {}

Как видим, здесь уже передаются параметры, соответствующие стандартному индикатору AD:

Все файлы классов-наследников базового класса абстрактного индикатора уже реализованы, и их можно посмотреть самостоятельно в прилагаемых к статье файлах в папке \MQL5\Include\DoEasy\Objects\Indicators\Standart.

Коллекция объектов индикаторов

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

В папке \MQL5\Include\DoEasy\Collections\ создадим новый класс в файле с именем IndicatorsCollection.mqh.

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

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

//+------------------------------------------------------------------+
//|                                         IndicatorsCollection.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "ListObj.mqh"
#include "..\Objects\Indicators\Standart\IndAC.mqh"
#include "..\Objects\Indicators\Standart\IndAD.mqh"
#include "..\Objects\Indicators\Standart\IndADX.mqh"
#include "..\Objects\Indicators\Standart\IndADXW.mqh"
#include "..\Objects\Indicators\Standart\IndAlligator.mqh"
#include "..\Objects\Indicators\Standart\IndAMA.mqh"
#include "..\Objects\Indicators\Standart\IndAO.mqh"
#include "..\Objects\Indicators\Standart\IndATR.mqh"
#include "..\Objects\Indicators\Standart\IndBands.mqh"
#include "..\Objects\Indicators\Standart\IndBears.mqh"
#include "..\Objects\Indicators\Standart\IndBulls.mqh"
#include "..\Objects\Indicators\Standart\IndBWMFI.mqh"
#include "..\Objects\Indicators\Standart\IndCCI.mqh"
#include "..\Objects\Indicators\Standart\IndChaikin.mqh"
#include "..\Objects\Indicators\Standart\IndDEMA.mqh"
#include "..\Objects\Indicators\Standart\IndDeMarker.mqh"
#include "..\Objects\Indicators\Standart\IndEnvelopes.mqh"
#include "..\Objects\Indicators\Standart\IndForce.mqh"
#include "..\Objects\Indicators\Standart\IndFractals.mqh"
#include "..\Objects\Indicators\Standart\IndFRAMA.mqh"
#include "..\Objects\Indicators\Standart\IndGator.mqh"
#include "..\Objects\Indicators\Standart\IndIchimoku.mqh"
#include "..\Objects\Indicators\Standart\IndMA.mqh"
#include "..\Objects\Indicators\Standart\IndMACD.mqh"
#include "..\Objects\Indicators\Standart\IndMFI.mqh"
#include "..\Objects\Indicators\Standart\IndMomentum.mqh"
#include "..\Objects\Indicators\Standart\IndOBV.mqh"
#include "..\Objects\Indicators\Standart\IndOsMA.mqh"
#include "..\Objects\Indicators\Standart\IndRSI.mqh"
#include "..\Objects\Indicators\Standart\IndRVI.mqh"
#include "..\Objects\Indicators\Standart\IndSAR.mqh"
#include "..\Objects\Indicators\Standart\IndStDev.mqh"
#include "..\Objects\Indicators\Standart\IndStoch.mqh"
#include "..\Objects\Indicators\Standart\IndTEMA.mqh"
#include "..\Objects\Indicators\Standart\IndTRIX.mqh"
#include "..\Objects\Indicators\Standart\IndVIDYA.mqh"
#include "..\Objects\Indicators\Standart\IndVolumes.mqh"
#include "..\Objects\Indicators\Standart\IndWPR.mqh"
//+------------------------------------------------------------------+

Далее посмотрим полный листинг тела класса, а затем разберём по два метода каждой из групп.

//+------------------------------------------------------------------+
//| Коллекция индикаторов                                            |
//+------------------------------------------------------------------+
class CIndicatorsCollection : public CObject
  {
private:
   CListObj                m_list;                       // Список объектов-индикаторов
   MqlParam                m_mql_param[];                // Массив параметров индикатора

//--- Создаёт новый объект-индикатор
   CIndicatorDE           *CreateIndicator(const ENUM_INDICATOR ind_type,MqlParam &mql_param[],const string symbol_name=NULL,const ENUM_TIMEFRAMES period=PERIOD_CURRENT);

public:
//--- Возвращает (1) себя, (2) список индикаторов, (3) список индикаторов по типу
   CIndicatorsCollection  *GetObject(void)               { return &this;                                       }
   CArrayObj              *GetList(void)                 { return &this.m_list;                                }
//--- Возвращает список индикаторов по (1) статусу, (2) типу, (3) таймфрейму, (4) группе, (5) символу, (6) имени, (7) короткому имени
   CArrayObj              *GetListIndByStatus(const ENUM_INDICATOR_STATUS status)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_STATUS,status,EQUAL);        }
   CArrayObj              *GetListIndByType(const ENUM_INDICATOR type)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_TYPE,type,EQUAL);            }
   CArrayObj              *GetListIndByTimeframe(const ENUM_TIMEFRAMES timeframe)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_TIMEFRAME,timeframe,EQUAL);  }
   CArrayObj              *GetListIndByGroup(const ENUM_INDICATOR_GROUP group)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_GROUP,group,EQUAL);          }
   CArrayObj              *GetListIndBySymbol(const string symbol)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_SYMBOL,symbol,EQUAL);        }
   CArrayObj              *GetListIndByName(const string name)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_NAME,name,EQUAL);            }
   CArrayObj              *GetListIndByShortname(const string shortname)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_SHORTNAME,shortname,EQUAL);  }
  
//--- Возвращает список объектов-индикаторов по типу индикатора, символу и таймфрейму
   CArrayObj              *GetListAC(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListAD(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListADX(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListADXWilder(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListAMA(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListAO(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListATR(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListBands(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListBearsPower(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListBullsPower(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListChaikin(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListCCI(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListDeMarker(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListForce(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListFractals(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListGator(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListMFI(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListMA(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListMACD(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListOBV(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListSAR(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListRSI(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListRVI(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListStochastic(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListTriX(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListWPR(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListVIDYA(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CArrayObj              *GetListVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe);
   
//--- Возвращает указатель на объект-индикатор в коллекции по типу индикатора и его параметрам
   CIndicatorDE           *GetIndAC(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CIndicatorDE           *GetIndAD(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume);
   CIndicatorDE           *GetIndADX(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period);
   CIndicatorDE           *GetIndADXWilder(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period);
   CIndicatorDE           *GetIndAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int jaw_period,
                                       const int jaw_shift,
                                       const int teeth_period,
                                       const int teeth_shift,
                                       const int lips_period,
                                       const int lips_shift,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndAMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ama_period,
                                       const int fast_ema_period,
                                       const int slow_ema_period,
                                       const int ama_shift,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndAO(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CIndicatorDE           *GetIndATR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period);
   CIndicatorDE           *GetIndBands(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const double deviation,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndBearsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period);
   CIndicatorDE           *GetIndBullsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period);
   CIndicatorDE           *GetIndChaikin(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int fast_ma_period,
                                       const int slow_ma_period,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_VOLUME applied_volume);
   CIndicatorDE           *GetIndCCI(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndDeMarker(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period);
   CIndicatorDE           *GetIndEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_PRICE applied_price,
                                       const double deviation);
   CIndicatorDE           *GetIndForce(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_VOLUME applied_volume);
   CIndicatorDE           *GetIndFractals(const string symbol,const ENUM_TIMEFRAMES timeframe);
   CIndicatorDE           *GetIndFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndGator(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int jaw_period,
                                       const int jaw_shift,
                                       const int teeth_period,
                                       const int teeth_shift,
                                       const int lips_period,
                                       const int lips_shift,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int tenkan_sen,
                                       const int kijun_sen,
                                       const int senkou_span_b);
   CIndicatorDE           *GetIndBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const ENUM_APPLIED_VOLUME applied_volume);
   CIndicatorDE           *GetIndMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int mom_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const ENUM_APPLIED_VOLUME applied_volume);
   CIndicatorDE           *GetIndMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int fast_ema_period,
                                       const int slow_ema_period,
                                       const int signal_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndMACD(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int fast_ema_period,
                                       const int slow_ema_period,
                                       const int signal_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndOBV(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const ENUM_APPLIED_VOLUME applied_volume);
   CIndicatorDE           *GetIndSAR(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const double step,
                                       const double maximum);
   CIndicatorDE           *GetIndRSI(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndRVI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period);
   CIndicatorDE           *GetIndStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndStochastic(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int Kperiod,
                                       const int Dperiod,
                                       const int slowing,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_STO_PRICE price_field);
   CIndicatorDE           *GetIndTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndTriX(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndWPR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int calc_period);
   CIndicatorDE           *GetIndVIDYA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int cmo_period,
                                       const int ema_period,
                                       const int ma_shift,
                                       const ENUM_APPLIED_PRICE applied_price);
   CIndicatorDE           *GetIndVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume);
  
//--- Создаёт новый объект-индикатор по типу индикатора и помещает его в список-коллекцию
   int                     CreateAC(const string symbol,const ENUM_TIMEFRAMES timeframe);
   int                     CreateAD(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume);
   int                     CreateADX(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period);
   int                     CreateADXWilder(const string symbol,const ENUM_TIMEFRAMES timeframe,const int adx_period);
   int                     CreateAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int jaw_period,
                                       const int jaw_shift,
                                       const int teeth_period,
                                       const int teeth_shift,
                                       const int lips_period,
                                       const int lips_shift,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateAMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ama_period,
                                       const int fast_ema_period,
                                       const int slow_ema_period,
                                       const int ama_shift,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateAO(const string symbol,const ENUM_TIMEFRAMES timeframe);
   int                     CreateATR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period);
   int                     CreateBands(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const double deviation,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateBearsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period);
   int                     CreateBullsPower(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period);
   int                     CreateChaikin(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int fast_ma_period,
                                       const int slow_ma_period,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_VOLUME applied_volume);
   int                     CreateCCI(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateDEMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateDeMarker(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period);
   int                     CreateEnvelopes(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_PRICE applied_price,
                                       const double deviation);
   int                     CreateForce(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_VOLUME applied_volume);
   int                     CreateFractals(const string symbol,const ENUM_TIMEFRAMES timeframe);
   int                     CreateFrAMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateGator(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int jaw_period,
                                       const int jaw_shift,
                                       const int teeth_period,
                                       const int teeth_shift,
                                       const int lips_period,
                                       const int lips_shift,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateIchimoku(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int tenkan_sen,
                                       const int kijun_sen,
                                       const int senkou_span_b);
   int                     CreateBWMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const ENUM_APPLIED_VOLUME applied_volume);
   int                     CreateMomentum(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int mom_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateMFI(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const ENUM_APPLIED_VOLUME applied_volume);
   int                     CreateMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateOsMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int fast_ema_period,
                                       const int slow_ema_period,
                                       const int signal_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateMACD(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int fast_ema_period,
                                       const int slow_ema_period,
                                       const int signal_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateOBV(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const ENUM_APPLIED_VOLUME applied_volume);
   int                     CreateSAR(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const double step,
                                       const double maximum);
   int                     CreateRSI(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateRVI(const string symbol,const ENUM_TIMEFRAMES timeframe,const int ma_period);
   int                     CreateStdDev(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateStochastic(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int Kperiod,
                                       const int Dperiod,
                                       const int slowing,
                                       const ENUM_MA_METHOD ma_method,
                                       const ENUM_STO_PRICE price_field);
   int                     CreateTEMA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const int ma_shift,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateTriX(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int ma_period,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateWPR(const string symbol,const ENUM_TIMEFRAMES timeframe,const int calc_period);
   int                     CreateVIDYA(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                       const int cmo_period,
                                       const int ema_period,
                                       const int ma_shift,
                                       const ENUM_APPLIED_PRICE applied_price);
   int                     CreateVolumes(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_APPLIED_VOLUME applied_volume);

//--- Конструктор
                           CIndicatorsCollection();

  };
//+------------------------------------------------------------------+

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

Методы, возвращающие списки с нужными типами индикаторов, стандартны для библиотеки, и много раз нами рассматривались:

//--- Возвращает (1) себя, (2) список индикаторов, (3) список индикаторов по типу
   CIndicatorsCollection  *GetObject(void)               { return &this;                                       }
   CArrayObj              *GetList(void)                 { return &this.m_list;                                }
//--- Возвращает список индикаторов по (1) статусу, (2) типу, (3) таймфрейму, (4) группе, (5) символу, (6) имени, (7) короткому имени
   CArrayObj              *GetListIndByStatus(const ENUM_INDICATOR_STATUS status)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_STATUS,status,EQUAL);        }
   CArrayObj              *GetListIndByType(const ENUM_INDICATOR type)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_TYPE,type,EQUAL);            }
   CArrayObj              *GetListIndByTimeframe(const ENUM_TIMEFRAMES timeframe)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_TIMEFRAME,timeframe,EQUAL);  }
   CArrayObj              *GetListIndByGroup(const ENUM_INDICATOR_GROUP group)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_GROUP,group,EQUAL);          }
   CArrayObj              *GetListIndBySymbol(const string symbol)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_SYMBOL,symbol,EQUAL);        }
   CArrayObj              *GetListIndByName(const string name)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_NAME,name,EQUAL);            }
   CArrayObj              *GetListIndByShortname(const string shortname)
                             { return CSelect::ByIndicatorProperty(this.GetList(),INDICATOR_PROP_SHORTNAME,shortname,EQUAL);  }

В конструкторе класса обнуляем массив структур параметров индикатора, очищаем список-коллекцию, задаём списку флаг сортированного списка и присваиваем ему идентификатор коллекции индикаторов:

//+------------------------------------------------------------------+
//| Конструктор                                                      |
//+------------------------------------------------------------------+
CIndicatorsCollection::CIndicatorsCollection()
  {
   ::ArrayResize(this.m_mql_param,0);
   this.m_list.Clear();
   this.m_list.Sort();
   this.m_list.Type(COLLECTION_INDICATORS_ID);
  }
//+------------------------------------------------------------------+

Приватный метод для создания объекта-индикатора просто создаёт новый объект-индикатор в зависимости от переданного в метод типа создаваемого индикатора и возвращает указатель на созданный объект:

//+------------------------------------------------------------------+
//| Создаёт новый объект-индикатор                                   |
//+------------------------------------------------------------------+
CIndicatorDE *CIndicatorsCollection::CreateIndicator(const ENUM_INDICATOR ind_type,MqlParam &mql_param[],const string symbol_name=NULL,const ENUM_TIMEFRAMES period=PERIOD_CURRENT)
  {
   string symbol=(symbol_name==NULL || symbol_name=="" ? ::Symbol() : symbol_name);
   ENUM_TIMEFRAMES timeframe=(period==PERIOD_CURRENT ? ::Period() : period);
   CIndicatorDE *indicator=NULL;
   switch(ind_type)
     {
      case IND_AC          : indicator=new CIndAC(symbol,timeframe,mql_param);         break;
      case IND_AD          : indicator=new CIndAD(symbol,timeframe,mql_param);         break;
      case IND_ADX         : indicator=new CIndADX(symbol,timeframe,mql_param);        break;
      case IND_ADXW        : indicator=new CIndADXW(symbol,timeframe,mql_param);       break;
      case IND_ALLIGATOR   : indicator=new CIndAlligator(symbol,timeframe,mql_param);  break;
      case IND_AMA         : indicator=new CIndAMA(symbol,timeframe,mql_param);        break;
      case IND_AO          : indicator=new CIndAO(symbol,timeframe,mql_param);         break;
      case IND_ATR         : indicator=new CIndATR(symbol,timeframe,mql_param);        break;
      case IND_BANDS       : indicator=new CIndBands(symbol,timeframe,mql_param);      break;
      case IND_BEARS       : indicator=new CIndBears(symbol,timeframe,mql_param);      break;
      case IND_BULLS       : indicator=new CIndBulls(symbol,timeframe,mql_param);      break;
      case IND_BWMFI       : indicator=new CIndBWMFI(symbol,timeframe,mql_param);      break;
      case IND_CCI         : indicator=new CIndCCI(symbol,timeframe,mql_param);        break;
      case IND_CHAIKIN     : indicator=new CIndCHO(symbol,timeframe,mql_param);        break;
      case IND_DEMA        : indicator=new CIndDEMA(symbol,timeframe,mql_param);       break;
      case IND_DEMARKER    : indicator=new CIndDeMarker(symbol,timeframe,mql_param);   break;
      case IND_ENVELOPES   : indicator=new CIndEnvelopes(symbol,timeframe,mql_param);  break;
      case IND_FORCE       : indicator=new CIndForce(symbol,timeframe,mql_param);      break;
      case IND_FRACTALS    : indicator=new CIndFractals(symbol,timeframe,mql_param);   break;
      case IND_FRAMA       : indicator=new CIndFRAMA(symbol,timeframe,mql_param);      break;
      case IND_GATOR       : indicator=new CIndGator(symbol,timeframe,mql_param);      break;
      case IND_ICHIMOKU    : indicator=new CIndIchimoku(symbol,timeframe,mql_param);   break;
      case IND_MA          : indicator=new CIndMA(symbol,timeframe,mql_param);         break;
      case IND_MACD        : indicator=new CIndMACD(symbol,timeframe,mql_param);       break;
      case IND_MFI         : indicator=new CIndMFI(symbol,timeframe,mql_param);        break;
      case IND_MOMENTUM    : indicator=new CIndMomentum(symbol,timeframe,mql_param);   break;
      case IND_OBV         : indicator=new CIndOBV(symbol,timeframe,mql_param);        break;
      case IND_OSMA        : indicator=new CIndOsMA(symbol,timeframe,mql_param);       break;
      case IND_RSI         : indicator=new CIndRSI(symbol,timeframe,mql_param);        break;
      case IND_RVI         : indicator=new CIndRVI(symbol,timeframe,mql_param);        break;
      case IND_SAR         : indicator=new CIndSAR(symbol,timeframe,mql_param);        break;
      case IND_STDDEV      : indicator=new CIndStDev(symbol,timeframe,mql_param);      break;
      case IND_STOCHASTIC  : indicator=new CIndStoch(symbol,timeframe,mql_param);      break;
      case IND_TEMA        : indicator=new CIndTEMA(symbol,timeframe,mql_param);       break;
      case IND_TRIX        : indicator=new CIndTRIX(symbol,timeframe,mql_param);       break;
      case IND_VIDYA       : indicator=new CIndVIDYA(symbol,timeframe,mql_param);      break;
      case IND_VOLUMES     : indicator=new CIndVolumes(symbol,timeframe,mql_param);    break;
      case IND_WPR         : indicator=new CIndWPR(symbol,timeframe,mql_param);        break;
      
      case IND_CUSTOM : break;
      default: break;
     }
   return indicator;
  }
//+------------------------------------------------------------------+

По умолчанию, а также временно и для пользовательского индикатора (его создание будет реализовано в последующих статьях) метод возвращает NULL.

Метод, создающий объект-индикатор Accelerator Oscillator:

//+------------------------------------------------------------------+
//| Создаёт новый объект-индикатор Accelerator Oscillator            |
//| и помещает его в список-коллекцию                                |
//+------------------------------------------------------------------+
int CIndicatorsCollection::CreateAC(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
//--- У индикатора AC нет параметров - обнуляем размер массива структур параметров
   ::ArrayResize(this.m_mql_param,0);
//--- Создаём объект-индикатор
   CIndicatorDE *indicator=this.CreateIndicator(IND_AC,this.m_mql_param,symbol,timeframe);
   if(indicator==NULL)
      return INVALID_HANDLE;
   int index=this.m_list.Search(indicator);
//--- Если такой индикатор уже есть в списке
   if(index!=WRONG_VALUE)
     {
      //--- Получаем объект-индикатор из списка и возвращаем хэндл индикатора
      indicator=this.m_list.At(index);
      return indicator.Handle();
     }
//--- Если такого индикатора нет в списке
   else
     {
      //--- Если не удалось добавить объект-индикатор в список
      //--- выводим об этом сообщение и возвращаем INVALID_HANDLE
      if(!this.m_list.Add(indicator))
        {
         Print(CMessage::Text(MSG_LIB_SYS_FAILED_ADD_IND_TO_LIST));
         return INVALID_HANDLE;
        }
      //--- Возвращаем хэндл добавленного в список нового индикатора
      return indicator.Handle();
     }
//--- Возвращаем INVALID_HANDLE
   return INVALID_HANDLE;
  }
//+------------------------------------------------------------------+

Логика метода описана в его листинге, и думаю, вопросов не должна вызывать. Отметим, что объект-индикатор создаётся в методе его создания CreateIndicator(), рассмотренного нами выше. В метод передаётся тип индикатора IND_AC. Так как у индикатора AC нет никаких входных параметров, то и массив структур параметров индикатора здесь не нужен. Поэтому массив обнуляется, что указывает на ненужность его использования при создании индикатора в классе CIndicatorDE, рассмотренного нами в прошлой статье.

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

Для примера рассмотрим метод создания индикатора Alligator, где требуются восемь входных параметров, и все они записываются в массив параметров индикатора в соответствии с порядком следования этих параметров у индикатора Alligator и в метод создания объекта-индикатора передаётся тип IND_ALLIGATOR:

//+------------------------------------------------------------------+
//| Создаёт новый объект-индикатор Alligator                         |
//| и помещает его в список-коллекцию                                |
//+------------------------------------------------------------------+
int CIndicatorsCollection::CreateAlligator(const string symbol,const ENUM_TIMEFRAMES timeframe,
                                           const int jaw_period,
                                           const int jaw_shift,
                                           const int teeth_period,
                                           const int teeth_shift,
                                           const int lips_period,
                                           const int lips_shift,
                                           const ENUM_MA_METHOD ma_method,
                                           const ENUM_APPLIED_PRICE applied_price)
  {
//--- Записываем в массив структур параметров необходимые параметры индикатора
   ::ArrayResize(this.m_mql_param,8);
   this.m_mql_param[0].type=TYPE_INT;
   this.m_mql_param[0].integer_value=jaw_period;
   this.m_mql_param[1].type=TYPE_INT;
   this.m_mql_param[1].integer_value=jaw_shift;
   this.m_mql_param[2].type=TYPE_INT;
   this.m_mql_param[2].integer_value=teeth_period;
   this.m_mql_param[3].type=TYPE_INT;
   this.m_mql_param[3].integer_value=teeth_shift;
   this.m_mql_param[4].type=TYPE_INT;
   this.m_mql_param[4].integer_value=lips_period;
   this.m_mql_param[5].type=TYPE_INT;
   this.m_mql_param[5].integer_value=lips_shift;
   this.m_mql_param[6].type=TYPE_INT;
   this.m_mql_param[6].integer_value=ma_method;
   this.m_mql_param[7].type=TYPE_INT;
   this.m_mql_param[7].integer_value=applied_price;
//--- Создаём объект-индикатор
   CIndicatorDE *indicator=this.CreateIndicator(IND_ALLIGATOR,this.m_mql_param,symbol,timeframe);
   if(indicator==NULL)
      return INVALID_HANDLE;
   int index=this.m_list.Search(indicator);
//--- Если такой индикатор уже есть в списке
   if(index!=WRONG_VALUE)
     {
      //--- Получаем объект-индикатор из списка и возвращаем хэндл индикатора
      indicator=this.m_list.At(index);
      return indicator.Handle();
     }
//--- Если такого индикатора нет в списке
   else
     {
      //--- Если не удалось добавить объект-индикатор в список
      //--- выводим об этом сообщение и возвращаем INVALID_HANDLE
      if(!this.m_list.Add(indicator))
        {
         Print(CMessage::Text(MSG_LIB_SYS_FAILED_ADD_IND_TO_LIST));
         return INVALID_HANDLE;
        }
      //--- Возвращаем хэндл добавленного в список нового индикатора
      return indicator.Handle();
     }
//--- Возвращаем INVALID_HANDLE
   return INVALID_HANDLE;
  }
//+------------------------------------------------------------------+

Это все отличия каждого метода друг от друга. Остальные методы создания индикаторов рассматривать не будем — они есть в прилагаемых к статье файлах.

Метод, возвращающий список всех объектов-индикаторов Accelerator Oscillator, находящихся в списке-коллекции, по символу и таймфрейму:

//+------------------------------------------------------------------+
//| Возвращает список объектов-индикаторов Accelerator Oscillator    |
//| по символу и таймфрейму                                          |
//+------------------------------------------------------------------+
CArrayObj *CIndicatorsCollection::GetListAC(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CArrayObj *list=GetListIndByType(IND_AC);
   list=CSelect::ByIndicatorProperty(list,INDICATOR_PROP_SYMBOL,symbol,EQUAL);
   return CSelect::ByIndicatorProperty(list,INDICATOR_PROP_TIMEFRAME,timeframe,EQUAL);
  }
//+------------------------------------------------------------------+

Сначала получаем список всех объектов-индикаторов Accelerator Oscillator, находящихся в списке-коллекции,
затем фильтруем полученный список по символу
и возвращаем полученный список, ещё раз отфильтрованный уже по таймфрейму.

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

Например, для получения списка всех объектов-индикаторов Accumulation/Distribution, находящихся в списке-коллекции, по символу и таймфрейму, метод будет таким:

//+------------------------------------------------------------------+
//| Возвращает список объектов-индикаторов Accumulation/Distribution |
//| по символу и таймфрейму                                          |
//+------------------------------------------------------------------+
CArrayObj *CIndicatorsCollection::GetListAD(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CArrayObj *list=GetListIndByType(IND_AD);
   list=CSelect::ByIndicatorProperty(list,INDICATOR_PROP_SYMBOL,symbol,EQUAL);
   return CSelect::ByIndicatorProperty(list,INDICATOR_PROP_TIMEFRAME,timeframe,EQUAL);
  }
//+------------------------------------------------------------------+

Здесь сначала получаем список всех индикаторов AD, находящихся в коллекции, и далее фильтруем список по символу и таймфрейму как и в вышерассмотренном методе.

Метод, возвращающий указатель на объект-индикатор в коллекции по типу индикатора и его параметрам сегодня реализуем только один — для индикатора Accelerator Oscillator:

//+------------------------------------------------------------------+
//| Возвращает указатель на объект-индикатор Accelerator Oscillator  |
//+------------------------------------------------------------------+
CIndicatorDE *CIndicatorsCollection::GetIndAC(const string symbol,const ENUM_TIMEFRAMES timeframe)
  {
   CArrayObj *list=GetListAC(symbol,timeframe);
   return(list==NULL || list.Total()==0 ? NULL : list.At(0));
  }
//+------------------------------------------------------------------+

Так как этот индикатор (и некоторые другие) не имеет входных параметров, то при выборе его из списка-коллекции по символу и таймфрейму, в списке будет содержаться только один объект-индикатор (по индексу 0), соответствующий типу IND_AC и запрошенным символу и таймфрейму.
Те же индикаторы, у которых имеются входные параметры, требуют для реализации их поиска по указанным параметрам дополнительных методов поиска по массиву структур параметров индикатора, и это уже выйдет за пределы размера данной статьи. Поэтому такие методы будут рассмотрены в следующей.

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

//+------------------------------------------------------------------+
//| Создаёт мультисимвольный мультипериодный AC                      |
//+------------------------------------------------------------------+
int CBuffersCollection::CreateAC(const string symbol,const ENUM_TIMEFRAMES timeframe,const int id=WRONG_VALUE)
  {
//--- Для проверки создаём объёкт-индикатор, выводим его данные и сразу удаляем
   ::ArrayResize(this.m_mql_param,0);
   CIndicatorDE *indicator=new CIndicatorDE(IND_AC,symbol,timeframe,INDICATOR_STATUS_STANDART,INDICATOR_GROUP_OSCILLATOR,"Accelerator Oscillator","AC("+symbol+","+TimeframeDescription(timeframe)+")",this.m_mql_param);
   indicator.Print();
   delete indicator;

//--- Создаём хэндл индикатора и устанавливаем идентификатор по умолчанию

Cегодня мы сделаем точно так же — в этом же методе создадим объект индикатора Accelerator Oscillator, но уже при помощи вновь написанных классов.

Забегая наперёд скажу: нам необходимо будет "видеть" список-коллекцию в классе коллекции таймсерий для того, чтобы нам открылась возможность хранения данных всех создаваемых индикаторов в объектах-барах, которые "лежат" в списках таймсерий.
Поэтому предварительно нам нужно подключить к классу коллекции таймсерий класс-коллекцию индикаторов в файле \MQL5\Include\DoEasy\Collections\TimeSeriesCollection.mqh:

//+------------------------------------------------------------------+
//|                                         TimeSeriesCollection.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "ListObj.mqh"
#include "..\Objects\Series\TimeSeriesDE.mqh"
#include "..\Objects\Symbols\Symbol.mqh"
#include "IndicatorsCollection.mqh"
//+------------------------------------------------------------------+

Далее в приватной секции класса объявим указатель на класс-коллекцию индикаторов:

//+------------------------------------------------------------------+
//| Коллекция таймсерий символов                                     |
//+------------------------------------------------------------------+
class CTimeSeriesCollection : public CBaseObjExt
  {
private:
   CListObj                m_list;                    // Список используемых таймсерий символов
   CIndicatorsCollection  *m_indicators;              // Указатель на объект-коллекцию индикаторов
//--- Возвращает индекс таймсерии по имени символа
   int                     IndexTimeSeries(const string symbol);
public:

И в конце листинга класса создадим метод инициализации, через который будем передавать в класс указатель на объект коллекции индикаторов в главном объекте библиотеки CEngine:

//--- Конструктор
                           CTimeSeriesCollection();
//--- Получение указателей на коллекцию индикаторов (метод вызывается в методе CollectionOnInit() объекта CEngine)
   void                    OnInit(CIndicatorsCollection *indicators) { this.m_indicators=indicators;  }
  };
//+------------------------------------------------------------------+

В файле класса-коллекции буферов \MQL5\Include\DoEasy\Collections\BuffersCollection.mqh так же объявим указатель на объект коллекции индикаторов:

//+------------------------------------------------------------------+
//| Коллекция индикаторных буферов                                   |
//+------------------------------------------------------------------+
class CBuffersCollection : public CObject
  {
private:
   CListObj                m_list;                       // Список объектов-буферов
   CTimeSeriesCollection  *m_timeseries;                 // Указатель на объект-коллекцию таймсерий
   CIndicatorsCollection  *m_indicators;                 // Указатель на объект-коллекцию индикаторов
   MqlParam                m_mql_param[];                // Массив параметров индикатора
//--- Возвращает индекс (1) последнего, (2) следующего рисуемого, (3) базового буфера
   int                     GetIndexLastPlot(void);
   int                     GetIndexNextPlot(void);
   int                     GetIndexNextBase(void);
//--- Создаёт новый объект-буфер и помещает его в список-коллекцию
   bool                    CreateBuffer(ENUM_BUFFER_STATUS status);
//--- Получает данные нужных таймсерий и баров для работы с одним баром буфера, возвращает количество баров
   int                     GetBarsData(CBuffer *buffer,const int series_index,int &index_bar_period);

public:

В метод класса OnInit() допишем присвоение этому указателю значения, передаваемого входным параметром:

//--- Конструктор
                           CBuffersCollection();
//--- Получение указателей на коллекции таймсерий и индикаторов (метод вызывается в методе CollectionOnInit() объекта CEngine)
   void                    OnInit(CTimeSeriesCollection *timeseries,CIndicatorsCollection *indicators)
                             { this.m_timeseries=timeseries; this.m_indicators=indicators;   }
  };
//+------------------------------------------------------------------+

И в методе создания индикатора AC изменим создание объекта-индикатора, сделанное нами в прошлой статье на его создание и получение при помощи класса-коллекции индикаторов:

//+------------------------------------------------------------------+
//| Создаёт мультисимвольный мультипериодный AC                      |
//+------------------------------------------------------------------+
int CBuffersCollection::CreateAC(const string symbol,const ENUM_TIMEFRAMES timeframe,const int id=WRONG_VALUE)
  {
//--- Для проверки создаём объёкт-индикатор, выводим его данные и сразу удаляем
//--- Параметры не нужны для AC, поэтому обнуляем массив структур параметров индикатора
   ::ArrayResize(this.m_mql_param,0);
//--- Создаём индикатор AC и добавляем его в коллекцию
   this.m_indicators.CreateAC(symbol,timeframe);
//--- Получаем из коллекции объект-индикатора AC
   CIndicatorDE *indicator=this.m_indicators.GetIndAC(symbol,timeframe);
//--- Выводим в журнал все данные созданного индикатора, выводим его краткое описание и удаляем объект-индикатор
   indicator.Print();
   indicator.PrintShort();
   delete indicator;

//--- Создаём хэндл индикатора и устанавливаем идентификатор по умолчанию

Теперь доработаем класс главного объекта библиотеки CEngine.
В файле \MQL5\Include\DoEasy\Engine.mqh пропишем подключение к листингу класса файла коллекции индикаторов:

//+------------------------------------------------------------------+
//|                                                       Engine.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "Services\TimerCounter.mqh"
#include "Collections\HistoryCollection.mqh"
#include "Collections\MarketCollection.mqh"
#include "Collections\EventsCollection.mqh"
#include "Collections\AccountsCollection.mqh"
#include "Collections\SymbolsCollection.mqh"
#include "Collections\ResourceCollection.mqh"
#include "Collections\TimeSeriesCollection.mqh"
#include "Collections\BuffersCollection.mqh"
#include "Collections\IndicatorsCollection.mqh"
#include "TradingControl.mqh"
//+------------------------------------------------------------------+

В приватной секции класса объявим объект класса-коллекции индикаторов:

//+------------------------------------------------------------------+
//| Класс-основа библиотеки                                          |
//+------------------------------------------------------------------+
class CEngine
  {
private:
   CHistoryCollection   m_history;                       // Коллекция исторических ордеров и сделок
   CMarketCollection    m_market;                        // Коллекция рыночных ордеров и сделок
   CEventsCollection    m_events;                        // Коллекция событий
   CAccountsCollection  m_accounts;                      // Коллекция аккаунтов
   CSymbolsCollection   m_symbols;                       // Коллекция символов
   CTimeSeriesCollection m_time_series;                  // Коллекция таймсерий
   CBuffersCollection   m_buffers;                       // Коллекция индикаторных буферов
   CIndicatorsCollection m_indicators;                   // Коллекция индикаторов
   CResourceCollection  m_resource;                      // Список ресурсов
   CTradingControl      m_trading;                       // Объект управления торговлей
   CPause               m_pause;                         // Объект "Пауза"
   CArrayObj            m_list_counters;                 // Список счётчиков таймера
   int                  m_global_error;                  // Код глобальной ошибки
   bool                 m_first_start;                   // Флаг первого запуска
   bool                 m_is_hedge;                      // Флаг хедж-счёта
   bool                 m_is_tester;                     // Флаг работы в тестере
   bool                 m_is_market_trade_event;         // Флаг торгового события на счёте
   bool                 m_is_history_trade_event;        // Флаг торгового события в истории счёта
   bool                 m_is_account_event;              // Флаг события изменения аккаунта
   bool                 m_is_symbol_event;               // Флаг события изменения свойств символа
   ENUM_TRADE_EVENT     m_last_trade_event;              // Последнее торговое событие на счёте
   int                  m_last_account_event;            // Последнее событие в свойствах счёта
   int                  m_last_symbol_event;             // Последнее событие в свойствах символа
   ENUM_PROGRAM_TYPE    m_program;                       // Тип программы
   string               m_name;                          // Имя программы
//--- Возвращает индекс счётчика по id
   int                  CounterIndex(const int id) const;
//--- Возвращает флаг первого запуска
   bool                 IsFirstStart(void);
//--- Работа с событиями (1) ордеров, сделок и позиций, (2) аккаунтов
   void                 TradeEventsControl(void);
   void                 AccountEventsControl(void);
//--- (1) Работа с коллекцией символов и (2) событиями списка символов в окне обзора рынка
   void                 SymbolEventsControl(void);
   void                 MarketWatchEventsControl(void);
//--- Возвращает последний (1) рыночный отложенный ордер, (2) маркет-ордер, (3) последнюю позицию, (4) позицию по тикету
   COrder              *GetLastMarketPending(void);
   COrder              *GetLastMarketOrder(void);
   COrder              *GetLastPosition(void);
   COrder              *GetPosition(const ulong ticket);
//--- Возвращает последний (1) удалённый отложенный ордер, (2) исторический маркет-ордер, (3) исторический ордер (маркет или отложенный) по его тикету
   COrder              *GetLastHistoryPending(void);
   COrder              *GetLastHistoryOrder(void);
   COrder              *GetHistoryOrder(const ulong ticket);
//--- Возвращает (1) первый и (2) последний исторический маркет-ордер из списка всех ордеров позиции, (3) последнюю сделку
   COrder              *GetFirstOrderPosition(const ulong position_id);
   COrder              *GetLastOrderPosition(const ulong position_id);
   COrder              *GetLastDeal(void);
//--- Извлекает нужное ushort-число из упакованного long-значения
   ushort               LongToUshortFromByte(const long source_value,const uchar index) const;
   
public:

В публичной секции напишем два метода для возврата указателя на объект-коллекции индикаторов и указателя на список индикаторов этой коллекции:

//--- Возвращает индекс бара на графике указанного таймфрейма по индексу бара текущего графика
   int                  IndexBarPeriodByBarCurrent(const int series_index,const string symbol,const ENUM_TIMEFRAMES timeframe)
                          { return this.m_time_series.IndexBarPeriodByBarCurrent(series_index,symbol,timeframe);  }
                          
//--- Возвращает (1) коллекцию индикаторов, (2) список индикаторов из коллекции 
   CIndicatorsCollection *GetIndicatorsCollection(void)                                { return &this.m_indicators;           }
   CArrayObj           *GetListIndicators(void)                                        { return this.m_indicators.GetList();  }

Эти методы нам пригодятся для обращения к коллекции индикаторов из своих программ.

Допишем в метод CollectionOnInit() передачу указателя на коллекцию индикаторов в классы-коллекции буферов и таймсерий:

//--- Передаёт в торговый класс и класс-коллекцию индикаторных буферов указатели на все необходимые коллекции
   void                 CollectionOnInit(void)
                          {
                           this.m_trading.OnInit(this.GetAccountCurrent(),m_symbols.GetObject(),m_market.GetObject(),m_history.GetObject(),m_events.GetObject());
                           this.m_buffers.OnInit(this.m_time_series.GetObject(),this.m_indicators.GetObject());
                           this.m_time_series.OnInit(this.m_indicators.GetObject());
                          }

Теперь при инициализации библиотеки во все классы, где требуется доступ к коллекции индикаторов, будет передан указатель на объект коллекции индикаторов, и они смогут работать с этой коллекцией.

На сегодня это все необходимые доработки для создания класса-коллекции индикаторов.

Тестирование

Для тестирования нам потребуется индикатор из прошлой статьи без каких-либо изменений.
Просто сохраним его в новой папке \MQL5\Indicators\TestDoEasy\Part54\ под новым именем TestDoEasyPart54.mq5.

Скомпилируем индикатор и запустим его на графике.
В журнал будут выведены полностью все параметры созданного индикатора Accelerator Oscillator , а затем его краткое описание:

Счёт 8550475: Artyom Trishkin (MetaQuotes Software Corp.) 10425.23 USD, 1:100, Hedge, Демонстрационный счёт MetaTrader 5
--- Инициализация библиотеки "DoEasy" ---
Работа только с текущим символом. Количество используемых символов: 1
"EURUSD"
Работа с заданным списком таймфреймов:
"H4" "H1"
Таймсерия символа EURUSD: 
- Таймсерия "EURUSD" H1: Запрошено: 1000, Фактически: 0, Создано: 0, На сервере: 0
- Таймсерия "EURUSD" H4: Запрошено: 1000, Фактически: 1000, Создано: 1000, На сервере: 6231
Время инициализации библиотеки: 00:00:00.156
 
============= Начало списка параметров: "Стандартный индикатор" =============
Статус индикатора: Стандартный индикатор
Тип индикатора: AC
Таймфрейм индикатора: H4
Хэндл индикатора: 10
Группа индикатора: Осциллятор
------
Пустое значение для построения, для которого нет отрисовки: EMPTY_VALUE
------
Символ индикатора: EURUSD
Имя индикатора: "Accelerator Oscillator"
Короткое имя индикатора: "AC(EURUSD,H4)"
================== Конец списка параметров: "Стандартный индикатор" ==================
 
Стандартный индикатор Accelerator Oscillator EURUSD H4
Буфер(P0/B0/C1): Гистограмма от нулевой линии EURUSD H4
Буфер[P0/B2/C2]: Расчётный буфер
Таймсерия "EURUSD" H1 создана успешно:
- Таймсерия "EURUSD" H1: Запрошено: 1000, Фактически: 1000, Создано: 1000, На сервере: 6256


Что дальше

В следующей статье продолжим работу над классом-коллекцией индикаторов.

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

К содержанию

Статьи этой серии:

Работа с таймсериями в библиотеке DoEasy (Часть 35): Объект "Бар" и список-таймсерия символа
Работа с таймсериями в библиотеке DoEasy (Часть 36): Объект таймсерий всех используемых периодов символа
Работа с таймсериями в библиотеке DoEasy (Часть 37): Коллекция таймсерий - база данных таймсерий по символам и периодам
Работа с таймсериями в библиотеке DoEasy (Часть 38): Коллекция таймсерий - реалтайм обновление и доступ к данным из программы
Работа с таймсериями в библиотеке DoEasy (Часть 39): Индикаторы на основе библиотеки - подготовка данных и события таймсерий
Работа с таймсериями в библиотеке DoEasy (Часть 40): Индикаторы на основе библиотеки - реалтайм обновление данных
Работа с таймсериями в библиотеке DoEasy (Часть 41): Пример мультисимвольного мультипериодного индикатора
Работа с таймсериями в библиотеке DoEasy (Часть 42): Класс объекта абстрактного индикаторного буфера
Работа с таймсериями в библиотеке DoEasy (Часть 43): Классы объектов индикаторных буферов
Работа с таймсериями в библиотеке DoEasy (Часть 44): Класс-коллекция объектов индикаторных буферов
Работа с таймсериями в библиотеке DoEasy (Часть 45): Мультипериодные индикаторные буферы
Работа с таймсериями в библиотеке DoEasy (Часть 46): Мультипериодные, мультисимвольные индикаторные буферы
Работа с таймсериями в библиотеке DoEasy (Часть 47): Мультипериодные мультисимвольные стандартные индикаторы
Работа с таймсериями в библиотеке DoEasy (Часть 48): Мультипериодные мультисимвольные индикаторы на одном буфере в подокне
Работа с таймсериями в библиотеке DoEasy (Часть 49): Мультипериодные мультисимвольные многобуферные стандартные индикаторы
Работа с таймсериями в библиотеке DoEasy (Часть 50): Мультипериодные мультисимвольные стандартные индикаторы со смещением
Работа с таймсериями в библиотеке DoEasy (Часть 51): Составные мультипериодные мультисимвольные стандартные индикаторы
Работа с таймсериями в библиотеке DoEasy (Часть 52): Кроссплатформенность мультипериодных мультисимвольных однобуферных стандартных индикаторов
Работа с таймсериями в библиотеке DoEasy (Часть 53): Класс абстрактного базового индикатора