Библиотека для простого и быстрого создания программ для MetaTrader (Часть XIV): Объект "Символ"

Artyom Trishkin | 25 июня, 2019

Содержание


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

Объект-символ

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

Объекты-символы разделим на категории:

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

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

Но всё это — позже, при создании коллекции объектов-символов, сейчас нам необходимо заняться созданием базового объекта-символа.

Начнём с определения перечислений и макроподстановок для свойств объекта-символа. Откроем файл Defines.mqh и в конце листинга впишем необходимые данные для работы с символом:

//+------------------------------------------------------------------+
//| Данные для работы с символами                                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Тип (статус) абстрактного символа                                |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_STATUS
  {
   SYMBOL_STATUS_FX,                                        // Форекс символ
   SYMBOL_STATUS_FX_MAJOR,                                  // Форекс символ-мажор
   SYMBOL_STATUS_FX_MINOR,                                  // Форекс символ-минор
   SYMBOL_STATUS_FX_EXOTIC,                                 // Форекс символ-экзотик
   SYMBOL_STATUS_FX_RUB,                                    // Форекс символ/рубль
   SYMBOL_STATUS_FX_METAL,                                  // Металл
   SYMBOL_STATUS_INDEX,                                     // Индекс
   SYMBOL_STATUS_INDICATIVE,                                // Индикатив
   SYMBOL_STATUS_CRYPTO,                                    // Криптовалютный символ
   SYMBOL_STATUS_COMMODITY,                                 // Товарный символ
   SYMBOL_STATUS_EXCHANGE,                                  // Биржевой символ
   SYMBOL_STATUS_BIN_OPTION,                                // Бинарный опцион
   SYMBOL_STATUS_CUSTOM,                                    // Пользовательский символ
  };
//+------------------------------------------------------------------+

Статусом символа будет являться его принадлежность к категории символа, которая будет выбираться перед созданием объекта-наследника от базового объекта-символа. Этим займёмся при описании создания коллекции символов.

Впишем целочисленные свойства символа:

//+------------------------------------------------------------------+
//| Целочисленные свойства символа                                   |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_PROP_INTEGER
  {
   SYMBOL_PROP_STATUS = 0,                                  // Статус символа
   SYMBOL_PROP_CUSTOM,                                      // Признак того, что символ является пользовательским
   SYMBOL_PROP_CHART_MODE,                                  // Тип цены для построения баров – Bid или Last (из перечисления ENUM_SYMBOL_CHART_MODE)
   SYMBOL_PROP_EXIST,                                       // Признак того, что символ с таким именем существует
   SYMBOL_PROP_SELECT,                                      // Признак того, что символ выбран в Market Watch
   SYMBOL_PROP_VISIBLE,                                     // Признак того, что выбранный символ отображается в Market Watch
   SYMBOL_PROP_SESSION_DEALS,                               // Количество сделок в текущей сессии 
   SYMBOL_PROP_SESSION_BUY_ORDERS,                          // Общее число ордеров на покупку в текущий момент
   SYMBOL_PROP_SESSION_SELL_ORDERS,                         // Общее число ордеров на продажу в текущий момент
   SYMBOL_PROP_VOLUME,                                      // Volume - объем в последней сделке
   SYMBOL_PROP_VOLUMEHIGH,                                  // Максимальный Volume за день
   SYMBOL_PROP_VOLUMELOW,                                   // Минимальный Volume за день
   SYMBOL_PROP_TIME,                                        // Время последней котировки
   SYMBOL_PROP_DIGITS,                                      // Количество знаков после запятой
   SYMBOL_PROP_DIGITS_LOTS,                                 // Количество знаков после запятой для лота
   SYMBOL_PROP_SPREAD,                                      // Размер спреда в пунктах
   SYMBOL_PROP_SPREAD_FLOAT,                                // Признак плавающего спреда
   SYMBOL_PROP_TICKS_BOOKDEPTH,                             // Максимальное количество показываемых заявок в стакане
   SYMBOL_PROP_TRADE_CALC_MODE,                             // Способ вычисления стоимости контракта (из перечисления ENUM_SYMBOL_CALC_MODE)
   SYMBOL_PROP_TRADE_MODE,                                  // Тип исполнения ордеров (из перечисления ENUM_SYMBOL_TRADE_MODE)
   SYMBOL_PROP_START_TIME,                                  // Дата начала торгов по инструменту (обычно используется для фьючерсов)
   SYMBOL_PROP_EXPIRATION_TIME,                             // Дата окончания торгов по инструменту (обычно используется для фьючерсов)
   SYMBOL_PROP_TRADE_STOPS_LEVEL,                           // Минимальный отступ в пунктах от текущей цены закрытия для установки Stop ордеров
   SYMBOL_PROP_TRADE_FREEZE_LEVEL,                          // Дистанция заморозки торговых операций (в пунктах)
   SYMBOL_PROP_TRADE_EXEMODE,                               // Режим заключения сделок (из перечисления ENUM_SYMBOL_TRADE_EXECUTION)
   SYMBOL_PROP_SWAP_MODE,                                   // Модель расчета свопа (из перечисления ENUM_SYMBOL_SWAP_MODE)
   SYMBOL_PROP_SWAP_ROLLOVER3DAYS,                          // День недели для начисления тройного свопа (из перечисления ENUM_DAY_OF_WEEK)
   SYMBOL_PROP_MARGIN_HEDGED_USE_LEG,                       // Режим расчета хеджированной маржи по наибольшей стороне (Buy или Sell)
   SYMBOL_PROP_EXPIRATION_MODE,                             // Флаги разрешенных режимов истечения ордера
   SYMBOL_PROP_FILLING_MODE,                                // Флаги разрешенных режимов заливки ордера
   SYMBOL_PROP_ORDER_MODE,                                  // Флаги разрешенных типов ордера
   SYMBOL_PROP_ORDER_GTC_MODE,                              // Срок действия StopLoss и TakeProfit ордеров, если SYMBOL_EXPIRATION_MODE=SYMBOL_EXPIRATION_GTC (из перечисления ENUM_SYMBOL_ORDER_GTC_MODE)
   SYMBOL_PROP_OPTION_MODE,                                 // Тип опциона (из перечисления ENUM_SYMBOL_OPTION_MODE)
   SYMBOL_PROP_OPTION_RIGHT,                                // Право опциона (Call/Put) (из перечисления ENUM_SYMBOL_OPTION_RIGHT)
   SYMBOL_PROP_BACKGROUND_COLOR                             // Цвет фона, которым подсвечивается символ в Market Watch
  }; 
#define SYMBOL_PROP_INTEGER_TOTAL    (35)                   // Общее количество целочисленных свойств
#define SYMBOL_PROP_INTEGER_SKIP     (1)                    // Количество неиспользуемых в сортировке целочисленных свойств символа
//+------------------------------------------------------------------+

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

Добавим перечисление вещественных свойств символа:

//+------------------------------------------------------------------+
//| Вещественные свойства символа                                    |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_PROP_DOUBLE
  {
   SYMBOL_PROP_BID = SYMBOL_PROP_INTEGER_TOTAL,             // Bid - лучшее предложение на продажу
   SYMBOL_PROP_BIDHIGH,                                     // Максимальный Bid за день
   SYMBOL_PROP_BIDLOW,                                      // Минимальный Bid за день
   SYMBOL_PROP_ASK,                                         // Ask - лучшее предложение на покупку
   SYMBOL_PROP_ASKHIGH,                                     // Максимальный Ask за день
   SYMBOL_PROP_ASKLOW,                                      // Минимальный Ask за день
   SYMBOL_PROP_LAST,                                        // Цена, по которой совершена последняя сделка
   SYMBOL_PROP_LASTHIGH,                                    // Максимальный Last за день
   SYMBOL_PROP_LASTLOW,                                     // Минимальный Last за день
   SYMBOL_PROP_VOLUME_REAL,                                 // Volume за день
   SYMBOL_PROP_VOLUMEHIGH_REAL,                             // Максимальный Volume за день
   SYMBOL_PROP_VOLUMELOW_REAL,                              // Минимальный Volume за день
   SYMBOL_PROP_OPTION_STRIKE,                               // Цена исполнения опциона
   SYMBOL_PROP_POINT,                                       // Значение одного пункта
   SYMBOL_PROP_TRADE_TICK_VALUE,                            // Значение SYMBOL_TRADE_TICK_VALUE_PROFIT
   SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT,                     // Рассчитанная стоимость тика для прибыльной позиции
   SYMBOL_PROP_TRADE_TICK_VALUE_LOSS,                       // Рассчитанная стоимость тика для убыточной позиции
   SYMBOL_PROP_TRADE_TICK_SIZE,                             // Минимальное изменение цены
   SYMBOL_PROP_TRADE_CONTRACT_SIZE,                         // Размер торгового контракта
   SYMBOL_PROP_TRADE_ACCRUED_INTEREST,                      // Накопленный купонный доход
   SYMBOL_PROP_TRADE_FACE_VALUE,                            // Номинальная стоимость – начальная стоимость облигации, установленная эмитентом
   SYMBOL_PROP_TRADE_LIQUIDITY_RATE,                        // Коэффициент ликвидности – доля от стоимости актива, которую можно использовать в качестве залога
   SYMBOL_PROP_VOLUME_MIN,                                  // Минимальный объем для заключения сделки
   SYMBOL_PROP_VOLUME_MAX,                                  // Максимальный объем для заключения сделки
   SYMBOL_PROP_VOLUME_STEP,                                 // Минимальный шаг изменения объема для заключения сделки
   SYMBOL_PROP_VOLUME_LIMIT,                                // Максимально допустимый совокупный объем открытой позиции и отложенных ордеров в одном направлении (покупка или продажа)
   SYMBOL_PROP_SWAP_LONG,                                   // Значение свопа в покупку
   SYMBOL_PROP_SWAP_SHORT,                                  // Значение свопа в продажу
   SYMBOL_PROP_MARGIN_INITIAL,                              // Начальная (инициирующая) маржа
   SYMBOL_PROP_MARGIN_MAINTENANCE,                          // Поддерживающая маржа по инструменту
   SYMBOL_PROP_MARGIN_LONG,                                 // Коэффициент взимания маржи по длинным позициям
   SYMBOL_PROP_MARGIN_SHORT,                                // Коэффициент взимания маржи по коротким позициям
   SYMBOL_PROP_MARGIN_STOP,                                 // Коэффициент взимания маржи по Stop ордерам
   SYMBOL_PROP_MARGIN_LIMIT,                                // Коэффициент взимания маржи по Limit ордерам
   SYMBOL_PROP_MARGIN_STOPLIMIT,                            // Коэффициент взимания маржи по Stop Limit ордерам
   SYMBOL_PROP_SESSION_VOLUME,                              // Cуммарный объём сделок в текущую сессию
   SYMBOL_PROP_SESSION_TURNOVER,                            // Cуммарный оборот в текущую сессию
   SYMBOL_PROP_SESSION_INTEREST,                            // Cуммарный объём открытых позиций
   SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME,                   // Общий объём ордеров на покупку в текущий момент
   SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME,                  // Общий объём ордеров на продажу в текущий момент
   SYMBOL_PROP_SESSION_OPEN,                                // Цена открытия сессии
   SYMBOL_PROP_SESSION_CLOSE,                               // Цена закрытия сессии
   SYMBOL_PROP_SESSION_AW,                                  // Средневзвешенная цена сессии
   SYMBOL_PROP_SESSION_PRICE_SETTLEMENT,                    // Цена поставки на текущую сессию
   SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN,                     // Минимально допустимое значение цены на сессию 
   SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX,                     // Максимально допустимое значение цены на сессию
   SYMBOL_PROP_MARGIN_HEDGED                                // Размер контракта или маржи для одного лота перекрытых позиций (разнонаправленные позиции по одному символу).
  };
#define SYMBOL_PROP_DOUBLE_TOTAL     (47)                   // Общее количество вещественных свойств
#define SYMBOL_PROP_DOUBLE_SKIP      (0)                    // Количество неиспользуемых в сортировке вещественных свойств символа
//+------------------------------------------------------------------+

Здесь, помимо свойств, описанных в перечислении ENUM_SYMBOL_INFO_DOUBLE, добавлены ещё пять свойств символа, которые по какой-то причине не попали в описание перечисления вещественных свойств, но они в нём есть и принадлежат данному перечислению.

Добавим перечисление строковых свойств символа и возможные критерии сортировки символов:

//+------------------------------------------------------------------+
//| Строковые свойства символа                                       |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_PROP_STRING
  {
   SYMBOL_PROP_NAME = (SYMBOL_PROP_INTEGER_TOTAL+SYMBOL_PROP_DOUBLE_TOTAL),   // Имя символа
   SYMBOL_PROP_BASIS,                                       // Имя базового актива для производного инструмента
   SYMBOL_PROP_CURRENCY_BASE,                               // Базовая валюта инструмента
   SYMBOL_PROP_CURRENCY_PROFIT,                             // Валюта прибыли
   SYMBOL_PROP_CURRENCY_MARGIN,                             // Валюта, в которой вычисляются залоговые средства
   SYMBOL_PROP_BANK,                                        // Источник текущей котировки
   SYMBOL_PROP_DESCRIPTION,                                 // Строковое описание символа
   SYMBOL_PROP_FORMULA,                                     // Формула для построения цены пользовательского символа
   SYMBOL_PROP_ISIN,                                        // Имя торгового символа в системе международных идентификационных кодов ценных бумаг — ISIN
   SYMBOL_PROP_PAGE,                                        // Адрес интернет страницы с информацией по символу
   SYMBOL_PROP_PATH,                                        // Путь в дереве символов
  };
#define SYMBOL_PROP_STRING_TOTAL     (11)                   // Общее количество строковых свойств
//+------------------------------------------------------------------+
//| Возможные критерии сортировки символов                           |
//+------------------------------------------------------------------+
#define FIRST_SYM_DBL_PROP          (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP)
#define FIRST_SYM_STR_PROP          (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP+SYMBOL_PROP_DOUBLE_TOTAL-SYMBOL_PROP_DOUBLE_SKIP)
enum ENUM_SORT_SYMBOLS_MODE
  {
//--- Сортировка по целочисленным свойствам
   SORT_BY_SYMBOL_STATUS = 0,                               // Сортировать по статусу символа
   SORT_BY_SYMBOL_CUSTOM,                                   // Сортировать по признаку пользовательского символа
   SORT_BY_SYMBOL_CHART_MODE,                               // Сортировать по типу цены для построения баров – Bid или Last (из перечисления ENUM_SYMBOL_CHART_MODE)
   SORT_BY_SYMBOL_EXIST,                                    // Сортировать по признаку того, что символ с таким именем существует
   SORT_BY_SYMBOL_SELECT,                                   // Сортировать по признаку того, что символ выбран в Market Watch
   SORT_BY_SYMBOL_VISIBLE,                                  // Сортировать по признаку того, что выбранный символ отображается в Market Watch
   SORT_BY_SYMBOL_SESSION_DEALS,                            // Сортировать по количеству сделок в текущей сессии 
   SORT_BY_SYMBOL_SESSION_BUY_ORDERS,                       // Сортировать по общему числу ордеров на покупку в текущий момент
   SORT_BY_SYMBOL_SESSION_SELL_ORDERS,                      // Сортировать по общему числу ордеров на продажу в текущий момент
   SORT_BY_SYMBOL_VOLUME,                                   // Сортировать по Volume - объему в последней сделке
   SORT_BY_SYMBOL_VOLUMEHIGH,                               // Сортировать по максимальному Volume за день
   SORT_BY_SYMBOL_VOLUMELOW,                                // Сортировать по минимальному Volume за день
   SORT_BY_SYMBOL_TIME,                                     // Сортировать по времени последней котировки
   SORT_BY_SYMBOL_DIGITS,                                   // Сортировать по количеству знаков после запятой
   SORT_BY_SYMBOL_DIGITS_LOT,                               // Сортировать по количеству знаков после запятой в лоте
   SORT_BY_SYMBOL_SPREAD,                                   // Сортировать по размеру спреда в пунктах
   SORT_BY_SYMBOL_SPREAD_FLOAT,                             // Сортировать по признаку плавающего спреда
   SORT_BY_SYMBOL_TICKS_BOOKDEPTH,                          // Сортировать по максимальному количеству показываемых заявок в стакане
   SORT_BY_SYMBOL_TRADE_CALC_MODE,                          // Сортировать по способу вычисления стоимости контракта (из перечисления ENUM_SYMBOL_CALC_MODE)
   SORT_BY_SYMBOL_TRADE_MODE,                               // Сортировать по типу исполнения ордеров (из перечисления ENUM_SYMBOL_TRADE_MODE)
   SORT_BY_SYMBOL_START_TIME,                               // Сортировать по дате начала торгов по инструменту (обычно используется для фьючерсов)
   SORT_BY_SYMBOL_EXPIRATION_TIME,                          // Сортировать по дате окончания торгов по инструменту (обычно используется для фьючерсов)
   SORT_BY_SYMBOL_TRADE_STOPS_LEVEL,                        // Сортировать по минимальному отступу в пунктах от текущей цены закрытия для установки Stop ордеров
   SORT_BY_SYMBOL_TRADE_FREEZE_LEVEL,                       // Сортировать по дистанции заморозки торговых операций (в пунктах)
   SORT_BY_SYMBOL_TRADE_EXEMODE,                            // Сортировать по режиму заключения сделок (из перечисления ENUM_SYMBOL_TRADE_EXECUTION)
   SORT_BY_SYMBOL_SWAP_MODE,                                // Сортировать по модели расчета свопа (из перечисления ENUM_SYMBOL_SWAP_MODE)
   SORT_BY_SYMBOL_SWAP_ROLLOVER3DAYS,                       // Сортировать по дню недели для начисления тройного свопа (из перечисления ENUM_DAY_OF_WEEK)
   SORT_BY_SYMBOL_MARGIN_HEDGED_USE_LEG,                    // Сортировать по режиму расчета хеджированной маржи по наибольшей стороне (Buy или Sell)
   SORT_BY_SYMBOL_EXPIRATION_MODE,                          // Сортировать по флагам разрешенных режимов истечения ордера
   SORT_BY_SYMBOL_FILLING_MODE,                             // Сортировать по флагам разрешенных режимов заливки ордера
   SORT_BY_SYMBOL_ORDER_MODE,                               // Сортировать по флагам разрешенных типов ордера
   SORT_BY_SYMBOL_ORDER_GTC_MODE,                           // Сортировать по сроку действия StopLoss и TakeProfit ордеров
   SORT_BY_SYMBOL_OPTION_MODE,                              // Сортировать по типу опциона (из перечисления ENUM_SYMBOL_OPTION_MODE)
   SORT_BY_SYMBOL_OPTION_RIGHT,                             // Сортировать по праву опциона (Call/Put) (из перечисления ENUM_SYMBOL_OPTION_RIGHT)
//--- Сортировка по вещественным свойствам
   SORT_BY_SYMBOL_BID = FIRST_SYM_DBL_PROP,                 // Сортировать по Bid
   SORT_BY_SYMBOL_BIDHIGH,                                  // Сортировать по максимальному Bid за день
   SORT_BY_SYMBOL_BIDLOW,                                   // Сортировать по минимальному Bid за день
   SORT_BY_SYMBOL_ASK,                                      // Сортировать по Ask
   SORT_BY_SYMBOL_ASKHIGH,                                  // Сортировать по максимальному Ask за день
   SORT_BY_SYMBOL_ASKLOW,                                   // Сортировать по минимальному Ask за день
   SORT_BY_SYMBOL_LAST,                                     // Сортировать по цене, по которой совершена последняя сделка
   SORT_BY_SYMBOL_LASTHIGH,                                 // Сортировать по максимальному Last за день
   SORT_BY_SYMBOL_LASTLOW,                                  // Сортировать по минимальному Last за день
   SORT_BY_SYMBOL_VOLUME_REAL,                              // Сортировать по Volume за день
   SORT_BY_SYMBOL_VOLUMEHIGH_REAL,                          // Сортировать по максимальному Volume за день
   SORT_BY_SYMBOL_VOLUMELOW_REAL,                           // Сортировать по минимальному Volume за день
   SORT_BY_SYMBOL_OPTION_STRIKE,                            // Сортировать по цене исполнения опциона
   SORT_BY_SYMBOL_POINT,                                    // Сортировать по значению одного пункта
   SORT_BY_SYMBOL_TRADE_TICK_VALUE,                         // Сортировать по значению SYMBOL_TRADE_TICK_VALUE_PROFIT
   SORT_BY_SYMBOL_TRADE_TICK_VALUE_PROFIT,                  // Сортировать по рассчитанной стоимости тика для прибыльной позиции
   SORT_BY_SYMBOL_TRADE_TICK_VALUE_LOSS,                    // Сортировать по рассчитанной стоимости тика для убыточной позиции
   SORT_BY_SYMBOL_TRADE_TICK_SIZE,                          // Сортировать по минимальному изменению цены
   SORT_BY_SYMBOL_TRADE_CONTRACT_SIZE,                      // Сортировать по размеру торгового контракта
   SORT_BY_SYMBOL_TRADE_ACCRUED_INTEREST,                   // Сортировать по накопленному купонному доходу
   SORT_BY_SYMBOL_TRADE_FACE_VALUE,                         // Сортировать по номинальной стоимости
   SORT_BY_SYMBOL_TRADE_LIQUIDITY_RATE,                     // Сортировать по коэффициенту ликвидности
   SORT_BY_SYMBOL_VOLUME_MIN,                               // Сортировать по минимальному объему для заключения сделки
   SORT_BY_SYMBOL_VOLUME_MAX,                               // Сортировать по максимальному объему для заключения сделки
   SORT_BY_SYMBOL_VOLUME_STEP,                              // Сортировать по минимальному шагу изменения объема для заключения сделки
   SORT_BY_SYMBOL_VOLUME_LIMIT,                             // Сортировать по максимально допустимому совокупному объему открытой позиции и отложенных ордеров в одном направлении
   SORT_BY_SYMBOL_SWAP_LONG,                                // Сортировать по значению свопа в покупку
   SORT_BY_SYMBOL_SWAP_SHORT,                               // Сортировать по значению свопа в продажу
   SORT_BY_SYMBOL_MARGIN_INITIAL,                           // Сортировать по начальной (инициирующей) марже
   SORT_BY_SYMBOL_MARGIN_MAINTENANCE,                       // Сортировать по поддерживающей марже по инструменту
   SORT_BY_SYMBOL_MARGIN_LONG,                              // Сортировать по коэффициенту взимания маржи по длинным позициям
   SORT_BY_SYMBOL_MARGIN_SHORT,                             // Сортировать по коэффициенту взимания маржи по коротким позициям
   SORT_BY_SYMBOL_MARGIN_STOP,                              // Сортировать по коэффициенту взимания маржи по Stop ордерам
   SORT_BY_SYMBOL_MARGIN_LIMIT,                             // Сортировать по коэффициенту взимания маржи по Limit ордерам
   SORT_BY_SYMBOL_MARGIN_STOPLIMIT,                         // Сортировать по коэффициенту взимания маржи по Stop Limit ордерам
   SORT_BY_SYMBOL_SESSION_VOLUME,                           // Сортировать по суммарному объёму сделок в текущую сессию
   SORT_BY_SYMBOL_SESSION_TURNOVER,                         // Сортировать по суммарному обороту в текущую сессию
   SORT_BY_SYMBOL_SESSION_INTEREST,                         // Сортировать по суммарному объёму открытых позиций
   SORT_BY_SYMBOL_SESSION_BUY_ORDERS_VOLUME,                // Сортировать по общему объёму ордеров на покупку в текущий момент
   SORT_BY_SYMBOL_SESSION_SELL_ORDERS_VOLUME,               // Сортировать по общему объёму ордеров на продажу в текущий момент
   SORT_BY_SYMBOL_SESSION_OPEN,                             // Сортировать по цене открытия сессии
   SORT_BY_SYMBOL_SESSION_CLOSE,                            // Сортировать по цене закрытия сессии
   SORT_BY_SYMBOL_SESSION_AW,                               // Сортировать по средневзвешенной цене сессии
   SORT_BY_SYMBOL_SESSION_PRICE_SETTLEMENT,                 // Сортировать по цене поставки на текущую сессию
   SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MIN,                  // Сортировать по минимально допустимому значению цены на сессию 
   SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MAX,                  // Сортировать по максимально допустимому значению цены на сессию
   SORT_BY_SYMBOL_MARGIN_HEDGED,                            // Сортировать по размеру контракта или маржи для одного лота перекрытых позиций
//--- Сортировка по строковым свойствам
   SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP,                // Сортировать по имени символа
   SORT_BY_SYMBOL_BASIS,                                    // Сортировать по имени базового актива для производного инструмента
   SORT_BY_SYMBOL_CURRENCY_BASE,                            // Сортировать по базовой валюте инструмента
   SORT_BY_SYMBOL_CURRENCY_PROFIT,                          // Сортировать по валюте прибыли
   SORT_BY_SYMBOL_CURRENCY_MARGIN,                          // Сортировать по валюте, в которой вычисляются залоговые средства
   SORT_BY_SYMBOL_BANK,                                     // Сортировать по источнику текущей котировки
   SORT_BY_SYMBOL_DESCRIPTION,                              // Сортировать по строковому описанию символа
   SORT_BY_SYMBOL_FORMULA,                                  // Сортировать по формуле для построения цены пользовательского символа
   SORT_BY_SYMBOL_ISIN,                                     // Сортировать по имени торгового символа в системе международных идентификационных кодов ценных бумаг — ISIN
   SORT_BY_SYMBOL_PAGE,                                     // Сортировать по адресу интернет страницы с информацией по символу
   SORT_BY_SYMBOL_PATH                                      // Сортировать по пути в дереве символов
  };
//+------------------------------------------------------------------+

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

Это все необходимые данные для работы с объектами-символами.

Теперь создадим класс объекта-символа.

В папке \MQL5\Include\DoEasy\Objects\ создадим новый файл класса CCymbol под именем Symbol.mqh. Сразу же заполним класс стандартными для библиотеки подключениями и методами:

//+------------------------------------------------------------------+
//|                                                       Symbol.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include <Object.mqh>
#include "..\..\Services\DELib.mqh"
//+------------------------------------------------------------------+
//| Класс абстрактного символа                                       |
//+------------------------------------------------------------------+
class CSymbol : public CObject
  {
private:
   long              m_long_prop[SYMBOL_PROP_INTEGER_TOTAL];         // Целочисленные свойства
   double            m_double_prop[SYMBOL_PROP_DOUBLE_TOTAL];        // Вещественные свойства
   string            m_string_prop[SYMBOL_PROP_STRING_TOTAL];        // Строковые свойства
//--- Возвращает индекс массива, по которому фактически расположено (1) double-свойство и (2) string-свойство символа
   int               IndexProp(ENUM_SYMBOL_PROP_DOUBLE property)  const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL;                                    }
   int               IndexProp(ENUM_SYMBOL_PROP_STRING property)  const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_DOUBLE_TOTAL;           }
public:
//--- Конструктор по умолчанию
                     CSymbol(void){;}
protected:
//--- Защищённый параметрический конструктор
                     CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name);

public:
//--- Устанавливает (1) целочисленное, (2) вещественное и (3) строковое свойство символа
   void              SetProperty(ENUM_SYMBOL_PROP_INTEGER property,long value)   { this.m_long_prop[property]=value;                                        }
   void              SetProperty(ENUM_SYMBOL_PROP_DOUBLE property,double value)  { this.m_double_prop[this.IndexProp(property)]=value;                      }
   void              SetProperty(ENUM_SYMBOL_PROP_STRING property,string value)  { this.m_string_prop[this.IndexProp(property)]=value;                      }
//--- Возвращает из массива свойств (1) целочисленное, (2) вещественное и (3) строковое свойство символа
   long              GetProperty(ENUM_SYMBOL_PROP_INTEGER property)        const { return this.m_long_prop[property];                                       }
   double            GetProperty(ENUM_SYMBOL_PROP_DOUBLE property)         const { return this.m_double_prop[this.IndexProp(property)];                     }
   string            GetProperty(ENUM_SYMBOL_PROP_STRING property)         const { return this.m_string_prop[this.IndexProp(property)];                     }

//--- Возвращает флаг поддержания символом данного свойства
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_INTEGER property)    { return true; }
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property)     { return true; }
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_STRING property)     { return true; }

//+------------------------------------------------------------------+
//| Описания свойств объекта-символа                                 |
//+------------------------------------------------------------------+
//--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства символа
   string            GetPropertyDescription(ENUM_SYMBOL_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_SYMBOL_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_SYMBOL_PROP_STRING property);
//--- Возвращает наименование статуса символа
   string            StatusDescription(void)    const;
//--- Выводит в журнал описание свойств символа (full_prop=true - все свойства, false - только поддерживаемые)
   void              Print(const bool full_prop=false);

//--- Сравнивает объекты CSymbol между собой по всем возможным свойствам (для сортировки списков по указанному свойству объекта-символа)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Сравнивает объекты CSymbol между собой по всем свойствам (для поиска равных объектов-событий)
   bool              IsEqual(CSymbol* compared_symbol) const;

  };

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

Теперь добавим в приватную секцию необходимые для работы класса переменные и методы:

//+------------------------------------------------------------------+
//|                                                       Symbol.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
#property strict    // Нужно для mql4
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include <Object.mqh>
#include "..\..\Services\DELib.mqh"
//+------------------------------------------------------------------+
//| Класс абстрактного символа                                       |
//+------------------------------------------------------------------+
class CSymbol : public CObject
  {
private:
   MqlTick           m_tick;                                         // Структура тика символа
   MqlBookInfo       m_book_info_array[];                            // Массив структур данных стакана
   string            m_symbol_name;                                  // Имя символа
   long              m_long_prop[SYMBOL_PROP_INTEGER_TOTAL];         // Целочисленные свойства
   double            m_double_prop[SYMBOL_PROP_DOUBLE_TOTAL];        // Вещественные свойства
   string            m_string_prop[SYMBOL_PROP_STRING_TOTAL];        // Строковые свойства
   int               m_digits_currency;                              // Число знаков после запятой валюты счёта
   int               m_global_error;                                 // Код глобальной ошибки
//--- Возвращает индекс массива, по которому фактически расположено (1) double-свойство и (2) string-свойство символа
   int               IndexProp(ENUM_SYMBOL_PROP_DOUBLE property)  const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL;                                    }
   int               IndexProp(ENUM_SYMBOL_PROP_STRING property)  const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_DOUBLE_TOTAL;           }
//--- Обнуляет все данные объекта-символа
   void              Reset(void);
public:
//--- Конструктор по умолчанию
                     CSymbol(void){;}
protected:
//--- Защищённый параметрический конструктор
                     CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name);

Из структуры тика будем получать данные по ценам Ask, Bid, Last и времени тика — для MQL5 в милисекундах, для MQL4 — в секундах. Хоть в MQL4 в структуре тика и присутствует поле милисекунд, но оно, к сожалению, не используется, поэтому для MQL4 будем брать секундное время * 1000 для перевода его в формат милисекунд.
Массив структур данных стакана нам будет нужен позже — когда будем делать получение содержимого стакана (в данной статье — нет).
Код глобальной ошибки — бывают ситуации, когда при ошибочном исполнении какого-либо метода или функции, уже невозможно продолжать работу программы, работающей на основе библиотеки, и необходимо, чтобы программа знала об ошибочном исполнении метода или функции, и могла вовремя и адекватно обработать данную ситуацию. Для таких случаев мы и введём эту переменную — в неё будем записывать код ошибки, а базовый объект библиотеки CEngine будет опрашивать код ошибки, и если он содержит ненулевое значение, то этот код сначала будет обработан в классе CEngine, а если нет возможности "решить проблему" внутренними средствами, то код будет отправлен в вызывающую программу для своевременной реакции на ошибку.
Перед созданием объекта-символа необходимо обнулить все его поля и структуры — для этого и предназначен метод Reset().

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

protected:
//--- Защищённый параметрический конструктор
                     CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name);

//--- Получает и возвращает целочисленные свойства выбранного символа из его параметров
   long              SymbolExists(void)                  const;
   long              SymbolCustom(void)                  const;
   long              SymbolChartMode(void)               const;
   long              SymbolMarginHedgedUseLEG(void)      const;
   long              SymbolOrderFillingMode(void)        const;
   long              SymbolOrderMode(void)               const;
   long              SymbolOrderGTCMode(void)            const;
   long              SymbolOptionMode(void)              const;
   long              SymbolOptionRight(void)             const;
   long              SymbolBackgroundColor(void)         const;
   long              SymbolCalcMode(void)                const;
   long              SymbolSwapMode(void)                const;
   long              SymbolExpirationMode(void)          const;
   long              SymbolDigitsLot(void);
//--- Получает и возвращает вещественные свойства выбранного символа из его параметров
   double            SymbolBidHigh(void)                 const;
   double            SymbolBidLow(void)                  const;
   double            SymbolVolumeReal(void)              const;
   double            SymbolVolumeHighReal(void)          const;
   double            SymbolVolumeLowReal(void)           const;
   double            SymbolOptionStrike(void)            const;
   double            SymbolTradeAccruedInterest(void)    const;
   double            SymbolTradeFaceValue(void)          const;
   double            SymbolTradeLiquidityRate(void)      const;
   double            SymbolMarginHedged(void)            const;
//--- Получает и возвращает строковые свойства выбранного символа из его параметров
   string            SymbolBasis(void)                   const;
   string            SymbolBank(void)                    const;
   string            SymbolISIN(void)                    const;
   string            SymbolFormula(void)                 const;
   string            SymbolPage(void)                    const;
//--- Возвращает число знаков после запятой валюты счёта
   int               DigitsCurrency(void)                const { return this.m_digits_currency; }
//--- Ищет символ и возвращает флаг его наличия на сервере
   bool              Exist(void)                         const;

public:

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

public:
//--- Устанавливает (1) целочисленное, (2) вещественное и (3) строковое свойство символа
   void              SetProperty(ENUM_SYMBOL_PROP_INTEGER property,long value)   { this.m_long_prop[property]=value;                                        }
   void              SetProperty(ENUM_SYMBOL_PROP_DOUBLE property,double value)  { this.m_double_prop[this.IndexProp(property)]=value;                      }
   void              SetProperty(ENUM_SYMBOL_PROP_STRING property,string value)  { this.m_string_prop[this.IndexProp(property)]=value;                      }
//--- Возвращает из массива свойств (1) целочисленное, (2) вещественное и (3) строковое свойство символа
   long              GetProperty(ENUM_SYMBOL_PROP_INTEGER property)        const { return this.m_long_prop[property];                                       }
   double            GetProperty(ENUM_SYMBOL_PROP_DOUBLE property)         const { return this.m_double_prop[this.IndexProp(property)];                     }
   string            GetProperty(ENUM_SYMBOL_PROP_STRING property)         const { return this.m_string_prop[this.IndexProp(property)];                     }

//--- Возвращает флаг поддержания символом данного свойства
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_INTEGER property)    { return true; }
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property)     { return true; }
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_STRING property)     { return true; }

//--- Возвращает флаг разрешения (1) рыночных, (2) лимитных, (3) стоп-, (4) стоп-лимит ордеров,
//--- флаг разрешения установки (5) StopLoss, (6) TakeProfit приказов, (7) закрытия встречной
   bool              IsMarketOrdersAllowed(void)            const { return((this.OrderModeFlags() & SYMBOL_ORDER_MARKET)==SYMBOL_ORDER_MARKET);             }
   bool              IsLimitOrdersAllowed(void)             const { return((this.OrderModeFlags() & SYMBOL_ORDER_LIMIT)==SYMBOL_ORDER_LIMIT);               }
   bool              IsStopOrdersAllowed(void)              const { return((this.OrderModeFlags() & SYMBOL_ORDER_STOP)==SYMBOL_ORDER_STOP);                 }
   bool              IsStopLimitOrdersAllowed(void)         const { return((this.OrderModeFlags() & SYMBOL_ORDER_STOP_LIMIT)==SYMBOL_ORDER_STOP_LIMIT);     }
   bool              IsStopLossOrdersAllowed(void)          const { return((this.OrderModeFlags() & SYMBOL_ORDER_SL)==SYMBOL_ORDER_SL);                     }
   bool              IsTakeProfitOrdersAllowed(void)        const { return((this.OrderModeFlags() & SYMBOL_ORDER_TP)==SYMBOL_ORDER_TP);                     }
   bool              IsCloseByOrdersAllowed(void)           const;

//--- Возвращает флаг заливки (1) FOK, (2) IOC
   bool              IsFillingModeFOK(void)                 const { return((this.FillingModeFlags() & SYMBOL_FILLING_FOK)==SYMBOL_FILLING_FOK);             }
   bool              IsFillingModeIOC(void)                 const { return((this.FillingModeFlags() & SYMBOL_FILLING_IOC)==SYMBOL_FILLING_IOC);             }

//--- Возвращает флаг истечения действия ордера (1) GTC, (2) DAY, (3) Specified, (4) Specified Day
   bool              IsExipirationModeGTC(void)             const { return((this.ExpirationModeFlags() & SYMBOL_EXPIRATION_GTC)==SYMBOL_EXPIRATION_GTC);    }
   bool              IsExipirationModeDAY(void)             const { return((this.ExpirationModeFlags() & SYMBOL_EXPIRATION_DAY)==SYMBOL_EXPIRATION_DAY);    }
   bool              IsExipirationModeSpecified(void)       const { return((this.ExpirationModeFlags() & SYMBOL_EXPIRATION_SPECIFIED)==SYMBOL_EXPIRATION_SPECIFIED);          }
   bool              IsExipirationModeSpecifiedDay(void)    const { return((this.ExpirationModeFlags() & SYMBOL_EXPIRATION_SPECIFIED_DAY)==SYMBOL_EXPIRATION_SPECIFIED_DAY);  }

//--- Возвращает описание разрешения (1) рыночных, (2) лимитных, (3) стоп- и (4) стоп-лимит ордеров,
//--- описание разрешения установки (5) StopLoss и (6) TakeProfit приказов, (7) закрытия встречной
   string            GetMarketOrdersAllowedDescription(void)      const;
   string            GetLimitOrdersAllowedDescription(void)       const;
   string            GetStopOrdersAllowedDescription(void)        const;
   string            GetStopLimitOrdersAllowedDescription(void)   const;
   string            GetStopLossOrdersAllowedDescription(void)    const;
   string            GetTakeProfitOrdersAllowedDescription(void)  const;
   string            GetCloseByOrdersAllowedDescription(void)     const;

//--- Возвращает описание разрешения типа заливки (1) FOK и (2) IOC, (3) разрешенных режимов истечения ордера
   string            GetFillingModeFOKAllowedDescrioption(void)   const;
   string            GetFillingModeIOCAllowedDescrioption(void)   const;

//--- Возвращает описание истечения действия ордера (1) GTC, (2) DAY, (3) Specified, (4) Specified Day
   string            GetExpirationModeGTCDescription(void)        const;
   string            GetExpirationModeDAYDescription(void)        const;
   string            GetExpirationModeSpecifiedDescription(void)  const;
   string            GetExpirationModeSpecDayDescription(void)    const;

//--- Возвращает описание (1) статуса, (2) типа цены для построения баров, 
//--- (3) способа вычисления залоговых средств, (4) режима торговли по инструменту,
//--- (5) режима заключения сделок по инструменту, (6) модели расчета свопа,
//--- (7) срока действия StopLoss и TakeProfit ордеров, (8) типа опциона, (9) права опциона
//--- флагов (10) разрешенных типов ордеров, (11) разрешённых типов заливки,
//--- (12) разрешенных режимов истечения ордера
   string            GetStatusDescription(void)                   const;
   string            GetChartModeDescription(void)                const;
   string            GetCalcModeDescription(void)                 const;
   string            GetTradeModeDescription(void)                const;
   string            GetTradeExecDescription(void)                const;
   string            GetSwapModeDescription(void)                 const;
   string            GetOrderGTCModeDescription(void)             const;
   string            GetOptionTypeDescription(void)               const;
   string            GetOptionRightDescription(void)              const;
   string            GetOrderModeFlagsDescription(void)           const;
   string            GetFillingModeFlagsDescription(void)         const;
   string            GetExpirationModeFlagsDescription(void)      const;
   

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

//--- Возвращает код глобальной ошибки
   int               GetError(void)                               const { return this.m_global_error;                                                       }
//--- Обновляет все данные символа, которые могут измениться
   void              Refresh(void);
//--- Обновляет котировочные данные по символу
   void              RefreshRates(void);

//--- (1) Добавляет, (2) убирает символ из окна MarketWatch (Обзор рынка), (3) Возвращает флаг синхронизированности данных по символу
   bool              SetToMarketWatch(void)                       const { return ::SymbolSelect(this.m_symbol_name,true);                                   }
   bool              RemoveFromMarketWatch(void)                  const { return ::SymbolSelect(this.m_symbol_name,false);                                  }
   bool              IsSynchronized(void)                         const { return ::SymbolIsSynchronized(this.m_symbol_name);                                }
//--- (1) Осуществляет (1) подписку на стакан цен, (2) закрытие стакана цен
   bool              BookAdd(void)                                const;
   bool              BookClose(void)                              const;

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

//+------------------------------------------------------------------+
//| Методы упрощённого доступа к свойствам объекта-символа           |
//+------------------------------------------------------------------+
//--- Целочисленные свойства
   long              Status(void)                                 const { return this.GetProperty(SYMBOL_PROP_STATUS);                                      }
   bool              IsCustom(void)                               const { return (bool)this.GetProperty(SYMBOL_PROP_CUSTOM);                                }
   color             ColorBackground(void)                        const { return (color)this.GetProperty(SYMBOL_PROP_BACKGROUND_COLOR);                     }
   ENUM_SYMBOL_CHART_MODE ChartMode(void)                         const { return (ENUM_SYMBOL_CHART_MODE)this.GetProperty(SYMBOL_PROP_CHART_MODE);          }
   bool              IsExist(void)                                const { return (bool)this.GetProperty(SYMBOL_PROP_EXIST);                                 }
   bool              IsSelect(void)                               const { return (bool)this.GetProperty(SYMBOL_PROP_SELECT);                                }
   bool              IsVisible(void)                              const { return (bool)this.GetProperty(SYMBOL_PROP_VISIBLE);                               }
   long              SessionDeals(void)                           const { return this.GetProperty(SYMBOL_PROP_SESSION_DEALS);                               }
   long              SessionBuyOrders(void)                       const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS);                          }
   long              SessionSellOrders(void)                      const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS);                         }
   long              Volume(void)                                 const { return this.GetProperty(SYMBOL_PROP_VOLUME);                                      }
   long              VolumeHigh(void)                             const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH);                                  }
   long              VolumeLow(void)                              const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW);                                   }
   datetime          Time(void)                                   const { return (datetime)this.GetProperty(SYMBOL_PROP_TIME);                              }
   int               Digits(void)                                 const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS);                                 }
   int               DigitsLot(void)                              const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS_LOTS);                            }
   int               Spread(void)                                 const { return (int)this.GetProperty(SYMBOL_PROP_SPREAD);                                 }
   bool              IsSpreadFloat(void)                          const { return (bool)this.GetProperty(SYMBOL_PROP_SPREAD_FLOAT);                          }
   int               TicksBookdepth(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_TICKS_BOOKDEPTH);                        }
   ENUM_SYMBOL_CALC_MODE TradeCalcMode(void)                      const { return (ENUM_SYMBOL_CALC_MODE)this.GetProperty(SYMBOL_PROP_TRADE_CALC_MODE);      }
   ENUM_SYMBOL_TRADE_MODE TradeMode(void)                         const { return (ENUM_SYMBOL_TRADE_MODE)this.GetProperty(SYMBOL_PROP_TRADE_MODE);          }
   datetime          StartTime(void)                              const { return (datetime)this.GetProperty(SYMBOL_PROP_START_TIME);                        }
   datetime          ExpirationTime(void)                         const { return (datetime)this.GetProperty(SYMBOL_PROP_EXPIRATION_TIME);                   }
   int               TradeStopLevel(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_STOPS_LEVEL);                      }
   int               TradeFreezeLevel(void)                       const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_FREEZE_LEVEL);                     }
   ENUM_SYMBOL_TRADE_EXECUTION TradeExecutionMode(void)           const { return (ENUM_SYMBOL_TRADE_EXECUTION)this.GetProperty(SYMBOL_PROP_TRADE_EXEMODE);  }
   ENUM_SYMBOL_SWAP_MODE SwapMode(void)                           const { return (ENUM_SYMBOL_SWAP_MODE)this.GetProperty(SYMBOL_PROP_SWAP_MODE);            }
   ENUM_DAY_OF_WEEK  SwapRollover3Days(void)                      const { return (ENUM_DAY_OF_WEEK)this.GetProperty(SYMBOL_PROP_SWAP_ROLLOVER3DAYS);        }
   bool              IsMarginHedgedUseLeg(void)                   const { return (bool)this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED_USE_LEG);                 }
   int               ExpirationModeFlags(void)                    const { return (int)this.GetProperty(SYMBOL_PROP_EXPIRATION_MODE);                        }
   int               FillingModeFlags(void)                       const { return (int)this.GetProperty(SYMBOL_PROP_FILLING_MODE);                           }
   int               OrderModeFlags(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_ORDER_MODE);                             }
   ENUM_SYMBOL_ORDER_GTC_MODE OrderModeGTC(void)                  const { return (ENUM_SYMBOL_ORDER_GTC_MODE)this.GetProperty(SYMBOL_PROP_ORDER_GTC_MODE);  }
   ENUM_SYMBOL_OPTION_MODE OptionMode(void)                       const { return (ENUM_SYMBOL_OPTION_MODE)this.GetProperty(SYMBOL_PROP_OPTION_MODE);        }
   ENUM_SYMBOL_OPTION_RIGHT OptionRight(void)                     const { return (ENUM_SYMBOL_OPTION_RIGHT)this.GetProperty(SYMBOL_PROP_OPTION_RIGHT);      }
//--- Вещественные свойства
   double            Bid(void)                                    const { return this.GetProperty(SYMBOL_PROP_BID);                                         }
   double            BidHigh(void)                                const { return this.GetProperty(SYMBOL_PROP_BIDHIGH);                                     }
   double            BidLow(void)                                 const { return this.GetProperty(SYMBOL_PROP_BIDLOW);                                      }
   double            Ask(void)                                    const { return this.GetProperty(SYMBOL_PROP_ASK);                                         }
   double            AskHigh(void)                                const { return this.GetProperty(SYMBOL_PROP_ASKHIGH);                                     }
   double            AskLow(void)                                 const { return this.GetProperty(SYMBOL_PROP_ASKLOW);                                      }
   double            Last(void)                                   const { return this.GetProperty(SYMBOL_PROP_LAST);                                        }
   double            LastHigh(void)                               const { return this.GetProperty(SYMBOL_PROP_LASTHIGH);                                    }
   double            LastLow(void)                                const { return this.GetProperty(SYMBOL_PROP_LASTLOW);                                     }
   double            VolumeReal(void)                             const { return this.GetProperty(SYMBOL_PROP_VOLUME_REAL);                                 }
   double            VolumeHighReal(void)                         const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH_REAL);                             }
   double            VolumeLowReal(void)                          const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW_REAL);                              }
   double            OptionStrike(void)                           const { return this.GetProperty(SYMBOL_PROP_OPTION_STRIKE);                               }
   double            Point(void)                                  const { return this.GetProperty(SYMBOL_PROP_POINT);                                       }
   double            TradeTickValue(void)                         const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE);                            }
   double            TradeTickValueProfit(void)                   const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT);                     }
   double            TradeTickValueLoss(void)                     const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS);                       }
   double            TradeTickSize(void)                          const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_SIZE);                             }
   double            TradeContractSize(void)                      const { return this.GetProperty(SYMBOL_PROP_TRADE_CONTRACT_SIZE);                         }
   double            TradeAccuredInterest(void)                   const { return this.GetProperty(SYMBOL_PROP_TRADE_ACCRUED_INTEREST);                      }
   double            TradeFaceValue(void)                         const { return this.GetProperty(SYMBOL_PROP_TRADE_FACE_VALUE);                            }
   double            TradeLiquidityRate(void)                     const { return this.GetProperty(SYMBOL_PROP_TRADE_LIQUIDITY_RATE);                        }
   double            LotsMin(void)                                const { return this.GetProperty(SYMBOL_PROP_VOLUME_MIN);                                  }
   double            LotsMax(void)                                const { return this.GetProperty(SYMBOL_PROP_VOLUME_MAX);                                  }
   double            LotsStep(void)                               const { return this.GetProperty(SYMBOL_PROP_VOLUME_STEP);                                 }
   double            VolumeLimit(void)                            const { return this.GetProperty(SYMBOL_PROP_VOLUME_LIMIT);                                }
   double            SwapLong(void)                               const { return this.GetProperty(SYMBOL_PROP_SWAP_LONG);                                   }
   double            SwapShort(void)                              const { return this.GetProperty(SYMBOL_PROP_SWAP_SHORT);                                  }
   double            MarginInitial(void)                          const { return this.GetProperty(SYMBOL_PROP_MARGIN_INITIAL);                              }
   double            MarginMaintenance(void)                      const { return this.GetProperty(SYMBOL_PROP_MARGIN_MAINTENANCE);                          }
   double            MarginLong(void)                             const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG);                                 }
   double            MarginShort(void)                            const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT);                                }
   double            MarginStop(void)                             const { return this.GetProperty(SYMBOL_PROP_MARGIN_STOP);                                 }
   double            MarginLimit(void)                            const { return this.GetProperty(SYMBOL_PROP_MARGIN_LIMIT);                                }
   double            MarginStopLimit(void)                        const { return this.GetProperty(SYMBOL_PROP_MARGIN_STOPLIMIT);                            }
   double            SessionVolume(void)                          const { return this.GetProperty(SYMBOL_PROP_SESSION_VOLUME);                              }
   double            SessionTurnover(void)                        const { return this.GetProperty(SYMBOL_PROP_SESSION_TURNOVER);                            }
   double            SessionInterest(void)                        const { return this.GetProperty(SYMBOL_PROP_SESSION_INTEREST);                            }
   double            SessionBuyOrdersVolume(void)                 const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME);                   }
   double            SessionSellOrdersVolume(void)                const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME);                  }
   double            SessionOpen(void)                            const { return this.GetProperty(SYMBOL_PROP_SESSION_OPEN);                                }
   double            SessionClose(void)                           const { return this.GetProperty(SYMBOL_PROP_SESSION_CLOSE);                               }
   double            SessionAW(void)                              const { return this.GetProperty(SYMBOL_PROP_SESSION_AW);                                  }
   double            SessionPriceSettlement(void)                 const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT);                    }
   double            SessionPriceLimitMin(void)                   const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN);                     }
   double            SessionPriceLimitMax(void)                   const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX);                     }
   double            MarginHedged(void)                           const { return this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED);                               }
   double            NormalizedPrice(const double price)          const;
//--- Строковые свойства
   string            Name(void)                                   const { return this.GetProperty(SYMBOL_PROP_NAME);                                        }
   string            Basis(void)                                  const { return this.GetProperty(SYMBOL_PROP_BASIS);                                       }
   string            CurrencyBase(void)                           const { return this.GetProperty(SYMBOL_PROP_CURRENCY_BASE);                               }
   string            CurrencyProfit(void)                         const { return this.GetProperty(SYMBOL_PROP_CURRENCY_PROFIT);                             }
   string            CurrencyMargin(void)                         const { return this.GetProperty(SYMBOL_PROP_CURRENCY_MARGIN);                             }
   string            Bank(void)                                   const { return this.GetProperty(SYMBOL_PROP_BANK);                                        }
   string            Description(void)                            const { return this.GetProperty(SYMBOL_PROP_DESCRIPTION);                                 }
   string            Formula(void)                                const { return this.GetProperty(SYMBOL_PROP_FORMULA);                                     }
   string            ISIN(void)                                   const { return this.GetProperty(SYMBOL_PROP_ISIN);                                        }
   string            Page(void)                                   const { return this.GetProperty(SYMBOL_PROP_PAGE);                                        }
   string            Path(void)                                   const { return this.GetProperty(SYMBOL_PROP_PATH);                                        }
//---
  };
//+------------------------------------------------------------------+

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

Реализация защищённого конструктора класса:

//+------------------------------------------------------------------+
//| Методы класса                                                    |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Закрытый параметрический конструктор                             |
//+------------------------------------------------------------------+
CSymbol::CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name) : m_global_error(ERR_SUCCESS)
  {
   this.m_symbol_name=name;
   if(!this.Exist())
     {
      ::Print(DFUN_ERR_LINE,"\"",this.m_symbol_name,"\"",": ",TextByLanguage("Ошибка. Такого символа нет на сервере","Error. There is no such symbol on the server"));
      this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL;
     }
   ::ResetLastError();
   if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick))
     {
      this.m_global_error=::GetLastError();
      ::Print(DFUN_ERR_LINE,"\"",this.m_symbol_name,"\": ",TextByLanguage("Не удалось получить текущие цены. Ошибка: ","Could not get current prices. Error: "),this.m_global_error);
     }
//--- Инициализация данных
   ::ZeroMemory(this.m_tick);
   this.Reset();
   this.m_digits_currency=(#ifdef __MQL5__ (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif);
//--- Сохранение целочисленных свойств
   this.m_long_prop[SYMBOL_PROP_STATUS]                                       = symbol_status;
   this.m_long_prop[SYMBOL_PROP_VOLUME]                                       = (long)this.m_tick.volume;
   this.m_long_prop[SYMBOL_PROP_TIME]                                         = #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ;
   this.m_long_prop[SYMBOL_PROP_SELECT]                                       = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SELECT);
   this.m_long_prop[SYMBOL_PROP_VISIBLE]                                      = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VISIBLE);
   this.m_long_prop[SYMBOL_PROP_SESSION_DEALS]                                = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_DEALS);
   this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS]                           = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS);
   this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS]                          = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS);
   this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH]                                   = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMEHIGH);
   this.m_long_prop[SYMBOL_PROP_VOLUMELOW]                                    = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMELOW);
   this.m_long_prop[SYMBOL_PROP_DIGITS]                                       = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_DIGITS);
   this.m_long_prop[SYMBOL_PROP_SPREAD]                                       = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD);
   this.m_long_prop[SYMBOL_PROP_SPREAD_FLOAT]                                 = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD_FLOAT);
   this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH]                              = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TICKS_BOOKDEPTH);
   this.m_long_prop[SYMBOL_PROP_TRADE_MODE]                                   = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_MODE);
   this.m_long_prop[SYMBOL_PROP_START_TIME]                                   = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_START_TIME);
   this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME]                              = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXPIRATION_TIME);
   this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL]                            = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_STOPS_LEVEL);
   this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL]                           = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_FREEZE_LEVEL);
   this.m_long_prop[SYMBOL_PROP_TRADE_EXEMODE]                                = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_EXEMODE);
   this.m_long_prop[SYMBOL_PROP_SWAP_ROLLOVER3DAYS]                           = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SWAP_ROLLOVER3DAYS);
   this.m_long_prop[SYMBOL_PROP_EXPIRATION_MODE]                              = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXPIRATION_MODE);
   this.m_long_prop[SYMBOL_PROP_EXIST]                                        = this.SymbolExists();
   this.m_long_prop[SYMBOL_PROP_CUSTOM]                                       = this.SymbolCustom();
   this.m_long_prop[SYMBOL_PROP_MARGIN_HEDGED_USE_LEG]                        = this.SymbolMarginHedgedUseLEG();
   this.m_long_prop[SYMBOL_PROP_ORDER_MODE]                                   = this.SymbolOrderMode();
   this.m_long_prop[SYMBOL_PROP_FILLING_MODE]                                 = this.SymbolOrderFillingMode();
   this.m_long_prop[SYMBOL_PROP_ORDER_GTC_MODE]                               = this.SymbolOrderGTCMode();
   this.m_long_prop[SYMBOL_PROP_OPTION_MODE]                                  = this.SymbolOptionMode();
   this.m_long_prop[SYMBOL_PROP_OPTION_RIGHT]                                 = this.SymbolOptionRight();
   this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR]                             = this.SymbolBackgroundColor();
   this.m_long_prop[SYMBOL_PROP_CHART_MODE]                                   = this.SymbolChartMode();
   this.m_long_prop[SYMBOL_PROP_TRADE_CALC_MODE]                              = this.SymbolCalcMode();
   this.m_long_prop[SYMBOL_PROP_SWAP_MODE]                                    = this.SymbolSwapMode();
   this.m_long_prop[SYMBOL_PROP_EXPIRATION_MODE]                              = this.SymbolExpirationMode();
//--- Сохранение вещественных свойств
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)]                    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKHIGH);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)]                     = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKLOW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)]                   = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTHIGH);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)]                    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTLOW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_POINT)]                      = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_POINT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)]           = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)]    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_PROFIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)]      = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_LOSS);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)]            = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_SIZE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)]        = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_CONTRACT_SIZE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)]                 = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MIN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)]                 = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MAX);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)]                = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_STEP);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)]               = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_LIMIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)]                  = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_LONG);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)]                 = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_SHORT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)]             = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_INITIAL);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)]         = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_MAINTENANCE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG)]                = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_LONG);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT)]               = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_SHORT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_STOP)]                = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_STOP);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LIMIT)]               = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_LIMIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_STOPLIMIT)]           = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_STOPLIMIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)]             = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)]           = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_TURNOVER);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)]           = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_INTEREST);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)]  = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)]               = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_OPEN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)]              = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_CLOSE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)]                 = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_AW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)]   = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_SETTLEMENT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)]    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MIN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)]    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MAX);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)]                        = this.m_tick.bid;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)]                        = this.m_tick.ask;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)]                       = this.m_tick.last;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)]                    = this.SymbolBidHigh();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)]                     = this.SymbolBidLow();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)]                = this.SymbolVolumeReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)]            = this.SymbolVolumeHighReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)]             = this.SymbolVolumeLowReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)]              = this.SymbolOptionStrike();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)]     = this.SymbolTradeAccruedInterest();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)]           = this.SymbolTradeFaceValue();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)]       = this.SymbolTradeLiquidityRate();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)]              = this.SymbolMarginHedged();
//--- Сохранение строковых свойств
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_NAME)]                       = this.m_symbol_name;
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_BASE)]              = ::SymbolInfoString(this.m_symbol_name,SYMBOL_CURRENCY_BASE);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_PROFIT)]            = ::SymbolInfoString(this.m_symbol_name,SYMBOL_CURRENCY_PROFIT);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_MARGIN)]            = ::SymbolInfoString(this.m_symbol_name,SYMBOL_CURRENCY_MARGIN);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_DESCRIPTION)]                = ::SymbolInfoString(this.m_symbol_name,SYMBOL_DESCRIPTION);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_PATH)]                       = ::SymbolInfoString(this.m_symbol_name,SYMBOL_PATH);
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_BASIS)]                      = this.SymbolBasis();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_BANK)]                       = this.SymbolBank();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_ISIN)]                       = this.SymbolISIN();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_FORMULA)]                    = this.SymbolFormula();
   this.m_string_prop[this.IndexProp(SYMBOL_PROP_PAGE)]                       = this.SymbolPage();
//--- Сохранение дополнительных целочисленных свойств
   this.m_long_prop[SYMBOL_PROP_DIGITS_LOTS]                                  = this.SymbolDigitsLot();
  }
//+------------------------------------------------------------------+

Входными параметрами конструктора являются статус символа и его имя. При создании коллекции символов будем идти в цикле по всем необходимым для работы символам, определять их принадлежность к заданной нами ранее категории (в перечислении ENUM_SYMBOL_STATUS) и создавать новый объект-наследник данного класса абстрактного символа. В наследник будем передавать только имя символа, а статус будет задаваться автоматически по типу объекта-наследника и отсылаться в конструктор класса-родителя при создании объекта-наследника. Этот момент мы уже разбирали при обсуждении создания объектов-ордеров во второй части описания библиотеки.
В списке инициализации конструктора сразу инициализируем код ошибки.
Далее, уже в теле метода, сначала проверяем есть ли такой символ на сервере, и если его нет, то выводим сообщение об ошибке в журнал и вписываем в код ошибки значение "Неизвестный символ". К слову — данная проверка в принципе излишняя, так как при создании объекта в него будут передаваться данные уже выбранного символа из списка. Но всё же, считаю, что быть она должна — никто не застрахован от того, что при создании объекта в него не будет передан неверный символ.
Далее мы получаем данные о последнем тике, и если получить их не удалось, то так же выводим об этом сообщение в журнал и присваиваем коду ошибки значение последней ошибки посредством GetLastError(). Но в любом случае объект создаётся, а код ошибки позволит определить в вызывающей программе — оставить этот объект, или удалить.
Затем все данные объекта-символа инициализируются (обнуляются) и задаётся значение количества знаков после запятой для валюты счёта для корректного вывода значений в журнал.
И все свойства объекта заполняются при помощи SymbolInfo-функций, а там, где для получения этих значений существует различие в MQL5 и MQL4, то данные заполняются специально созданными для этого методами, которые будут рассмотрены далее.

Метод сравнения двух объектов-символов между собой для поиска и сортировки:

//+------------------------------------------------------------------+
//|Сравнивает объекты CSymbol между собой по всем возможным свойствам|
//+------------------------------------------------------------------+
int CSymbol::Compare(const CObject *node,const int mode=0) const
  {
   const CSymbol *symbol_compared=node;
//--- сравнение целочисленных свойств двух символов
   if(mode<SYMBOL_PROP_INTEGER_TOTAL)
     {
      long value_compared=symbol_compared.GetProperty((ENUM_SYMBOL_PROP_INTEGER)mode);
      long value_current=this.GetProperty((ENUM_SYMBOL_PROP_INTEGER)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- сравнение вещественных свойств двух символов
   else if(mode<SYMBOL_PROP_INTEGER_TOTAL+SYMBOL_PROP_DOUBLE_TOTAL)
     {
      double value_compared=symbol_compared.GetProperty((ENUM_SYMBOL_PROP_DOUBLE)mode);
      double value_current=this.GetProperty((ENUM_SYMBOL_PROP_DOUBLE)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
//--- сравнение строковых свойств двух символов
   else if(mode<SYMBOL_PROP_INTEGER_TOTAL+SYMBOL_PROP_DOUBLE_TOTAL+SYMBOL_PROP_STRING_TOTAL)
     {
      string value_compared=symbol_compared.GetProperty((ENUM_SYMBOL_PROP_STRING)mode);
      string value_current=this.GetProperty((ENUM_SYMBOL_PROP_STRING)mode);
      return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0);
     }
   return 0;
  }
//+------------------------------------------------------------------+

Метод сравнения двух объектов-символов между собой для определения их равенства:

//+------------------------------------------------------------------+
//| Сравнивает объекты CSymbol между собой по всем свойствам         |
//+------------------------------------------------------------------+
bool CSymbol::IsEqual(CSymbol *compared_symbol) const
  {
   int beg=0, end=SYMBOL_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SYMBOL_PROP_INTEGER prop=(ENUM_SYMBOL_PROP_INTEGER)i;
      if(this.GetProperty(prop)!=compared_symbol.GetProperty(prop)) return false; 
     }
   beg=end; end+=SYMBOL_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SYMBOL_PROP_DOUBLE prop=(ENUM_SYMBOL_PROP_DOUBLE)i;
      if(this.GetProperty(prop)!=compared_symbol.GetProperty(prop)) return false; 
     }
   beg=end; end+=SYMBOL_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SYMBOL_PROP_STRING prop=(ENUM_SYMBOL_PROP_STRING)i;
      if(this.GetProperty(prop)!=compared_symbol.GetProperty(prop)) return false; 
     }
   return true;
  }
//+------------------------------------------------------------------+

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

Метод инициализации всех свойств объекта-символа:

//+------------------------------------------------------------------+
//| Обнуляет все данные объекта-символа                              |
//+------------------------------------------------------------------+
void CSymbol::Reset(void)
  {
   int beg=0, end=SYMBOL_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SYMBOL_PROP_INTEGER prop=(ENUM_SYMBOL_PROP_INTEGER)i;
      this.SetProperty(prop,0);
     }
   beg=end; end+=SYMBOL_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SYMBOL_PROP_DOUBLE prop=(ENUM_SYMBOL_PROP_DOUBLE)i;
      this.SetProperty(prop,0);
     }
   beg=end; end+=SYMBOL_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SYMBOL_PROP_STRING prop=(ENUM_SYMBOL_PROP_STRING)i;
      this.SetProperty(prop,NULL);
     }
  }
//+------------------------------------------------------------------+

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

Методы получения целочисленных свойств символа, которые либо полностью, либо частично отсутствуют в MQL4:

//+------------------------------------------------------------------+
//| Целочисленные свойства                                           |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Возвращает флаг существования символа                            |
//+------------------------------------------------------------------+
long CSymbol::SymbolExists(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXIST) #else this.Exist() #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает флаг пользовательского символа                        |
//+------------------------------------------------------------------+
long CSymbol::SymbolCustom(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_CUSTOM) #else false #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает тип цены для построения баров – Bid или Last          |
//+------------------------------------------------------------------+
long CSymbol::SymbolChartMode(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_CHART_MODE) #else SYMBOL_CHART_MODE_BID #endif);
  }
//+------------------------------------------------------------------+
//|Возвращает режим расчета хеджированной маржи по наибольшей стороне|
//+------------------------------------------------------------------+
long CSymbol::SymbolMarginHedgedUseLEG(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_MARGIN_HEDGED_USE_LEG) #else false #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает флаги политик заполнения ордеров                      |
//+------------------------------------------------------------------+
long CSymbol::SymbolOrderFillingMode(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_FILLING_MODE) #else 0 #endif );
  }
//+------------------------------------------------------------------+
//| Возвращает флаг разрешения закрытия встречной                    |
//+------------------------------------------------------------------+
bool CSymbol::IsCloseByOrdersAllowed(void) const
  {
   return(#ifdef __MQL5__(this.OrderModeFlags() & SYMBOL_ORDER_CLOSEBY)==SYMBOL_ORDER_CLOSEBY #else (bool)::MarketInfo(this.m_symbol_name,MODE_CLOSEBY_ALLOWED)  #endif );
  }  
//+------------------------------------------------------------------+
//| Возвращает срок действия отложенных ордеров и                    |
//| установленных уровней StopLoss/TakeProfit                        |
//+------------------------------------------------------------------+
long CSymbol::SymbolOrderGTCMode(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_ORDER_GTC_MODE) #else SYMBOL_ORDERS_GTC #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает тип опциона                                           |
//+------------------------------------------------------------------+
long CSymbol::SymbolOptionMode(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_OPTION_MODE) #else SYMBOL_OPTION_MODE_NONE #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает право опциона                                         |
//+------------------------------------------------------------------+
long CSymbol::SymbolOptionRight(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_OPTION_RIGHT) #else SYMBOL_OPTION_RIGHT_NONE #endif);
  }
//+------------------------------------------------------------------+
//|Возвращает цвет фона, которым подсвечивается символ в Market Watch|
//+------------------------------------------------------------------+
long CSymbol::SymbolBackgroundColor(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_BACKGROUND_COLOR) #else clrNONE #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает способ вычисления величины залоговых средств          |
//+------------------------------------------------------------------+
long CSymbol::SymbolCalcMode(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_CALC_MODE) #else (long)::MarketInfo(this.m_symbol_name,MODE_MARGINCALCMODE) #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает способ начисления свопов                              |
//+------------------------------------------------------------------+
long CSymbol::SymbolSwapMode(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SWAP_MODE) #else (long)::MarketInfo(this.m_symbol_name,MODE_SWAPTYPE) #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает Флаги разрешенных режимов истечения ордера            |
//+------------------------------------------------------------------+
long CSymbol::SymbolExpirationMode(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXPIRATION_MODE) #else (long)SYMBOL_EXPIRATION_GTC #endif);
  }
//+------------------------------------------------------------------+

Здесь у нас используются директивы условной компиляции #ifdef __MQL5__ — для компиляции под MQL5 и #else— для компиляции под MQL4 #endif

Для MQL5 мы просто получаем данные из функции SymbolInfoInteger() с требуемым идентификатором свойства, а для MQL4 возвращаем либо жёстко заданную величину значения (если знаем точно, что именно такое значение используется в MQL4), либо нулевое значение (или false, или заданную макроподстановку для отсутствующего значения).

Здесь же — ниже в листинге — разместим коды ещё двух методов:

Метод, возвращающий флаги разрешённых типов ордеров для символа:

//+------------------------------------------------------------------+
//| Возвращает флаги разрешённых типов ордеров                       |
//+------------------------------------------------------------------+
long CSymbol::SymbolOrderMode(void) const
  {
   return
     (
      #ifdef __MQL5__
         ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_ORDER_MODE)
      #else 
         (SYMBOL_ORDER_MARKET+SYMBOL_ORDER_LIMIT+SYMBOL_ORDER_STOP+SYMBOL_ORDER_SL+SYMBOL_ORDER_TP+(this.IsCloseByOrdersAllowed() ? SYMBOL_ORDER_CLOSEBY : 0))
      #endif 
     );
  }
//+------------------------------------------------------------------+

Так как в MQL5 для каждого из символов есть возможность получения флагов, указывающих на разрешённость выставления разных типов ордеров:

Нам необходимо для MQL5 просто получить данные флаги из функции SymbolInfoInteger() с идентификатором свойства SYMBOL_ORDER_MODE, возвращающего все флаги, установленные для символа.

А вот для MQL4, где мы можем получить только данные о разрешении закрытия встречным ордером из функции MarketInfo() с идентификатором запроса MODE_CLOSEBY_ALLOWED (возвращается методом IsCloseByOrdersAllowed(), который в листинге выше).
Поэтому здесь нам необходимо самостоятельно собрать нужные флаги для возврата в MQL4-программу:

Метод получения количества знаков после запятой в значении лота для символа:

//+------------------------------------------------------------------+
//| Рассчитывает и возвращает количество знаков                      |
//| после запятой в лоте символа                                     |
//+------------------------------------------------------------------+
long CSymbol::SymbolDigitsLot(void)
  {
   if(this.LotsMax()==0 || this.LotsMin()==0 || this.LotsStep()==0)
     {
      ::Print(DFUN_ERR_LINE,TextByLanguage("Не удалось получить данные \"","Failed to get data of \""),this.Name(),"\"");
      this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL;
      return 2;
     }
   double val=::round(this.LotsMin()/this.LotsStep())*this.LotsStep();
   string val_str=(string)val;
   int len=::StringLen(val_str);
   int n=len-::StringFind(val_str,".",0)-1;
   if(::StringSubstr(val_str,len-1,1)=="0")
      n--;
   return n;
  }
//+------------------------------------------------------------------+

Данный метод высчитывает количество знаков после запятой в значении лота символа.
У нас уже есть такая функция в файле сервисных функций DELib.mqh:

//+------------------------------------------------------------------+
//| Возвращает количество десятичных знаков в лоте символа           |
//+------------------------------------------------------------------+
uint DigitsLots(const string symbol_name) 
  { 
   return (int)ceil(fabs(log(SymbolInfoDouble(symbol_name,SYMBOL_VOLUME_STEP))/log(10)));
  }
//+------------------------------------------------------------------+

Но она не лишена некоторых изъянов, о которых мне сообщили в одной из веток обсуждения статей: при значении шага лота 0.25, функция не вернёт верное значение. Таким образом, я решил поискать более точный метод, и в конце концов пришёл к решению, что самым точным методом будет просто посчитать количество знаков после запятой в строковом значении лота, приведённого к шагу лота: lots=MathRound(lots/lotStep)*lotStep. На данное решение натолкнуло обсуждение в ветке, посвящённой этой проблеме и один из множества предложенных методов поиска. Да, это поиск в строке. Но нам нужно найти нужное количество знаков лишь один раз для каждого из используемых символов, а делее уже использовать константное значение, и данный метод не имеет недостатков всех расчётных методов. Так что — остановимся на предложенном решении.

Методы получения вещественных и строковых свойств символа, которые либо полностью, либо частично отсутствуют в MQL4:

//+------------------------------------------------------------------+
//| Вещественные свойства                                            |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Возвращает максимальный Bid за день                              |
//+------------------------------------------------------------------+
double CSymbol::SymbolBidHigh(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_BIDHIGH) #else ::MarketInfo(this.m_symbol_name,MODE_HIGH) #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает мимсимальный Bid за день                              |
//+------------------------------------------------------------------+
double CSymbol::SymbolBidLow(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_BIDLOW) #else ::MarketInfo(this.m_symbol_name,MODE_LOW) #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает реальный Volume за день                               |
//+------------------------------------------------------------------+
double CSymbol::SymbolVolumeReal(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_REAL) #else 0 #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает реальный максимальный Volume за день                  |
//+------------------------------------------------------------------+
double CSymbol::SymbolVolumeHighReal(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUMEHIGH_REAL) #else 0 #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает реальный минимальный Volume за день                   |
//+------------------------------------------------------------------+
double CSymbol::SymbolVolumeLowReal(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUMELOW_REAL) #else 0 #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает цену исполнения опциона                               |
//+------------------------------------------------------------------+
double CSymbol::SymbolOptionStrike(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_OPTION_STRIKE) #else 0 #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает накопленный купонный доход                            |
//+------------------------------------------------------------------+
double CSymbol::SymbolTradeAccruedInterest(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_ACCRUED_INTEREST) #else 0 #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает начальную стоимость облигации                         |
//+------------------------------------------------------------------+
double CSymbol::SymbolTradeFaceValue(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_FACE_VALUE) #else 0 #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает коэффициент ликвидности                               |
//+------------------------------------------------------------------+
double CSymbol::SymbolTradeLiquidityRate(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_LIQUIDITY_RATE) #else 0 #endif);
  }
//+------------------------------------------------------------------+
//| Возвращает размер контракта или маржи                            |
//| для одного лота перекрытых позиций                               |
//+------------------------------------------------------------------+
double CSymbol::SymbolMarginHedged(void) const
  {
   return(#ifdef __MQL5__ ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_HEDGED) #else ::MarketInfo(this.m_symbol_name, MODE_MARGINHEDGED) #endif);
  }
//+------------------------------------------------------------------+
//| Строковые свойства                                               |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Возвращает имя базового актива для производного инструмента      |
//+------------------------------------------------------------------+
string CSymbol::SymbolBasis(void) const
  {
   return
     (
      #ifdef __MQL5__ 
         ::SymbolInfoString(this.m_symbol_name,SYMBOL_BASIS) 
      #else 
         ": "+TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") 
      #endif
     );
  }
//+------------------------------------------------------------------+
//| Возвращает источник котировки для символа                        |
//+------------------------------------------------------------------+
string CSymbol::SymbolBank(void) const
  {
   return
     (
      #ifdef __MQL5__ 
         ::SymbolInfoString(this.m_symbol_name,SYMBOL_BANK) 
      #else 
         ": "+TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") 
      #endif
     );
  }
//+------------------------------------------------------------------+
//| Возвращает имя символа в ISIN                                    |
//+------------------------------------------------------------------+
string CSymbol::SymbolISIN(void) const
  {
   return
     (
      #ifdef __MQL5__ 
         ::SymbolInfoString(this.m_symbol_name,SYMBOL_ISIN) 
      #else 
         ": "+TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") 
      #endif
     );
  }
  
//+------------------------------------------------------------------+
//| Возвращает формулу для построения цены пользовательского символа |
//+------------------------------------------------------------------+
string CSymbol::SymbolFormula(void) const
  {
   return
     (
      #ifdef __MQL5__ 
         ::SymbolInfoString(this.m_symbol_name,SYMBOL_FORMULA) 
      #else 
         ": "+TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") 
      #endif
     );
  }
//+------------------------------------------------------------------+
//| Возвращает адрес интернет страницы с информацией по символу      |
//+------------------------------------------------------------------+
string CSymbol::SymbolPage(void) const
  {
   return
     (
      #ifdef __MQL5__ 
         ::SymbolInfoString(this.m_symbol_name,SYMBOL_PAGE) 
      #else 
         ": "+TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") 
      #endif
     );
  }
//+------------------------------------------------------------------+

Здесь всё идентично методам получения целочисленных свойств: получение возвращаемого значения разделено директивами условной компиляции, и значения свойств либо возвращаются соответствующими функциями MQL5 и MQL4, либо для MQL4 возвращается 0 (при отсутствующем аналоге MQL5) или строковое сообщение о неподдержании MQL4 данного строкового свойства.

Метод вывода в журнал полного списка всех свойств объекта-символа:

//+------------------------------------------------------------------+
//| Выводит в журнал свойства символа                                |
//+------------------------------------------------------------------+
void CSymbol::Print(const bool full_prop=false)
  {
   ::Print("============= ",
           TextByLanguage("Начало списка параметров: \"","The beginning of the parameter list: \""),
           this.Name(),"\""," ",(this.Description()!= #ifdef __MQL5__ "" #else NULL #endif  ? "("+this.Description()+")" : ""),
           " =================="
          );
   int beg=0, end=SYMBOL_PROP_INTEGER_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SYMBOL_PROP_INTEGER prop=(ENUM_SYMBOL_PROP_INTEGER)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=SYMBOL_PROP_DOUBLE_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SYMBOL_PROP_DOUBLE prop=(ENUM_SYMBOL_PROP_DOUBLE)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("------");
   beg=end; end+=SYMBOL_PROP_STRING_TOTAL;
   for(int i=beg; i<end; i++)
     {
      ENUM_SYMBOL_PROP_STRING prop=(ENUM_SYMBOL_PROP_STRING)i;
      if(!full_prop && !this.SupportProperty(prop)) continue;
      ::Print(this.GetPropertyDescription(prop));
     }
   ::Print("================== ",
           TextByLanguage("Конец списка параметров: ","End of the parameter list: \""),
           this.Name(),"\""," ",(this.Description()!= #ifdef __MQL5__ "" #else NULL #endif  ? "("+this.Description()+")" : ""),
           " ==================\n"
          );
  }
//+------------------------------------------------------------------+

В трёх циклах по всем свойствам объекта выводятся описания каждого последующего свойства в цикле методами GetPropertyDescription(), возвращающими описание свойства объекта по его типу ( целочисленный, вещественный или строковый), переданного в метод:

//+------------------------------------------------------------------+
//| Возвращает описание целочисленного свойства символа              |
//+------------------------------------------------------------------+
string CSymbol::GetPropertyDescription(ENUM_SYMBOL_PROP_INTEGER property)
  {
   return
     (
   //--- Общие свойства
      property==SYMBOL_PROP_STATUS              ?  TextByLanguage("Статус","Status")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(string)this.GetStatusDescription()
         )  :
      property==SYMBOL_PROP_CUSTOM              ?  TextByLanguage("Пользовательский символ","Custom symbol")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_CHART_MODE          ?  TextByLanguage("Тип цены для построения баров","Price type used for generating symbols bars")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetChartModeDescription()
         )  :
      property==SYMBOL_PROP_EXIST               ?  TextByLanguage("Символ с таким именем существует","Symbol with this name exists")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_SELECT  ?  TextByLanguage("Символ выбран в Market Watch","Symbol is selected in Market Watch")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_VISIBLE ?  TextByLanguage("Символ отображается в Market Watch","Symbol is visible in Market Watch")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_SESSION_DEALS       ?  TextByLanguage("Количество сделок в текущей сессии","Number of deals in the current session")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_BUY_ORDERS  ?  TextByLanguage("Общее число ордеров на покупку в текущий момент","Number of Buy orders at the moment")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_SELL_ORDERS ?  TextByLanguage("Общее число ордеров на продажу в текущий момент","Number of Sell orders at the moment")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_VOLUME              ?  TextByLanguage("Объем в последней сделке","Volume of the last deal")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_VOLUMEHIGH          ?  TextByLanguage("Максимальный объём за день","Maximal day volume")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_VOLUMELOW           ?  TextByLanguage("Минимальный объём за день","Minimal day volume")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_TIME                ?  TextByLanguage("Время последней котировки","Time of the last quote")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(this.GetProperty(property)==0 ? TextByLanguage("(Ещё не было тиков)","(No ticks yet)") : TimeMSCtoString(this.GetProperty(property)))
         )  :
      property==SYMBOL_PROP_DIGITS              ?  TextByLanguage("Количество знаков после запятой","Digits after a decimal point")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_DIGITS_LOTS         ?  TextByLanguage("Количество знаков после запятой в значении лота","Digits after a decimal point in the value of the lot")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_SPREAD              ?  TextByLanguage("Размер спреда в пунктах","Spread value in points")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_SPREAD_FLOAT        ?  TextByLanguage("Плавающий спред","Spread is floating")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_TICKS_BOOKDEPTH     ?  TextByLanguage("Максимальное количество показываемых заявок в стакане","Maximal number of requests shown in Depth of Market")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_TRADE_CALC_MODE     ?  TextByLanguage("Способ вычисления стоимости контракта","Contract price calculation mode")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetCalcModeDescription()
         )  :
      property==SYMBOL_PROP_TRADE_MODE ?  TextByLanguage("Тип исполнения ордеров","Order execution type")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetTradeModeDescription()
         )  :
      property==SYMBOL_PROP_START_TIME          ?  TextByLanguage("Дата начала торгов по инструменту","Date of the symbol trade beginning")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)==0  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+TimeMSCtoString(this.GetProperty(property)*1000))
         )  :
      property==SYMBOL_PROP_EXPIRATION_TIME     ?  TextByLanguage("Дата окончания торгов по инструменту","Date of the symbol trade end")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)==0  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+TimeMSCtoString(this.GetProperty(property)*1000))
         )  :
      property==SYMBOL_PROP_TRADE_STOPS_LEVEL   ?  TextByLanguage("Минимальный отступ от цены закрытия для установки Stop ордеров","Minimal indention from the close price to place Stop orders")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_TRADE_FREEZE_LEVEL  ?  TextByLanguage("Дистанция заморозки торговых операций","Distance to freeze trade operations in points")+
         (!this.SupportProperty(property)    ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(string)this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_TRADE_EXEMODE       ?  TextByLanguage("Режим заключения сделок","Deal execution mode")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetTradeExecDescription()
         )  :
      property==SYMBOL_PROP_SWAP_MODE           ?  TextByLanguage("Модель расчета свопа","Swap calculation model")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetSwapModeDescription()
         )  :
      property==SYMBOL_PROP_SWAP_ROLLOVER3DAYS  ?  TextByLanguage("День недели для начисления тройного свопа","Day of week to charge 3 days swap rollover")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+DayOfWeekDescription(this.SwapRollover3Days())
         )  :
      property==SYMBOL_PROP_MARGIN_HEDGED_USE_LEG  ?  TextByLanguage("Расчет хеджированной маржи по наибольшей стороне","Calculating hedging margin using the larger leg")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(this.GetProperty(property)   ?  TextByLanguage("Да","Yes") : TextByLanguage("Нет","No"))
         )  :
      property==SYMBOL_PROP_EXPIRATION_MODE     ?  TextByLanguage("Флаги разрешенных режимов истечения ордера","Flags of allowed order expiration modes")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetExpirationModeFlagsDescription()
         )  :
      property==SYMBOL_PROP_FILLING_MODE        ?  TextByLanguage("Флаги разрешенных режимов заливки ордера","Flags of allowed order filling modes")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetFillingModeFlagsDescription()
         )  :
      property==SYMBOL_PROP_ORDER_MODE          ?  TextByLanguage("Флаги разрешенных типов ордера","Flags of allowed order types")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetOrderModeFlagsDescription()
         )  :
      property==SYMBOL_PROP_ORDER_GTC_MODE      ?  TextByLanguage("Срок действия StopLoss и TakeProfit ордеров","Expiration of Stop Loss and Take Profit orders")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetOrderGTCModeDescription()
         )  :
      property==SYMBOL_PROP_OPTION_MODE         ?  TextByLanguage("Тип опциона","Option type")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetOptionTypeDescription()
         )  :
      property==SYMBOL_PROP_OPTION_RIGHT        ?  TextByLanguage("Право опциона","Option right")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetOptionRightDescription()
         )  :
      property==SYMBOL_PROP_BACKGROUND_COLOR    ?  TextByLanguage("Цвет фона символа в Market Watch","Background color of the symbol in Market Watch")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         #ifdef __MQL5__
         (this.GetProperty(property)>clrWhite  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+::ColorToString((color)this.GetProperty(property),true))
         #else TextByLanguage(": Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание вещественного свойства символа               |
//+------------------------------------------------------------------+
string CSymbol::GetPropertyDescription(ENUM_SYMBOL_PROP_DOUBLE property)
  {
   int dg=this.Digits();
   int dgl=this.DigitsLot();
   int dgc=this.DigitsCurrency();
   return
     (
      property==SYMBOL_PROP_BID              ?  TextByLanguage("Цена Bid","Price Bid")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(this.GetProperty(property)==0 ? TextByLanguage("(Ещё не было тиков)","(No ticks yet)") : ::DoubleToString(this.GetProperty(property),dg))
         )  :
      property==SYMBOL_PROP_BIDHIGH          ?  TextByLanguage("Максимальный Bid за день","Maximal Bid of the day")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==SYMBOL_PROP_BIDLOW           ?  TextByLanguage("Минимальный Bid за день","Minimal Bid of the day")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==SYMBOL_PROP_ASK              ?  TextByLanguage("Цена Ask","Price Ask")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+(this.GetProperty(property)==0 ? TextByLanguage("(Ещё не было тиков)","(No ticks yet)") : ::DoubleToString(this.GetProperty(property),dg))
         )  :
      property==SYMBOL_PROP_ASKHIGH          ?  TextByLanguage("Максимальный Ask за день","Maximal Ask of the day")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_ASKLOW           ?  TextByLanguage("Минимальный Ask за день","Minimal Ask of the day")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_LAST             ?  TextByLanguage("Цена последней сделки","Price of the last deal")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_LASTHIGH         ?  TextByLanguage("Максимальный Last за день","Maximal Last of the day")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_LASTLOW          ?  TextByLanguage("Минимальный Last за день","Minimal Last of the day")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_VOLUME_REAL      ?  TextByLanguage("Реальный объём за день","Real volume of the last deal")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgl) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_VOLUMEHIGH_REAL  ?  TextByLanguage("Максимальный реальный объём за день","Maximum real volume of the day")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgl) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_VOLUMELOW_REAL   ?  TextByLanguage("Минимальный реальный объём за день","Minimum real volume of the day")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgl) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_OPTION_STRIKE    ?  TextByLanguage("Цена исполнения опциона","The strike price of an option")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_POINT            ?  TextByLanguage("Значение одного пункта","Symbol point value")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==SYMBOL_PROP_TRADE_TICK_VALUE ?  TextByLanguage("Рассчитанная стоимость тика для позиции","Calculated tick price for a position")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dgc)
         )  :
      property==SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT   ?  TextByLanguage("Рассчитанная стоимость тика для прибыльной позиции","Calculated tick price for a profitable position")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgc) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_TRADE_TICK_VALUE_LOSS  ?  TextByLanguage("Рассчитанная стоимость тика для убыточной позиции","Calculated tick price for a losing position")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgc) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_TRADE_TICK_SIZE  ?  TextByLanguage("Минимальное изменение цены","Minimal price change")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dg)
         )  :
      property==SYMBOL_PROP_TRADE_CONTRACT_SIZE ?  TextByLanguage("Размер торгового контракта","Trade contract size")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dgc)
         )  :
      property==SYMBOL_PROP_TRADE_ACCRUED_INTEREST ?  TextByLanguage("Накопленный купонный доход","Accumulated coupon interest")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgc) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_TRADE_FACE_VALUE ?  TextByLanguage("Начальная стоимость облигации, установленная эмитентом","Initial bond value set by the issuer")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgc) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_TRADE_LIQUIDITY_RATE   ?  TextByLanguage("Коэффициент ликвидности","Liquidity Rate")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),2) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_VOLUME_MIN       ?  TextByLanguage("Минимальный объем для заключения сделки","Minimal volume for a deal")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dgl)
         )  :
      property==SYMBOL_PROP_VOLUME_MAX       ?  TextByLanguage("Максимальный объем для заключения сделки","Maximal volume for a deal")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dgl)
         )  :
      property==SYMBOL_PROP_VOLUME_STEP      ?  TextByLanguage("Минимальный шаг изменения объема для заключения сделки","Minimal volume change step for deal execution")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dgl)
         )  :
      property==SYMBOL_PROP_VOLUME_LIMIT     ?  TextByLanguage("Максимально допустимый общий объем позиции и отложенных ордеров в одном направлении","Maximum allowed aggregate volume of an open position and pending orders in one direction")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgl) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SWAP_LONG        ?  TextByLanguage("Значение свопа на покупку","Long swap value")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dgc)
         )  :

      property==SYMBOL_PROP_SWAP_SHORT       ?  TextByLanguage("Значение свопа на продажу","Short swap value")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dgc)
         )  :
      property==SYMBOL_PROP_MARGIN_INITIAL   ?  TextByLanguage("Начальная (инициирующая) маржа","Initial margin")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dgc)
         )  :
      property==SYMBOL_PROP_MARGIN_MAINTENANCE  ?  TextByLanguage("Поддерживающая маржа по инструменту","Maintenance margin")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dgc)
         )  :
      property==SYMBOL_PROP_MARGIN_LONG      ?  TextByLanguage("Коэффициент взимания маржи по длинным позициям","Coefficient of margin charging for long positions")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgc) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_MARGIN_SHORT     ?  TextByLanguage("Коэффициент взимания маржи по коротким позициям","Coefficient of margin charging for short positions")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgc) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_MARGIN_STOP      ?  TextByLanguage("Коэффициент взимания маржи по Stop ордерам","Coefficient of margin charging for Stop orders")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgc) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_MARGIN_LIMIT     ?  TextByLanguage("Коэффициент взимания маржи по Limit ордерам","Coefficient of margin charging for Limit orders")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgc) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_MARGIN_STOPLIMIT ?  TextByLanguage("Коэффициент взимания маржи по Stop Limit ордерам","Coefficient of margin charging for StopLimit orders")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgc) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_VOLUME   ?  TextByLanguage("Cуммарный объём сделок в текущую сессию","Summary volume of current session deals")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgl) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_TURNOVER ?  TextByLanguage("Cуммарный оборот в текущую сессию","Summary turnover of the current session")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgc) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_INTEREST ?  TextByLanguage("Cуммарный объём открытых позиций","Summary open interest")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgl) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME ?  TextByLanguage("Общий объём ордеров на покупку в текущий момент","Current volume of Buy orders")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgl) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME   ?  TextByLanguage("Общий объём ордеров на продажу в текущий момент","Current volume of Sell orders")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dgl) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_OPEN     ?  TextByLanguage("Цена открытия сессии","Open price of the current session")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_CLOSE    ?  TextByLanguage("Цена закрытия сессии","Close price of the current session")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_AW       ?  TextByLanguage("Средневзвешенная цена сессии","Average weighted price of the current session")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_PRICE_SETTLEMENT  ?  TextByLanguage("Цена поставки на текущую сессию","Settlement price of the current session")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN   ?  TextByLanguage("Минимально допустимое значение цены на сессию","Minimal price of the current session")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX   ?  TextByLanguage("Максимально допустимое значение цены на сессию","Maximal price of the current session")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+ #ifdef __MQL5__::DoubleToString(this.GetProperty(property),dg) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif 
         )  :
      property==SYMBOL_PROP_MARGIN_HEDGED    ?  TextByLanguage("Размер контракта или маржи для одного лота перекрытых позиций","Contract size or margin value per one lot of hedged positions")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+::DoubleToString(this.GetProperty(property),dgc)
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание строкового свойства символа                  |
//+------------------------------------------------------------------+
string CSymbol::GetPropertyDescription(ENUM_SYMBOL_PROP_STRING property)
  {
   return
     (
      property==SYMBOL_PROP_NAME             ?  TextByLanguage("Имя символа","Symbol name")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
          ": "+this.GetProperty(property)
         )  :
      property==SYMBOL_PROP_BASIS            ?  TextByLanguage("Имя базового актива для производного инструмента","The underlying asset of a derivative")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_CURRENCY_BASE    ?  TextByLanguage("Базовая валюта инструмента","Basic currency of a symbol")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_CURRENCY_PROFIT  ?  TextByLanguage("Валюта прибыли","Profit currency")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_CURRENCY_MARGIN  ?  TextByLanguage("Валюта залоговых средств","Margin currency")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_BANK             ?  TextByLanguage("Источник текущей котировки","Feeder of the current quote")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_DESCRIPTION      ?  TextByLanguage("Описание символа","Symbol description")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_FORMULA          ?  TextByLanguage("Формула для построения цены пользовательского символа","The formula used for custom symbol pricing")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_ISIN             ?  TextByLanguage("Имя торгового символа в системе международных идентификационных кодов","The name of a symbol in the ISIN system")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_PAGE             ?  TextByLanguage("Адрес интернет страницы с информацией по символу","The address of the web page containing symbol information")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": \""+this.GetProperty(property)+"\"")
         )  :
      property==SYMBOL_PROP_PATH             ?  TextByLanguage("Путь в дереве символов","Path in the symbol tree")+
         (!this.SupportProperty(property) ?  TextByLanguage(": Свойство не поддерживается",": Property is not support") :
         (this.GetProperty(property)=="" || this.GetProperty(property)==NULL  ?  TextByLanguage(": (Отсутствует)",": (Not set)") : ": \""+this.GetProperty(property)+"\"")
         )  :
      ""
     );
  }
//+------------------------------------------------------------------+

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

Метод поиска символа в списке символов сервера и возрата флага его наличия/отсутствия:

//+------------------------------------------------------------------+
//| Ищет символ и возвращает флаг его наличия на сервере             |
//+------------------------------------------------------------------+
bool CSymbol::Exist(void) const
  {
   int total=::SymbolsTotal(false);
   for(int i=0;i<total;i++)
      if(::SymbolName(i,false)==this.m_symbol_name)
         return true;
   return false;
  }
//+------------------------------------------------------------------+

В цикле по полному списку всех символов на сервере (в функциях SymbolsTotal() и SymbolName() флаг = false) сравниваем каждый последующий символ из списка (его имя) с именем символа текущего объекта-символа. При нахождении возвращаем true — символ есть на сервере. Иначе false— нет символа на сервере.

Методы для подписки на стакан цен и отписки от него:

//+------------------------------------------------------------------+
//| Осуществляет подписку на стакан цен                              |
//+------------------------------------------------------------------+
bool CSymbol::BookAdd(void) const
  {
   return #ifdef __MQL5__ ::MarketBookAdd(this.m_symbol_name) #else false #endif ;
  }
//+------------------------------------------------------------------+
//| Осуществляет закрытие стакана цен                                |
//+------------------------------------------------------------------+
bool CSymbol::BookClose(void) const
  {
   return #ifdef __MQL5__ ::MarketBookRelease(this.m_symbol_name) #else false #endif ;
  }
//+------------------------------------------------------------------+

Методы просто возвращают для MQL5 результат работы функций MarketBookAdd() и MarketBookRelease(), а для MQL4 сразу возвращается false — там нет возможности работы со стаканом цен. Пока данные методы добавлены в объект-символ, но работу с ними и с остальными методами работы со стаканом цен мы организуем в последующих статьях.

Методы, возвращающие строковые описания свойств объекта-символа:

//+------------------------------------------------------------------+
//| Возвращает описание статуса                                      |
//+------------------------------------------------------------------+
string CSymbol::GetStatusDescription() const
  {
   return
     (
      this.Status()==SYMBOL_STATUS_FX              ? TextByLanguage("Форекс символ","Forex symbol")                  :
      this.Status()==SYMBOL_STATUS_FX_MAJOR        ? TextByLanguage("Форекс символ-мажор","Forex major symbol")      :
      this.Status()==SYMBOL_STATUS_FX_MINOR        ? TextByLanguage("Форекс символ-минор","Forex minor symbol")      :
      this.Status()==SYMBOL_STATUS_FX_EXOTIC       ? TextByLanguage("Форекс символ-экзотик","Forex Exotic Symbol")   :
      this.Status()==SYMBOL_STATUS_FX_RUB          ? TextByLanguage("Форекс символ/рубль","Forex symbol RUB")        :
      this.Status()==SYMBOL_STATUS_FX_METAL        ? TextByLanguage("Металл","Metal")                                :
      this.Status()==SYMBOL_STATUS_INDEX           ? TextByLanguage("Индекс","Index")                                :
      this.Status()==SYMBOL_STATUS_INDICATIVE      ? TextByLanguage("Индикатив","Indicative")                        :
      this.Status()==SYMBOL_STATUS_CRYPTO          ? TextByLanguage("Криптовалютный символ","Crypto symbol")         :
      this.Status()==SYMBOL_STATUS_COMMODITY       ? TextByLanguage("Товарный символ","Commodity symbol")            :
      this.Status()==SYMBOL_STATUS_EXCHANGE        ? TextByLanguage("Биржевой символ","Exchange symbol")             : 
      this.Status()==SYMBOL_STATUS_BIN_OPTION      ? TextByLanguage("Бинарный опцион","Binary option")               : 
      this.Status()==SYMBOL_STATUS_CUSTOM          ? TextByLanguage("Пользовательский символ","Custom symbol")       :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание типа цены для построения баров               |
//+------------------------------------------------------------------+
string CSymbol::GetChartModeDescription(void) const
  {
   return
     (
      this.ChartMode()==SYMBOL_CHART_MODE_BID ? TextByLanguage("Бары строятся по ценам Bid","Bars are based on Bid prices") : 
      TextByLanguage("Бары строятся по ценам Last","Bars are based on Last prices")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание способа вычисления залоговых средств         |
//+------------------------------------------------------------------+
string CSymbol::GetCalcModeDescription(void) const
  {
   return
     (
      this.TradeCalcMode()==SYMBOL_CALC_MODE_FOREX                ? 
         TextByLanguage("Расчет прибыли и маржи для Форекс","Forex mode")                                               :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE    ? 
         TextByLanguage("Расчет прибыли и маржи для Форекс без учета плеча","Forex No Leverage mode")                   :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_FUTURES              ? 
         TextByLanguage("Расчет залога и прибыли для фьючерсов","Futures mode")                                         :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_CFD                  ? 
         TextByLanguage("Расчет залога и прибыли для CFD","CFD mode")                                                   :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_CFDINDEX             ? 
         TextByLanguage("Расчет залога и прибыли для CFD на индексы","CFD index mode")                                  :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_CFDLEVERAGE          ? 
         TextByLanguage("Расчет залога и прибыли для CFD при торговле с плечом","CFD Leverage mode")                    :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_EXCH_STOCKS          ? 
         TextByLanguage("Расчет залога и прибыли для торговли ценными бумагами на бирже","Exchange mode")               :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_EXCH_FUTURES         ? 
         TextByLanguage("Расчет залога и прибыли для торговли фьючерсными контрактами на бирже","Futures mode")         :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS   ? 
         TextByLanguage("Расчет залога и прибыли для торговли фьючерсными контрактами на FORTS","FORTS Futures mode")   :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_EXCH_BONDS           ? 
         TextByLanguage("Расчет прибыли и маржи по торговым облигациям на бирже","Exchange Bonds mode")                 :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX     ? 
         TextByLanguage("Расчет прибыли и маржи при торговле ценными бумагами на MOEX","Exchange MOEX Stocks mode")     :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_EXCH_BONDS_MOEX      ? 
         TextByLanguage("Расчет прибыли и маржи по торговым облигациям на MOEX","Exchange MOEX Bonds mode")             :
      this.TradeCalcMode()==SYMBOL_CALC_MODE_SERV_COLLATERAL      ? 
         TextByLanguage("Используется в качестве неторгуемого актива на счете","Collateral mode")                       :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание режима торговли по инструменту               |
//+------------------------------------------------------------------+
string CSymbol::GetTradeModeDescription(void) const
  {
   return
     (
      this.TradeMode()==SYMBOL_TRADE_MODE_DISABLED    ? TextByLanguage("Торговля по символу запрещена","Trade is disabled for the symbol")                     :
      this.TradeMode()==SYMBOL_TRADE_MODE_LONGONLY    ? TextByLanguage("Разрешены только покупки","Allowed only long positions")                               :
      this.TradeMode()==SYMBOL_TRADE_MODE_SHORTONLY   ? TextByLanguage("Разрешены только продажи","Allowed only short positions")                              :
      this.TradeMode()==SYMBOL_TRADE_MODE_CLOSEONLY   ? TextByLanguage("Разрешены только операции закрытия позиций","Allowed only position close operations")  :
      this.TradeMode()==SYMBOL_TRADE_MODE_FULL        ? TextByLanguage("Нет ограничений на торговые операции","No trade restrictions")                         :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание режима заключения сделок по инструменту      |
//+------------------------------------------------------------------+
string CSymbol::GetTradeExecDescription(void) const
  {
   return
     (
      this.TradeExecutionMode()==SYMBOL_TRADE_EXECUTION_REQUEST   ? TextByLanguage("Торговля по запросу","Execution by request")       :
      this.TradeExecutionMode()==SYMBOL_TRADE_EXECUTION_INSTANT   ? TextByLanguage("Торговля по потоковым ценам","Instant execution")  :
      this.TradeExecutionMode()==SYMBOL_TRADE_EXECUTION_MARKET    ? TextByLanguage("Исполнение ордеров по рынку","Market execution")   :
      this.TradeExecutionMode()==SYMBOL_TRADE_EXECUTION_EXCHANGE  ? TextByLanguage("Биржевое исполнение","Exchange execution")         :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание модели расчета свопа                         |
//+------------------------------------------------------------------+
string CSymbol::GetSwapModeDescription(void) const
  {
   return
     (
      this.SwapMode()==SYMBOL_SWAP_MODE_DISABLED         ? 
         TextByLanguage("Нет свопов","Swaps disabled (no swaps)")                                                                                                                                                    :
      this.SwapMode()==SYMBOL_SWAP_MODE_POINTS           ? 
         TextByLanguage("Свопы начисляются в пунктах","Swaps are charged in points")                                                                                                                                 :
      this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_SYMBOL  ? 
         TextByLanguage("Свопы начисляются в деньгах в базовой валюте символа","Swaps are charged in money in base currency of the symbol")                                                                          :
      this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_MARGIN  ? 
         TextByLanguage("Свопы начисляются в деньгах в маржинальной валюте символа","Swaps are charged in money in margin currency of the symbol")                                                                   :
      this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT ? 
         TextByLanguage("Свопы начисляются в деньгах в валюте депозита клиента","Swaps are charged in money, in client deposit currency")                                                                            :
      this.SwapMode()==SYMBOL_SWAP_MODE_INTEREST_CURRENT ? 
         TextByLanguage("Свопы начисляются в годовых процентах от цены инструмента на момент расчета свопа","Swaps are charged as the specified annual interest from the instrument price at calculation of swap")   :
      this.SwapMode()==SYMBOL_SWAP_MODE_INTEREST_OPEN    ? 
         TextByLanguage("Свопы начисляются в годовых процентах от цены открытия позиции по символу","Swaps are charged as the specified annual interest from the open price of position")                            :
      this.SwapMode()==SYMBOL_SWAP_MODE_REOPEN_CURRENT   ? 
         TextByLanguage("Свопы начисляются переоткрытием позиции по цене закрытия","Swaps are charged by reopening positions by the close price")                                                                    :
      this.SwapMode()==SYMBOL_SWAP_MODE_REOPEN_BID       ? 
         TextByLanguage("Свопы начисляются переоткрытием позиции по текущей цене Bid","Swaps are charged by reopening positions by the current Bid price")                                                           :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание срока действия StopLoss и TakeProfit ордеров |
//+------------------------------------------------------------------+
string CSymbol::GetOrderGTCModeDescription(void) const
  {
   return
     (
      this.OrderModeGTC()==SYMBOL_ORDERS_GTC                   ? 
         TextByLanguage("Отложенные ордеры и уровни Stop Loss/Take Profit действительны неограниченно по времени до явной отмены","Pending orders and Stop Loss/Take Profit levels are valid for an unlimited period until their explicit cancellation") :
      this.OrderModeGTC()==SYMBOL_ORDERS_DAILY                 ? 
         TextByLanguage("При смене торгового дня отложенные ордеры и все уровни StopLoss и TakeProfit удаляются","At the end of the day, all Stop Loss and Take Profit levels, as well as pending orders are deleted")                                   :
      this.OrderModeGTC()==SYMBOL_ORDERS_DAILY_EXCLUDING_STOPS ? 
         TextByLanguage("При смене торгового дня удаляются только отложенные ордеры, уровни StopLoss и TakeProfit сохраняются","At the end of the day, only pending orders are deleted, while Stop Loss and Take Profit levels are preserved")           :
      ""
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание типа опциона                                 |
//+------------------------------------------------------------------+
string CSymbol::GetOptionTypeDescription(void) const
  {
   return
     (
      #ifdef __MQL4__ TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #else 
      this.OptionMode()==SYMBOL_OPTION_MODE_EUROPEAN ? 
         TextByLanguage("Европейский тип опциона – может быть погашен только в указанную дату","European option may only be exercised on a specified date")                               :
      this.OptionMode()==SYMBOL_OPTION_MODE_AMERICAN ? 
         TextByLanguage("Американский тип опциона – может быть погашен в любой день до истечения срока опциона","American option may be exercised on any trading day or before expiry")   :
      ""
      #endif 
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание права опциона                                |
//+------------------------------------------------------------------+
string CSymbol::GetOptionRightDescription(void) const
  {
   return
     (
      #ifdef __MQL4__ TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #else 
      this.OptionRight()==SYMBOL_OPTION_RIGHT_CALL ? 
         TextByLanguage("Опцион, дающий право купить актив по фиксированной цене","A call option gives you the right to buy an asset at a specified price")    :
      this.OptionRight()==SYMBOL_OPTION_RIGHT_PUT  ? 
         TextByLanguage("Опцион, дающий право продать актив по фиксированной цене  ","A put option gives you the right to sell an asset at a specified price") :
      ""
      #endif 
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание флагов разрешенных типов ордеров             |
//+------------------------------------------------------------------+
string CSymbol::GetOrderModeFlagsDescription(void) const
  {
   string first=#ifdef __MQL5__ "\n - " #else ""   #endif ;
   string next= #ifdef __MQL5__ "\n - " #else "; " #endif ;
   return
     (
      first+this.GetMarketOrdersAllowedDescription()+
      next+this.GetLimitOrdersAllowedDescription()+
      next+this.GetStopOrdersAllowedDescription()+
      next+this.GetStopLimitOrdersAllowedDescription()+
      next+this.GetStopLossOrdersAllowedDescription()+
      next+this.GetTakeProfitOrdersAllowedDescription()+
      next+this.GetCloseByOrdersAllowedDescription()
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание флагов разрешённых типов заливки             |
//+------------------------------------------------------------------+
string CSymbol::GetFillingModeFlagsDescription(void) const
  {
   string first=#ifdef __MQL5__ "\n - " #else ""   #endif ;
   string next= #ifdef __MQL5__ "\n - " #else "; " #endif ;
   return
     (
      first+TextByLanguage("Вернуть (Да)","Return (Yes)")+
      next+this.GetFillingModeFOKAllowedDescrioption()+
      next+this.GetFillingModeIOCAllowedDescrioption()
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание флагов разрешенных режимов истечения ордера  |
//+------------------------------------------------------------------+
string CSymbol::GetExpirationModeFlagsDescription(void) const
  {
   string first=#ifdef __MQL5__ "\n - " #else ""   #endif ;
   string next= #ifdef __MQL5__ "\n - " #else "; " #endif ;
   return
     (
      first+this.GetExpirationModeGTCDescription()+
      next+this.GetExpirationModeDAYDescription()+
      next+this.GetExpirationModeSpecifiedDescription()+
      next+this.GetExpirationModeSpecDayDescription()
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание разрешения рыночных ордеров                  |
//+------------------------------------------------------------------+
string CSymbol::GetMarketOrdersAllowedDescription(void) const
  {
   return
     (this.IsMarketOrdersAllowed() ? 
      TextByLanguage("Рыночный ордер (Да)","Market order (Yes)") : 
      TextByLanguage("Рыночный ордер (Нет)","Market order (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание разрешения лимитных ордеров                  |
//+------------------------------------------------------------------+
string CSymbol::GetLimitOrdersAllowedDescription(void) const
  {
   return
     (this.IsLimitOrdersAllowed() ? 
      TextByLanguage("Лимит ордер (Да)","Limit order (Yes)") : 
      TextByLanguage("Лимит ордер (Нет)","Limit order (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание разрешения стоп ордеров                      |
//+------------------------------------------------------------------+
string CSymbol::GetStopOrdersAllowedDescription(void) const
  {
   return
     (this.IsStopOrdersAllowed() ? 
      TextByLanguage("Стоп ордер (Да)","Stop order (Yes)") : 
      TextByLanguage("Стоп ордер (Нет)","Stop order (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание разрешения стоп-лимит ордеров                |
//+------------------------------------------------------------------+
string CSymbol::GetStopLimitOrdersAllowedDescription(void) const
  {
   return
     (this.IsStopLimitOrdersAllowed() ? 
      TextByLanguage("Стоп-лимит ордер (Да)","StopLimit order (Yes)") : 
      TextByLanguage("Стоп-лимит ордер (Нет)","StopLimit order (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание разрешения установки StopLoss приказов       |
//+------------------------------------------------------------------+
string CSymbol::GetStopLossOrdersAllowedDescription(void) const
  {
   return
     (this.IsStopLossOrdersAllowed() ? 
      TextByLanguage("StopLoss (Да)","StopLoss (Yes)") : 
      TextByLanguage("StopLoss (Нет)","StopLoss (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание разрешения установки TakeProfit приказов     |
//+------------------------------------------------------------------+
string CSymbol::GetTakeProfitOrdersAllowedDescription(void) const
  {
   return
     (this.IsTakeProfitOrdersAllowed() ? 
      TextByLanguage("TakeProfit (Да)","TakeProfit (Yes)") : 
      TextByLanguage("TakeProfit (Нет)","TakeProfit (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание разрешения закрытия встречной                |
//+------------------------------------------------------------------+
string CSymbol::GetCloseByOrdersAllowedDescription(void) const
  {
   return
     (this.IsCloseByOrdersAllowed() ? 
      TextByLanguage("Закрытие встречным (Да)","CloseBy order (Yes)") : 
      TextByLanguage("Закрытие встречным (Нет)","CloseBy order (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание разрешения типа заливки FOK                  |
//+------------------------------------------------------------------+
string CSymbol::GetFillingModeFOKAllowedDescrioption(void) const
  {
   return
     (this.IsFillingModeFOK() ? 
      TextByLanguage("Всё/Ничего (Да)","Fill or Kill (Yes)") : 
      TextByLanguage("Всё/Ничего (Нет)","Fill or Kill (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание разрешения типа заливки IOC                  |
//+------------------------------------------------------------------+
string CSymbol::GetFillingModeIOCAllowedDescrioption(void) const
  {
   return
     (this.IsFillingModeIOC() ? 
      TextByLanguage("Всё/Частично (Да)","Immediate or Cancel order (Yes)") : 
      TextByLanguage("Всё/Частично (Нет)","Immediate or Cancel (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание истечения действия ордера GTC                |
//+------------------------------------------------------------------+
string CSymbol::GetExpirationModeGTCDescription(void) const
  {
   return
     (this.IsExipirationModeGTC() ? 
      TextByLanguage("Неограниченно (Да)","Unlimited (Yes)") : 
      TextByLanguage("Неограниченно (Нет)","Unlimited (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание истечения действия ордера DAY                |
//+------------------------------------------------------------------+
string CSymbol::GetExpirationModeDAYDescription(void) const
  {
   return
     (this.IsExipirationModeDAY() ? 
      TextByLanguage("До конца дня (Да)","Valid till the end of the day (Yes)") : 
      TextByLanguage("До конца дня (Нет)","Valid till the end of the day (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание истечения действия ордера Specified          |
//+------------------------------------------------------------------+
string CSymbol::GetExpirationModeSpecifiedDescription(void) const
  {
   return
     (this.IsExipirationModeSpecified() ? 
      TextByLanguage("Срок указывается в ордере (Да)","Time is specified in the order (Yes)") : 
      TextByLanguage("Срок указывается в ордере (Нет)","Time is specified in the order (No)")
     );
  }
//+------------------------------------------------------------------+
//| Возвращает описание истечения действия ордера Specified Day      |
//+------------------------------------------------------------------+
string CSymbol::GetExpirationModeSpecDayDescription(void) const
  {
   return
     (this.IsExipirationModeSpecifiedDay() ? 
      TextByLanguage("День указывается в ордере (Да)","Date is specified in the order (Yes)") : 
      TextByLanguage("День указывается в ордере (Нет)","Date is specified in the order (No)")
     );
  }
//+------------------------------------------------------------------+

В методах всё просто: проверяется значение свойства и возвращается его строковое описание.
Некоторые методы, а именно методы описания флагов, выводят в составе возвращаемого описания строковые значения других методов, также возвращающих описания уже конкретных флагов, из которых составлено значение проверяемого свойства. Таким образом получается отформатированное составное описание всех флагов одного свойства.
Для MQL5 флаги одного свойства выводятся в столбик под названием описываемого свойства, например:

Флаги разрешенных типов ордера: 
 - Рыночный ордер (Да)
 - Лимит ордер (Да)
 - Стоп ордер (Да)
 - Стоп-лимит ордер (Да)
 - StopLoss (Да)
 - TakeProfit (Да)
 - Закрытие встречным (Да)

Для MQL4 эти свойства выводятся в одну строку:

Флаги разрешенных типов ордера: Рыночный ордер (Да); Лимит ордер (Да); Стоп ордер (Да); Стоп-лимит ордер (Нет); StopLoss (Да); TakeProfit (Да); Закрытие встречным (Да)

Связано это с тем, что в MQL4 функция Print() не воспринимает коды переноса строки "\n". Поэтому в методах сделано раздельное форматирование для MQL5 и MQL4 директивами условной компиляции.

Сервисный метод, возвращающий нормализованную цену с учётом свойств символа:

//+------------------------------------------------------------------+
//| Возвращает нормализованную цену с учетом свойств символа         |
//+------------------------------------------------------------------+
double CSymbol::NormalizedPrice(const double price) const
  {
   double tsize=this.TradeTickSize();
   return(tsize!=0 ? ::NormalizeDouble(::round(price/tsize)*tsize,this.Digits()) : ::NormalizeDouble(price,this.Digits()));
  }
//+------------------------------------------------------------------+

Метод нормализует цену с учётом размера минимального изменения цены.

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

//+------------------------------------------------------------------+
//| Обновляет все данные символа, которые могут измениться           |
//+------------------------------------------------------------------+
void CSymbol::Refresh(void)
  {
   ::ResetLastError();
   if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick))
     {
      this.m_global_error=::GetLastError();
      ::Print(DFUN_ERR_LINE,this.Name(),": ",TextByLanguage("Не удалось получить текущие цены. Ошибка: ","Could not get current prices. Error: "),this.m_global_error);
      return;
     }
//--- Обновление целочисленных свойств
   this.m_long_prop[SYMBOL_PROP_VOLUME]                                       = (long)this.m_tick.volume;
   this.m_long_prop[SYMBOL_PROP_TIME]                                         = #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ;
   this.m_long_prop[SYMBOL_PROP_SELECT]                                       = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SELECT);
   this.m_long_prop[SYMBOL_PROP_VISIBLE]                                      = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VISIBLE);
   this.m_long_prop[SYMBOL_PROP_SESSION_DEALS]                                = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_DEALS);
   this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS]                           = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS);
   this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS]                          = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS);
   this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH]                                   = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMEHIGH);
   this.m_long_prop[SYMBOL_PROP_VOLUMELOW]                                    = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_VOLUMELOW);
   this.m_long_prop[SYMBOL_PROP_SPREAD]                                       = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD);
   this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH]                              = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TICKS_BOOKDEPTH);
   this.m_long_prop[SYMBOL_PROP_START_TIME]                                   = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_START_TIME);
   this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME]                              = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXPIRATION_TIME);
   this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL]                            = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_STOPS_LEVEL);
   this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL]                           = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_FREEZE_LEVEL);
   this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR]                             = this.SymbolBackgroundColor();
//--- Обновление вещественных свойств
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)]                    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKHIGH);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)]                     = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKLOW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)]                   = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTHIGH);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)]                    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTLOW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)]           = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)]    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_PROFIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)]      = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_LOSS);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)]            = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_SIZE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)]        = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_CONTRACT_SIZE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)]                 = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MIN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)]                 = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_MAX);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)]                = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_STEP);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)]               = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_VOLUME_LIMIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)]                  = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_LONG);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)]                 = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SWAP_SHORT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)]             = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_INITIAL);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)]         = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_MAINTENANCE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG)]                = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_LONG);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT)]               = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_SHORT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_STOP)]                = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_STOP);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LIMIT)]               = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_LIMIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_STOPLIMIT)]           = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_MARGIN_STOPLIMIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)]             = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)]           = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_TURNOVER);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)]           = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_INTEREST);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)]  = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)]               = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_OPEN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)]              = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_CLOSE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)]                 = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_AW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)]   = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_SETTLEMENT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)]    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MIN);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)]    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_SESSION_PRICE_LIMIT_MAX);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)]                        = this.m_tick.ask;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)]                        = this.m_tick.bid;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)]                       = this.m_tick.last;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)]                    = this.SymbolBidHigh();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)]                     = this.SymbolBidLow();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)]                = this.SymbolVolumeReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)]            = this.SymbolVolumeHighReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)]             = this.SymbolVolumeLowReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)]              = this.SymbolOptionStrike();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)]     = this.SymbolTradeAccruedInterest();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)]           = this.SymbolTradeFaceValue();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)]       = this.SymbolTradeLiquidityRate();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)]              = this.SymbolMarginHedged();
  }
//+------------------------------------------------------------------+
//| Обновляет котировочные данные по символу                         |
//+------------------------------------------------------------------+
void CSymbol::RefreshRates(void)
  {
   ::ResetLastError();
   if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick))
     {
      this.m_global_error=::GetLastError();
      ::Print(DFUN_ERR_LINE,this.Name(),": ",TextByLanguage("Не удалось получить текущие цены. Ошибка: ","Could not get current prices. Error: "),this.m_global_error);
      return;
     }
//--- Обновление целочисленных свойств
   this.m_long_prop[SYMBOL_PROP_VOLUME]                                       = (long)this.m_tick.volume;
   this.m_long_prop[SYMBOL_PROP_TIME]                                         = #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ;
   this.m_long_prop[SYMBOL_PROP_SPREAD]                                       = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SPREAD);
   this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL]                            = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_STOPS_LEVEL);
   this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL]                           = ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_TRADE_FREEZE_LEVEL);
//--- Обновление вещественных свойств
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)]                    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKHIGH);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)]                     = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_ASKLOW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)]                   = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTHIGH);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)]                    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_LASTLOW);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)]           = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)]    = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_PROFIT);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)]      = ::SymbolInfoDouble(this.m_symbol_name,SYMBOL_TRADE_TICK_VALUE_LOSS);
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)]                        = this.m_tick.ask;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)]                        = this.m_tick.bid;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)]                       = this.m_tick.last;
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)]                    = this.SymbolBidHigh();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)]                     = this.SymbolBidLow();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)]                = this.SymbolVolumeReal();
   this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)]              = this.SymbolOptionStrike();
  }  
//+------------------------------------------------------------------+

Здесь просто: заново заполняются требуемые свойства символа из его данных.
Оба метода предназначены для получения актуальной информации о свойствах символа. Метод Refresh() необходимо будет вызывать перед непосредственным получением требуемой информации, а метод RefreshRates() — постоянно в таймере для всех объектов-символов в составе списка-коллекции, которым мы займёмся далее.

На этом мы закончили создание методов объекта абстрактного символа.

Теперь нам необходимо внести некоторые дополнения в файл ToMQL4.mqh, в котором мы прописываем необходимые перечисления и макроподстановки для безошибочной компиляции в MQL4.

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

//+------------------------------------------------------------------+
//|                                                       ToMQL4.mqh |
//|              Copyright 2017, Artem A. Trishkin, Skype artmedia70 |
//|                         https://www.mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Artem A. Trishkin, Skype artmedia70"
#property link      "https://www.mql5.com/ru/users/artmedia70"
#property strict
#ifdef __MQL4__
//+------------------------------------------------------------------+
//| Коды ошибок                                                      |
//+------------------------------------------------------------------+
#define ERR_SUCCESS                       (ERR_NO_ERROR)
#define ERR_MARKET_UNKNOWN_SYMBOL         (ERR_UNKNOWN_SYMBOL)
//+------------------------------------------------------------------+

Также мы использовали флаги, отвечающие за различные режимы ордеров на символе, обозначим и их:

//+------------------------------------------------------------------+
//| Флаги разрешенных режимов истечения ордера                       |
//+------------------------------------------------------------------+
#define SYMBOL_EXPIRATION_GTC             (1)
#define SYMBOL_EXPIRATION_DAY             (2)
#define SYMBOL_EXPIRATION_SPECIFIED       (4)
#define SYMBOL_EXPIRATION_SPECIFIED_DAY   (8)
//+------------------------------------------------------------------+
//| Флаги разрешенных режимов заливки ордера                         |
//+------------------------------------------------------------------+
#define SYMBOL_FILLING_FOK                (1)
#define SYMBOL_FILLING_IOC                (2)
//+------------------------------------------------------------------+
//| Флаги разрешенных типов ордера                                   |
//+------------------------------------------------------------------+
#define SYMBOL_ORDER_MARKET               (1)
#define SYMBOL_ORDER_LIMIT                (2)
#define SYMBOL_ORDER_STOP                 (4)
#define SYMBOL_ORDER_STOP_LIMIT           (8)
#define SYMBOL_ORDER_SL                   (16)
#define SYMBOL_ORDER_TP                   (32)
#define SYMBOL_ORDER_CLOSEBY              (64)
//+------------------------------------------------------------------+

Добавим отсутствующие в MQL4 перечисления:

//+------------------------------------------------------------------+
//| Цены, на основе которых строится график по символу               |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_CHART_MODE
  {
   SYMBOL_CHART_MODE_BID,                 // Бары строятся по ценам Bid
   SYMBOL_CHART_MODE_LAST                 // Бары строятся по ценам Last
  };
//+------------------------------------------------------------------+
//| Срок действия отложенных ордеров и                               |
//| установленных уровней StopLoss/TakeProfit                        |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_ORDER_GTC_MODE
  {
   SYMBOL_ORDERS_GTC,                     // Отложенные ордеры и уровни Stop Loss/Take Profit действительны неограниченно по времени до явной отмены
   SYMBOL_ORDERS_DAILY,                   // При смене торгового дня отложенные ордеры и все уровни StopLoss и TakeProfit удаляются
   SYMBOL_ORDERS_DAILY_EXCLUDING_STOPS    // При смене торгового дня удаляются только отложенные ордеры, уровни StopLoss и TakeProfit сохраняются
  };
//+------------------------------------------------------------------+
//| Типы опционов                                                    |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_OPTION_MODE
  {
   SYMBOL_OPTION_MODE_EUROPEAN,           // Европейский тип опциона – может быть погашен только в указанную дату
   SYMBOL_OPTION_MODE_AMERICAN            // Американский тип опциона – может быть погашен в любой день до истечения срока опциона
  };
#define SYMBOL_OPTION_MODE_NONE     (2)   // Отсутствующий тип опциона - в MQL4 их нет
//+------------------------------------------------------------------+
//| Право, предоставляемое опционом                                  |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_OPTION_RIGHT
  {
   SYMBOL_OPTION_RIGHT_CALL,              // Опцион, дающий право купить актив по фиксированной цене
   SYMBOL_OPTION_RIGHT_PUT                // Опцион, дающий право продать актив по фиксированной цене
  };
#define SYMBOL_OPTION_RIGHT_NONE    (2)   // Нет опциона - нет и права
//+------------------------------------------------------------------+

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

Два последующих перечисления имеют особенности: в них нет соответствия последовательности значений констант в MQL5 и MQL4.

Поэтому пришлось поменять местами последовательность указания констант, входящих в состав перечислений. В комментариях к значениям констант прописаны их значения для MQL5 и MQL4, и порядок их следования здесь установлен для соответствия значениям в MQL4 — чтобы возвращались верные значения:

//+------------------------------------------------------------------+
//| Способ вычисления величины залоговых средств по инструменту      |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_CALC_MODE
  {
   SYMBOL_CALC_MODE_FOREX,                // (MQL5 - 0, MQL4 - 0) Forex mode – расчет прибыли и маржи для Форекс
   SYMBOL_CALC_MODE_CFD,                  // (MQL5 - 3, MQL4 - 1) CFD mode – расчет залога и прибыли для CFD (контракт на разницу цен)
   SYMBOL_CALC_MODE_FUTURES,              // (MQL5 - 2, MQL4 - 2) Futures mode – расчет залога и прибыли для фьючерсов
   SYMBOL_CALC_MODE_CFDINDEX,             // (MQL5 - 4, MQL4 - 3) CFD index mode – расчет залога и прибыли для CFD на индексы
   SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE,    // (MQL5 - 1, MQL4 - N) Forex No Leverage mode – расчет прибыли и маржи для Форекс без учета плеча
   SYMBOL_CALC_MODE_CFDLEVERAGE,          // CFD Leverage mode – расчет залога и прибыли для CFD при торговле с плечом
   SYMBOL_CALC_MODE_EXCH_STOCKS,          // Exchange mode – расчет залога и прибыли для торговли ценными бумагами на бирже
   SYMBOL_CALC_MODE_EXCH_FUTURES,         // Futures mode – расчет залога и прибыли для торговли фьючерсными контрактами на бирже
   SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS,   // FORTS Futures mode –  расчет залога и прибыли для торговли фьючерсными контрактами на FORTS
   SYMBOL_CALC_MODE_EXCH_BONDS,           // Расчет прибыли и маржи по торговым облигациям на бирже
   SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX,     // Расчет прибыли и маржи при торговле ценными бумагами на MOEX
   SYMBOL_CALC_MODE_EXCH_BONDS_MOEX,      // Расчет прибыли и маржи по торговым облигациям на MOEX
   SYMBOL_CALC_MODE_SERV_COLLATERAL       // Collateral mode - инструмент используется в качестве неторгуемого актива на торговом счете
  };  
//+------------------------------------------------------------------+
//| Способы начисления свопов при переносе позиции                   |
//+------------------------------------------------------------------+
enum ENUM_SYMBOL_SWAP_MODE
  {
   SYMBOL_SWAP_MODE_POINTS,               // (MQL5 - 1, MQL4 - 0) Свопы начисляются в пунктах
   SYMBOL_SWAP_MODE_CURRENCY_SYMBOL,      // (MQL5 - 2, MQL4 - 1) Свопы начисляются в деньгах в базовой валюте символа
   SYMBOL_SWAP_MODE_INTEREST_OPEN,        // (MQL5 - 6, MQL4 - 2) Свопы начисляются в годовых процентах от цены открытия позиции по символу
   SYMBOL_SWAP_MODE_CURRENCY_MARGIN,      // (MQL5 - 3, MQL4 - 3) Свопы начисляются в деньгах в маржинальной валюте символа
   SYMBOL_SWAP_MODE_DISABLED,             // (MQL5 - 0, MQL4 - N) Нет свопов
   SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT,     // Свопы начисляются в деньгах в валюте депозита клиента
   SYMBOL_SWAP_MODE_INTEREST_CURRENT,     // Свопы начисляются в годовых процентах от цены инструмента на момент расчета свопа
   SYMBOL_SWAP_MODE_REOPEN_CURRENT,       // Свопы начисляются переоткрытием позиции по цене закрытия
   SYMBOL_SWAP_MODE_REOPEN_BID            // Свопы начисляются переоткрытием позиции по текущей цене Bid
  };
//+------------------------------------------------------------------+

Теперь все данные для объекта-символа созданы.

Нам нужно (раз уж мы ввели код ошибок, возвращаемый из классов в главный объект библиотеки Engine) ввести переменную-член класса CEngine для хранения кода ошибки. Откроем файл \MQL5\Include\DoEasy\ Engine.mqh и впишем в него необходимые изменения.
В приватной секции класса объявим переменную для хранения кодов ошибок:

class CEngine : public CObject
  {
private:
   CHistoryCollection   m_history;                       // Коллекция исторических ордеров и сделок
   CMarketCollection    m_market;                        // Коллекция рыночных ордеров и сделок
   CEventsCollection    m_events;                        // Коллекция событий
   CAccountsCollection  m_accounts;                      // Коллекция аккаунтов
   CArrayObj            m_list_counters;                 // Список счётчиков таймера
   int                  m_global_error;                  // Код глобальной ошибки
   bool                 m_first_start;                   // Флаг первого запуска
   bool                 m_is_hedge;                      // Флаг хедж-счёта
   bool                 m_is_tester;                     // Флаг работы в тестере

В конструкторе класса, в его списке инициализации инициализируем код ошибки, и далее — в блоках создания милисекундного таймера для MQL5 и MQL4, впишем в переменную код последней ошибки:

//+------------------------------------------------------------------+
//| CEngine конструктор                                              |
//+------------------------------------------------------------------+
CEngine::CEngine() : m_first_start(true),m_last_trade_event(TRADE_EVENT_NO_EVENT),m_last_account_event(ACCOUNT_EVENT_NO_EVENT),m_global_error(ERR_SUCCESS)
  {
   this.m_list_counters.Sort();
   this.m_list_counters.Clear();
   this.CreateCounter(COLLECTION_ORD_COUNTER_ID,COLLECTION_ORD_COUNTER_STEP,COLLECTION_ORD_PAUSE);
   this.CreateCounter(COLLECTION_ACC_COUNTER_ID,COLLECTION_ACC_COUNTER_STEP,COLLECTION_ACC_PAUSE);
   
   this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif;
   this.m_is_tester=::MQLInfoInteger(MQL_TESTER);
   ::ResetLastError();
   #ifdef __MQL5__
      if(!::EventSetMillisecondTimer(TIMER_FREQUENCY))
        {
         ::Print(DFUN_ERR_LINE,"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: ",(string)::GetLastError());
         this.m_global_error=::GetLastError();
        }
   //---__MQL4__
   #else 
      if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY))
        {
         ::Print(DFUN_ERR_LINE,"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: ",(string)::GetLastError());
         this.m_global_error=::GetLastError();
        }
   #endif 
  }
//+------------------------------------------------------------------+

Осталось подключить файл вновь созданного класса к главному объекту библиотеки (временно — только для текущей проверки):

//+------------------------------------------------------------------+
//|                                                       Engine.mqh |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ru/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://mql5.com/ru/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Включаемые файлы                                                 |
//+------------------------------------------------------------------+
#include "Collections\HistoryCollection.mqh"
#include "Collections\MarketCollection.mqh"
#include "Collections\EventsCollection.mqh"
#include "Collections\AccountsCollection.mqh"
#include "Services\TimerCounter.mqh"
#include "Objects\Symbols\Symbol.mqh"
//+------------------------------------------------------------------+
//| Класс-основа библиотеки                                          |
//+------------------------------------------------------------------+
class CEngine : public CObject
  {

Теперь у нас всё готово для тестирования объекта-символа.

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

//+------------------------------------------------------------------+
//| Возвращает событие аккаунта по его номеру в списке               |
//+------------------------------------------------------------------+
ENUM_ACCOUNT_EVENT CAccountsCollection::GetEvent(const int shift=WRONG_VALUE)
  {
   int total=this.m_list_changes.Total();
   if(total==0)
      return ACCOUNT_EVENT_NO_EVENT;   
   int index=(shift<0 || shift>total-1 ? total-1 : total-shift-1);
   int event=this.m_list_changes.At(index);
   return ENUM_ACCOUNT_EVENT(event!=NULL ? event : ACCOUNT_EVENT_NO_EVENT);
  }
//+------------------------------------------------------------------+

И вот, что я писал о принципе возврата событий из метода:

События в списке изменений свойств аккаунта располагаются в порядке их добавления — самое первое находится по индексу 0, а самое последнее — по индексу (размер_списка-1). Нам же нужно, чтобы пользователь мог получить искомое событие как в таймсерии — в нулевом индексе должно находиться самое последнее событие. Для этого в методе сделан расчёт индекса: index = (размер_списка - номер_искомого_события-1). При таком расчёте, если передать 0 или -1, то будет возвращено последнее событие в списке, если 1, то предпоследнее, если передать число, превышающее размер списка, то будет возвращено последнее событие.

Здесь нарушена логика: если в метод передать 0, то получаем последнее событие, и если передать значение, превышающее размер массива, то по логике вещей желательно бы вернуть первое событие, а мы возвращаем последнее — это нелогично. Логично — для получения последнего события передать значение либо 0, либо меньше нуля (по умолчанию), и далее — по очерёдности: 1 — предпоследнее, 2 — пред-предпоследнее, и т.д. — как в таймсерии.
А если не знать размер массива, и передать заведомо большое число, то по логике нужно ожидать получение самого дальнего по времени значения — первого, а метод вернёт последнее. Исправим это нелогичное поведение:

//+------------------------------------------------------------------+
//| Возвращает событие аккаунта по его номеру в списке               |
//+------------------------------------------------------------------+
ENUM_ACCOUNT_EVENT CAccountsCollection::GetEvent(const int shift=WRONG_VALUE)
  {
   int total=this.m_list_changes.Total();
   if(total==0)
      return ACCOUNT_EVENT_NO_EVENT;   
   int index=(shift<=0 ? total-1 : shift>total-1 ? 0 : total-shift-1);
   int event=this.m_list_changes.At(index);
   return ENUM_ACCOUNT_EVENT(event!=NULL ? event : ACCOUNT_EVENT_NO_EVENT);
  }
//+------------------------------------------------------------------+

Здесь: если передан 0 или -1, то возвращаем последнее событие, если передано значение, превышающее размер массива, то возвращаем первое событие, в остальных случаях индекс возвращаемого события рассчитывается.

Тест объекта-символа

Для тестирования объекта-символа возьмём советник из прошлой статьи и сохраним его под новым именем TestDoEasyPart14.mq5.

Проверять объект-символ будем в обработчике OnInit(). Для этого просто впишем в конец OnInit() строки кода:

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Вызов данной функции выводит в журнал список констант перечисления, 
//--- заданного в файле DELib.mqh в строках 22 и 25, для проверки корректности констант
   //EnumNumbersTest();

//--- Установка глобальных переменных советника
   prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_";
   for(int i=0;i<TOTAL_BUTT;i++)
     {
      butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i);
      butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i);
     }
   lot=NormalizeLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0));
   magic_number=InpMagic;
   stoploss=InpStopLoss;
   takeprofit=InpTakeProfit;
   distance_pending=InpDistance;
   distance_stoplimit=InpDistanceSL;
   slippage=InpSlippage;
   trailing_stop=InpTrailingStop*Point();
   trailing_step=InpTrailingStep*Point();
   trailing_start=InpTrailingStart;
   stoploss_to_modify=InpStopLossModify;
   takeprofit_to_modify=InpTakeProfitModify;

//--- Проверка и удаление неудалённых графических объектов советника
   if(IsPresentObects(prefix))
      ObjectsDeleteAll(0,prefix);

//--- Создание панели кнопок
   if(!CreateButtons(InpButtShiftX,InpButtShiftY))
      return INIT_FAILED;
//--- Установка состояния кнопки активизации трейлингов
   ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on);

//--- Установка параметров торгового класса CTrade
#ifdef __MQL5__
   trade.SetDeviationInPoints(slippage);
   trade.SetExpertMagicNumber(magic_number);
   trade.SetTypeFillingBySymbol(Symbol());
   trade.SetMarginMode();
   trade.LogLevel(LOG_LEVEL_NO);
#endif 
//--- Быстрая проверка объекта-символа
   string smb=Symbol();
   CSymbol* sy=new CSymbol(SYMBOL_STATUS_FX,smb);
   if(sy!=NULL)
     {
      sy.Refresh();
      sy.RefreshRates();
      sy.Print();
      delete sy;
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

Здесь: создаём новый объект-символ, и так как определение принадлежности символа к определённой группе мы будем делать в следующей статье, то просто передаём в конструктор статус "форекс-символ" и имя символа.
Если объект создан, то обновляем все его данные, обновляем котировочные данные, распечатываем в журнал все свойства объекта-символа и удаляем объект — чтобы не было утечки памяти при завершении работы этого тестового советника.

Если сейчас попытаться скомпилировать советник, то получим ошибку доступа к защищённому конструктору класса:

'CSymbol::CSymbol' - cannot access protected member function    TestDoEasyPart14.mq5    131     20
   see declaration of 'CSymbol::CSymbol'        Symbol.mqh      39      22
1 error(s), 0 warning(s)                2       1

Перейдём к файлу Symbol.mqh и перенесём защищённый параметрический конструктор временно из защищённой секции в публичную секцию класса:

//+------------------------------------------------------------------+
//| Класс абстрактного символа                                       |
//+------------------------------------------------------------------+
class CSymbol : public CObject
  {
private:
   MqlTick           m_tick;                                         // Структура тика символа
   MqlBookInfo       m_book_info_array[];                            // Массив структур данных стакана
   string            m_symbol_name;                                  // Имя символа
   long              m_long_prop[SYMBOL_PROP_INTEGER_TOTAL];         // Целочисленные свойства
   double            m_double_prop[SYMBOL_PROP_DOUBLE_TOTAL];        // Вещественные свойства
   string            m_string_prop[SYMBOL_PROP_STRING_TOTAL];        // Строковые свойства
   int               m_digits_currency;                              // Число знаков после запятой валюты счёта
   int               m_global_error;                                 // Код глобальной ошибки
//--- Возвращает индекс массива, по которому фактически расположено (1) double-свойство и (2) string-свойство символа
   int               IndexProp(ENUM_SYMBOL_PROP_DOUBLE property)  const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL;                                    }
   int               IndexProp(ENUM_SYMBOL_PROP_STRING property)  const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_DOUBLE_TOTAL;           }
//--- Обнуляет все данные объекта-символа
   void              Reset(void);
public:
//--- Конструктор по умолчанию
                     CSymbol(void){;}
                     CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name);
protected:
//--- Защищённый параметрический конструктор

//--- Получает и возвращает целочисленные свойства выбранного символа из его параметров

Теперь всё компилируется.

Запустим советник на графике символа в MetaTrader 5.
При этом в журнал распечатаются все свойства объекта-символа:

Счёт 18222304: Artyom Trishkin (MetaQuotes Software Corp. 10000.00 RUR, 1:100, Демонстрационный счёт MetaTrader 5)
============= Начало списка параметров: "EURUSD" (Euro vs US Dollar) ==================
Статус: Форекс символ
Пользовательский символ: Нет
Тип цены для построения баров: Бары строятся по ценам Bid
Символ с таким именем существует: Да
Символ выбран в Market Watch: Да
Символ отображается в Market Watch: Да
Количество сделок в текущей сессии: 0
Общее число ордеров на покупку в текущий момент: 0
Общее число ордеров на продажу в текущий момент: 0
Объем в последней сделке: 0
Максимальный объём за день: 0
Минимальный объём за день: 0
Время последней котировки: 2019.06.17 15:37:13.016
Количество знаков после запятой: 5
Количество знаков после запятой в значении лота: 2
Размер спреда в пунктах: 10
Плавающий спред: Да
Максимальное количество показываемых заявок в стакане: 10
Способ вычисления стоимости контракта: Расчет прибыли и маржи для Форекс
Тип исполнения ордеров: Нет ограничений на торговые операции
Дата начала торгов по инструменту: (Отсутствует)
Дата окончания торгов по инструменту: (Отсутствует)
Минимальный отступ от цены закрытия для установки Stop ордеров: 0
Дистанция заморозки торговых операций: 0
Режим заключения сделок: Торговля по потоковым ценам
Модель расчета свопа: Свопы начисляются в пунктах
День недели для начисления тройного свопа: Среда
Расчет хеджированной маржи по наибольшей стороне: Нет
Флаги разрешенных режимов истечения ордера: 
 - Неограниченно (Да)
 - До конца дня (Да)
 - Срок указывается в ордере (Да)
 - День указывается в ордере (Да)
Флаги разрешенных режимов заливки ордера: 
 - Вернуть (Да)
 - Всё/Ничего (Да)
 - Всё/Частично (Нет)
Флаги разрешенных типов ордера: 
 - Рыночный ордер (Да)
 - Лимит ордер (Да)
 - Стоп ордер (Да)
 - Стоп-лимит ордер (Да)
 - StopLoss (Да)
 - TakeProfit (Да)
 - Закрытие встречным (Да)
Срок действия StopLoss и TakeProfit ордеров: Отложенные ордеры и уровни Stop Loss/Take Profit действительны неограниченно по времени до явной отмены
Тип опциона: Европейский тип опциона – может быть погашен только в указанную дату
Право опциона: Опцион, дающий право купить актив по фиксированной цене
Цвет фона символа в Market Watch: (Отсутствует)
------
Цена Bid: 1.12411
Максимальный Bid за день: 1.12467
Минимальный Bid за день: 1.12033
Цена Ask: 1.12421
Максимальный Ask за день: 1.12477
Минимальный Ask за день: 1.12043
Цена последней сделки: 0.00000
Максимальный Last за день: 0.00000
Минимальный Last за день: 0.00000
Реальный объём за день: 0.00
Максимальный реальный объём за день: 0.00
Минимальный реальный объём за день: 0.00
Цена исполнения опциона: 0.00000
Значение одного пункта: 0.00001
Рассчитанная стоимость тика для позиции: 64.22
Рассчитанная стоимость тика для прибыльной позиции: 64.22
Рассчитанная стоимость тика для убыточной позиции: 64.23
Минимальное изменение цены: 0.00001
Размер торгового контракта: 100000.00
Накопленный купонный доход: 0.00
Начальная стоимость облигации, установленная эмитентом: 0.00
Коэффициент ликвидности: 0.00
Минимальный объем для заключения сделки: 0.01
Максимальный объем для заключения сделки: 500.00
Минимальный шаг изменения объема для заключения сделки: 0.01
Максимально допустимый общий объем позиции и отложенных ордеров в одном направлении: 0.00
Значение свопа на покупку: -0.70
Значение свопа на продажу: -1.00
Начальная (инициирующая) маржа: 0.00
Поддерживающая маржа по инструменту: 0.00
Коэффициент взимания маржи по длинным позициям: 0.00
Коэффициент взимания маржи по коротким позициям: 0.00
Коэффициент взимания маржи по Stop ордерам: 0.00
Коэффициент взимания маржи по Limit ордерам: 0.00
Коэффициент взимания маржи по Stop Limit ордерам: 0.00
Cуммарный объём сделок в текущую сессию: 0.00
Cуммарный оборот в текущую сессию: 0.00
Cуммарный объём открытых позиций: 0.00
Общий объём ордеров на покупку в текущий момент: 0.00
Общий объём ордеров на продажу в текущий момент: 0.00
Цена открытия сессии: 0.00000
Цена закрытия сессии: 0.00000
Средневзвешенная цена сессии: 0.00000
Цена поставки на текущую сессию: 0.00000
Минимально допустимое значение цены на сессию: 0.00000
Максимально допустимое значение цены на сессию: 0.00000
Размер контракта или маржи для одного лота перекрытых позиций: 100000.00
------
Имя символа: EURUSD
Имя базового актива для производного инструмента: (Отсутствует)
Базовая валюта инструмента: "EUR"
Валюта прибыли: "USD"
Валюта залоговых средств: "EUR"
Источник текущей котировки: (Отсутствует)
Описание символа: "Euro vs US Dollar"
Формула для построения цены пользовательского символа: (Отсутствует)
Имя торгового символа в системе международных идентификационных кодов: (Отсутствует)
Адрес интернет страницы с информацией по символу: "http://www.google.com/finance?q=EURUSD"
Путь в дереве символов: "Forex\EURUSD"
================== Конец списка параметров: EURUSD" (Euro vs US Dollar) ==================

Запустим советник на графике символа в MetaTrader 4.
При этом в журнал распечатаются все свойства объекта-символа:

Счёт 49610941: Artyom Trishkin (MetaQuotes Software Corp. 5000000.00 USD, 1:100, Hedge, Демонстрационный счёт MetaTrader 4)
============= Начало списка параметров: "EURUSD" (Euro vs US Dollar) ==================
Статус: Форекс символ
Пользовательский символ: Нет
Тип цены для построения баров: Бары строятся по ценам Bid
Символ с таким именем существует: Да
Символ выбран в Market Watch: Да
Символ отображается в Market Watch: Да
Количество сделок в текущей сессии: Свойство не поддерживается в MQL4
Общее число ордеров на покупку в текущий момент: Свойство не поддерживается в MQL4
Общее число ордеров на продажу в текущий момент: Свойство не поддерживается в MQL4
Объем в последней сделке: Свойство не поддерживается в MQL4
Максимальный объём за день: Свойство не поддерживается в MQL4
Минимальный объём за день: Свойство не поддерживается в MQL4
Время последней котировки: 2019.06.17 19:40:41.000
Количество знаков после запятой: 5
Количество знаков после запятой в значении лота: 2
Размер спреда в пунктах: 20
Плавающий спред: Да
Максимальное количество показываемых заявок в стакане: Свойство не поддерживается в MQL4
Способ вычисления стоимости контракта: Расчет прибыли и маржи для Форекс
Тип исполнения ордеров: Нет ограничений на торговые операции
Дата начала торгов по инструменту: (Отсутствует)
Дата окончания торгов по инструменту: (Отсутствует)
Минимальный отступ от цены закрытия для установки Stop ордеров: 8
Дистанция заморозки торговых операций: 0
Режим заключения сделок: Торговля по потоковым ценам
Модель расчета свопа: Свопы начисляются в пунктах
День недели для начисления тройного свопа: Среда
Расчет хеджированной маржи по наибольшей стороне: Нет
Флаги разрешенных режимов истечения ордера: Неограниченно (Да); До конца дня (Нет); Срок указывается в ордере (Нет); День указывается в ордере (Нет)
Флаги разрешенных режимов заливки ордера: Вернуть (Да); Всё/Ничего (Нет); Всё/Частично (Нет)
Флаги разрешенных типов ордера: Рыночный ордер (Да); Лимит ордер (Да); Стоп ордер (Да); Стоп-лимит ордер (Нет); StopLoss (Да); TakeProfit (Да); Закрытие встречным (Да)
Срок действия StopLoss и TakeProfit ордеров: Отложенные ордеры и уровни Stop Loss/Take Profit действительны неограниченно по времени до явной отмены
Тип опциона: Свойство не поддерживается в MQL4
Право опциона: Свойство не поддерживается в MQL4
Цвет фона символа в Market Watch: Свойство не поддерживается в MQL4
------
Цена Bid: 1.12328
Максимальный Bid за день: 1.12462
Минимальный Bid за день: 1.12029
Цена Ask: 1.12348
Максимальный Ask за день: Свойство не поддерживается в MQL4
Минимальный Ask за день: Свойство не поддерживается в MQL4
Цена последней сделки: Свойство не поддерживается в MQL4
Максимальный Last за день: Свойство не поддерживается в MQL4
Минимальный Last за день: Свойство не поддерживается в MQL4
Реальный объём за день: Свойство не поддерживается в MQL4
Максимальный реальный объём за день: Свойство не поддерживается в MQL4
Минимальный реальный объём за день: Свойство не поддерживается в MQL4
Цена исполнения опциона: Свойство не поддерживается в MQL4
Значение одного пункта: 0.00001
Рассчитанная стоимость тика для позиции: 1.00
Рассчитанная стоимость тика для прибыльной позиции: Свойство не поддерживается в MQL4
Рассчитанная стоимость тика для убыточной позиции: Свойство не поддерживается в MQL4
Минимальное изменение цены: 0.00001
Размер торгового контракта: 100000.00
Накопленный купонный доход: Свойство не поддерживается в MQL4
Начальная стоимость облигации, установленная эмитентом: Свойство не поддерживается в MQL4
Коэффициент ликвидности: Свойство не поддерживается в MQL4
Минимальный объем для заключения сделки: 0.01
Максимальный объем для заключения сделки: 100000.00
Минимальный шаг изменения объема для заключения сделки: 0.01
Максимально допустимый общий объем позиции и отложенных ордеров в одном направлении: Свойство не поддерживается в MQL4
Значение свопа на покупку: 0.33
Значение свопа на продажу: -1.04
Начальная (инициирующая) маржа: 0.00
Поддерживающая маржа по инструменту: 0.00
Коэффициент взимания маржи по длинным позициям: Свойство не поддерживается в MQL4
Коэффициент взимания маржи по коротким позициям: Свойство не поддерживается в MQL4
Коэффициент взимания маржи по Stop ордерам: Свойство не поддерживается в MQL4
Коэффициент взимания маржи по Limit ордерам: Свойство не поддерживается в MQL4
Коэффициент взимания маржи по Stop Limit ордерам: Свойство не поддерживается в MQL4
Cуммарный объём сделок в текущую сессию: Свойство не поддерживается в MQL4
Cуммарный оборот в текущую сессию: Свойство не поддерживается в MQL4
Cуммарный объём открытых позиций: Свойство не поддерживается в MQL4
Общий объём ордеров на покупку в текущий момент: Свойство не поддерживается в MQL4
EURUSD,H4: Общий объём ордеров на продажу в текущий момент: Свойство не поддерживается в MQL4
Цена открытия сессии: Свойство не поддерживается в MQL4
Цена закрытия сессии: Свойство не поддерживается в MQL4
Средневзвешенная цена сессии: Свойство не поддерживается в MQL4
Цена поставки на текущую сессию: Свойство не поддерживается в MQL4
Минимально допустимое значение цены на сессию: Свойство не поддерживается в MQL4
Максимально допустимое значение цены на сессию: Свойство не поддерживается в MQL4
Размер контракта или маржи для одного лота перекрытых позиций: 50000.00
------
Имя символа: EURUSD
Имя базового актива для производного инструмента: ": Свойство не поддерживается в MQL4"
Базовая валюта инструмента: "EUR"
Валюта прибыли: "USD"
Валюта залоговых средств: "EUR"
Источник текущей котировки: ": Свойство не поддерживается в MQL4"
Описание символа: "Euro vs US Dollar"
Формула для построения цены пользовательского символа: ": Свойство не поддерживается в MQL4"
Имя торгового символа в системе международных идентификационных кодов: ": Свойство не поддерживается в MQL4"
Адрес интернет страницы с информацией по символу: ": Свойство не поддерживается в MQL4"
Путь в дереве символов: "Forex\EURUSD"
================== Конец списка параметров: EURUSD" (Euro vs US Dollar) ==================

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

Что дальше

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

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

К содержанию

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

Часть 1. Концепция, организация данных
Часть 2. Коллекция исторических ордеров и сделок
Часть 3. Коллекция рыночных ордеров и позиций, организация поиска
Часть 4. Торговые события. Концепция
Часть 5. Классы и коллекция торговых событий. Отправка событий в программу
Часть 6. События на счёте с типом неттинг
Часть 7. События срабатывания StopLimit-ордеров, подготовка функционала для регистрации событий модификации ордеров и позиций
Часть 8. События модификации ордеров и позиций
Часть 9. Совместимость с MQL4 - Подготовка данных
Часть 10. Совместимость с MQL4 - События открытия позиций и активации отложенных ордеров
Часть 11. Совместимость с MQL4 - События закрытия позиций
Часть12. Класс объекта "аккаунт", коллекция объектов-аккаунтов
Часть13. События объекта "аккаунт"