![Библиотека для простого и быстрого создания программ для MetaTrader (Часть XV): Коллекция объектов-символов](https://c.mql5.com/i/articles/overlay.png)
Библиотека для простого и быстрого создания программ для MetaTrader (Часть XV): Коллекция объектов-символов
Содержание
- Концепция коллекции символов
- Объекты-наследники базового абстрактного объекта "символ"
- Класс коллекции символов
- Тест коллекции символов
- Что дальше
Концепция коллекции символов
Концепция построения классов-коллекций объектов ранее была нами определена в третьей части описания библиотеки, и здесь мы не будем отходить от принятой структуры хранения данных. Таким образом, для коллекции символов нам необходимо создать список, в котором будут храниться объекты-наследники класса "символ", который был создан в прошлой статье. Наследники абстрактного символа будут уточнять информацию о символе, в них будет организовано определение доступности в программе свойств базового объекта-символа, и различаться такие объекты-символы будут по их принадлежности к группам (статус символа):
- Форекс символ — все форекс-символы, не попавшие в следующие категории форекс-символов:
- Форекс символ-мажор — пользовательская категория наиболее используемых форекс-символов
- Форекс символ-минор — пользовательская категория менее используемых форекс-символов
- Форекс символ-экзотик — пользовательская категория редко используемых форекс-символов
- Форекс символ/рубль — пользовательская категория форекс-символов с рублём
- Металл — пользовательская категория символов-металлов
- Индекс — пользовательская категория символов-индексов
- Индикатив — пользовательская категория символов-индикативов
- Криптовалютный символ — пользовательская категория символов-криптовалют
- Товарный символ — пользовательская категория товарных символов
- Биржевой символ — все биржевые символы, не попавшие в следующие категории биржевых символов:
- Фьючерс
- Контракт на разницу (CFD)
- Ценная бумага
- Облигация
- Опцион
- Неторгуемый актив
- Пользовательский символ
- Общая категория — символы, не попавшие в вышеперечисленные категории
Для определения группы принадлежности символа (его статуса) создадим пользовательские наборы данных — массивы наименований
символов, в которых в первую очередь будем производить поиск категории символа, к которой он должен принадлежать. Если символ не
будет найден в пользовательской категории (его наименование отсутствует во всех массивах имён символов, заданных пользователем),
то принадлежность символа будет определяться по его свойству: "способ вычисления величины залоговых средств" (
ENUM_SYMBOL_CALC_MODE), где
можно определить принадлежность символа к некоторым из перечисленных выше категорий. То есть проводим поиск в две проверки: в
категориях, заданных пользователем, и если там не удалось определить категорию, то устанавливаем категорию по способу вычисления
залоговых средств для символа. Ранее планировалось использовать ещё один способ — определение по имени папки, в которой находится
символ в дереве каталогов символов на сервере. Но данный способ слишком ненадёжный — имена папок могут быть любыми на разных серверах
для одного и того же символа. Поэтому от него я отказался.
Пользовательская категория будет иметь приоритет — так как если пользователь желает, чтобы символ, например, USDUSC находился в его категории
"мажор", то это его право — и символ будет там находиться, независимо от того, что это индикатив.
С категориями определились — для них создадим необходимые классы-наследники абстрактного символа, созданного нами в прошлой
статье.
Для хранения всех объектов символов у нас будет использоваться класс CListObj, унаследованный от класса стандартной
библиотеки
CArrayObj, и который был нами рассмотрен в пятой
статье при обсуждении реорганизации классов библиотеки. В программах, работающих на основе этой библиотеки, будет
возможность выбрать с каким списком символов необходимо работать:
- Только один — текущий символ, к которому прикреплена программа
- Предопределённый набор символов, указанный в программе
- Работа со списком символов, находящихся в окне "Обзор рынка"
- Работа с полным списком символов, доступных на сервере
Таким образом, мы покроем большинство необходимых задач программирования доступа к рабочим инструментам-символам.
Стоит
отметить два момента:
во-первых, это работа со списком символов из обзора рынка — в данном режиме необходимо будет использовать поиск событий окна "Обзор
рынка" — для своевременной реакции на его изменения (добавление/удаление символа из списка и его сортировка мышью),
и во-вторых, при работе с полным списком символов, доступных на сервере, необходимо продумать нормальную обработку
возможного большого количества доступных символов — ведь при первом запуске будет просматриваться полный список символов на
сервере, и будут создаваться объекты-символы, для которых необходимо получить все их свойства. Этот процесс не быстрый — у меня
на обычном средненьком ноутбуке процесс создания коллекции всех символов, находящихся на сервере, занял примерно две минуты.
Изначально, думаю, при выборе такого метода работы, необходимо хотя бы предупредить пользователя о возможно долгом сборе
первоначальной информации.
Этим, и ещё отслеживанием событий символов и событий окна "Обзор рынка", займёмся в последующих статьях, а пока будем создавать
список-коллекцию.
Для начала создадим ещё один включаемый файл, в нём будем хранить все нужные для библиотеки данные — массивы пользовательских
групп символов, файлы, изображения, и прочие нужные впоследствии наборы данных для библиотеки.
В каталоге расположения библиотеки \MQL5\Include\DoEasy\ создадим новый включаемый файл с именем Datas.mqh
и сразу же впишем в него некоторые массивы, которые я заранее уже подготовил, пробежавшись по нескольким счетам, и собрав из
структуры дерева окна "Обзор рынка" данные о группах символов, заданных на разных серверах:
//+------------------------------------------------------------------+ //| Datas.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" //+------------------------------------------------------------------+ //| Наборы данных | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Форекс-символы-мажоры | //+------------------------------------------------------------------+ string DataSymbolsFXMajors[]= { "AUDCAD","AUDCHF","AUDJPY","AUDNZD","AUDUSD","CADCHF","CADJPY","CHFJPY","EURAUD","EURCAD","EURCHF","EURGBP","EURJPY","EURNZD", "EURUSD","GBPAUD","GBPCAD","GBPCHF","GBPJPY","GBPNZD","GBPUSD","NZDCAD","NZDCHF","NZDJPY","NZDUSD","USDCAD","USDCHF","USDJPY" }; //+------------------------------------------------------------------+ //| Форекс-символы-миноры | //+------------------------------------------------------------------+ string DataSymbolsFXMinors[]= { "EURCZK","EURDKK","EURHKD","EURNOK","EURPLN","EURSEK","EURSGD","EURTRY","EURZAR","GBPSEK","GBPSGD" ,"NZDSGD","USDCZK","USDDKK","USDHKD","USDNOK","USDPLN","USDSEK","USDSGD","USDTRY","USDZAR" }; //+------------------------------------------------------------------+ //| Форекс-символы-экзотики | //+------------------------------------------------------------------+ string DataSymbolsFXExotics[]= { "EURMXN","USDCNH","USDMXN","EURTRY","USDTRY" }; //+------------------------------------------------------------------+ //| Форекс рублёвые символы | //+------------------------------------------------------------------+ string DataSymbolsFXRub[]= { "EURRUB","USDRUB" }; //+------------------------------------------------------------------+ //| Форекс-символы-индикативы | //+------------------------------------------------------------------+ string DataSymbolsFXIndicatives[]= { "EUREUC","USDEUC","USDUSC" }; //+------------------------------------------------------------------+ //| Символы-металлы | //+------------------------------------------------------------------+ string DataSymbolsMetalls[]= { "XAGUSD","XAUUSD" }; //+------------------------------------------------------------------+ //| Товарные символы | //+------------------------------------------------------------------+ string DataSymbolsCommodities[]= { "BRN","WTI","NG" }; //+------------------------------------------------------------------+ //| Индексы | //+------------------------------------------------------------------+ string DataSymbolsIndexes[]= { "CAC40","HSI50","ASX200","STOXX50","NQ100","FTSE100","DAX30","IBEX35","SPX500","NIKK225" "Volatility 10 Index","Volatility 25 Index","Volatility 50 Index","Volatility 75 Index","Volatility 100 Index", "HF Volatility 10 Index","HF Volatility 50 Index","Crash 1000 Index","Boom 1000 Index","Step Index" }; //+------------------------------------------------------------------+ //| Криптовалютные символы | //+------------------------------------------------------------------+ string DataSymbolsCrypto[]= { "BCHUSD","BTCEUR","BTCUSD","DSHUSD","EOSUSD","ETHEUR","ETHUSD","LTCUSD","XRPUSD" }; //+------------------------------------------------------------------+ //| Опционы | //+------------------------------------------------------------------+ string DataSymbolsOptions[]= { "BO Volatility 10 Index","BO Volatility 25 Index","BO Volatility 50 Index","BO Volatility 75 Index","BO Volatility 100 Index" }; //+------------------------------------------------------------------+
Как видно из листинга — это просто перечисление имён символов, которые добавляем в требуемые массивы, определяющие группу символов, находящихся в каждом из массивов. При желании и необходимости, можно переработать состав этих массивов имён символов — что-то отправить в другой массив, что-то добавить/удалить, и т.д.
Далее. Более "плотное" тестирование поведения абстрактного объекта-символа дало понимание, что использование констант
SYMBOL_MARGIN_LONG, SYMBOL_MARGIN_SHORT, SYMBOL_MARGIN_STOP, SYMBOL_MARGIN_LIMIT и SYMBOL_MARGIN_STOPLIMIT не привело к
желаемому получению свойств символа. Поэтому пришлось заменить получение данных свойств на их получение посредством функции
SymbolInfoMarginRate().
И так как в данную
функцию отправляется тип ордера, то пришлось
создать для каждого из типов ордеров свою константу в вещественных свойствах
объекта-символа в файле Defines.mqh:
//+------------------------------------------------------------------+ //| Вещественные свойства символа | //+------------------------------------------------------------------+ 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_INITIAL, // Коэффициент взимания начальной маржи по длинным позициям SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL, // Коэффициент взимания начальной маржи по BuyStop ордерам SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL, // Коэффициент взимания начальной маржи по BuyLimit ордерам SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL, // Коэффициент взимания начальной маржи по BuyStopLimit ордерам SYMBOL_PROP_MARGIN_LONG_MAINTENANCE, // Коэффициент взимания поддерживающей маржи по длинным позициям SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE, // Коэффициент взимания поддерживающей маржи по BuyStop ордерам SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE, // Коэффициент взимания поддерживающей маржи по BuyLimit ордерам SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE, // Коэффициент взимания поддерживающей маржи по BuyStopLimit ордерам SYMBOL_PROP_MARGIN_SHORT_INITIAL, // Коэффициент взимания начальной маржи по коротким позициям SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL, // Коэффициент взимания начальной маржи по SellStop ордерам SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL, // Коэффициент взимания начальной маржи по SellLimit ордерам SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL, // Коэффициент взимания начальной маржи по SellStopLimit ордерам SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE, // Коэффициент взимания поддерживающей маржи по коротким позициям SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE, // Коэффициент взимания поддерживающей маржи по SellStop ордерам SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE, // Коэффициент взимания поддерживающей маржи по SellLimit ордерам SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE, // Коэффициент взимания поддерживающей маржи по SellStopLimit ордерам 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 (58) // Общее количество вещественных свойств #define SYMBOL_PROP_DOUBLE_SKIP (0) // Количество неиспользуемых в сортировке вещественных свойств символа //+------------------------------------------------------------------+
Соответственно, и общее количество вещественных свойств увеличилось до 58 (вместо 47 ранее)
И точно так же пришлось добавить соответствующие константы в перечисление возможных критериев сортировки символов:
//+------------------------------------------------------------------+ //| Возможные критерии сортировки символов | //+------------------------------------------------------------------+ #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_INITIAL, // Сортировать по коэффициенту взимания начальной маржи по длинным позициям SORT_BY_SYMBOL_MARGIN_BUY_STOP_INITIAL, // Сортировать по коэффициенту взимания начальной маржи по BuyStop ордерам SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_INITIAL, // Сортировать по коэффициенту взимания начальной маржи по BuyLimit ордерам SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_INITIAL, // Сортировать по коэффициенту взимания начальной маржи по BuyStopLimit ордерам SORT_BY_SYMBOL_MARGIN_LONG_MAINTENANCE, // Сортировать по коэффициенту взимания поддерживающей маржи по длинным позициям SORT_BY_SYMBOL_MARGIN_BUY_STOP_MAINTENANCE, // Сортировать по коэффициенту взимания поддерживающей маржи по BuyStop ордерам SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_MAINTENANCE, // Сортировать по коэффициенту взимания поддерживающей маржи по BuyLimit ордерам SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_MAINTENANCE, // Сортировать по коэффициенту взимания поддерживающей маржи по BuyStopLimit ордерам SORT_BY_SYMBOL_MARGIN_SHORT_INITIAL, // Сортировать по коэффициенту взимания начальной маржи по коротким позициям SORT_BY_SYMBOL_MARGIN_SELL_STOP_INITIAL, // Сортировать по коэффициенту взимания начальной маржи по SellStop ордерам SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_INITIAL, // Сортировать по коэффициенту взимания начальной маржи по SellLimit ордерам SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_INITIAL, // Сортировать по коэффициенту взимания начальной маржи по SellStopLimit ордерам SORT_BY_SYMBOL_MARGIN_SHORT_MAINTENANCE, // Сортировать по коэффициенту взимания поддерживающей маржи по коротким позициям SORT_BY_SYMBOL_MARGIN_SELL_STOP_MAINTENANCE, // Сортировать по коэффициенту взимания поддерживающей маржи по SellStop ордерам SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_MAINTENANCE, // Сортировать по коэффициенту взимания поддерживающей маржи по SellLimit ордерам SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_MAINTENANCE, // Сортировать по коэффициенту взимания поддерживающей маржи по SellStopLimit ордерам 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 // Сортировать по пути в дереве символов }; //+------------------------------------------------------------------+
Ну и раз уж мы редактируем файл Deines.mqh, то сразу и впишем в него всё необходимое, попутно рассматривая что добавляем, и зачем это нужно.
Для коллекции символов нам потребуется таймер — ведь обновлять данные по всем символам, находящимся в коллекции нам необходимо по таймеру.
Причём есть особенность: нам нужно будет обновлять котировочные данные всех символов, и остальные данные — те, которые могут измениться,
чтобы отследить их в классе событий символов (об этом в следующей статье), а также нам нужно проверять в таймере список символов в окне
"Обзор рынка" — чтобы вовремя реагировать на его изменения и обновлять список коллекции.
Котировочные данные нам нужно обновлять чаще, чем остальные данные символов и их список в окне "Обзор рынка". Значит, нам потребуются два таймера для
коллекции символов — таймер котировочных данных, и таймер для остальных действий со списками символов.
Впишем необходимые макроподстановки для двух таймеров коллекции символов:
//--- Параметры таймера1 коллекции символов #define COLLECTION_SYM_PAUSE1 (100) // Пауза таймера1 коллекции символов в милисекундах (для сканирования символов в обзоре рынка) #define COLLECTION_SYM_COUNTER_STEP1 (16) // Шаг приращения счётчика таймера1 символов #define COLLECTION_SYM_COUNTER_ID1 (3) // Идентификатор счётчика таймера1 символов //--- Параметры таймера2 коллекции символов #define COLLECTION_SYM_PAUSE2 (300) // Пауза таймера2 коллекции символов в милисекундах (для событий списка символов в обзоре рынка) #define COLLECTION_SYM_COUNTER_STEP2 (16) // Шаг приращения счётчика таймера2 символов #define COLLECTION_SYM_COUNTER_ID2 (4) // Идентификатор счётчика таймера2 символов
Разница между этими данными лишь в паузе для каждого таймера и их идентификаторах — для первого таймера паузой будет 100 милисекунд, для второго — 300.
Для каждой коллекции у нас есть свой идентификатор. Не является исключением и коллекция символов.
Назначим для её списка
свой
идентификатор:
//--- Идентификаторы списков коллекций #define COLLECTION_HISTORY_ID (0x7778+1) // Идентификатор списка исторической коллекции #define COLLECTION_MARKET_ID (0x7778+2) // Идентификатор списка рыночной коллекции #define COLLECTION_EVENTS_ID (0x7778+3) // Идентификатор списка коллекции событий #define COLLECTION_ACCOUNT_ID (0x7778+4) // Идентификатор списка коллекции аккаунтов #define COLLECTION_SYMBOLS_ID (0x7778+5) // Идентификатор списка коллекции символов
Для определения цвета фона, которым подсвечивается символ в окне "Обзор рынка" и вывода его строкового описания, мы в прошлой статье использовали конструкцию сравнения цвета с цветом clrWhite — если значение свойства больше long-значения данного цвета, то считается, что цвет фона не задан:
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 ) :
Однако, по сообщению разработчиков это неверно — long-значение цвета фона символа в окне "Обзор рынка", оказывается, может быть больше
long-значения "белого" цвета. А значит — в некоторых случаях такая проверка не будет возвращать правильный результат.
Для правильной идентификации отсутствия цвета фона, нужно сравнивать значение свойства со значением CLR_DEFAULT и CLR_NONE.
Зададим
макроподстановкой значение цвета "по умолчанию" ("отсутствующий" цвет CLR_NONE уже есть в MQL5 и MQL4):
//--- Параметры символов #define CLR_DEFAULT (0xFF000000) // Цвет по умолчанию //+------------------------------------------------------------------+
В итоге, раздел макроподстановок файла Defines.mqh у нас теперь выглядит так:
//+------------------------------------------------------------------+ //| Макроподстановки | //+------------------------------------------------------------------+ //--- "Описание функции с номером строки ошибки" #define DFUN_ERR_LINE (__FUNCTION__+(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian" ? ", Стр. " : ", Line ")+(string)__LINE__+": ") #define DFUN (__FUNCTION__+": ") // "Описание функции" #define COUNTRY_LANG ("Russian") // Язык страны #define END_TIME (D'31.12.3000 23:59:59') // Конечная дата для запросов данных истории счёта #define TIMER_FREQUENCY (16) // Минимальная частота таймера библиотеки в милисекундах //--- Параметры таймера коллекции ордеров и сделок #define COLLECTION_ORD_PAUSE (250) // Пауза таймера коллекции ордеров и сделок в милисекундах #define COLLECTION_ORD_COUNTER_STEP (16) // Шаг приращения счётчика таймера коллекции ордеров и сделок #define COLLECTION_ORD_COUNTER_ID (1) // Идентификатор счётчика таймера коллекции ордеров и сделок //--- Параметры таймера коллекции аккаунтов #define COLLECTION_ACC_PAUSE (1000) // Пауза таймера коллекции аккаунтов в милисекундах #define COLLECTION_ACC_COUNTER_STEP (16) // Шаг приращения счётчика таймера аккаунтов #define COLLECTION_ACC_COUNTER_ID (2) // Идентификатор счётчика таймера аккаунтов //--- Параметры таймера1 коллекции символов #define COLLECTION_SYM_PAUSE1 (100) // Пауза таймера1 коллекции символов в милисекундах (для сканирования символов в обзоре рынка) #define COLLECTION_SYM_COUNTER_STEP1 (16) // Шаг приращения счётчика таймера1 символов #define COLLECTION_SYM_COUNTER_ID1 (3) // Идентификатор счётчика таймера1 символов //--- Параметры таймера2 коллекции символов #define COLLECTION_SYM_PAUSE2 (300) // Пауза таймера2 коллекции символов в милисекундах (для событий списка символов в обзоре рынка) #define COLLECTION_SYM_COUNTER_STEP2 (16) // Шаг приращения счётчика таймера2 символов #define COLLECTION_SYM_COUNTER_ID2 (4) // Идентификатор счётчика таймера2 символов //--- Идентификаторы списков коллекций #define COLLECTION_HISTORY_ID (0x7778+1) // Идентификатор списка исторической коллекции #define COLLECTION_MARKET_ID (0x7778+2) // Идентификатор списка рыночной коллекции #define COLLECTION_EVENTS_ID (0x7778+3) // Идентификатор списка коллекции событий #define COLLECTION_ACCOUNT_ID (0x7778+4) // Идентификатор списка коллекции аккаунтов #define COLLECTION_SYMBOLS_ID (0x7778+5) // Идентификатор списка коллекции символов //--- Параметры данных для файловых операций #define DIRECTORY ("DoEasy\\") // Каталог библиотеки для расположения папок объектов классов //--- Параметры символов #define CLR_DEFAULT (0xFF000000) // Цвет по умолчанию //+------------------------------------------------------------------+
Выше мы говорили о режимах работы с коллекцией символов: работа с текущим символом, работа с предопределённым в программе списком символов,
работа с окном "Обзор рынка" и работа с полным списком доступных символов на сервере.
Зададим все эти режимы в перечислении:
//+------------------------------------------------------------------+ //| Данные для работы с символами | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Режимы работы с символами | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Работа только с текущим символом SYMBOLS_MODE_DEFINES, // Работа с заданным списком символов SYMBOLS_MODE_MARKET_WATCH, // Работа с символами из окна "Обзор рынка" SYMBOLS_MODE_ALL // Работа с полным списком символов }; //+------------------------------------------------------------------+
В прошлой статье мы обозначили категории символов, по которым их будем распределять. А в самом начале данной статьи мы рассмотрели немного расширенный список категорий символов. Его и будем использовать.
Добавим перечисление категорий (статусов) символов:
//+------------------------------------------------------------------+ //| Тип (статус) абстрактного символа | //+------------------------------------------------------------------+ 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_METAL, // Металл SYMBOL_STATUS_INDEX, // Индекс SYMBOL_STATUS_INDICATIVE, // Индикатив SYMBOL_STATUS_CRYPTO, // Криптовалютный символ SYMBOL_STATUS_COMMODITY, // Товарный символ SYMBOL_STATUS_EXCHANGE, // Биржевой символ SYMBOL_STATUS_FUTURES, // Фьючерс SYMBOL_STATUS_CFD, // Контракт на разницу SYMBOL_STATUS_STOCKS, // Ценная бумага SYMBOL_STATUS_BONDS, // Облигация SYMBOL_STATUS_OPTION, // Опцион SYMBOL_STATUS_COLLATERAL, // Неторгуемый актив SYMBOL_STATUS_CUSTOM, // Пользовательский символ SYMBOL_STATUS_COMMON // Общая категория }; //+------------------------------------------------------------------+
На этом подготовка данных для коллекции символов и изменения в файле Defines.mqh завершены.
Изменения также коснулись класса CSymbol, созданного нами в прошлой
статье.
Так как мы теперь получаем данные о коэффициентах
взимания маржи для разных типов ордеров посредством функции SymbolInfoMarginRate(),
а для возврата запрашиваемых из неё значений используются переменные, переданные в функцию по ссылке, то нам необходимо создать эти
переменные.
И если учитывать, что ордеров у нас восемь штук, и по каждому из них мы можем получить два типа коэффициентов — коэффициент взимания начальной маржи и коэффициент взимания поддерживающей маржи, то переменных для получения всех этих значений должно быть 16 штук. Поэтому проще и нагляднее создать под них структуру, состоящую из двух вложенных структур: в первой структуре будут определены две double-переменные для хранения коэффициентов взимания начальной и поддерживающей маржи, а во второй будут содержаться первые объявленные структуры для хранения данных по типам ордеров, для которых нужно получать коэффициенты.
Объявим в файле класса-символа Symbol.mqh, в приватной секции класса CSymbol эти структуры и переменную-член класса с типом второй структуры для обращения к структуре:
//+------------------------------------------------------------------+ //| Класс абстрактного символа | //+------------------------------------------------------------------+ class CSymbol : public CObject { private: struct SMarginRate { double Initial; // коэффициент взимания начальной маржи double Maintenance; // коэффициент взимания поддерживающей маржи }; struct SMarginRateMode { SMarginRate Long; // MarginRate длинных позиций SMarginRate Short; // MarginRate коротких позиций SMarginRate BuyStop; // MarginRate BuyStop-ордеров SMarginRate BuyLimit; // MarginRate BuyLimit-ордеров SMarginRate BuyStopLimit; // MarginRate BuyStopLimit-ордеров SMarginRate SellStop; // MarginRate SellStop-ордеров SMarginRate SellLimit; // MarginRate SellLimit-ордеров SMarginRate SellStopLimit; // MarginRate SellStopLimit-ордеров }; SMarginRateMode m_margin_rate; // Структура коэффициентов взимания маржи
Добавим в приватную секцию класса метод, заполняющий все свойства
символа по каждому коэффициенту взимания маржи, метод, инициализирующий
переменные структур, хранящих все коэффициенты взимания маржи, а также добавим два вспомогательных метода для
получения текущего дня недели и для получения количества знаков после
запятой в значении double-числа:
SMarginRateMode m_margin_rate; // Структура коэффициентов взимания маржи 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; } //--- (1) Заполняет все свойства символа "коэффициент взимания маржи", (2) инициализирует коэффициенты bool MarginRates(void); void InitMarginRates(void); //--- Обнуляет все данные объекта-символа void Reset(void); //--- Возвращает текущий день недели ENUM_DAY_OF_WEEK CurrentDayOfWeek(void) const; //--- Возвращает количество знаков после запятой в double-значении int GetDigits(const double value) const; public:
Там же — в приватной секции класса объявим методы, возвращающие данные по коэффициентам взимания маржи для каждого из типов ордеров:
//--- Получает и возвращает вещественные свойства выбранного символа из его параметров 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; bool SymbolMarginLong(void); bool SymbolMarginShort(void); bool SymbolMarginBuyStop(void); bool SymbolMarginBuyLimit(void); bool SymbolMarginBuyStopLimit(void); bool SymbolMarginSellStop(void); bool SymbolMarginSellLimit(void); bool SymbolMarginSellStopLimit(void); //--- Получает и возвращает строковые свойства выбранного символа из его параметров
Иногда в программе требуется узнать существование символа на сервере по имени символа. У нас уже есть метод Exist(), который возвращает такую информацию по символу класса. Перегрузим метод, чтобы он мог возвращать данные по переданному имени символа. Для этого объявим ещё одну форму вызова метода в приватной секции класса:
//--- Ищет символ и возвращает флаг его наличия на сервере bool Exist(void) const; bool Exist(const string name) const;
и объявим в защищённой секции класса перегруженный метод, возвращающий значение существования символа по его имени в зависимости от типа программы MQL5 или MQL4:
protected: //--- Защищённый параметрический конструктор CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name); //--- Получает и возвращает целочисленные свойства выбранного символа из его параметров bool SymbolExists(const string name) const; long SymbolExists(void) const;
В публичной секции класса, в его разделе для методов описания свойств объявим
виртуальный метод для вывода в журнал краткого описания символа.
В наследниках класса, в которых будет задаваться
уточняющая информация по объекту-символу, мы реализуем этот виртуальный метод.
//+------------------------------------------------------------------+ //| Описания свойств объекта-символа | //+------------------------------------------------------------------+ //--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства символа string GetPropertyDescription(ENUM_SYMBOL_PROP_INTEGER property); string GetPropertyDescription(ENUM_SYMBOL_PROP_DOUBLE property); string GetPropertyDescription(ENUM_SYMBOL_PROP_STRING property); //--- Выводит в журнал описание свойств символа (full_prop=true - все свойства, false - только поддерживаемые) void Print(const bool full_prop=false); //--- Выводит в журнал краткое описание символа (реализация в наследниках) virtual void PrintShort(void) {;} //--- Сравнивает объекты CSymbol между собой по всем возможным свойствам (для сортировки списков по указанному свойству объекта-символа)
В прошлой статье при реализации объекта-символа мы добавили в публичную секцию класса несколько сервисных методов.
Добавим
ещё несколько методов для возврата времени начала и окончания
котировочной и торговой
сессий, а также приватные методы, возвращающие целое число часов, минут и секунд в
сессии и метод, возвращающий описание продолжительности сессии в виде
"ЧЧ:ММ:СС" :
//--- (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) время начала и (2) время окончания котировочной сессии дня недели, (3) время начала и конца требуемой котировочной сессии long SessionQuoteTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; long SessionQuoteTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; bool GetSessionQuote(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to); //--- Возвращает (1) время начала и (2) время окончания торговой сессии дня недели, (3) время начала и конца требуемой торговой сессии long SessionTradeTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; long SessionTradeTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const; bool GetSessionTrade(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to); //--- (1) Осуществляет (1) подписку на стакан цен, (2) закрытие стакана цен, (3) заполняет данные стакана цен в массив структур bool BookAdd(void) const; bool BookClose(void) const; //--- Возвращает (1) описание продолжительности сессии в чч:мм:сс, число (1) часов, (2) минут и (3) секунд во времени продолжительности сессии string SessionDurationDescription(const ulong duration_sec) const; private: int SessionHours(const ulong duration_sec) const; int SessionMinutes(const ulong duration_sec) const; int SessionSeconds(const ulong duration_sec) const; public: //+------------------------------------------------------------------+
В публичной секции в разделе методов упрощённого доступа к свойствам объекта-символа добавим
вторую форму вызова метода, возвращающего флаг наличия символа на сервере (ранее мы оъявили приватный перегруженный метод,
который ищет символ на сервере по его имени и возвращает флаг с результатом поиска)
//+------------------------------------------------------------------+ //| Методы упрощённого доступа к свойствам объекта-символа | //+------------------------------------------------------------------+ //--- Целочисленные свойства 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 IsExist(const string name) const { return this.SymbolExists(name); } 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); }
В публичной секции в разделе методов упрощённого доступа к вещественным свойствам символа добавим методы, возвращающие все
коэффициенты взимания маржи:
//--- Вещественные свойства 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 MarginLongInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_INITIAL); } double MarginBuyStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL); } double MarginBuyLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL); } double MarginBuyStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL); } double MarginLongMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE); } double MarginBuyStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE); } double MarginBuyLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE); } double MarginBuyStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE); } double MarginShortInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_INITIAL); } double MarginSellStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL); } double MarginSellLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL); } double MarginSellStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL); } double MarginShortMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE); } double MarginSellStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE); } double MarginSellLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE); } double MarginSellStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE); } 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; //--- Строковые свойства
Для получения данных о свойствах символа, необходимо, чтобы символ был выбран в окне "Обзор рынка". Но может быть ситуация, когда символ не выбран в окне, но его свойства необходимо получить. Для этого нам необходимо создать флаг, указывающий на то, был ли выбран символ в окне "Обзор рынка" до того, как мы обращаемся к его свойствам. И далее действуем по схеме: если символ не выбран, то выбираем его, получаем свойства и опять скрываем из окна "Обзор рынка". Если же символ уже выбран, то просто получаем его свойства.
Так же нам необходимо в конструкторе класса инициализировать данные коэффициентов
взимания маржи и заполнить их для MQL5. Для MQL4 такие
данные отсутствуют и их значения остаются нулевыми после инициализации.
И добавим вызов методов сохранения этих свойств в полях свойств класса.
Для этого в конструкторе класса добавим необходимый код:
//+------------------------------------------------------------------+ //| Закрытый параметрический конструктор | //+------------------------------------------------------------------+ 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; } bool select=::SymbolInfoInteger(this.m_symbol_name,SYMBOL_SELECT); ::ResetLastError(); if(!select) { if(!this.SetToMarketWatch()) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,"\"",this.m_symbol_name,"\": ",TextByLanguage("Не удалось поместить в обзор рынка. Ошибка: ","Failed to put in the market watch. Error: "),this.m_global_error); } } ::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.InitMarginRates(); ::ResetLastError(); #ifdef __MQL5__ if(!this.MarginRates()) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,this.Name(),": ",TextByLanguage("Не удалось получить коэффициенты взимания маржи. Ошибка: ","Failed to get margin rates. Error: "),this.m_global_error); return; } #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_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_EXPIRATION_MODE] = this.SymbolExpirationMode(); 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_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_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_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)] = this.m_margin_rate.Long.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)] = this.m_margin_rate.BuyStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)] = this.m_margin_rate.BuyLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)] = this.m_margin_rate.BuyStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)] = this.m_margin_rate.Long.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)] = this.m_margin_rate.BuyStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)] = this.m_margin_rate.BuyLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)] = this.m_margin_rate.Short.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)] = this.m_margin_rate.SellStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)] = this.m_margin_rate.SellLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)] = this.m_margin_rate.SellStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)] = this.m_margin_rate.Short.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)] = this.m_margin_rate.SellStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)] = this.m_margin_rate.SellLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance; //--- Сохранение строковых свойств 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(); //--- if(!select) this.RemoveFromMarketWatch(); } //+------------------------------------------------------------------+
Теперь нам необходимо написать реализации всех объявленных методов.
За пределами тела класса напишем реализацию метода, заполняющего все переменные, хранящие коэффициенты взимания маржи:
//+------------------------------------------------------------------+ //| Заполняет переменные коэффициентов взимания маржи | //+------------------------------------------------------------------+ bool CSymbol::MarginRates(void) { bool res=true; #ifdef __MQL5__ res &=this.SymbolMarginLong(); res &=this.SymbolMarginBuyStop(); res &=this.SymbolMarginBuyLimit(); res &=this.SymbolMarginBuyStopLimit(); res &=this.SymbolMarginShort(); res &=this.SymbolMarginSellStop(); res &=this.SymbolMarginSellLimit(); res &=this.SymbolMarginSellStopLimit(); #else this.InitMarginRates(); res=false; #endif return res; } //+------------------------------------------------------------------+
В методе для MQL5 просто вызываются методы, считывающие из
свойств символа данные по коэффициентам, и записывающие их в соответствующие переменные структуры, и результат возврата всех методов
суммируется и возвращается в вызывающую программу. Методы будут рассмотрены ниже.
Для MQL4 просто выполняется обнуление всех полей структуры.
Метод инициализации полей структуры свойств значений коэффициентов взимания маржи:
//+------------------------------------------------------------------+ //| Инициализирует коэффициенты взимания маржи | //+------------------------------------------------------------------+ void CSymbol::InitMarginRates(void) { this.m_margin_rate.Long.Initial=0; this.m_margin_rate.Long.Maintenance=0; this.m_margin_rate.BuyStop.Initial=0; this.m_margin_rate.BuyStop.Maintenance=0; this.m_margin_rate.BuyLimit.Initial=0; this.m_margin_rate.BuyLimit.Maintenance=0; this.m_margin_rate.BuyStopLimit.Initial=0; this.m_margin_rate.BuyStopLimit.Maintenance=0; this.m_margin_rate.Short.Initial=0; this.m_margin_rate.Short.Maintenance=0; this.m_margin_rate.SellStop.Initial=0; this.m_margin_rate.SellStop.Maintenance=0; this.m_margin_rate.SellLimit.Initial=0; this.m_margin_rate.SellLimit.Maintenance=0; this.m_margin_rate.SellStopLimit.Initial=0; this.m_margin_rate.SellStopLimit.Maintenance=0; } //+------------------------------------------------------------------+
Здесь просто обнуляются все поля структуры m_margin_rate.
Реализация второй формы вызова метода, возвращающего флаг наличия символа на сервере:
//+------------------------------------------------------------------+ //| Возвращает флаг существования символа | //+------------------------------------------------------------------+ long CSymbol::SymbolExists(void) const { return(#ifdef __MQL5__ ::SymbolInfoInteger(this.m_symbol_name,SYMBOL_EXIST) #else this.Exist() #endif); } //+------------------------------------------------------------------+ bool CSymbol::SymbolExists(const string name) const { return(#ifdef __MQL5__ (bool)::SymbolInfoInteger(name,SYMBOL_EXIST) #else this.Exist(name) #endif); } //+------------------------------------------------------------------+
Здесь: для MQL5 возвращается свойство символа SYMBOL_EXIST, а для MQL4 выполняется поиск символа на сервере при помощи второй формы вызова метода Exist(const string name).
Реализация методов, заполняющих в структуре коэффициенты взимания маржи для всех типов ордеров:
//+------------------------------------------------------------------+ //| Заполняет коэффициенты взимания маржи по длинным позициям | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginLong(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY,this.m_margin_rate.Long.Initial,this.m_margin_rate.Long.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Заполняет коэффициенты взимания маржи по коротким позициям | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginShort(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL,this.m_margin_rate.Short.Initial,this.m_margin_rate.Short.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Заполняет коэффициенты взимания маржи по BuyStop-ордерам | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginBuyStop(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY_STOP,this.m_margin_rate.BuyStop.Initial,this.m_margin_rate.BuyStop.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Заполняет коэффициенты взимания маржи по BuyLimit-ордерам | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginBuyLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY_LIMIT,this.m_margin_rate.BuyLimit.Initial,this.m_margin_rate.BuyLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Заполняет коэффициенты взимания маржи по BuyStopLimit-ордерам | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginBuyStopLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_BUY_STOP_LIMIT,this.m_margin_rate.BuyStopLimit.Initial,this.m_margin_rate.BuyStopLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Заполняет коэффициенты взимания маржи по SellStop-ордерам | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginSellStop(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL_STOP,this.m_margin_rate.SellStop.Initial,this.m_margin_rate.SellStop.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Заполняет коэффициенты взимания маржи по SellLimit-ордерам | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginSellLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL_LIMIT,this.m_margin_rate.SellLimit.Initial,this.m_margin_rate.SellLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+ //| Заполняет коэффициенты взимания маржи по SellStopLimit-ордерам | //+------------------------------------------------------------------+ bool CSymbol::SymbolMarginSellStopLimit(void) { return(#ifdef __MQL5__ ::SymbolInfoMarginRate(this.m_symbol_name,ORDER_TYPE_SELL_STOP_LIMIT,this.m_margin_rate.SellStopLimit.Initial,this.m_margin_rate.SellStopLimit.Maintenance) #else false #endif); } //+------------------------------------------------------------------+
Здесь: для MQL5 вызывается функция SymbolInfoMarginRate(),
в которой заполняются требуемые свойства, хранящиеся в структуре
m_margin_rate, и возвращается результат работы функции. Для MQL4
возвращаем
false.
В методе, возвращающем описание целочисленных свойств символа в блоке возврата описания цвета фона символа в окне "Обзор рынка" внесём изменения:
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)==CLR_DEFAULT || this.GetProperty(property)==CLR_NONE ? TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+::ColorToString((color)this.GetProperty(property),true)) #else TextByLanguage(": Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) :
Ранее мы сравнивали цвет с белым (clrWhite), и если значение цвета больше, чем значение "белого" цвета, то считалось, что цвет не задан. Мы уже обсудили ошибочность данного метода сравнения, и поэтому здесь для определения отсутствия заданного цвета фона для символа в окне "Обзор рынка", сравниваем цвет с "цветом по умолчанию" или с "отсутствующим цветом".
В метод, возвращающий описания вещественных свойств символа GetPropertyDescription(ENUM_SYMBOL_PROP_DOUBLE property), добавим вывод описания всех коэффициентов взимания маржи:
//--- Коэффициент взимания начальной маржи позиции Long property==SYMBOL_PROP_MARGIN_LONG_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по длинным позициям","Coefficient of margin initial charging for long positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : //--- Коэффициент взимания начальной маржи позиции Short property==SYMBOL_PROP_MARGIN_SHORT_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по коротким позициям","Coefficient of margin initial charging for short positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : //--- Коэффициент взимания поддерживающей маржи позиции Long property==SYMBOL_PROP_MARGIN_LONG_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по длинным позициям","Coefficient of margin maintenance charging for long positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : //--- Коэффициент взимания поддерживающей маржи позиции Short property==SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по коротким позициям","Coefficient of margin maintenance charging for short positions")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : //--- Коэффициенты взимания начальной маржи по ордерам Long property==SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по BuyStop ордерам","Coefficient of margin initial charging for BuyStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по BuyLimit ордерам","Coefficient of margin initial charging for BuyLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по BuyStopLimit ордерам","Coefficient of margin initial charging for BuyStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : //--- Коэффициенты взимания начальной маржи по ордерам Short property==SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по SellStop ордерам","Coefficient of margin initial charging for SellStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по SellLimit ордерам","Coefficient of margin initial charging for SellLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL ? TextByLanguage("Коэффициент взимания начальной маржи по SellStopLimit ордерам","Coefficient of margin initial charging for SellStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : //--- Коэффициенты взимания поддерживающей маржи по ордерам Long property==SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по BuyStop ордерам","Coefficient of margin maintenance charging for BuyStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по BuyLimit ордерам","Coefficient of margin maintenance charging for BuyLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по BuyStopLimit ордерам","Coefficient of margin maintenance charging for BuyStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : //--- Коэффициенты взимания поддерживающей маржи по ордерам Short property==SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по SellStop ордерам","Coefficient of margin maintenance charging for SellStop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по SellLimit ордерам","Coefficient of margin maintenance charging for SellLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE ? TextByLanguage("Коэффициент взимания поддерживающей маржи по SellStopLimit ордерам","Coefficient of margin maintenance charging for SellStopLimit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property is not support") : ": "+ #ifdef __MQL5__ (this.GetProperty(property)==0 ? TextByLanguage(": (Не задан)",": (Not set)") : (::DoubleToString(this.GetProperty(property),8))) #else TextByLanguage("Свойство не поддерживается в MQL4","Property is not supported in MQL4") #endif ) : //---
Реализация второй формы вызова метода, ищущего символ по его имени на сервере, и возвращающий флаг наличия символа:
//+------------------------------------------------------------------+ //| Ищет символ и возвращает флаг его наличия на сервере | //+------------------------------------------------------------------+ 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; } //+------------------------------------------------------------------+ bool CSymbol::Exist(const string name) const { int total=::SymbolsTotal(false); for(int i=0;i<total;i++) if(::SymbolName(i,false)==name) return true; return false; } //+------------------------------------------------------------------+
Реализация метода, подсчитывающего и возвращающего количество знаков после запятой в double-значении:
//+------------------------------------------------------------------+ //| Возвращает количество знаков после запятой в double-значении | //+------------------------------------------------------------------+ int CSymbol::GetDigits(const double value) const { string val_str=(string)value; int len=::StringLen(val_str); int n=len-::StringFind(val_str,".",0)-1; if(::StringSubstr(val_str,len-1,1)=="0") n--; return n; } //+------------------------------------------------------------------+
Данный метод мы обсуждали в прошлой статье. Здесь он просто был вынесен в отдельный метод, так как требуется неоднократный расчёт для нескольких значений — для минимального лота и шага изменения лота.
Реализация методов, возвращающих время начала котировочной сессии от начала дня, время окончания котировочной сессии от начала дня и время
начала и конца котировочной сессии:
//+------------------------------------------------------------------+ //| Возвращает время начала котировочной сессии | //| в секундах от начала дня | //+------------------------------------------------------------------+ long CSymbol::SessionQuoteTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionQuote(this.m_symbol_name,day,session_index,from,to) ? from : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Возвращает время в секундах от начала дня | //| до окончания котировочной сессии | //+------------------------------------------------------------------+ long CSymbol::SessionQuoteTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionQuote(this.m_symbol_name,day,session_index,from,to) ? to : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Возвращает время начала и конца требуемой котировочной сессии | //+------------------------------------------------------------------+ bool CSymbol::GetSessionQuote(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to) { ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return ::SymbolInfoSessionQuote(this.m_symbol_name,day,session_index,from,to); } //+------------------------------------------------------------------+
В первые два метода передаются индекс сессии и день недели, в третий дополнительно передаются переменные с типом datetime, в которые будут записаны данные о начале и конце требуемой сессии, полученные посредством функции SymbolInfoSessionQuote().
Для удобства, если в качестве дня недели передано -1, то данные по сессии берутся для текущего дня недели. Индекс сессии должен начинаться от
нуля. Время возвращается в виде количества секунд от начала дня, определяемого параметром
day_of_week. Таким образом, всегда можно узнать реальное запрашиваемое время прибавлением ко времени начала дня то количество
секунд, которое было получено из метода.
Таким же образом реализованы методы получения времён торговых сессий:
//+------------------------------------------------------------------+ //| Возвращает время начала торговой сессии | //| в секундах от начала дня | //+------------------------------------------------------------------+ long CSymbol::SessionTradeTimeFrom(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionTrade(this.m_symbol_name,day,session_index,from,to) ? from : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Возвращает время в секундах от начала дня | //| до окончания торговой сессии | //+------------------------------------------------------------------+ long CSymbol::SessionTradeTimeTo(const uint session_index,ENUM_DAY_OF_WEEK day_of_week=WRONG_VALUE) const { MqlDateTime time={0}; datetime from=0,to=0; ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return(::SymbolInfoSessionTrade(this.m_symbol_name,day,session_index,from,to) ? to : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Возвращает время начала и конца требуемой торговой сессии | //+------------------------------------------------------------------+ bool CSymbol::GetSessionTrade(const uint session_index,ENUM_DAY_OF_WEEK day_of_week,datetime &from,datetime &to) { ENUM_DAY_OF_WEEK day=(day_of_week<0 || day_of_week>SATURDAY ? this.CurrentDayOfWeek() : day_of_week); return ::SymbolInfoSessionTrade(this.m_symbol_name,day,session_index,from,to); } //+------------------------------------------------------------------+
В этих методах всё аналогично описанным выше, за исключением того, что здесь для получения нужных данных используется функция SymbolInfoSessionTrade().
Реализация метода, возвращающего текущий день недели в виде значения перечисления ENUM_DAY_OF_WEEK:
//+------------------------------------------------------------------+ //| Возвращает текущий день недели | //+------------------------------------------------------------------+ ENUM_DAY_OF_WEEK CSymbol::CurrentDayOfWeek(void) const { MqlDateTime time={0}; ::TimeCurrent(time); return(ENUM_DAY_OF_WEEK)time.day_of_week; } //+------------------------------------------------------------------+
Здесь всё просто: объявляем структуру даты и времени,
обращаемся к функции
TimeCurrent(), вторая форма вызова которой заполняет структуру
даты и времени, переданную в функцию, и в итоге возвращаем
день недели из заполненной
структуры.
Реализация метода, возвращающего число секунд во времени продолжительности указанной сессии:
//+------------------------------------------------------------------+ //| Возвращает число скунд во времени продолжительности сессии | //+------------------------------------------------------------------+ int CSymbol::SessionSeconds(const ulong duration_sec) const { return int(duration_sec % 60); } //+------------------------------------------------------------------+
В метод передаётся число секунд и возвращается остаток от деления на количество минут в этом промежутке времени.
Реализация метода, возвращающего число минут во времени продолжительности указанной сессии:
//+------------------------------------------------------------------+ //| Возвращает число минут во времени продолжительности сессии | //+------------------------------------------------------------------+ int CSymbol::SessionMinutes(const ulong duration_sec) const { return int((duration_sec-this.SessionSeconds(duration_sec)) % 3600)/60; } //+------------------------------------------------------------------+
В метод передаётся число секунд и возвращается рассчитанное количество минут в этом промежутке времени за исключением числа секунд, не кратных одной минуте.
Реализация метода, возвращающего число часов во времени продолжительности указанной сессии:
//+------------------------------------------------------------------+ //| Возвращает число часов во времени продолжительности сессии | //+------------------------------------------------------------------+ int CSymbol::SessionHours(const ulong duration_sec) const { return int(duration_sec-this.SessionSeconds(duration_sec)-this.SessionMinutes(duration_sec))/3600; } //+------------------------------------------------------------------+
В метод передаётся число секунд и возвращается количество
часов в этом промежутке времени
за исключением числа секунд, не кратных одной минуте и числа
минут, не кратных одному часу.
Реализация метода, возвращающего описание продолжительности сессии в виде "ЧЧ:ММ:СС":
//+------------------------------------------------------------------+ //| Возвращает описание продолжительности сессии в чч:мм:сс | //+------------------------------------------------------------------+ string CSymbol::SessionDurationDescription(const ulong duration_sec) const { int sec=this.SessionSeconds(duration_sec); int min=this.SessionMinutes(duration_sec); int hour=this.SessionHours(duration_sec); return ::IntegerToString(hour,2,'0')+":"+::IntegerToString(min,2,'0')+":"+::IntegerToString(sec,2,'0'); } //+------------------------------------------------------------------+
Здесь просто получаем продолжительность сессии в секундах, получаем
рассчитанную продолжительность сессии в секундах, минутах
и
часах, и выводим отформатированное сообщение в формате
Часы:Минуты:Секунды при помощи функции
IntegerToString() с
размером длины строки для часов, минут и секунд равной двум знакам,
и заполнителем в виде
"0" в случае, если в значении часа, минуты или секунд будет лишь одно
число.
Например, если получили 2 часа, то выводиться будет как 02.
Так как статусы объектов-символов мы немного переработали, то и подправим метод, выводящий описание статуса объекта-символа:
//+------------------------------------------------------------------+ //| Возвращает описание статуса | //+------------------------------------------------------------------+ 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_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_FUTURES ? TextByLanguage("Фьючерс","Furures") : this.Status()==SYMBOL_STATUS_CFD ? TextByLanguage("Контракт на разницу","Contract For Difference") : this.Status()==SYMBOL_STATUS_STOCKS ? TextByLanguage("Ценная бумага","Stocks") : this.Status()==SYMBOL_STATUS_BONDS ? TextByLanguage("Облигация","Bonds") : this.Status()==SYMBOL_STATUS_OPTION ? TextByLanguage("Опцион","Option") : this.Status()==SYMBOL_STATUS_COLLATERAL ? TextByLanguage("Неторгуемый актив","Collateral") : this.Status()==SYMBOL_STATUS_CUSTOM ? TextByLanguage("Пользовательский символ","Custom symbol") : this.Status()==SYMBOL_STATUS_COMMON ? TextByLanguage("Символ общей группы","Common group symbol") : ::EnumToString((ENUM_SYMBOL_STATUS)this.Status()) ); } //+------------------------------------------------------------------+
В метод обновления всех данных символа допишем для MQL5 получение
коэффициентов взимания маржи для всех типов ордеров и позиций.
Для MQL4, где они не используются, их значения будут
нулевыми после начальной инициализации в конструкторе класса:
//+------------------------------------------------------------------+ //| Обновляет все данные символа, которые могут измениться | //+------------------------------------------------------------------+ void CSymbol::Refresh(void) { ::ResetLastError(); if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick)) { this.m_global_error=::GetLastError(); return; } #ifdef __MQL5__ ::ResetLastError(); if(!this.MarginRates()) { this.m_global_error=::GetLastError(); return; } #endif //--- Обновление целочисленных свойств 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_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(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)] = this.m_margin_rate.Long.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)] = this.m_margin_rate.BuyStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)] = this.m_margin_rate.BuyLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)] = this.m_margin_rate.BuyStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)] = this.m_margin_rate.Long.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)] = this.m_margin_rate.BuyStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)] = this.m_margin_rate.BuyLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)] = this.m_margin_rate.Short.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)] = this.m_margin_rate.SellStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)] = this.m_margin_rate.SellLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)] = this.m_margin_rate.SellStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)] = this.m_margin_rate.Short.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)] = this.m_margin_rate.SellStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)] = this.m_margin_rate.SellLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance; } //+------------------------------------------------------------------+
Здесь: для MQL5 сразу вызываем метод получения данных о
коэффициентах взимания маржи MarginRates(), и если хоть один из коэффициентов не был получен (метод вернул
false), то просто записываем код
ошибки в переменную, хранящую код ошибки класса и без сообщения выходим из метода.
Сообщение об ошибке не выводим в журнал по
причине, что метод работает в таймере, и если вдруг выйдет ошибочное получение данных, то очень быстро журнал заполнится мусорными
сообщениями об одной и той же ошибке. А так как этот код ошибки можно всегда получить в классе CEngine, то и оставим обязанность её получения и
обработки для него.
В самом конце метода все полученные данные о коэффициентах записываются в
поля соответствующих свойств объекта-символа.
По той же вышеописанной причине удалим из метода обновления котировочных
данных строку с выводом сообщения об ошибке в журнал:
//+------------------------------------------------------------------+ //| Обновляет котировочные данные по символу | //+------------------------------------------------------------------+ 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(); } //+------------------------------------------------------------------+
Теперь метод будет выглядеть так:
//+------------------------------------------------------------------+ //| Обновляет котировочные данные по символу | //+------------------------------------------------------------------+ void CSymbol::RefreshRates(void) { ::ResetLastError(); if(!::SymbolInfoTick(this.m_symbol_name,this.m_tick)) { this.m_global_error=::GetLastError(); 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(); } //+------------------------------------------------------------------+
На этом доработка класса абстрактного символа CSymbol завершена.
Мы рассмотрели важные и наиболее значимые изменения методов класса за исключением мелких правок, которые были внесены, но не описаны здесь потому, что это просто некоторые орфографические и "смысловые" ошибки. В основном в методах описания свойств. Их можно будет видеть в прилагаемых к статье файлах.
Теперь нам необходимо создать объекты-наследники базового класса абстрактного символа. И уже именно эти объекты, распределённые по
категориям, будем размещать в коллекцию объектов-символов.
Объекты-наследники базового абстрактного объекта "символ"
Вернёмся немного назад и посмотрим озвученные нами категории симвлов, а также сразу и определимся с наименованиями соответствующих классов-наследников базового класса CSymbol:
- Форекс символ — класс CSymbolFX
- Форекс символ-мажор — класс CSymbolFXMajor
- Форекс символ-минор — класс CSymbolFXMinor
- Форекс символ-экзотик — класс CSymbolFXExotic
- Форекс символ/рубль — класс CSymbolFXRub
- Металл — класс CSymbolMetall
- Индекс — класс CSymbolIndex
- Индикатив — класс CSymbolIndicative
- Криптовалютный символ — класс CSymbolCrypto
- Товарный символ — класс CSymbolCommodity
- Биржевой символ — класс CSymbolExchange
- Фьючерс — класс CSymbolFutures
- Контракт на разницу (CFD) — класс CSymbolCFD
- Ценная бумага — класс CSymbolStocks
- Облигация — класс CSymbolBonds
- Опцион — класс CSymbolOption
- Неторгуемый актив — класс CSymbolCollateral
- Пользовательский символ — класс CSymbolCustom
- Общая категория — класс CSymbolCommon
В папке библиотеки \MQL5\Include\DoEasy\Objects\Symbols\ создадим новый класс CSymbolFX с именем файла SymbolFX.mqh.
Базовым классом для него должен быть класс абстрактного символа
CSymbol.
Сразу же объявим все необходимые методы для работы класса:
//+------------------------------------------------------------------+ //| SymbolFX.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 "Symbol.mqh" //+------------------------------------------------------------------+ //| Форекс символ | //+------------------------------------------------------------------+ class CSymbolFX : public CSymbol { public: //--- Конструктор CSymbolFX(const string name) : CSymbol(SYMBOL_STATUS_FX,name) {} //--- Поддерживаемые целочисленные свойства символа virtual bool SupportProperty(ENUM_SYMBOL_PROP_INTEGER property); //--- Поддерживаемые вещественные свойства символа virtual bool SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property); //--- Поддерживаемые строковые свойства символа virtual bool SupportProperty(ENUM_SYMBOL_PROP_STRING property); //--- Выводит в журнал краткое описание символа virtual void PrintShort(void); }; //+------------------------------------------------------------------+
В конструктор класса будем передавать имя
символа, а в списке инициализации конструктора класса отправим в
базовый класс категорию символа (его статус)
"Форекс-символ" и
имя символа, передаваемое в конструктор класса CSymbolFX при его
создании.
Виртуальные методы поддержания объектом целочисленных, вещественных
и строковых свойств были объявлены в базовом классе, а в
классах-наследниках мы сделаем их реализацию. Виртуальный метод
PrintShort(), так же объявленный в базовом классе и реализованный в
классе-наследнике, будет выводить краткую информацию по символу в журнал.
Забегая наперёд скажу — почти все эти методы у всех классов-наследников практически одинаковые, и их можно было сделать в базовом классе, не создавая при этом классы-наследники. Но в таком случае теряется гибкость проведения возможных изменений этих методов для каждой из групп символов. Поэтому было решено сделать разделение по категориям именно через классы-наследники, чтобы в будущем иметь при необходимости возможность изменить каждый из классов-наследников раздельно друг от друга, что гораздо проще и быстрее.
Реализация метода, возвращающего флаг поддержания объектом-символом целочисленного свойства:
//+------------------------------------------------------------------+ //| Возвращает истину, если символ поддерживает переданное | //| целочисленное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CSymbolFX::SupportProperty(ENUM_SYMBOL_PROP_INTEGER property) { if(property==SYMBOL_PROP_EXIST #ifdef __MQL4__ || property==SYMBOL_PROP_CUSTOM || property==SYMBOL_PROP_SESSION_DEALS || property==SYMBOL_PROP_SESSION_BUY_ORDERS || property==SYMBOL_PROP_SESSION_SELL_ORDERS || property==SYMBOL_PROP_VOLUME || property==SYMBOL_PROP_VOLUMEHIGH || property==SYMBOL_PROP_VOLUMELOW || property==SYMBOL_PROP_TICKS_BOOKDEPTH || property==SYMBOL_PROP_OPTION_MODE || property==SYMBOL_PROP_OPTION_RIGHT || property==SYMBOL_PROP_BACKGROUND_COLOR #endif ) return false; return true; } //+------------------------------------------------------------------+
В метод передаётся проверяемое целочисленное свойство, и
далее для MQL5 и MQL4,
если переданное свойство "Существование символа", то возвращаем false
— ведь если символ создан, то он существует, и данное его свойство нам не нужно ни для вывода в журнал, ни тем более для поиска и
сортировки. Все остальные проверки относятся
только к MQL4 и возвращается false
при передаче в метод заведомо неподдерживаемого свойства символа в MQL4.
Если переданное свойство не было среди
перечисленных в проверке свойств — значит оно поддерживается, и возвращаем
true.
Реализация метода, возвращающего флаг поддержания объектом-символом вещественного свойства:
//+------------------------------------------------------------------+ //| Возвращает истину, если символ поддерживает переданное | //| вещественное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CSymbolFX::SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property) { if( #ifdef __MQL5__ (this.ChartMode()==SYMBOL_CHART_MODE_BID && ( property==SYMBOL_PROP_LAST || property==SYMBOL_PROP_LASTHIGH || property==SYMBOL_PROP_LASTLOW ) ) || (this.ChartMode()==SYMBOL_CHART_MODE_LAST && ( property==SYMBOL_PROP_BID || property==SYMBOL_PROP_BIDHIGH || property==SYMBOL_PROP_BIDLOW || property==SYMBOL_PROP_ASK || property==SYMBOL_PROP_ASKHIGH || property==SYMBOL_PROP_ASKLOW ) ) //--- __MQL4__ #else property==SYMBOL_PROP_ASKHIGH || property==SYMBOL_PROP_ASKLOW || property==SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT || property==SYMBOL_PROP_TRADE_TICK_VALUE_LOSS || property==SYMBOL_PROP_LAST || property==SYMBOL_PROP_LASTHIGH || property==SYMBOL_PROP_LASTLOW || property==SYMBOL_PROP_VOLUME_LIMIT || property==SYMBOL_PROP_MARGIN_LONG_INITIAL || property==SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL || property==SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_LONG_MAINTENANCE || property==SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE || property==SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SHORT_INITIAL || property==SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL || property==SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL || property==SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE || property==SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE || property==SYMBOL_PROP_SESSION_VOLUME || property==SYMBOL_PROP_SESSION_TURNOVER || property==SYMBOL_PROP_SESSION_INTEREST || property==SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME || property==SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME || property==SYMBOL_PROP_SESSION_OPEN || property==SYMBOL_PROP_SESSION_CLOSE || property==SYMBOL_PROP_SESSION_AW || property==SYMBOL_PROP_SESSION_PRICE_SETTLEMENT || property==SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN || property==SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX || property==SYMBOL_PROP_VOLUME_REAL || property==SYMBOL_PROP_VOLUMEHIGH_REAL || property==SYMBOL_PROP_VOLUMELOW_REAL || property==SYMBOL_PROP_OPTION_STRIKE || property==SYMBOL_PROP_TRADE_ACCRUED_INTEREST || property==SYMBOL_PROP_TRADE_FACE_VALUE || property==SYMBOL_PROP_TRADE_LIQUIDITY_RATE #endif ) return false; return true; } //+------------------------------------------------------------------+
Здесь логика та же, что и в прошлом методе. Но сначала проверяем полученное свойство для MQL5,
и если это одно из свойств цены последней сделки (Last), но
при этом график строится по ценам Bid, то все эти свойства будут
равны нулю, и соответственно — они в данном случае не поддерживаются.
Аналогично поступаем со свойствами цен Bid в случае, если график
строится по ценам Last — все свойства цены Bid не поддерживаются.
Для
MQL4 поступаем точно так же, как и в прошлом методе — при передаче в метод заведомо не поддерживаемого свойства символа, возвращаем false.
Реализация метода, возвращающего флаг поддержания объектом-символом строкового свойства:
//+------------------------------------------------------------------+ //| Возвращает истину, если символ поддерживает переданное | //| строковое свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CSymbolFX::SupportProperty(ENUM_SYMBOL_PROP_STRING property) { if( #ifdef __MQL5__ property==SYMBOL_PROP_FORMULA && !this.IsCustom() #else property==SYMBOL_PROP_BASIS || property==SYMBOL_PROP_BANK || property==SYMBOL_PROP_ISIN || property==SYMBOL_PROP_FORMULA || property==SYMBOL_PROP_PAGE #endif ) return false; return true; } //+------------------------------------------------------------------+
Здесь всё так же, как и в двух предыдущих: для MQL5 — если
переданное свойство "Формула для расчёта пользовательского символа",
и при этом этот символ не пользовательский, то возвращаем false — свойство не
поддерживается. А далее — проверки заведомо не поддерживаемых свойств символа
для MQL4 и возврат false,
если передано не поддерживаемое в MQL4 свойство.
Метод вывода в журнал краткого описания символа:
//+------------------------------------------------------------------+ //| Выводит в журнал краткое описание символа | //+------------------------------------------------------------------+ void CSymbolFX::PrintShort(void) { ::Print(this.GetStatusDescription()+" "+this.Name()); } //+------------------------------------------------------------------+
Метод просто выводит в журнал строку, состоящую из строкового описания статуса символа и его наименования.
Остальные классы-наследники устроены точно так же и имеют такие же методы с такой же реализацией.
Отличием является класс
пользовательского символа — такого типа символов однозначно нет в MQL4, поэтому и все проверки относятся лишь к MQL5:
//+------------------------------------------------------------------+ //| SymbolCustom.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 "Symbol.mqh" //+------------------------------------------------------------------+ //| Пользовательский символ | //+------------------------------------------------------------------+ class CSymbolCustom : public CSymbol { public: //--- Конструктор CSymbolCustom(const string name) : CSymbol(SYMBOL_STATUS_CUSTOM,name) {} //--- Поддерживаемые целочисленные свойства символа virtual bool SupportProperty(ENUM_SYMBOL_PROP_INTEGER property); //--- Поддерживаемые вещественные свойства символа virtual bool SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property); //--- Поддерживаемые строковые свойства символа virtual bool SupportProperty(ENUM_SYMBOL_PROP_STRING property); //--- Выводит в журнал краткое описание символа virtual void PrintShort(void); }; //+------------------------------------------------------------------+ //| Возвращает истину, если символ поддерживает переданное | //| целочисленное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CSymbolCustom::SupportProperty(ENUM_SYMBOL_PROP_INTEGER property) { if(property==SYMBOL_PROP_EXIST) return false; return true; } //+------------------------------------------------------------------+ //| Возвращает истину, если символ поддерживает переданное | //| вещественное свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CSymbolCustom::SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property) { if( (this.ChartMode()==SYMBOL_CHART_MODE_BID && ( property==SYMBOL_PROP_LAST || property==SYMBOL_PROP_LASTHIGH || property==SYMBOL_PROP_LASTLOW ) ) || (this.ChartMode()==SYMBOL_CHART_MODE_LAST && ( property==SYMBOL_PROP_BID || property==SYMBOL_PROP_BIDHIGH || property==SYMBOL_PROP_BIDLOW || property==SYMBOL_PROP_ASK || property==SYMBOL_PROP_ASKHIGH || property==SYMBOL_PROP_ASKLOW ) ) ) return false; return true; } //+------------------------------------------------------------------+ //| Возвращает истину, если символ поддерживает переданное | //| строковое свойство, возвращает ложь в противном случае | //+------------------------------------------------------------------+ bool CSymbolCustom::SupportProperty(ENUM_SYMBOL_PROP_STRING property) { return true; } //+------------------------------------------------------------------+ //| Выводит в журнал краткое описание символа | //+------------------------------------------------------------------+ void CSymbolCustom::PrintShort(void) { ::Print(this.GetStatusDescription()+" "+this.Name()); } //+------------------------------------------------------------------+
На этом мы завершили разработку классов-наследников CSymbol.
Реализацию остальных классов-наследников можно будет
посмотреть в конце статьи в прикреплённых файлах.
Так как нам потребуется поиск и сортировка в коллекции символов, то следует создать для этого необходимый функционал. Откроем файл Select.mqh,
расположенный в папке библиотеки
\MQL5\Include\DoEasy\Services\, и внесём в него дополнения.
Первым делом подключим
класс абстрактного символа:
//+------------------------------------------------------------------+ //| Select.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 <Arrays\ArrayObj.mqh> #include "..\Objects\Orders\Order.mqh" #include "..\Objects\Events\Event.mqh" #include "..\Objects\Accounts\Account.mqh" #include "..\Objects\Symbols\Symbol.mqh" //+------------------------------------------------------------------+
В публичной секции класса объявим все необходимые методы для поиска и
сортировки:
//+------------------------------------------------------------------+ //| Класс для выборки объектов, удовлетворяющих критерию | //+------------------------------------------------------------------+ class CSelect { private: //--- Метод сравнения двух величин template<typename T> static bool CompareValues(T value1,T value2,ENUM_COMPARER_TYPE mode); public: //+------------------------------------------------------------------+ //| Методы работы с ордерами | //+------------------------------------------------------------------+ //--- Возвращает список ордеров, у которых одно из (1) целочисленных, (2) вещественных и (3) строковых свойств удовлетворяет заданному критерию static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Возвращает индекс ордера в списке с максимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства ордера static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property); static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property); static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property); //--- Возвращает индекс ордера в списке с минимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства ордера static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property); static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property); static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property); //+------------------------------------------------------------------+ //| Методы работы с событиями | //+------------------------------------------------------------------+ //--- Возвращает список событий, у которых одно из (1) целочисленных, (2) вещественных и (3) строковых свойств удовлетворяет заданному критерию static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Возвращает индекс события в списке с максимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства события static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property); static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property); static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property); //--- Возвращает индекс события в списке с минимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства события static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property); static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property); static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property); //+------------------------------------------------------------------+ //| Методы работы с аккаунтами | //+------------------------------------------------------------------+ //--- Возвращает список аккаунтов, у которых одно из (1) целочисленных, (2) вещественных и (3) строковых свойств удовлетворяет заданному критерию static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Возвращает индекс события в списке с максимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства события static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property); static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property); static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property); //--- Возвращает индекс события в списке с минимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства события static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property); static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property); static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property); //+------------------------------------------------------------------+ //| Методы работы с символами | //+------------------------------------------------------------------+ //--- Возвращает список символов, у которых одно из (1) целочисленных, (2) вещественных и (3) строковых свойств удовлетворяет заданному критерию static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Возвращает индекс символа в списке с максимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства ордера static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property); static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property); static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property); //--- Возвращает индекс символа в списке с минимальным значением (1) целочисленного, (2) вещественного и (3) строкового свойства ордера static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property); static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property); static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property); //--- }; //+------------------------------------------------------------------+
За пределами класса напишем их реализацию:
//+------------------------------------------------------------------+ //| Методы работы со списками символов | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Возвращает список символов, у которых одно из целочисленных | //| свойств удовлетворяет заданному критерию | //+------------------------------------------------------------------+ CArrayObj *CSelect::BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); int total=list_source.Total(); for(int i=0; i<total; i++) { CSymbol *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; long obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Возвращает список символов, у которых одно из вещественных | //| свойств удовлетворяет заданному критерию | //+------------------------------------------------------------------+ CArrayObj *CSelect::BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); for(int i=0; i<list_source.Total(); i++) { CSymbol *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; double obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Возвращает список символов, у которых одно из строковых | //| свойств удовлетворяет заданному критерию | //+------------------------------------------------------------------+ CArrayObj *CSelect::BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode) { if(list_source==NULL) return NULL; CArrayObj *list=new CArrayObj(); if(list==NULL) return NULL; list.FreeMode(false); ListStorage.Add(list); for(int i=0; i<list_source.Total(); i++) { CSymbol *obj=list_source.At(i); if(!obj.SupportProperty(property)) continue; string obj_prop=obj.GetProperty(property); if(CompareValues(obj_prop,value,mode)) list.Add(obj); } return list; } //+------------------------------------------------------------------+ //| Возвращает индекс символа в списке | //| с максимальным значением целочисленного свойства | //+------------------------------------------------------------------+ int CSelect::FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CSymbol *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CSymbol *obj=list_source.At(i); long obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); long obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Возвращает индекс символа в списке | //| с максимальным значением вещественного свойства | //+------------------------------------------------------------------+ int CSelect::FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CSymbol *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CSymbol *obj=list_source.At(i); double obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); double obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Возвращает индекс символа в списке | //| с максимальным значением строкового свойства | //+------------------------------------------------------------------+ int CSelect::FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CSymbol *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CSymbol *obj=list_source.At(i); string obj1_prop=obj.GetProperty(property); max_obj=list_source.At(index); string obj2_prop=max_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i; } return index; } //+------------------------------------------------------------------+ //| Возвращает индекс символа в списке | //| с минимальным значением целочисленного свойства | //+------------------------------------------------------------------+ int CSelect::FindSymbolMin(CArrayObj* list_source,ENUM_SYMBOL_PROP_INTEGER property) { int index=0; CSymbol *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++){ CSymbol *obj=list_source.At(i); long obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); long obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+ //| Возвращает индекс символа в списке | //| с минимальным значением вещественного свойства | //+------------------------------------------------------------------+ int CSelect::FindSymbolMin(CArrayObj* list_source,ENUM_SYMBOL_PROP_DOUBLE property) { int index=0; CSymbol *min_obj=NULL; int total=list_source.Total(); if(total== 0) return WRONG_VALUE; for(int i=1; i<total; i++){ CSymbol *obj=list_source.At(i); double obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); double obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+ //| Возвращает индекс символа в списке | //| с минимальным значением строкового свойства | //+------------------------------------------------------------------+ int CSelect::FindSymbolMin(CArrayObj* list_source,ENUM_SYMBOL_PROP_STRING property) { int index=0; CSymbol *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++){ CSymbol *obj=list_source.At(i); string obj1_prop=obj.GetProperty(property); min_obj=list_source.At(index); string obj2_prop=min_obj.GetProperty(property); if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i; } return index; } //+------------------------------------------------------------------+
Подобные методы у нас есть для каждого класса-коллекции, и их работа рассматривалась в третьей
части описания билиотеки при создании класса CSelect, поэтому здесь не будем останавливаться на их разборе.
Теперь у нас всё готово для создания класса-коллекции символов.
Для работы с коллекцией символов из программы можно
будет использовать четыре режима:
- Работа только с одним символом,
- Работа со списком символов,
- Работа с окном "Обзор рынка",
- Работа с полным спискм символов на сервере.
Для того чтобы класс коллекции символов "знал" с чем ему работать, будем использовать такую схему:
В программе —
в её настройках, задаётся перечисление методов работы с символами. Это может быть один из четырёх озвученных режимов работы.
В программе так же должен быть строковый массив, который будет заполняться функцией из библиотеки по такому принципу:
- если выбрана работа с одним символом, то в массиве будет содержаться только текущий символ,
- если выбрана работа с пользовательским списком символов, который тоже может находиться в настройках программы, и в нём через
запятую прописаны нужные символы, то массив будет заполнен символами из этой строки; если в этой строке будет прописан только
один текущий символ или список пустой, то работа будет с текущим символом
- если выбрана работа с обзором рынка, то в массиве, в его единственной ячейке, будет вместо названия символа прописано "MARKET_WATCH"
- если же выбрана работа с полным списком символов на сервере, то в массиве будет вместо названия символа прописано "ALL"
Всё это будет производиться автоматически, и от пользователя нужно будет лишь сделать организацию выбора нужного режима работы с коллекцией символов и создать минимум один строковый массив, максимум — строковый массив и строку предопределённых символов в настройках.
Класс коллекции символов
В папке библиотеки \MQL5\Include\DoEasy\Collections\ создадим новый класс CSymbolsCollection в файле SymbolsCollection.mqh.
Базовым классом для него должен быть класс объекта стандартной
библиотеки
CObject.
Сразу же подключим к вновь созданному файлу все необходимые для работы файлы классов:
//+------------------------------------------------------------------+ //| SymbolsCollection.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 "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\Symbols\SymbolFX.mqh" #include "..\Objects\Symbols\SymbolFXMajor.mqh" #include "..\Objects\Symbols\SymbolFXMinor.mqh" #include "..\Objects\Symbols\SymbolFXExotic.mqh" #include "..\Objects\Symbols\SymbolFXRub.mqh" #include "..\Objects\Symbols\SymbolMetall.mqh" #include "..\Objects\Symbols\SymbolIndex.mqh" #include "..\Objects\Symbols\SymbolIndicative.mqh" #include "..\Objects\Symbols\SymbolCrypto.mqh" #include "..\Objects\Symbols\SymbolCommodity.mqh" #include "..\Objects\Symbols\SymbolExchange.mqh" #include "..\Objects\Symbols\SymbolFutures.mqh" #include "..\Objects\Symbols\SymbolCFD.mqh" #include "..\Objects\Symbols\SymbolStocks.mqh" #include "..\Objects\Symbols\SymbolBonds.mqh" #include "..\Objects\Symbols\SymbolOption.mqh" #include "..\Objects\Symbols\SymbolCollateral.mqh" #include "..\Objects\Symbols\SymbolCustom.mqh" #include "..\Objects\Symbols\SymbolCommon.mqh" //+------------------------------------------------------------------+ //| Коллекция исторических ордеров и сделок | //+------------------------------------------------------------------+ class CSymbolsCollection : public CObject { private: public: //--- Конструктор CSymbolsCollection(); }; //+------------------------------------------------------------------+
И добавим уже ставшие стандартными для классов-коллекций библиотеки переменные-члены класса и методы:
//+------------------------------------------------------------------+ //| SymbolsCollection.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 "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\Symbols\SymbolFX.mqh" #include "..\Objects\Symbols\SymbolFXMajor.mqh" #include "..\Objects\Symbols\SymbolFXMinor.mqh" #include "..\Objects\Symbols\SymbolFXExotic.mqh" #include "..\Objects\Symbols\SymbolFXRub.mqh" #include "..\Objects\Symbols\SymbolMetall.mqh" #include "..\Objects\Symbols\SymbolIndex.mqh" #include "..\Objects\Symbols\SymbolIndicative.mqh" #include "..\Objects\Symbols\SymbolCrypto.mqh" #include "..\Objects\Symbols\SymbolCommodity.mqh" #include "..\Objects\Symbols\SymbolExchange.mqh" #include "..\Objects\Symbols\SymbolFutures.mqh" #include "..\Objects\Symbols\SymbolCFD.mqh" #include "..\Objects\Symbols\SymbolStocks.mqh" #include "..\Objects\Symbols\SymbolBonds.mqh" #include "..\Objects\Symbols\SymbolOption.mqh" #include "..\Objects\Symbols\SymbolCollateral.mqh" #include "..\Objects\Symbols\SymbolCustom.mqh" #include "..\Objects\Symbols\SymbolCommon.mqh" //+------------------------------------------------------------------+ //| Коллекция исторических ордеров и сделок | //+------------------------------------------------------------------+ class CSymbolsCollection : public CObject { private: CListObj m_list_all_symbols; // Список всех объектов-символов public: //--- Возвращает полный список-коллекцию "как есть" CArrayObj *GetList(void) { return &this.m_list_all_symbols; } //--- Возвращает список по выбранному (1) целочисленному, (2) вещественному и (3) строковому свойству, удовлетворяющему сравниваемому критерию CArrayObj *GetList(ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } //--- Конструктор CSymbolsCollection(); }; //+------------------------------------------------------------------+
Все эти переменные и методы нами уже рассматривались при создании прошлых коллекций. Думаю, что не стоит здесь останавливаться на их повторном обсуждении.
Допишем все остальные требующиеся переменные и методы для работы класса-коллекции символов:
//+------------------------------------------------------------------+ //| SymbolsCollection.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 "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\Symbols\SymbolFX.mqh" #include "..\Objects\Symbols\SymbolFXMajor.mqh" #include "..\Objects\Symbols\SymbolFXMinor.mqh" #include "..\Objects\Symbols\SymbolFXExotic.mqh" #include "..\Objects\Symbols\SymbolFXRub.mqh" #include "..\Objects\Symbols\SymbolMetall.mqh" #include "..\Objects\Symbols\SymbolIndex.mqh" #include "..\Objects\Symbols\SymbolIndicative.mqh" #include "..\Objects\Symbols\SymbolCrypto.mqh" #include "..\Objects\Symbols\SymbolCommodity.mqh" #include "..\Objects\Symbols\SymbolExchange.mqh" #include "..\Objects\Symbols\SymbolFutures.mqh" #include "..\Objects\Symbols\SymbolCFD.mqh" #include "..\Objects\Symbols\SymbolStocks.mqh" #include "..\Objects\Symbols\SymbolBonds.mqh" #include "..\Objects\Symbols\SymbolOption.mqh" #include "..\Objects\Symbols\SymbolCollateral.mqh" #include "..\Objects\Symbols\SymbolCustom.mqh" #include "..\Objects\Symbols\SymbolCommon.mqh" //+------------------------------------------------------------------+ //| Коллекция исторических ордеров и сделок | //+------------------------------------------------------------------+ class CSymbolsCollection : public CObject { private: CListObj m_list_all_symbols; // Список всех объектов-символов ENUM_SYMBOLS_MODE m_mode_list; // Режим работы со списками символов int m_delta_symbol; // Разница в количестве символов по сравнению с прошлой проверкой int m_last_num_symbol; // Количество символов в окне "Обзор рынка" на прошлой проверке int m_global_error; // Код глобальной ошибки //--- Возвращает флаг наличия объекта-символа по его имени в списке всех символов bool IsPresentSymbolInList(const string symbol_name); //--- Создаёт объект-символ и помещает его в список bool CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name); //--- Возвращает тип используемого списка символов (Обзор рынка/Сервер) ENUM_SYMBOLS_MODE TypeSymbolsList(const string &symbol_used_array[]); //--- Определяет по имени и возвращает принадлежность символа к группе ENUM_SYMBOL_STATUS SymbolStatus(const string symbol_name) const; //--- Возвращает принадлежность символа к категории по пользовательским критериям ENUM_SYMBOL_STATUS StatusByCustomPredefined(const string symbol_name) const; //--- Возвращает принадлежность символа к категориям по расчёту залоговых средств ENUM_SYMBOL_STATUS StatusByCalcMode(const string symbol_name) const; //--- Возвращает принадлежность символа к предопределённым (1) мажорам, (2) минорам, (3) экзотикам, (4) рублёвым, //--- (5) индикативам, (6) металлам, (7) товарам, (8) индексам, (9) криптовалюте, (10) опционам bool IsPredefinedFXMajor(const string name) const; bool IsPredefinedFXMinor(const string name) const; bool IsPredefinedFXExotic(const string name) const; bool IsPredefinedFXRUB(const string name) const; bool IsPredefinedIndicative(const string name) const; bool IsPredefinedMetall(const string name) const; bool IsPredefinedCommodity(const string name) const; bool IsPredefinedIndex(const string name) const; bool IsPredefinedCrypto(const string name) const; bool IsPredefinedOption(const string name) const; //--- Ищет символ и возвращает флаг его наличия на сервере bool Exist(const string name) const; public: //--- Возвращает полный список-коллекцию "как есть" CArrayObj *GetList(void) { return &this.m_list_all_symbols; } //--- Возвращает список по выбранному (1) целочисленному, (2) вещественному и (3) строковому свойству, удовлетворяющему сравниваемому критерию CArrayObj *GetList(ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } //--- Возвращает количество новых символов в окне "Обзор рынка" int NewSymbols(void) const { return this.m_delta_symbol; } //--- Возвращает режим работы со списками символов ENUM_SYMBOLS_MODE ModeSymbolsList(void) const { return this.m_mode_list; } //--- Конструктор CSymbolsCollection(); //--- Устанавливает список используемых символов bool SetUsedSymbol(const string &symbol_used_array[]); //--- Обновляет (1) все, (2) котировочные данные символов коллекции void Refresh(void); void RefreshRates(void); }; //+------------------------------------------------------------------+
Класс должен знать с каким списком символов ему работать: либо это один текущий символ, либо это заданный пользователем набор символов, либо
работа со списком символов, находящихся в окне "Обзор рынка", или же работа с полным списком всех символов на сервере. Переменная-член
класса
m_mode_list хранит один из перечисленных режимов работы с
символами.
При работе со списком символов, находящихся в окне "Обзор рынка", необходимо постоянно отслеживать этот список (будет реализовано в
следующей статье) и знать
количество символов на прошлой проверке, и соответственно — на
сколько изменилось это количество при событии добавления/удаления символа/символов из списка в окне обзора рынка, чтобы
вовремя перестроить список коллекции символов
m_list_all_symbols и продолжить безошибочно с ними работать.
Как и в прошлых коллекциях, мы ввели новую переменную-член
класса, хранящую
код ошибки, которую можно "поглядеть" в базовом классе библиотеки
CEngine, и вовремя и правильно её обработать.
При создании нового объекта-символа и добавления его в коллекцию, необходимо проверить, что точно такого же символа нет в списке. Для
этого служит метод
IsPresentSymbolInList().
Для создания нового символа и добавления
его в коллекцию, будет использоваться метод
CreateNewSymbol().
Так как в коллекции символов организована работа
в четырёх режимах списков символов, то для определения того, с каким режимом необходимо работать, объявлен метод
TypeSymbolsList().
Перед созданием нового символа, сначала нужно
определить и установить группу, к которой его отнести, или к которой его относит пользователь. Для определения группы символа (его
статуса) предназначен метод
SymbolStatus().
При определении статуса символа, его имя сначала
ищется в заданных пользовательских массивах с использованием метода
StatusByCustomPredefined().
Затем, если метод вернул "общий" статус,
то статус символа определяется по типу расчёта залоговых средств методом
StatusByCalcMode().
Для
поиска по пользовательским массивам и определения принадлежности символа к той, или иной категории, назначенной пользователем,
предназначены вспомогательные методы, возвращающие флаг принадлежности символа к мажорам, минорам, индексам и прочим группам.
Метод Exist() возвращает флаг существования символа на сервере.
Метод
NewSymbols() нужен будет для возврата количества новых символов,
добавленных или удалённых из окна "Обзор рынка", а метод
ModeSymbolsList() возвращает в вызывающую программу режим работы с
одним из четырёх списков (текущий символ, предопределённый набор символов, список из обзора рынка и полный список символов на сервере).
Метод SetUsedSymbol() принимает массив символов или описание
режима работы со списком символов внутри переданного массива и создаёт список-коллекцию символов.
Метод Refresh() обновляет все данные всех символов коллекции,
которые могут измениться, а метод
RefreshRates() обновляет только котировочные данные всех символов
коллекции. Оба метода должны вызываться из таймера главного объекта библиотеки CEngine.
Итак, все методы, необходимые для работы класса коллекции символов на данном этапе, мы определили. Теперь рассмотрим их устройство.
Реализация конструктора класса:
//+------------------------------------------------------------------+ //| Конструктор | //+------------------------------------------------------------------+ CSymbolsCollection::CSymbolsCollection(void) : m_last_num_symbol(0),m_delta_symbol(0),m_mode_list(SYMBOLS_MODE_CURRENT) { this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_NAME); this.m_list_all_symbols.Clear(); this.m_list_all_symbols.Type(COLLECTION_SYMBOLS_ID); } //+------------------------------------------------------------------+
В списке инициализации конструктора инициализируем количество символов на
прошлой проверке, разницу между текущим и прошлым количеством символов
и установим режим работы со списком символов как "работа с текущим символом".
В
теле класса
зададим сортировку списку коллекции символов по имени, очистим
список и присвоим ему идентификатор "список коллекции символов".
Метод обновления всех данных всех символов коллекции:
//+------------------------------------------------------------------+ //| Обновляет все данные символов коллекции | //+------------------------------------------------------------------+ void CSymbolsCollection::Refresh(void) { int total=this.m_list_all_symbols.Total(); if(total==0) return; for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; symbol.Refresh(); } } //+------------------------------------------------------------------+
В цикле по количеству всех символов коллекции получаем очередной символ из списка коллекции и обновляем его данные при помощи метода Refresh() класса CSymbol, рассмотренного нами в прошлой статье.
Метод обновления котировочных данных всех символов коллекции:
//+------------------------------------------------------------------+ //| Обновляет котировочные данные символов коллекции | //+------------------------------------------------------------------+ void CSymbolsCollection::RefreshRates(void) { int total=this.m_list_all_symbols.Total(); if(total==0) return; for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; symbol.RefreshRates(); } } //+------------------------------------------------------------------+
В цикле по количеству всех символов коллекции получаем очередной символ из списка коллекции и обновляем его данные при помощи метода RefreshRates() класса CSymbol.
Метод создания нового объекта-символа и размещения его в списке коллекции символов:
//+------------------------------------------------------------------+ //| Создаёт объект-символ и помещает его в список | //+------------------------------------------------------------------+ bool CSymbolsCollection::CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name) { if(this.IsPresentSymbolInList(name)) { return true; } if(#ifdef __MQL5__ !::SymbolInfoInteger(name,SYMBOL_EXIST) #else !this.Exist(name) #endif ) { string t1=TextByLanguage("Ошибка входных данных: нет символа ","Input error: no "); string t2=TextByLanguage(" на сервере"," symbol on the server"); ::Print(DFUN,t1,name,t2); this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL; return false; } CSymbol *symbol=NULL; switch(symbol_status) { case SYMBOL_STATUS_FX : symbol=new CSymbolFX(name); break; // Форекс символ case SYMBOL_STATUS_FX_MAJOR : symbol=new CSymbolFXMajor(name); break; // Форекс символ-мажор case SYMBOL_STATUS_FX_MINOR : symbol=new CSymbolFXMinor(name); break; // Форекс символ-минор case SYMBOL_STATUS_FX_EXOTIC : symbol=new CSymbolFXExotic(name); break; // Форекс символ-экзотик case SYMBOL_STATUS_FX_RUB : symbol=new CSymbolFXRub(name); break; // Форекс символ/рубль case SYMBOL_STATUS_METAL : symbol=new CSymbolMetall(name); break; // Металл case SYMBOL_STATUS_INDEX : symbol=new CSymbolIndex(name); break; // Индекс case SYMBOL_STATUS_INDICATIVE : symbol=new CSymbolIndicative(name); break; // Индикатив case SYMBOL_STATUS_CRYPTO : symbol=new CSymbolCrypto(name); break; // Криптовалютный символ case SYMBOL_STATUS_COMMODITY : symbol=new CSymbolCommodity(name); break; // Товарный символ case SYMBOL_STATUS_EXCHANGE : symbol=new CSymbolExchange(name); break; // Биржевой символ case SYMBOL_STATUS_FUTURES : symbol=new CSymbolFutures(name); break; // Фьючерс case SYMBOL_STATUS_CFD : symbol=new CSymbolCFD(name); break; // Контракт на разницу case SYMBOL_STATUS_STOCKS : symbol=new CSymbolStocks(name); break; // Ценная бумага case SYMBOL_STATUS_BONDS : symbol=new CSymbolBonds(name); break; // Облигация case SYMBOL_STATUS_OPTION : symbol=new CSymbolOption(name); break; // Опцион case SYMBOL_STATUS_COLLATERAL : symbol=new CSymbolCollateral(name); break; // Неторгуемый актив case SYMBOL_STATUS_CUSTOM : symbol=new CSymbolCustom(name); break; // Пользовательский символ default : symbol=new CSymbolCommon(name); break; // Остальное } if(symbol==NULL) { ::Print(DFUN,TextByLanguage("Не удалось создать объект-символ ","Failed to create symbol object "),name); return false; } if(!this.m_list_all_symbols.Add(symbol)) { string t1=TextByLanguage("Не удалось добавить символ ","Failed to add "); string t2=TextByLanguage(" в список"," symbol to the list"); ::Print(DFUN,t1,name,t2); delete symbol; return false; } return true; } //+------------------------------------------------------------------+
В метод передаётся статус и наименование
символа, если такой символ уже есть в списке коллекции символов, то
ничего не делая, "молча"
возвращаем true
— ошибки нет, но и символ не нужно добавлять — есть такой уже.
Далее проверяем
существование символа на сервере по его имени, и если такого символа нет, то выводим сообщение об отсутствии такого символа, присваиваем
коду ошибки значение "неизвестный символ" и возвращаем false.
Если
символ существует, то
в зависимости от статуса, переданного в метод, создаём новый
объект-символ. Для создания объекта-символа используем классы-наследники абстрактного символа, соответствующие переданному
статусу.
При ошибке создания объекта выводим об этом сообщение и возвращаем
false.
При удачном создании нового объекта-символа, добавляем
его в список коллекции символов, и возвращаем true
при успешном добавлении, или выводим сообщение об ошибке и возвращаем falseпри
неудаче.
Реализация метода, возвращающего флаг наличия символа в списке коллекции:
//+------------------------------------------------------------------+ //| Возвращает флаг наличия объекта-символа | //| по его имени в списке всех символов | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPresentSymbolInList(const string symbol_name) { CArrayObj *list=dynamic_cast<CListObj*>(&this.m_list_all_symbols); list.Sort(SORT_BY_SYMBOL_NAME); list=CSelect::BySymbolProperty(list,SYMBOL_PROP_NAME,symbol_name,EQUAL); return(list==NULL || list.Total()==0 ? false : true); } //+------------------------------------------------------------------+
В метод передаётся имя искомого символа, затем список сортируется по имени символа и фильтруется по переданному имени. Если список не пустой — значит символ с таким именем найден в списке — возвращаем true, иначе — возвращаем false — нет символа в списке.
Реализация метода, устанавливающего список символов коллекции:
//+------------------------------------------------------------------+ //| Устанавливает список используемых символов | //+------------------------------------------------------------------+ bool CSymbolsCollection::SetUsedSymbol(const string &symbol_used_array[]) { this.m_mode_list=this.TypeSymbolsList(symbol_used_array); this.m_list_all_symbols.Clear(); this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_NAME); //--- Используется только текущий символ if(this.m_mode_list==SYMBOLS_MODE_CURRENT) { string name=::Symbol(); ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); return this.CreateNewSymbol(status,name); } else { bool res=true; //--- Используется предопределённый список символов if(this.m_mode_list==SYMBOLS_MODE_DEFINES) { int total=::ArraySize(symbol_used_array); for(int i=0;i<total;i++) { string name=symbol_used_array[i]; ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name); res &=add; if(!add) continue; } return res; } //--- Используется полный список символов сервера else if(this.m_mode_list==SYMBOLS_MODE_ALL) { int total=::SymbolsTotal(false); for(int i=0;i<total;i++) { string name=::SymbolName(i,false); ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name); res &=add; if(!add) continue; } return res; } //--- Используется список символов из окна "Обзор рынка" else if(this.m_mode_list==SYMBOLS_MODE_MARKET_WATCH) { int total=::SymbolsTotal(true); for(int i=0;i<total;i++) { string name=::SymbolName(i,true); ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name); res &=add; if(!add) continue; } return res; } } return false; } //+------------------------------------------------------------------+
Метод создаёт список-коллекцию символов в зависимости от содержания массива
символов, переданного в него. Сначала определяется метод работы со списком
символов (один символ/пользовательский набор символов/обзор рынка/полный список), затем список
очищается и сортируется по имени.
Если используется
только текущий символ, то
- определяем статус символа по его имени и
- возвращаем результат создания нового объекта-символа и добавления его в список коллекции символов.
Если используется предопределённый список символов, то
- в цикле по переданному в метод массиву имён символов получаем очередное имя символа из массива
- определяем статус символа по его имени
- добавляем к возвращаемой переменной результат создания и добавления объекта-символа в список-коллекцию символов
- если символ не удалось создать или добавить в список — переходим к следующему
- по завершении цикла возвращаем состояние переменной, в которую
записывались результаты создания символов коллекции
Остальные два режима обрабатываются точно так же, как и режим работы с предопределённым списком. Только вместо массива, передаваемого в метод, символы берём либо из окна обзора рынка, либо из полного списка символов на сервере.
Реализация метода, возвращающего режим работы со списками символов:
//+------------------------------------------------------------------+ //|Возвращает тип используемого списка символов (Обзор рынка/Сервер) | //+------------------------------------------------------------------+ ENUM_SYMBOLS_MODE CSymbolsCollection::TypeSymbolsList(const string &symbol_used_array[]) { int total=::ArraySize(symbol_used_array); if(total<1) return SYMBOLS_MODE_CURRENT; string type=::StringSubstr(symbol_used_array[0],13); return ( type=="MARKET_WATCH" ? SYMBOLS_MODE_MARKET_WATCH : type=="ALL" ? SYMBOLS_MODE_ALL : (total==1 && symbol_used_array[0]==::Symbol() ? SYMBOLS_MODE_CURRENT : SYMBOLS_MODE_DEFINES) ); } //+------------------------------------------------------------------+
В метод передаётся массив с именами символов, либо с описанием
режимов работы со списками.
Если передан пустой массив, то возвращаем режим работы только с текущим
символом.
Далее получаем из нулевой ячейки массива её содержимое, и
- если в подстроке, начиная с индекса 13, содержится запись "MARKET_WATCH", то возвращаем режим работы с окном "Обзор рынка".
- Если там записана строка "ALL" — возвращаем режим работы с полным списком символов.
- Иначе,
- если в массиве всего одна запись, и
она содержит имя текущего символа, то возвращаем режим работы только с текущим символом.
- Ну и в последнем из возможных вариантов — возвращаем режим работы с
предопределённым списком.
Реализация метода, возвращающего принадлежность символа к группе по его имени:
//+------------------------------------------------------------------+ //| Определяет по имени и возвращает принадлежность символа к группе | //+------------------------------------------------------------------+ ENUM_SYMBOL_STATUS CSymbolsCollection::SymbolStatus(const string symbol_name) const { ENUM_SYMBOL_STATUS status=this.StatusByCustomPredefined(symbol_name); return(status==SYMBOL_STATUS_COMMON ? this.StatusByCalcMode(symbol_name) : status); } //+------------------------------------------------------------------+
В метод передаётся имя символа. Затем проверяется
его принадлежность к заданным пользовательским группам. Если в итоге
возвращён статус "общая группа", то ищем группу по свойству символа
"режим расчёта залоговых средств". В итоге возвращаем полученный статус.
Он, к слову, может быть приравнен к одной из групп по режиму расчёта прибыли и маржи, а может так и остаться в общей группе символов.
В итоге получается, что символ будет иметь статус пользовательской группы, либо — если в пользовательских группах его не оказалось, то
ему может быть присвоена группа по
способу расчёта
залоговых средств, либо — если и в этой группе его определить не удалось, то символ останется в общей группе.
Реализация методов, возвращающих флаг принадлежности символа к определённым пользовательским группам:
//+------------------------------------------------------------------+ //| Возвращает принадлежность символа к мажорам | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXMajor(const string name) const { int total=::ArraySize(DataSymbolsFXMajors); for(int i=0;i<total;i++) if(name==DataSymbolsFXMajors[i]) return true; return false; } //+------------------------------------------------------------------+ //| Возвращает принадлежность символа к минорам | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXMinor(const string name) const { int total=::ArraySize(DataSymbolsFXMinors); for(int i=0;i<total;i++) if(name==DataSymbolsFXMinors[i]) return true; return false; } //+------------------------------------------------------------------+ //| Возвращает принадлежность символа к экзотикам | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXExotic(const string name) const { int total=::ArraySize(DataSymbolsFXExotics); for(int i=0;i<total;i++) if(name==DataSymbolsFXExotics[i]) return true; return false; } //+------------------------------------------------------------------+ //| Возвращает принадлежность символа к рублёвым | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedFXRUB(const string name) const { int total=::ArraySize(DataSymbolsFXRub); for(int i=0;i<total;i++) if(name==DataSymbolsFXRub[i]) return true; return false; } //+------------------------------------------------------------------+ //| Возвращает принадлежность символа к индикативам | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedIndicative(const string name) const { int total=::ArraySize(DataSymbolsFXIndicatives); for(int i=0;i<total;i++) if(name==DataSymbolsFXIndicatives[i]) return true; return false; } //+------------------------------------------------------------------+ //| Возвращает принадлежность символа к металлам | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedMetall(const string name) const { int total=::ArraySize(DataSymbolsMetalls); for(int i=0;i<total;i++) if(name==DataSymbolsMetalls[i]) return true; return false; } //+------------------------------------------------------------------+ //| Возвращает принадлежность символа к товарам | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedCommodity(const string name) const { int total=::ArraySize(DataSymbolsCommodities); for(int i=0;i<total;i++) if(name==DataSymbolsCommodities[i]) return true; return false; } //+------------------------------------------------------------------+ //| Возвращает принадлежность символа к индексам | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedIndex(const string name) const { int total=::ArraySize(DataSymbolsIndexes); for(int i=0;i<total;i++) if(name==DataSymbolsIndexes[i]) return true; return false; } //+------------------------------------------------------------------+ //| Возвращает принадлежность символа к криптовалюте | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedCrypto(const string name) const { int total=::ArraySize(DataSymbolsCrypto); for(int i=0;i<total;i++) if(name==DataSymbolsCrypto[i]) return true; return false; } //+------------------------------------------------------------------+ //| Возвращает принадлежность символа к опционам | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPredefinedOption(const string name) const { int total=::ArraySize(DataSymbolsOptions); for(int i=0;i<total;i++) if(name==DataSymbolsOptions[i]) return true; return false; } //+------------------------------------------------------------------+
В зависимости от наименования метода (от проверяемой пользовательской группы), в методах просто ищется в пользовательском массиве,
соответствующем его группе, наличие символа, имя которого передано в метод.
Если такой символ найден в массиве, то возвращается true.
Иначе —
false.
Метод, возвращающий статус символа по наличию его в пользовательских группах:
//+------------------------------------------------------------------+ //| Возвращает категорию по пользовательским критериям | //+------------------------------------------------------------------+ ENUM_SYMBOL_STATUS CSymbolsCollection::StatusByCustomPredefined(const string symbol_name) const { return ( this.IsPredefinedFXMajor(symbol_name) ? SYMBOL_STATUS_FX_MAJOR : this.IsPredefinedFXMinor(symbol_name) ? SYMBOL_STATUS_FX_MINOR : this.IsPredefinedFXExotic(symbol_name) ? SYMBOL_STATUS_FX_EXOTIC : this.IsPredefinedFXRUB(symbol_name) ? SYMBOL_STATUS_FX_RUB : this.IsPredefinedOption(symbol_name) ? SYMBOL_STATUS_OPTION : this.IsPredefinedCommodity(symbol_name) ? SYMBOL_STATUS_COMMODITY : this.IsPredefinedCrypto(symbol_name) ? SYMBOL_STATUS_CRYPTO : this.IsPredefinedMetall(symbol_name) ? SYMBOL_STATUS_METAL : this.IsPredefinedIndex(symbol_name) ? SYMBOL_STATUS_INDEX : this.IsPredefinedIndicative(symbol_name) ? SYMBOL_STATUS_INDICATIVE : SYMBOL_STATUS_COMMON ); } //+------------------------------------------------------------------+
В метод передаётся имя символа и поочерёдно
проверяется его наличие в каждой из пользовательских групп при помощи вышерассмотренных методов. Как только символ встречается
в любой из групп — возвращается статус, соответствующий той группе, где символ найден.
Если ни в одной из групп символ найден не был, то возвращается статус "общая группа
символов".
Метод, возвращающий принадлежность символа к группе по способу вычисления залоговых средств:
//+------------------------------------------------------------------+ //|Возвращает принадлежность к категории по расчёту залоговых средств| //+------------------------------------------------------------------+ ENUM_SYMBOL_STATUS CSymbolsCollection::StatusByCalcMode(const string symbol_name) const { ENUM_SYMBOL_CALC_MODE calc_mode=(ENUM_SYMBOL_CALC_MODE)::SymbolInfoInteger(symbol_name,SYMBOL_TRADE_CALC_MODE); return ( calc_mode==SYMBOL_CALC_MODE_EXCH_OPTIONS_MARGIN ? SYMBOL_STATUS_OPTION : calc_mode==SYMBOL_CALC_MODE_SERV_COLLATERAL ? SYMBOL_STATUS_COLLATERAL : calc_mode==SYMBOL_CALC_MODE_FUTURES ? SYMBOL_STATUS_FUTURES : calc_mode==SYMBOL_CALC_MODE_CFD || calc_mode==SYMBOL_CALC_MODE_CFDINDEX || calc_mode==SYMBOL_CALC_MODE_CFDLEVERAGE ? SYMBOL_STATUS_CFD : calc_mode==SYMBOL_CALC_MODE_FOREX || calc_mode==SYMBOL_CALC_MODE_FOREX_NO_LEVERAGE ? SYMBOL_STATUS_FX : calc_mode==SYMBOL_CALC_MODE_EXCH_STOCKS || calc_mode==SYMBOL_CALC_MODE_EXCH_STOCKS_MOEX ? SYMBOL_STATUS_STOCKS : calc_mode==SYMBOL_CALC_MODE_EXCH_BONDS || calc_mode==SYMBOL_CALC_MODE_EXCH_BONDS_MOEX ? SYMBOL_STATUS_BONDS : calc_mode==SYMBOL_CALC_MODE_EXCH_FUTURES || calc_mode==SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS ? SYMBOL_STATUS_FUTURES : SYMBOL_STATUS_COMMON ); } //+------------------------------------------------------------------+
В метод передаётся имя символа, затем получаем
для этого символа способ расчёта величины залоговых средств, и далее, в
зависимости от полученного значения возвращаем статус символа. Если ни
один из сбособов расчёта не был идентифицирован, то возвращаем статус "общая группа символов".
Метод, ищущий символ на сервере, и возвращающий флаг его наличия:
//+------------------------------------------------------------------+ //| Ищет символ и возвращает флаг его наличия на сервере | //+------------------------------------------------------------------+ bool CSymbolsCollection::Exist(const string name) const { int total=::SymbolsTotal(false); for(int i=0;i<total;i++) if(::SymbolName(i,false)==name) return true; return false; } //+------------------------------------------------------------------+
Класс коллекции символов готов. Теперь нам нужно запустить его в работу. И, как говорится, "по традиции" — у нас всё начинается с класса CEngine, запускается и управляется из него же. Внесём в него необходимые правки.
Подключим к файлу класса CEngine файл класса коллекции символов, и объявим объект-коллекцию символов и необходимые для работы методы:
//+------------------------------------------------------------------+ //| 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 "Services\TimerCounter.mqh" #include "Collections\HistoryCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\EventsCollection.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" //+------------------------------------------------------------------+ //| Класс-основа библиотеки | //+------------------------------------------------------------------+ class CEngine : public CObject { private: CHistoryCollection m_history; // Коллекция исторических ордеров и сделок CMarketCollection m_market; // Коллекция рыночных ордеров и сделок CEventsCollection m_events; // Коллекция событий CAccountsCollection m_accounts; // Коллекция аккаунтов CSymbolsCollection m_symbols; // Коллекция символов CArrayObj m_list_counters; // Список счётчиков таймера int m_global_error; // Код глобальной ошибки bool m_first_start; // Флаг первого запуска bool m_is_hedge; // Флаг хедж-счёта bool m_is_tester; // Флаг работы в тестере bool m_is_market_trade_event; // Флаг торгового события на счёте bool m_is_history_trade_event; // Флаг торгового события в истории счёта bool m_is_account_event; // Флаг события изменения аккаунта ENUM_TRADE_EVENT m_last_trade_event; // Последнее торговое событие на счёте ENUM_ACCOUNT_EVENT m_last_account_event; // Последнее событие в свойствах счёта //--- Возвращает индекс счётчика по id int CounterIndex(const int id) const; //--- Возвращает (1) флаг первого запуска, (2) факт наличия флага в торговом событии bool IsFirstStart(void); //--- Работа с событиями (1) ордеров, сделок и позиций, (2) аккаунтов void TradeEventsControl(void); void AccountEventsControl(void); //--- (1) Работа с коллекцией символов и (2) событиями списка символов в окне обзора рынка void SymbolEventsControl(void); void MarketWatchEventsControl(void); //--- Возвращает последний (1) рыночный отложенный ордер, (2) маркет-ордер, (3) последнюю позицию, (4) позицию по тикету COrder *GetLastMarketPending(void); COrder *GetLastMarketOrder(void); COrder *GetLastPosition(void); COrder *GetPosition(const ulong ticket); //--- Возвращает последний (1) удалённый отложенный ордер, (2) исторический маркет-ордер, (3) исторический ордер (маркет или отложенный) по его тикету COrder *GetLastHistoryPending(void); COrder *GetLastHistoryOrder(void); COrder *GetHistoryOrder(const ulong ticket); //--- Возвращает (1) первый и (2) последний исторический маркет-ордер из списка всех ордеров позиции, (3) последнюю сделку COrder *GetFirstOrderPosition(const ulong position_id); COrder *GetLastOrderPosition(const ulong position_id); COrder *GetLastDeal(void); public: //--- Возвращает список рыночных (1) позиций, (2) отложенных ордеров и (3) маркет-ордеров CArrayObj *GetListMarketPosition(void); CArrayObj *GetListMarketPendings(void); CArrayObj *GetListMarketOrders(void); //--- Возвращает список исторических (1) ордеров, (2) удалённых отложенных ордеров, (3) сделок, (4) всех маркет-ордеров позиции по её идентификатору CArrayObj *GetListHistoryOrders(void); CArrayObj *GetListHistoryPendings(void); CArrayObj *GetListDeals(void); CArrayObj *GetListAllOrdersByPosID(const ulong position_id); //--- Возвращает список (1) аккаунтов, (2) событий аккаунтов, (3) событие изменения аккаунта по его индексу в списке //--- (4) текущий аккаунт, (5) описание события CArrayObj *GetListAllAccounts(void) { return this.m_accounts.GetList(); } CArrayInt *GetListAccountEvents(void) { return this.m_accounts.GetListChanges(); } ENUM_ACCOUNT_EVENT GetAccountEventByIndex(const int index) { return this.m_accounts.GetEvent(index); } CAccount *GetAccountCurrent(void); string GetAccountEventDescription(ENUM_ACCOUNT_EVENT event); //--- Возвращает список используемых символов CArrayObj *GetListAllUsedSymbols(void) { return this.m_symbols.GetList(); } //--- Возвращает список событий ордеров, сделок и позиций CArrayObj *GetListAllOrdersEvents(void) { return this.m_events.GetList(); } //--- Сбрасывает последнее торговое событие void ResetLastTradeEvent(void) { this.m_events.ResetLastTradeEvent(); } //--- Возвращает (1) последнее торговое событие, (2) последнее событие в свойствах счёта, (3) флаг счёта-хедж, (4) флаг работы в тестере ENUM_TRADE_EVENT LastTradeEvent(void) const { return this.m_last_trade_event; } ENUM_ACCOUNT_EVENT LastAccountEvent(void) const { return this.m_last_account_event; } bool IsHedge(void) const { return this.m_is_hedge; } bool IsTester(void) const { return this.m_is_tester; } bool IsAccountsEvent(void) const { return this.m_accounts.IsAccountEvent(); } //--- Возвращает код события аккаунта int GetAccountEventsCode(void) const { return this.m_accounts.GetEventCode(); } //--- Возвращает код глобальной ошибки CEngine int GetError(void) const { return this.m_global_error; } //--- Создаёт счётчик таймера void CreateCounter(const int id,const ulong frequency,const ulong pause); //--- Таймер void OnTimer(void); //--- Устанавливает список используемых символов bool SetUsedSymbols(const string &array_symbols[]) { return this.m_symbols.SetUsedSymbol(array_symbols); } //--- Конструктор/Деструктор CEngine(); ~CEngine(); }; //+------------------------------------------------------------------+
В методе SymbolEventsControl() будем осуществлять обновление
котировочных данных всех символов коллекции, а в методе
MarketWatchEventsControl() будем обновлять остальные данные всех
символов коллекции и отслеживать события в окне "Обзор рынка" (в классе событий коллекции символов в следующей статье).
Метод GetListAllUsedSymbols() возвращает в вызывающую
программу полный список коллекции символов при помощи метода GetList() класса CSymbolsCollection.
Метод SetUsedSymbols() вызывает одноимённый метод
SetUsedSymbol() класса CSymbolsCollection, который в свою очередь заполняет список коллекции объектами-символами всех используемых
символов в программе.
Рассмотрим устройство этих методов.
В конструкторе класса создадим счётчики первого и второго
таймеров коллекции символов. В первом таймере будем обновлять котировочные данные всех символов коллекции, а во втором — остальные
данные символов и управлять отслеживанием событий окна "Обзор рынка".
//+------------------------------------------------------------------+ //| 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_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif; this.m_is_tester=::MQLInfoInteger(MQL_TESTER); 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.CreateCounter(COLLECTION_SYM_COUNTER_ID1,COLLECTION_SYM_COUNTER_STEP1,COLLECTION_SYM_PAUSE1); this.CreateCounter(COLLECTION_SYM_COUNTER_ID2,COLLECTION_SYM_COUNTER_STEP2,COLLECTION_SYM_PAUSE2); ::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 } //+------------------------------------------------------------------+
В обработчик OnTimer() класса впишем строки работы с двумя таймерами коллекции символов:
//+------------------------------------------------------------------+ //| CEngine таймер | //+------------------------------------------------------------------+ void CEngine::OnTimer(void) { //--- Таймер коллекций исторических ордеров и сделок и рыночных ордеров и позиций int index=this.CounterIndex(COLLECTION_ORD_COUNTER_ID); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- Если это не тестер if(!this.IsTester()) { //--- Если пауза завершилась - работаем с событиями коллекций ордеров, сделок и позиций if(counter.IsTimeDone()) this.TradeEventsControl(); } //--- Если тестер - работаем с событиями коллекций по тику else this.TradeEventsControl(); } } //--- Таймер коллекции аккаунтов index=this.CounterIndex(COLLECTION_ACC_COUNTER_ID); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- Если это не тестер if(!this.IsTester()) { //--- Если пауза завершилась - работаем с событиями коллекции аккаунтов if(counter.IsTimeDone()) this.AccountEventsControl(); } //--- Если тестер - работаем с событиями коллекций по тику else this.AccountEventsControl(); } } //--- Таймер1 коллекции символов (обновление котировочных данных символов в коллекции) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID1); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- Если это не тестер if(!this.IsTester()) { //--- Если пауза завершилась - обновляем котировочные данные всех символов в коллекции if(counter.IsTimeDone()) this.SymbolEventsControl(); } //--- Если тестер - обновляем котировочные данные всех символов в коллекции по тику else this.SymbolEventsControl(); } } //--- Таймер2 коллекции символов (обновление всех данных всех символов в коллекции и отслеживание событий списка символов в окне обзора рынка) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID2); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- Если это не тестер if(!this.IsTester()) { //--- Если пауза завершилась if(counter.IsTimeDone()) { //--- обновляем данные всех символов в коллекции this.m_symbols.Refresh(); //--- Если работаем со списком из обзора рынка - проверяем события окна обзора рынка if(this.m_symbols.ModeSymbolsList()==SYMBOLS_MODE_MARKET_WATCH) this.MarketWatchEventsControl(); } } //--- Если тестер - обновляем данные всех символов в коллекции по тику else this.m_symbols.Refresh(); } } } //+------------------------------------------------------------------+
Здесь вся логика расписана в комментариях к коду, и останавливаться на её повторном разборе, думаю, не имеет смысла.
Метод, работающий с коллекцией символов, в данной реализации просто обновляет
котировочные данные всех символов коллекции посредством метода RefreshRates класса CSymbolsCollection:
//+------------------------------------------------------------------+ //| Работа с коллекцией символов | //+------------------------------------------------------------------+ void CEngine::SymbolEventsControl(void) { this.m_symbols.RefreshRates(); } //+------------------------------------------------------------------+
Метод работы с событиями окна "Обзор рынка" в данной реализиции ничего не делает, лишь проверяет,
что вызван из тестера, и выходит в случае работы в тестере (в тестере нет смысла отслеживать события окна обзора рынка):
//+------------------------------------------------------------------+ //| Работа с событиями списка символов в окне обзора рынка | //+------------------------------------------------------------------+ void CEngine::MarketWatchEventsControl(void) { if(this.IsTester()) return; //--- Отслеживание событий окна "Обзор рынка" //--- } //+------------------------------------------------------------------+
Всю работу с событиями коллекции символов сделаем в следующей статье.
Это все необходимые изменения класса CEngine.
Так как нам необходимо передавать в класс коллекции символов требуемый режим работы с символами, то нам необходима функция, которая будет определять режим работы и заполнять соответствующим образом массив символов, который будет передаваться в основной объект библиотеки CEngine.
Откроем файл сервисных функций DELib.mqh из папки \MQL5\Include\DoEasy\Services\ и впишем в него нужную функцию:
//+------------------------------------------------------------------+ //| Подготавливает массив символов для коллекции символов | //+------------------------------------------------------------------+ bool CreateUsedSymbolsArray(const ENUM_SYMBOLS_MODE mode_used_symbols,string defined_used_symbols,string &used_symbols_array[]) { //--- Если работа с текущим символом if(mode_used_symbols==SYMBOLS_MODE_CURRENT) { //--- Запишем в единственную ячейку массива имя текущего символа ArrayResize(used_symbols_array,1); used_symbols_array[0]=Symbol(); return true; } //--- Если работа с предопределённым набором символов (из строки defined_used_symbols) else if(mode_used_symbols==SYMBOLS_MODE_DEFINES) { //--- Установим разделитель - запятая string separator=","; //--- Заменим ошибочные разделители на верный if(StringFind(defined_used_symbols,";")>WRONG_VALUE) StringReplace(defined_used_symbols,";",separator); if(StringFind(defined_used_symbols,":")>WRONG_VALUE) StringReplace(defined_used_symbols,":",separator); if(StringFind(defined_used_symbols,"|")>WRONG_VALUE) StringReplace(defined_used_symbols,"|",separator); if(StringFind(defined_used_symbols,"/")>WRONG_VALUE) StringReplace(defined_used_symbols,"/",separator); if(StringFind(defined_used_symbols,"\\")>WRONG_VALUE) StringReplace(defined_used_symbols,"\\",separator); if(StringFind(defined_used_symbols,"'")>WRONG_VALUE) StringReplace(defined_used_symbols,"'",separator); if(StringFind(defined_used_symbols,"-")>WRONG_VALUE) StringReplace(defined_used_symbols,"-",separator); if(StringFind(defined_used_symbols,"`")>WRONG_VALUE) StringReplace(defined_used_symbols,"`",separator); //--- Пока есть пробелы - удаляем while(StringFind(defined_used_symbols," ")>WRONG_VALUE && !IsStopped()) StringReplace(defined_used_symbols," ",""); //--- Пока есть двойные разделители (после удаления между ними пробелов) - меняем на разделитель while(StringFind(defined_used_symbols,separator+separator)>WRONG_VALUE && !IsStopped()) StringReplace(defined_used_symbols,separator+separator,separator); //--- Если остался один разделитель перед первым символом в строке - заменяем на пробел if(StringFind(defined_used_symbols,separator)==0) StringSetCharacter(defined_used_symbols,0,32); //--- Если остался один разделитель после последнего символа в строке - заменяем на пробел if(StringFind(defined_used_symbols,separator)==StringLen(defined_used_symbols)-1) StringSetCharacter(defined_used_symbols,StringLen(defined_used_symbols)-1,32); //--- Убираем всё лишнее слева и справа #ifdef __MQL5__ StringTrimLeft(defined_used_symbols); StringTrimRight(defined_used_symbols); //--- __MQL4__ #else defined_used_symbols=StringTrimLeft(defined_used_symbols); defined_used_symbols=StringTrimRight(defined_used_symbols); #endif //--- Подготавливаем массив ArrayResize(used_symbols_array,0); ResetLastError(); //--- разделяем строку по разделителям (запятая) и вписываем все найденные подстроки в массив int n=StringSplit(defined_used_symbols,StringGetCharacter(separator,0),used_symbols_array); //--- если ничего не нашли - выведем об этом сообщение (при этом автоматически будет выбрана работа с текущим символом) if(n<1) { string err= (n==0 ? DFUN_ERR_LINE+TextByLanguage("Ошибка. Строка предопределённых символов пустая, будет использоваться ","Error. String of predefined symbols is empty, the symbol will be used: ")+Symbol() : DFUN_ERR_LINE+TextByLanguage("Не удалось подготовить массив используемых символов. Ошибка ","Failed to create an array of used characters. Error ")+(string)GetLastError() ); Print(err); return false; } } //--- Если работа с окном "Обзор рынка" или с полным списком else { //--- В единственную ячейку массива впишем наименование режима работы (mode_used_symbols) ArrayResize(used_symbols_array,1); used_symbols_array[0]=EnumToString(mode_used_symbols); } return true; } //+------------------------------------------------------------------+
В метод передаются режим работы с коллекцией символов,
который должен задаваться либо в настройках программы, либо жёстко задаваться (если не требуется выбора режимов),
строка с перечислением через запятую списка символов, с которыми
необходимо работать (либо пустая строка) и
массив, в который будут вписан список символов, либо режим работы
(для режимов работы с обзором рынка и полным списком символов на сервере), и который будет отправляться в класс CEngine для установки режима
работы библиотеки с символами.
Все действия, проводимые функцией со списком и массивом подробно описаны прямо в листинге и отдельно их рассматривать не имеет
смысла.
На этом разработка класса коллекции символов завершена, и у нас всё готово для его тестирования.
Тест коллекции символов
Для тестирования коллекции возьмём советник из прошлой статьи и сохраним его под новым именем \MQL5\Experts\TestDoEasy\ Part15\TestDoEasyPart15_1.mq5.
Сразу же во входных параметрах допишем выбор режима работы с коллекцией символов библиотеки и строковую переменную, хранящую список пользовательских символов, с которыми нужно работать в случае выбора в настройках такого режима:
//--- input variables input ulong InpMagic = 123; // Magic number input double InpLots = 0.1; // Lots input uint InpStopLoss = 50; // StopLoss in points input uint InpTakeProfit = 50; // TakeProfit in points input uint InpDistance = 50; // Pending orders distance (points) input uint InpDistanceSL = 50; // StopLimit orders distance (points) input uint InpSlippage = 0; // Slippage in points input double InpWithdrawal = 10; // Withdrawal funds (in tester) input uint InpButtShiftX = 40; // Buttons X shift input uint InpButtShiftY = 10; // Buttons Y shift input uint InpTrailingStop = 50; // Trailing Stop (points) input uint InpTrailingStep = 20; // Trailing Step (points) input uint InpTrailingStart = 0; // Trailing Start (points) input uint InpStopLossModify = 20; // StopLoss for modification (points) input uint InpTakeProfitModify = 60; // TakeProfit for modification (points) input ENUM_SYMBOLS_MODE InpModeUsedSymbols = SYMBOLS_MODE_CURRENT; // Mode of used symbols list input string InpUsedSymbols = "EURUSD,AUDUSD,EURAUD,EURCAD,EURGBP,EURJPY,EURUSD,GBPUSD,NZDUSD,USDCAD,USDJPY"; // List of used symbols (comma - separator) //--- global variables
В список глобальных переменных добавим переменную для хранения
пользовательского списка символов и строковый массив для передачи списка
символов в библиотеку:
//--- global variables CEngine engine; #ifdef __MQL5__ CTrade trade; #endif SDataButt butt_data[TOTAL_BUTT]; string prefix; double lot; double withdrawal=(InpWithdrawal<0.1 ? 0.1 : InpWithdrawal); ulong magic_number; uint stoploss; uint takeprofit; uint distance_pending; uint distance_stoplimit; uint slippage; bool trailing_on; double trailing_stop; double trailing_step; uint trailing_start; uint stoploss_to_modify; uint takeprofit_to_modify; string used_symbols; string array_used_symbols[]; //+------------------------------------------------------------------+
В обработчике 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; //--- Заполнение массива используемых символов used_symbols=InpUsedSymbols; CreateUsedSymbolsArray(InpModeUsedSymbols,used_symbols,array_used_symbols); //--- Установка типа используемого списка символов в коллекции символов engine.SetUsedSymbols(array_used_symbols); //--- Проверка и удаление неудалённых графических объектов советника
Функция SetUsedSymbols(), рассмотренная нами выше, создаст массив символов для отправки его в класс коллекции символов. В зависимости от выбранного режима в массиве будет либо текущий символ, либо пользовательский список символов, либо строковое описание режима работы с окном "Обзор рынка" или с полным списком символов на сервере.
В самом конце обработчика OnInit() впишем код для быстрой проверки списков символов, создаваемых классом коллекции символов:
//--- Установка параметров торгового класса CTrade #ifdef __MQL5__ trade.SetDeviationInPoints(slippage); trade.SetExpertMagicNumber(magic_number); trade.SetTypeFillingBySymbol(Symbol()); trade.SetMarginMode(); trade.LogLevel(LOG_LEVEL_NO); #endif //--- Быстрая проверка коллекции объектов-символов CArrayObj *list=engine.GetListAllUsedSymbols(); CSymbol *symbol=NULL; if(list!=NULL) { int total=list.Total(); for(int i=0;i<total;i++) { symbol=list.At(i); if(symbol==NULL) continue; symbol.Refresh(); symbol.RefreshRates(); symbol.PrintShort(); if(InpModeUsedSymbols<SYMBOLS_MODE_MARKET_WATCH) symbol.Print(); } } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Здесь: получаем полный список всех символов коллекции, в цикле по полученному списку получаем из него очередной символ, обновляем все данные и распечатываем в журнал описание символа — сначала краткое, а затем, если не выбран режим "Работа с окном обзора рынка" или "Работа с полным списком символов на сервере", то выводим в журнал полное описание свойств символа.
Запустим советник в окне терминала и выберем в настройках режим "Работа с символами из окна Обзор рынка". В результате в журнал будет распечатан список с краткими описаниями всех символов коллекции, созданный классом коллекции символов:
2019.06.27 10:01:52.756 Ценная бумага ALNU 2019.06.27 10:01:52.756 Ценная бумага SU25075RMFS1 2019.06.27 10:01:52.756 Облигация SU46022RMFS8 2019.06.27 10:01:52.756 Облигация SU26214RMFS5 2019.06.27 10:01:52.756 Ценная бумага AESL 2019.06.27 10:01:52.756 Ценная бумага 123456.bin 2019.06.27 10:01:52.756 Ценная бумага ARMD 2019.06.27 10:01:52.757 Облигация SU46018RMFS6 2019.06.27 10:01:52.757 Ценная бумага GAZP 2019.06.27 10:01:52.757 Металл XAUUSD 2019.06.27 10:01:52.757 Ценная бумага EURRUB_TOD 2019.06.27 10:01:52.757 Ценная бумага GBPRUB_TOM 2019.06.27 10:01:52.757 Фьючерс Si-9.19 2019.06.27 10:01:52.757 Фьючерс RTS-3.20 2019.06.27 10:01:52.758 Форекс символ-минор USDNOK 2019.06.27 10:01:52.758 Форекс символ-мажор USDJPY 2019.06.27 10:01:52.758 Форекс символ-мажор EURUSD 2019.06.27 10:01:52.758 Форекс символ-минор USDCZK 2019.06.27 10:01:52.758 Форекс символ-мажор USDCAD 2019.06.27 10:01:52.758 Форекс символ-минор USDZAR 2019.06.27 10:01:52.758 Форекс символ-минор USDSEK 2019.06.27 10:01:52.758 Форекс символ-мажор AUDUSD 2019.06.27 10:01:52.758 Форекс символ-минор USDDKK 2019.06.27 10:01:52.758 Форекс символ-мажор NZDUSD 2019.06.27 10:01:52.759 Форекс символ-минор USDPLN 2019.06.27 10:01:52.759 Форекс символ-мажор GBPUSD 2019.06.27 10:01:52.759 Форекс символ USDRUR 2019.06.27 10:01:52.759 Форекс символ-экзотик USDMXN 2019.06.27 10:01:52.759 Форекс символ USDHUF 2019.06.27 10:01:52.759 Форекс символ-минор USDTRY 2019.06.27 10:01:52.759 Форекс символ-минор USDHKD 2019.06.27 10:01:52.760 Форекс символ-мажор USDCHF 2019.06.27 10:01:52.760 Форекс символ-минор USDSGD
Теперь проверим поиск заданных значений в коллекции символов.
Переименуем советник и сохраним его под новым именем
\MQL5\Experts\TestDoEasy\
Part15\TestDoEasyPart15_2.mq5.
Поменяем в обработчике OnInit() код быстрой проверки списка символов коллекции. Удалим распечатку символов в журнал, оставив лишь обновление данных символов коллекции, и допишем строки получения максимального и минимального свопа длинной и короткой позиций, и максимальный и минимальный спред символов в коллекции. Полученные данные выведем в журнал:
//--- Установка параметров торгового класса CTrade #ifdef __MQL5__ trade.SetDeviationInPoints(slippage); trade.SetExpertMagicNumber(magic_number); trade.SetTypeFillingBySymbol(Symbol()); trade.SetMarginMode(); trade.LogLevel(LOG_LEVEL_NO); #endif //--- Быстрая проверка коллекции объектов-символов CArrayObj *list=engine.GetListAllUsedSymbols(); CSymbol *symbol=NULL; if(list!=NULL) { int total=list.Total(); for(int i=0;i<total;i++) { symbol=list.At(i); if(symbol==NULL) continue; symbol.Refresh(); symbol.RefreshRates(); } } //--- Получение минимального и максимального значений //--- получим свойства текущего аккаунта (нам нужно количество знаков после запятой для валюты счёта) CAccount *account=engine.GetAccountCurrent(); if(account!=NULL) { int index_min=0, index_max=0, dgc=(int)account.CurrencyDigits(); //--- Если работа с окном "Обзор рынка", то оставим в списке только видимые символы if(InpModeUsedSymbols==SYMBOLS_MODE_MARKET_WATCH) list=CSelect::BySymbolProperty(list,SYMBOL_PROP_VISIBLE,true,EQUAL); //--- мин/макс своп длинных позиций index_min=CSelect::FindSymbolMin(list,SYMBOL_PROP_SWAP_LONG); // индекс символа в списке коллекции с минимальным значением свопа длинных позиций index_max=CSelect::FindSymbolMax(list,SYMBOL_PROP_SWAP_LONG); // индекс символа в списке коллекции с максимальным значением свопа длинных позиций if(index_max!=WRONG_VALUE && index_min!=WRONG_VALUE) { symbol=list.At(index_min); if(symbol!=NULL) Print("Минимальный своп длинных позиций у символа ",symbol.Name()," = ",NormalizeDouble(symbol.SwapLong(),dgc)); symbol=list.At(index_max); if(symbol!=NULL) Print("Максимальный своп длинных позиций у символа ",symbol.Name()," = ",NormalizeDouble(symbol.SwapLong(),dgc)); } //--- мин/макс своп коротких позиций index_min=CSelect::FindSymbolMin(list,SYMBOL_PROP_SWAP_SHORT); // индекс символа в списке коллекции с минимальным значением свопа коротких позиций index_max=CSelect::FindSymbolMax(list,SYMBOL_PROP_SWAP_SHORT); // индекс символа в списке коллекции с максимальным значением свопа коротких позиций if(index_max!=WRONG_VALUE && index_min!=WRONG_VALUE) { symbol=list.At(index_min); if(symbol!=NULL) Print("Минимальный своп коротких позиций у символа ",symbol.Name()," = ",NormalizeDouble(symbol.SwapShort(),dgc)); symbol=list.At(index_max); if(symbol!=NULL) Print("Максимальный своп коротких позиций у символа ",symbol.Name()," = ",NormalizeDouble(symbol.SwapShort(),dgc)); } //--- мин/макс спред index_min=CSelect::FindSymbolMin(list,SYMBOL_PROP_SPREAD); // индекс символа в списке коллекции с минимальным значением спреда index_max=CSelect::FindSymbolMax(list,SYMBOL_PROP_SPREAD); // индекс символа в списке коллекции с максимальным значением спреда if(index_max!=WRONG_VALUE && index_min!=WRONG_VALUE) { symbol=list.At(index_min); if(symbol!=NULL) Print("Минимальный спред у символа ",symbol.Name()," = ",symbol.Spread()); symbol=list.At(index_max); if(symbol!=NULL) Print("Максимальный спред у символа ",symbol.Name()," = ",symbol.Spread()); } } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Скомпилируем и запустим советник на графике терминала. Выберем в настройках работу с полным списком всех символов на сервере. После создания списка коллекции всех символов на сервере (займёт некоторое время), в журнал будет выведена информация по максимальному и минимальному свопу длинных и коротких позиций, и по максимальному и минимальному спреду из всех символов, имеющихся в списке коллекции символов:
2019.06.27 10:36:28.885 Минимальный своп длинных позиций у символа USDZAR = -192.9 2019.06.27 10:36:28.885 Максимальный своп длинных позиций у символа USDMXN = 432.7 2019.06.27 10:36:28.886 Минимальный своп коротких позиций у символа XAUUSD = -17.8 2019.06.27 10:36:28.886 Максимальный своп коротких позиций у символа USDMXN = 200.0 2019.06.27 10:36:28.886 Минимальный спред у символа SU52001RMFS3 = 0 2019.06.27 10:36:28.886 Максимальный спред у символа GBPRUB_TOM = 3975
Что дальше
В следующей статье разработаем класс событий коллекции символов.
Ниже прикреплены все файлы текущей версии библиотеки и файлы тестового советника. Их можно скачать и протестировать всё
самостоятельно.
При возникновении вопросов, замечаний и пожеланий, вы можете озвучить их в комментариях к статье.
Статьи этой серии:
Часть 1. Концепция, организация данныхЧасть 2. Коллекция исторических ордеров и сделок
Часть 3. Коллекция рыночных ордеров и позиций, организация поиска
Часть 4. Торговые события. Концепция
Часть 5. Классы и коллекция торговых событий. Отправка событий в программу
Часть 6. События на счёте с типом неттинг
Часть 7. События срабатывания StopLimit-ордеров, подготовка функционала для регистрации событий модификации ордеров и позиций
Часть 8. События модификации ордеров и позиций
Часть 9. Совместимость с MQL4 - Подготовка данных
Часть 10. Совместимость с MQL4 - События открытия позиций и активации отложенных ордеров
Часть 11. Совместимость с MQL4 - События закрытия позиций
Часть 12. Класс объекта "аккаунт", коллекция объектов-аккаунтов
Часть 13. События объекта "аккаунт"
Часть 14. Объект "Символ"
![Управление оптимизацией (Часть 2): Создание ключевых объектов и логики приложения](https://c.mql5.com/2/36/mql5-avatar-opt_control__1.png)
![Управление оптимизацией (Часть I): Создание графического интерфейса](https://c.mql5.com/2/36/mql5-avatar-opt_control.png)
![Создаем кроссплатформенный советник-сеточник (Часть III): сетка на коррекциях с мартингейлом](https://c.mql5.com/2/36/mql5_ea_adviser_grid__1.png)
![Почтовая рассылка сервисами Google](https://c.mql5.com/2/36/logo_Csharp.png)
![MQL5 - Язык торговых стратегий для клиентского терминала MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования