
Библиотека для простого и быстрого создания программ для MetaTrader (Часть XIII): События объекта "аккаунт"
Содержание
Концепция событий аккаунта
Ранее для отслеживания событий ордеров и позиций (Часть IV — Часть XI), мы создали отдельный класс, который занимается именно отслеживанием событий ордеров и позиций и отправляет данные об их изменениях в главный объект библиотеки CEngine.
Для отслеживания событий аккаунта, мы пойдём иным путём: так как у нас есть возможность отслеживать события только одного-единственного счёта — того, к которому на данный момент подключен терминал, то отдельный класс для отслеживания событий только одного счёта, думаю, будет излишним, и мы создадим методы работы с событиями прямо в классе-коллекции аккаунтов.
Для того, чтобы понять произошло ли какое-нибудь изменение в свойствах счёта, мы будем сравнивать текущее состояние свойств счёта с его прошлым состоянием, и при нахождении изменений, будем отправлять событие на график управляющей программы.
Некоторая часть функционала для отслеживания событий аккаунта уже была нами создана в прошлой статье при создании коллекции объектов-аккаунтов. В данной статье доработаем уже подготовленный функционал до завершённого рабочего состояния.
Методы работы с событиями аккаунта
Начнём работу с создания необходимых перечислений и макроподстановок в файле Defines.mqh. Так как был получен ответ от разработчиков о реальных размерах в байтах, выделяемых под строковые свойства аккаунта, то задавать их будем жёстко в коде класса CAccount и, соответственно, надобность в макроподстановке, задающей размер uchar-массивов для хранения строковых свойств объекта-аккаунта, исчезла. Удалим из листинга Defines.mqh макроподстановку
#define UCHAR_ARRAY_SIZE (64) // Размер uchar-массивов для хранения string-свойств
Так же было решено вписать все необходимые перечисления и макроподстановки для работы с объектами-аккаунтами в самый конец файла — после данных для работы с торговыми событиями. Причиной тому послужило то, что в программу будем отправлять коды событий не только аккаунтов, но и коды торговых событий, которые у нас уже реализованы и отправляются в программу. Соответственно,числовые значения кодов событий аккаунта у нас будут начинаться с числового значения самого последнего кода торгового события+1. Если вдруг у нас увеличится количество торговых событий, то чтобы не переписывать числовые значения кодов событий аккаунта, мы объявим макроподстановку, в которой будет прописываться рассчитываемое общее количество всех торговых событий. И точно так же зададим макроподстановку со значением общего количества событий аккаунта — на случай, если будем реализовывать ещё какие-либо события (например, события символов) — тогда числовые коды этих новых событий будут начинаться уже от общего количества событий аккаунта+1.
В конце списка возможных торговых событий на счёте впишем макроподстановку, в которой будет указано значение, соответствующее числовому значению последнего торгового события+1:
//+------------------------------------------------------------------+ //| Список возможных торговых событий на счёте | //+------------------------------------------------------------------+ enum ENUM_TRADE_EVENT { TRADE_EVENT_NO_EVENT = 0, // Нет торгового события TRADE_EVENT_PENDING_ORDER_PLASED, // Отложенный ордер установлен TRADE_EVENT_PENDING_ORDER_REMOVED, // Отложенный ордер удалён //--- члены перечисления, совпадающие с членами перечисления ENUM_DEAL_TYPE //--- (порядок следования констант ниже менять нельзя, удалять и добавлять новые - нельзя) TRADE_EVENT_ACCOUNT_CREDIT = DEAL_TYPE_CREDIT, // Начисление кредита (3) TRADE_EVENT_ACCOUNT_CHARGE, // Дополнительные сборы TRADE_EVENT_ACCOUNT_CORRECTION, // Корректирующая запись TRADE_EVENT_ACCOUNT_BONUS, // Перечисление бонусов TRADE_EVENT_ACCOUNT_COMISSION, // Дополнительные комиссии TRADE_EVENT_ACCOUNT_COMISSION_DAILY, // Комиссия, начисляемая в конце торгового дня TRADE_EVENT_ACCOUNT_COMISSION_MONTHLY, // Комиссия, начисляемая в конце месяца TRADE_EVENT_ACCOUNT_COMISSION_AGENT_DAILY, // Агентская комиссия, начисляемая в конце торгового дня TRADE_EVENT_ACCOUNT_COMISSION_AGENT_MONTHLY, // Агентская комиссия, начисляемая в конце месяца TRADE_EVENT_ACCOUNT_INTEREST, // Начисления процентов на свободные средства TRADE_EVENT_BUY_CANCELLED, // Отмененная сделка покупки TRADE_EVENT_SELL_CANCELLED, // Отмененная сделка продажи TRADE_EVENT_DIVIDENT, // Начисление дивиденда TRADE_EVENT_DIVIDENT_FRANKED, // Начисление франкированного дивиденда TRADE_EVENT_TAX = DEAL_TAX, // Начисление налога //--- константы, относящиеся к типу сделки DEAL_TYPE_BALANCE из перечисления ENUM_DEAL_TYPE TRADE_EVENT_ACCOUNT_BALANCE_REFILL = DEAL_TAX+1, // Пополнение средств на балансе TRADE_EVENT_ACCOUNT_BALANCE_WITHDRAWAL = DEAL_TAX+2, // Снятие средств с баланса //--- Остальные возможные торговые события//--- (менять порядок следования констант ниже, удалять и добавлять новые - можно) TRADE_EVENT_PENDING_ORDER_ACTIVATED = DEAL_TAX+3, // Отложенный ордер активирован ценой TRADE_EVENT_PENDING_ORDER_ACTIVATED_PARTIAL, // Отложенный ордер активирован ценой частично TRADE_EVENT_POSITION_OPENED, // Позиция открыта TRADE_EVENT_POSITION_OPENED_PARTIAL, // Позиция открыта частично TRADE_EVENT_POSITION_CLOSED, // Позиция закрыта TRADE_EVENT_POSITION_CLOSED_BY_POS, // Позиция закрыта встречной TRADE_EVENT_POSITION_CLOSED_BY_SL, // Позиция закрыта по StopLoss TRADE_EVENT_POSITION_CLOSED_BY_TP, // Позиция закрыта по TakeProfit TRADE_EVENT_POSITION_REVERSED_BY_MARKET, // Разворот позиции новой сделкой (неттинг) TRADE_EVENT_POSITION_REVERSED_BY_PENDING, // Разворот позиции активацией отложенного ордера (неттинг) TRADE_EVENT_POSITION_REVERSED_BY_MARKET_PARTIAL, // Разворот позиции частичным исполнением маркет-ордера (неттинг) TRADE_EVENT_POSITION_REVERSED_BY_PENDING_PARTIAL, // Разворот позиции частичной активацией отложенного ордера (неттинг) TRADE_EVENT_POSITION_VOLUME_ADD_BY_MARKET, // Добавлен объём к позиции новой сделкой (неттинг) TRADE_EVENT_POSITION_VOLUME_ADD_BY_MARKET_PARTIAL, // Добавлен объём к позиции частичным исполнением маркет-ордера (неттинг) TRADE_EVENT_POSITION_VOLUME_ADD_BY_PENDING, // Добавлен объём к позиции активацией отложенного ордера (неттинг) TRADE_EVENT_POSITION_VOLUME_ADD_BY_PENDING_PARTIAL, // Добавлен объём к позиции частичной активацией отложенного ордера (неттинг) TRADE_EVENT_POSITION_CLOSED_PARTIAL, // Позиция закрыта частично TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_POS, // Позиция закрыта частично встречной TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_SL, // Позиция закрыта частично по StopLoss TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_TP, // Позиция закрыта частично по TakeProfit TRADE_EVENT_TRIGGERED_STOP_LIMIT_ORDER, // Срабатывание StopLimit ордера TRADE_EVENT_MODIFY_ORDER_PRICE, // Изменение цены установки ордера TRADE_EVENT_MODIFY_ORDER_PRICE_STOP_LOSS, // Изменение цены установки ордера и StopLoss TRADE_EVENT_MODIFY_ORDER_PRICE_TAKE_PROFIT, // Изменение цены установки ордера и TakeProfit TRADE_EVENT_MODIFY_ORDER_PRICE_STOP_LOSS_TAKE_PROFIT, // Изменение цены установки ордера, StopLoss и TakeProfit TRADE_EVENT_MODIFY_ORDER_STOP_LOSS_TAKE_PROFIT, // Изменение StopLoss и TakeProfit ордера TRADE_EVENT_MODIFY_ORDER_STOP_LOSS, // Изменение StopLoss ордера TRADE_EVENT_MODIFY_ORDER_TAKE_PROFIT, // Изменение TakeProfit ордера TRADE_EVENT_MODIFY_POSITION_STOP_LOSS_TAKE_PROFIT, // Изменение StopLoss и TakeProfit позиции TRADE_EVENT_MODIFY_POSITION_STOP_LOSS, // Изменение StopLoss позиции TRADE_EVENT_MODIFY_POSITION_TAKE_PROFIT, // Изменение TakeProfit позиции }; #define TRADE_EVENTS_NEXT_CODE (TRADE_EVENT_MODIFY_POSITION_TAKE_PROFIT+1)// Код следующего события после последнего кода торгового события //+------------------------------------------------------------------+
Именно с этого кода будут начинаться коды событий аккаунта.
Данные для работы с аккаунтом — целочисленные, вещественные и строковые свойства аккаунта, а так же возможные критерии сортировки аккаунтов мы прописали в прошлой статье, но разместили их перед данными для работы с событиями счёта. Теперь же мы их перенесём в конец, и пропишем дополнительные данные для работы с событиями аккаунта — список флагов событий аккаунта и список возможных событий аккаунта:
//+------------------------------------------------------------------+ //| Данные для работы с аккаунтами | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Список флагов событий аккаунта | //+------------------------------------------------------------------+ enum ENUM_ACCOUNT_EVENT_FLAGS { ACCOUNT_EVENT_FLAG_NO_EVENT = 0, // Нет события ACCOUNT_EVENT_FLAG_LEVERAGE = 1, // Изменение предоставленного плеча ACCOUNT_EVENT_FLAG_LIMIT_ORDERS = 2, // Изменение максимально допустимого количества действующих отложенных ордеров ACCOUNT_EVENT_FLAG_TRADE_ALLOWED = 4, // Изменение разрешения торговли на счёте ACCOUNT_EVENT_FLAG_TRADE_EXPERT = 8, // Изменение разрешения автоторговли на счёте ACCOUNT_EVENT_FLAG_BALANCE = 16, // Изменение баланса больше заданной величины в +/- ACCOUNT_EVENT_FLAG_EQUITY = 32, // Изменение собственных средств больше заданной величины в +/- ACCOUNT_EVENT_FLAG_PROFIT = 64, // Изменение профита больше заданной величины в +/- ACCOUNT_EVENT_FLAG_CREDIT = 128, // Изменение размера предоставленного кредита в валюте депозита ACCOUNT_EVENT_FLAG_MARGIN = 256, // Изменение размера зарезервированных залоговых средств на счете в валюте депозита больше заданной величины в +/- ACCOUNT_EVENT_FLAG_MARGIN_FREE = 512, // Изменение размера средств на счете в валюте депозита, доступных для открытия позиции больше заданной величины в +/- ACCOUNT_EVENT_FLAG_MARGIN_LEVEL = 1024, // Изменение уровня залоговых средств на счете в процентах больше заданной величины в +/- ACCOUNT_EVENT_FLAG_MARGIN_INITIAL = 2048, // Изменение размера средств, зарезервированных на счёте, для обеспечения гарантийной суммы по всем отложенным ордерам больше заданной величины в +/- ACCOUNT_EVENT_FLAG_MARGIN_MAINTENANCE = 4096, // Изменение размера средств, зарезервированных на счёте, для обеспечения минимальной суммы по всем открытым позициям больше заданной величины в +/- ACCOUNT_EVENT_FLAG_MARGIN_SO_CALL = 8192, // Изменение уровня залоговых средств, при котором происходит MarginCall ACCOUNT_EVENT_FLAG_MARGIN_SO_SO = 16384, // Изменение уровня залоговых средств, при достижении которого происходит StopOut ACCOUNT_EVENT_FLAG_ASSETS = 32768, // Изменение текущего размера активов на счёте больше заданной величины в +/- ACCOUNT_EVENT_FLAG_LIABILITIES = 65536, // Изменение текущего размера обязательств на счёте больше заданной величины в +/- ACCOUNT_EVENT_FLAG_COMISSION_BLOCKED = 131072, // Изменение текущей суммы заблокированных комиссий по счёту больше заданной величины в +/- }; //+------------------------------------------------------------------+ //| Список возможных событий аккаунта | //+------------------------------------------------------------------+ enum ENUM_ACCOUNT_EVENT { ACCOUNT_EVENT_NO_EVENT = TRADE_EVENTS_NEXT_CODE, // Нет события ACCOUNT_EVENT_LEVERAGE_INC, // Увеличение предоставленного плеча ACCOUNT_EVENT_LEVERAGE_DEC, // Уменьшение предоставленного плеча ACCOUNT_EVENT_LIMIT_ORDERS_INC, // Увеличение максимально допустимого количества действующих отложенных ордеров ACCOUNT_EVENT_LIMIT_ORDERS_DEC, // Уменьшение максимально допустимого количества действующих отложенных ордеров ACCOUNT_EVENT_TRADE_ALLOWED_ON, // Разрешение торговли на счёте ACCOUNT_EVENT_TRADE_ALLOWED_OFF, // Запрет торговли на счёте ACCOUNT_EVENT_TRADE_EXPERT_ON, // Разрешение автоторговли на счёте ACCOUNT_EVENT_TRADE_EXPERT_OFF, // Запрет автоторговли на счёте ACCOUNT_EVENT_BALANCE_INC, // Увеличение баланса больше заданной величины ACCOUNT_EVENT_BALANCE_DEC, // Уменьшение баланса больше заданной величины ACCOUNT_EVENT_EQUITY_INC, // Увеличение собственных средств больше заданной величины ACCOUNT_EVENT_EQUITY_DEC, // Уменьшение собственных средств больше заданной величины ACCOUNT_EVENT_PROFIT_INC, // Увеличение профита больше заданной величины ACCOUNT_EVENT_PROFIT_DEC, // Уменьшение профита больше заданной величины ACCOUNT_EVENT_CREDIT_INC, // Увеличение размера предоставленного кредита в валюте депозита ACCOUNT_EVENT_CREDIT_DEC, // Уменьшение размера предоставленного кредита в валюте депозита ACCOUNT_EVENT_MARGIN_INC, // Увеличение размера зарезервированных залоговых средств на счете в валюте депозита ACCOUNT_EVENT_MARGIN_DEC, // Уменьшение размера зарезервированных залоговых средств на счете в валюте депозита ACCOUNT_EVENT_MARGIN_FREE_INC, // Увеличение размера средств на счете в валюте депозита, доступных для открытия позиции ACCOUNT_EVENT_MARGIN_FREE_DEC, // Уменьшение размера средств на счете в валюте депозита, доступных для открытия позиции ACCOUNT_EVENT_MARGIN_LEVEL_INC, // Увеличение уровня залоговых средств на счете в процентах ACCOUNT_EVENT_MARGIN_LEVEL_DEC, // Уменьшение уровня залоговых средств на счете в процентах ACCOUNT_EVENT_MARGIN_INITIAL_INC, // Увеличение размера средств, зарезервированных на счёте, для обеспечения гарантийной суммы по всем отложенным ордерам ACCOUNT_EVENT_MARGIN_INITIAL_DEC, // Уменьшение размера средств, зарезервированных на счёте, для обеспечения гарантийной суммы по всем отложенным ордерам ACCOUNT_EVENT_MARGIN_MAINTENANCE_INC, // Увеличение размера средств, зарезервированных на счёте, для обеспечения минимальной суммы по всем открытым позициям ACCOUNT_EVENT_MARGIN_MAINTENANCE_DEC, // Уменьшение размера средств, зарезервированных на счёте, для обеспечения минимальной суммы по всем открытым позициям ACCOUNT_EVENT_MARGIN_SO_CALL_INC, // Увеличение уровня залоговых средств, при котором происходит MarginCall ACCOUNT_EVENT_MARGIN_SO_CALL_DEC, // Уменьшение уровня залоговых средств, при котором происходит MarginCall ACCOUNT_EVENT_MARGIN_SO_SO_INC, // Увеличение уровня залоговых средств, при достижении которого происходит StopOut ACCOUNT_EVENT_MARGIN_SO_SO_DEC, // Уменьшение уровня залоговых средств, при достижении которого происходит StopOut ACCOUNT_EVENT_ASSETS_INC, // Увеличение текущего размера активов на счёте ACCOUNT_EVENT_ASSETS_DEC, // Уменьшение текущего размера активов на счёте ACCOUNT_EVENT_LIABILITIES_INC, // Увеличение текущего размера обязательств на счёте ACCOUNT_EVENT_LIABILITIES_DEC, // Уменьшение текущего размера обязательств на счёте ACCOUNT_EVENT_COMISSION_BLOCKED_INC, // Увеличение текущей суммы заблокированных комиссий по счёту ACCOUNT_EVENT_COMISSION_BLOCKED_DEC, // Уменьшение текущей суммы заблокированных комиссий по счёту }; #define ACCOUNT_EVENTS_NEXT_CODE (ACCOUNT_EVENT_COMISSION_BLOCKED_DEC+1) // Код следующего событя после последнего кода события аккаунта //+------------------------------------------------------------------+ //| Целочисленные свойства аккаунта | //+------------------------------------------------------------------+ enum ENUM_ACCOUNT_PROP_INTEGER { ACCOUNT_PROP_LOGIN, // Номер счёта ACCOUNT_PROP_TRADE_MODE, // Тип торгового счета ACCOUNT_PROP_LEVERAGE, // Размер предоставленного плеча ACCOUNT_PROP_LIMIT_ORDERS, // Максимально допустимое количество действующих отложенных ордеров ACCOUNT_PROP_MARGIN_SO_MODE, // Режим задания минимально допустимого уровня залоговых средств ACCOUNT_PROP_TRADE_ALLOWED, // Разрешенность торговли для текущего счета со стороны сервера ACCOUNT_PROP_TRADE_EXPERT, // Разрешенность торговли для эксперта со стороны сервера ACCOUNT_PROP_MARGIN_MODE, // Режим расчета маржи ACCOUNT_PROP_CURRENCY_DIGITS, // Количество знаков после запятой для валюты счета, необходимых для точного отображения торговых результатов ACCOUNT_PROP_SERVER_TYPE // Тип торгового сервера (MetaTrader5, MetaTrader4) }; #define ACCOUNT_PROP_INTEGER_TOTAL (10) // Общее количество целочисленных свойств счетов #define ACCOUNT_PROP_INTEGER_SKIP (0) // Количество неиспользуемых в сортировке целочисленных свойств счетов //+------------------------------------------------------------------+ //| Вещественные свойства аккаунта | //+------------------------------------------------------------------+ enum ENUM_ACCOUNT_PROP_DOUBLE { ACCOUNT_PROP_BALANCE = ACCOUNT_PROP_INTEGER_TOTAL, // Баланс счета в валюте депозита ACCOUNT_PROP_CREDIT, // Размер предоставленного кредита в валюте депозита ACCOUNT_PROP_PROFIT, // Размер текущей прибыли на счете в валюте депозита ACCOUNT_PROP_EQUITY, // Значение собственных средств на счете в валюте депозита ACCOUNT_PROP_MARGIN, // Размер зарезервированных залоговых средств на счете в валюте депозита ACCOUNT_PROP_MARGIN_FREE, // Размер свободных средств на счете в валюте депозита, доступных для открытия позиции ACCOUNT_PROP_MARGIN_LEVEL, // Уровень залоговых средств на счете в процентах ACCOUNT_PROP_MARGIN_SO_CALL, // Уровень залоговых средств, при котором требуется пополнение счета (Margin Call) ACCOUNT_PROP_MARGIN_SO_SO, // Уровень залоговых средств, при достижении которого происходит принудительное закрытие самой убыточной позиции (Stop Out) ACCOUNT_PROP_MARGIN_INITIAL, // Размер средств, зарезервированных на счёте, для обеспечения гарантийной суммы по всем отложенным ордерам ACCOUNT_PROP_MARGIN_MAINTENANCE, // Размер средств, зарезервированных на счёте, для обеспечения минимальной суммы по всем открытым позициям ACCOUNT_PROP_ASSETS, // Текущий размер активов на счёте ACCOUNT_PROP_LIABILITIES, // Текущий размер обязательств на счёте ACCOUNT_PROP_COMMISSION_BLOCKED // Текущая сумма заблокированных комиссий по счёту }; #define ACCOUNT_PROP_DOUBLE_TOTAL (14) // Общее количество вещественных свойств счетов #define ACCOUNT_PROP_DOUBLE_SKIP (0) // Количество неиспользуемых в сортировке вещественных свойств счетов //+------------------------------------------------------------------+ //| Строковые свойства аккаунта | //+------------------------------------------------------------------+ enum ENUM_ACCOUNT_PROP_STRING { ACCOUNT_PROP_NAME = (ACCOUNT_PROP_INTEGER_TOTAL+ACCOUNT_PROP_DOUBLE_TOTAL), // Имя клиента ACCOUNT_PROP_SERVER, // Имя торгового сервера ACCOUNT_PROP_CURRENCY, // Валюта депозита ACCOUNT_PROP_COMPANY // Имя компании, обслуживающей счет }; #define ACCOUNT_PROP_STRING_TOTAL (4) // Общее количество строковых свойств счетов #define ACCOUNT_PROP_STRING_SKIP (0) // Количество неиспользуемых в сортировке строковых свойств счетов //+------------------------------------------------------------------+ //| Возможные критерии сортировки аккаунтов | //+------------------------------------------------------------------+ #define FIRST_ACC_DBL_PROP (ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_INTEGER_SKIP) #define FIRST_ACC_STR_PROP (ACCOUNT_PROP_INTEGER_TOTAL-ACCOUNT_PROP_INTEGER_SKIP+ACCOUNT_PROP_DOUBLE_TOTAL-ACCOUNT_PROP_DOUBLE_SKIP) enum ENUM_SORT_ACCOUNT_MODE { SORT_BY_ACCOUNT_LOGIN = 0, // Сортировать по номеру счёта SORT_BY_ACCOUNT_TRADE_MODE = 1, // Сортировать по типу торгового счета SORT_BY_ACCOUNT_LEVERAGE = 2, // Сортировать по размеру предоставленного плеча SORT_BY_ACCOUNT_LIMIT_ORDERS = 3, // Сортировать по максимально допустимому количеству действующих отложенных ордеров SORT_BY_ACCOUNT_MARGIN_SO_MODE = 4, // Сортировать по режиму задания минимально допустимого уровня залоговых средств SORT_BY_ACCOUNT_TRADE_ALLOWED = 5, // Сортировать по разрешенности торговли для текущего счета SORT_BY_ACCOUNT_TRADE_EXPERT = 6, // Сортировать по разрешенности торговли для эксперта SORT_BY_ACCOUNT_MARGIN_MODE = 7, // Сортировать по режиму расчета маржи SORT_BY_ACCOUNT_CURRENCY_DIGITS = 8, // Сортировать по количеству знаков после запятой для валюты счета SORT_BY_ACCOUNT_SERVER_TYPE = 9, // Сортировать по типу торгового сервера (MetaTrader5, MetaTrader4) SORT_BY_ACCOUNT_BALANCE = FIRST_ACC_DBL_PROP, // Сортировать по балансу счета в валюте депозита SORT_BY_ACCOUNT_CREDIT = FIRST_ACC_DBL_PROP+1, // Сортировать по размеру предоставленного кредита в валюте депозита SORT_BY_ACCOUNT_PROFIT = FIRST_ACC_DBL_PROP+2, // Сортировать по размеру текущей прибыли на счете в валюте депозита SORT_BY_ACCOUNT_EQUITY = FIRST_ACC_DBL_PROP+3, // Сортировать по значению собственных средств на счете в валюте депозита SORT_BY_ACCOUNT_MARGIN = FIRST_ACC_DBL_PROP+4, // Сортировать по размеру зарезервированных залоговых средств на счете в валюте депозита SORT_BY_ACCOUNT_MARGIN_FREE = FIRST_ACC_DBL_PROP+5, // Сортировать по размеру свободных средств на счете в валюте депозита, доступных для открытия позиции SORT_BY_ACCOUNT_MARGIN_LEVEL = FIRST_ACC_DBL_PROP+6, // Сортировать по уровню залоговых средств на счете в процентах SORT_BY_ACCOUNT_MARGIN_SO_CALL = FIRST_ACC_DBL_PROP+7, // Сортировать по уровню залоговых средств, при котором требуется пополнение счета (Margin Call) SORT_BY_ACCOUNT_MARGIN_SO_SO = FIRST_ACC_DBL_PROP+8, // Сортировать по уровню залоговых средств, при достижении которого происходит принудительное закрытие самой убыточной позиции (Stop Out) SORT_BY_ACCOUNT_MARGIN_INITIAL = FIRST_ACC_DBL_PROP+9, // Сортировать по размеру средств, зарезервированных на счёте, для обеспечения гарантийной суммы по всем отложенным ордерам SORT_BY_ACCOUNT_MARGIN_MAINTENANCE = FIRST_ACC_DBL_PROP+10, // Сортировать по размеру средств, зарезервированных на счёте, для обеспечения минимальной суммы по всем открытым позициям SORT_BY_ACCOUNT_ASSETS = FIRST_ACC_DBL_PROP+11, // Сортировать по текущему размеру активов на счёте SORT_BY_ACCOUNT_LIABILITIES = FIRST_ACC_DBL_PROP+12, // Сортировать по текущему размеру обязательств на счёте SORT_BY_ACCOUNT_COMMISSION_BLOCKED = FIRST_ACC_DBL_PROP+13, // Сортировать по текущей сумме заблокированных комиссий по счёту SORT_BY_ACCOUNT_NAME = FIRST_ACC_STR_PROP, // Сортировать по имени клиента SORT_BY_ACCOUNT_SERVER = FIRST_ACC_STR_PROP+1, // Сортировать по имени торгового сервера SORT_BY_ACCOUNT_CURRENCY = FIRST_ACC_STR_PROP+2, // Сортировать по валюте депозита SORT_BY_ACCOUNT_COMPANY = FIRST_ACC_STR_PROP+3 // Сортировать по имени компании, обслуживающей счет }; //+------------------------------------------------------------------+
Так как за один раз у нас вполне могут измениться сразу несколько свойств аккаунта, то чтобы не потерять ни одно из изменений его свойств, будем, как обычно, работать с набором флагов событий, которые будут записываться в переменную-код события, а далее уже будем проверять наличие конкретного флага в составе этой переменной и на основании имеющихся флагов в коде события определять что именно произошло в свойствах аккаунта. Все найденные события будем хранить в массиве, доступ к которому будет предоставлен в классе CEngine, а в последствии — и в программе.
Как можно было заметить, в списке целочисленных свойств аккаунта было добавлено ещё одно свойство — тип торгового сервера. Соответственно, было изменено общее количество целочисленных свойств — с 9 до 10.
В данном свойстве аккаунта будем хранить принадлежность счёта к MetaTrader 5 или MetaTrader 4. Причиной добавления данного свойства послужило то, что в список всех аккаунтов, к которым когда-либо было подключение программы на основе библиотеки, попадают все счета — как для MetaTrader 5, так и для MetaTrader 4 в случае, если запустить программу на основе библиотеки в обоих терминалах. Вот для того, чтобы можно было различать типы торговых серверов, мы и ввели данное свойство, которое будет присутствовать в описании аккаунта, выводимом в журнал методом PrintShort() класса CAccount, а так же будет возможность фильтрации объектов-аккаунтов по их принадлежности к платформам.
Перейдём к файлу Acount.mqh и в приватной секции в структуре данных аккаунта добавим новое свойство и впишем точные размеры массивов для хранения строковых свойств аккаунта:
//+------------------------------------------------------------------+ //| Класс аккаунта | //+------------------------------------------------------------------+ class CAccount : public CObject { private: struct SData { //--- Целочисленные свойства счёта long login; // ACCOUNT_LOGIN (Номер счёта) int trade_mode; // ACCOUNT_TRADE_MODE (Тип торгового счета) long leverage; // ACCOUNT_LEVERAGE (Размер предоставленного плеча) int limit_orders; // ACCOUNT_LIMIT_ORDERS (Максимально допустимое количество действующих отложенных ордеров) int margin_so_mode; // ACCOUNT_MARGIN_SO_MODE (Режим задания минимально допустимого уровня залоговых средств) bool trade_allowed; // ACCOUNT_TRADE_ALLOWED (Разрешенность торговли для текущего счета со стороны сервера) bool trade_expert; // ACCOUNT_TRADE_EXPERT (Разрешенность торговли для эксперта со стороны сервера) int margin_mode; // ACCOUNT_MARGIN_MODE (Режим расчета маржи) int currency_digits; // ACCOUNT_CURRENCY_DIGITS (Количество знаков после запятой для валюты счета) int server_type; // Тип торгового сервера (MetaTrader5, MetaTrader4) //--- Вещественные свойства счёта double balance; // ACCOUNT_BALANCE (Баланс счета в валюте депозита) double credit; // ACCOUNT_CREDIT (Размер предоставленного кредита в валюте депозита) double profit; // ACCOUNT_PROFIT (Размер текущей прибыли на счете в валюте депозита) double equity; // ACCOUNT_EQUITY (Значение собственных средств на счете в валюте депозита) double margin; // ACCOUNT_MARGIN (Размер зарезервированных залоговых средств на счете в валюте депозита) double margin_free; // ACCOUNT_MARGIN_FREE (Размер свободных средств на счете в валюте депозита, доступных для открытия позиции) double margin_level; // ACCOUNT_MARGIN_LEVEL (Уровень залоговых средств на счете в процентах) double margin_so_call; // ACCOUNT_MARGIN_SO_CALL (Уровень залоговых средств, при котором происходит MarginCall) double margin_so_so; // ACCOUNT_MARGIN_SO_SO (Уровень залоговых средств, при достижении которого происходит StopOut) double margin_initial; // ACCOUNT_MARGIN_INITIAL (Размер средств, зарезервированных на счёте, для обеспечения гарантийной суммы по всем отложенным ордерам) double margin_maintenance; // ACCOUNT_MARGIN_MAINTENANCE (Размер средств, зарезервированных на счёте, для обеспечения минимальной суммы по всем открытым позициям) double assets; // ACCOUNT_ASSETS (Текущий размер активов на счёте) double liabilities; // ACCOUNT_LIABILITIES (Текущий размер обязательств на счёте) double comission_blocked; // ACCOUNT_COMMISSION_BLOCKED (Текущая сумма заблокированных комиссий по счёту) //--- Строковые свойства счёта uchar name[128]; // ACCOUNT_NAME (Имя клиента) uchar server[64]; // ACCOUNT_SERVER (Имя торгового сервера) uchar currency[32]; // ACCOUNT_CURRENCY (Валюта депозита) uchar company[128]; // ACCOUNT_COMPANY (Имя компании, обслуживающей счет) }; SData m_struct_obj; // Структура объекта-аккаунта uchar m_uchar_array[]; // uchar-массив структуры объекта-аккаунта
В публичной секции класса добавим ещё один метод упрощённого доступа к свойствам объекта-аккаунта, возвращающего тип торгового сервера:
//+------------------------------------------------------------------+ //| Методы упрощённого доступа к свойствам объекта-аккаунта | //+------------------------------------------------------------------+ //--- Возвращает целочисленные свойства аккаунта ENUM_ACCOUNT_TRADE_MODE TradeMode(void) const { return (ENUM_ACCOUNT_TRADE_MODE)this.GetProperty(ACCOUNT_PROP_TRADE_MODE); } ENUM_ACCOUNT_STOPOUT_MODE MarginSOMode(void) const { return (ENUM_ACCOUNT_STOPOUT_MODE)this.GetProperty(ACCOUNT_PROP_MARGIN_SO_MODE); } ENUM_ACCOUNT_MARGIN_MODE MarginMode(void) const { return (ENUM_ACCOUNT_MARGIN_MODE)this.GetProperty(ACCOUNT_PROP_MARGIN_MODE); } long Login(void) const { returnthis.GetProperty(ACCOUNT_PROP_LOGIN); } long Leverage(void) const { returnthis.GetProperty(ACCOUNT_PROP_LEVERAGE); } long LimitOrders(void) const { returnthis.GetProperty(ACCOUNT_PROP_LIMIT_ORDERS); } long TradeAllowed(void) const { returnthis.GetProperty(ACCOUNT_PROP_TRADE_ALLOWED); } long TradeExpert(void) const { returnthis.GetProperty(ACCOUNT_PROP_TRADE_EXPERT); } long CurrencyDigits(void) const { returnthis.GetProperty(ACCOUNT_PROP_CURRENCY_DIGITS); } long ServerType(void) const { returnthis.GetProperty(ACCOUNT_PROP_SERVER_TYPE); }
В методы описания свойств аккаунта добавим ещё один метод, возвращающий описание типа торгового сервера:
//+------------------------------------------------------------------+ //| Описания свойств объекта-аккаунта | //+------------------------------------------------------------------+ //--- Возвращает описание (1) целочисленного, (2) вещественного и (3) строкового свойства аккаунта string GetPropertyDescription(ENUM_ACCOUNT_PROP_INTEGER property); string GetPropertyDescription(ENUM_ACCOUNT_PROP_DOUBLE property); string GetPropertyDescription(ENUM_ACCOUNT_PROP_STRING property); //--- Возвращает наименование типа торгового счёта (демо, конкурс, реал) string TradeModeDescription(void) const; //--- Возвращает наименование типа торгового сервера (MetaTrader5, MetaTrader4) string ServerTypeDescription(void) const; //--- Возвращает описание режима задания минимально допустимого уровня залоговых средств string MarginSOModeDescription(void) const; //--- Возвращает описание режима расчета маржи string MarginModeDescription(void) const; //--- Выводит в журнал описание свойств аккаунта (full_prop=true - все свойства, false - только поддерживаемые - реализуется в наследниках класса) void Print(constbool full_prop=false); //--- Выводит в журнал краткое описание счёта void PrintShort(void);
В конструкторе класса заполним свойство, хранящее тип торгового сервера:
//+------------------------------------------------------------------+ //| Конструктор | //+------------------------------------------------------------------+ CAccount::CAccount(void) { //--- Сохранение целочисленных свойств this.m_long_prop[ACCOUNT_PROP_LOGIN] = ::AccountInfoInteger(ACCOUNT_LOGIN); this.m_long_prop[ACCOUNT_PROP_TRADE_MODE] = ::AccountInfoInteger(ACCOUNT_TRADE_MODE); this.m_long_prop[ACCOUNT_PROP_LEVERAGE] = ::AccountInfoInteger(ACCOUNT_LEVERAGE); this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS] = ::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE] = ::AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE); this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED] = ::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED); this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT] = ::AccountInfoInteger(ACCOUNT_TRADE_EXPERT); this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE] = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_MARGIN_MODE) #else ACCOUNT_MARGIN_MODE_RETAIL_HEDGING#endif ; this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS] = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2#endif ; this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE] = (::TerminalInfoString(TERMINAL_NAME)=="MetaTrader 5" ? 5 : 4); //--- Сохранение вещественных свойств this.m_double_prop[this.IndexProp(ACCOUNT_PROP_BALANCE)] = ::AccountInfoDouble(ACCOUNT_BALANCE); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_CREDIT)] = ::AccountInfoDouble(ACCOUNT_CREDIT); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_PROFIT)] = ::AccountInfoDouble(ACCOUNT_PROFIT); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_EQUITY)] = ::AccountInfoDouble(ACCOUNT_EQUITY); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN)] = ::AccountInfoDouble(ACCOUNT_MARGIN); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_FREE)] = ::AccountInfoDouble(ACCOUNT_MARGIN_FREE); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_LEVEL)] = ::AccountInfoDouble(ACCOUNT_MARGIN_LEVEL); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_CALL)] = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_SO)] = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_SO); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_INITIAL)] = ::AccountInfoDouble(ACCOUNT_MARGIN_INITIAL); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_MAINTENANCE)]=::AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_ASSETS)] = ::AccountInfoDouble(ACCOUNT_ASSETS); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_LIABILITIES)] = ::AccountInfoDouble(ACCOUNT_LIABILITIES); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_COMMISSION_BLOCKED)]=::AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED); //--- Сохранение строковых свойств this.m_string_prop[this.IndexProp(ACCOUNT_PROP_NAME)] = ::AccountInfoString(ACCOUNT_NAME); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_SERVER)] = ::AccountInfoString(ACCOUNT_SERVER); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_CURRENCY)] = ::AccountInfoString(ACCOUNT_CURRENCY); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_COMPANY)] = ::AccountInfoString(ACCOUNT_COMPANY); } //+-------------------------------------------------------------------+
Здесь: просто читаем наименование терминала, и если это MetaTrader 5, то вписываем значение 5, иначе — вписываем 4.
В метод создания структуры объекта ObjectToStruct() впишем заполнение нового свойства:
//+------------------------------------------------------------------+ //| Создаёт структуру объекта-аккаунта | //+------------------------------------------------------------------+ bool CAccount::ObjectToStruct(void) { //--- Сохранение целочисленных свойств this.m_struct_obj.login=this.Login(); this.m_struct_obj.trade_mode=this.TradeMode(); this.m_struct_obj.leverage=this.Leverage(); this.m_struct_obj.limit_orders=(int)this.LimitOrders(); this.m_struct_obj.margin_so_mode=this.MarginSOMode(); this.m_struct_obj.trade_allowed=this.TradeAllowed(); this.m_struct_obj.trade_expert=this.TradeExpert(); this.m_struct_obj.margin_mode=this.MarginMode(); this.m_struct_obj.currency_digits=(int)this.CurrencyDigits(); this.m_struct_obj.server_type=(int)this.ServerType(); //--- Сохранение вещественных свойств this.m_struct_obj.balance=this.Balance(); this.m_struct_obj.credit=this.Credit(); this.m_struct_obj.profit=this.Profit(); this.m_struct_obj.equity=this.Equity(); this.m_struct_obj.margin=this.Margin(); this.m_struct_obj.margin_free=this.MarginFree(); this.m_struct_obj.margin_level=this.MarginLevel(); this.m_struct_obj.margin_so_call=this.MarginSOCall(); this.m_struct_obj.margin_so_so=this.MarginSOSO(); this.m_struct_obj.margin_initial=this.MarginInitial(); this.m_struct_obj.margin_maintenance=this.MarginMaintenance(); this.m_struct_obj.assets=this.Assets(); this.m_struct_obj.liabilities=this.Liabilities(); this.m_struct_obj.comission_blocked=this.ComissionBlocked(); //--- Сохранение строковых свойств ::StringToCharArray(this.Name(),this.m_struct_obj.name); ::StringToCharArray(this.Server(),this.m_struct_obj.server); ::StringToCharArray(this.Currency(),this.m_struct_obj.currency); ::StringToCharArray(this.Company(),this.m_struct_obj.company); //--- Сохранение структуры в uchar-массив ::ResetLastError(); if(!::StructToCharArray(this.m_struct_obj,this.m_uchar_array)) { ::Print(DFUN,TextByLanguage("Не удалось сохранить структуру объекта в uchar-массив, ошибка ","Failed to save object structure to uchar array, error "),(string)::GetLastError()); returnfalse; } returntrue; } //+------------------------------------------------------------------+
а в метод создания объекта из структуры StructToObject() впишем получение свойства из структуры:
//+------------------------------------------------------------------+ //| Создаёт объект-аккаунт из структуры | //+------------------------------------------------------------------+ void CAccount::StructToObject(void) { //--- Сохранение целочисленных свойств this.m_long_prop[ACCOUNT_PROP_LOGIN] = this.m_struct_obj.login; this.m_long_prop[ACCOUNT_PROP_TRADE_MODE] = this.m_struct_obj.trade_mode; this.m_long_prop[ACCOUNT_PROP_LEVERAGE] = this.m_struct_obj.leverage; this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS] = this.m_struct_obj.limit_orders; this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE] = this.m_struct_obj.margin_so_mode; this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED] = this.m_struct_obj.trade_allowed; this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT] = this.m_struct_obj.trade_expert; this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE] = this.m_struct_obj.margin_mode; this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS] = this.m_struct_obj.currency_digits; this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE] = this.m_struct_obj.server_type; //--- Сохранение вещественных свойств this.m_double_prop[this.IndexProp(ACCOUNT_PROP_BALANCE)] = this.m_struct_obj.balance; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_CREDIT)] = this.m_struct_obj.credit; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_PROFIT)] = this.m_struct_obj.profit; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_EQUITY)] = this.m_struct_obj.equity; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN)] = this.m_struct_obj.margin; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_FREE)] = this.m_struct_obj.margin_free; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_LEVEL)] = this.m_struct_obj.margin_level; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_CALL)] = this.m_struct_obj.margin_so_call; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_SO)] = this.m_struct_obj.margin_so_so; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_INITIAL)] = this.m_struct_obj.margin_initial; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_MAINTENANCE)]=this.m_struct_obj.margin_maintenance; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_ASSETS)] = this.m_struct_obj.assets; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_LIABILITIES)] = this.m_struct_obj.liabilities; this.m_double_prop[this.IndexProp(ACCOUNT_PROP_COMMISSION_BLOCKED)]=this.m_struct_obj.comission_blocked; //--- Сохранение строковых свойств this.m_string_prop[this.IndexProp(ACCOUNT_PROP_NAME)] = ::CharArrayToString(this.m_struct_obj.name); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_SERVER)] = ::CharArrayToString(this.m_struct_obj.server); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_CURRENCY)] = ::CharArrayToString(this.m_struct_obj.currency); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_COMPANY)] = ::CharArrayToString(this.m_struct_obj.company); } //+------------------------------------------------------------------+
Теперь в методе вывода краткого описания свойств аккаунта допишем вывод типа торгового сервера:
//+------------------------------------------------------------------+ //| Выводит в журнал краткое описание счёта | //+------------------------------------------------------------------+ void CAccount::PrintShort(void) { string mode=(this.MarginMode()==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING ? ", Hedge" : this.MarginMode()==ACCOUNT_MARGIN_MODE_EXCHANGE ? ", Exhange" : ""); string names=TextByLanguage("Счёт ","Account ")+(string)this.Login()+": "+this.Name()+" ("+this.Company()+" "; string values=::DoubleToString(this.Balance(),(int)this.CurrencyDigits())+" "+this.Currency()+", 1:"+(string)+this.Leverage()+mode+", "+this.TradeModeDescription()+" "+this.ServerTypeDescription()+")"; ::Print(names,values); } //+------------------------------------------------------------------+
В метод, возвращающий описание целочисленных свойств аккаунта, допишем описание нового свойства:
//+------------------------------------------------------------------+ //| Возвращает описание целочисленного свойства аккаунта | //+------------------------------------------------------------------+ string CAccount::GetPropertyDescription(ENUM_ACCOUNT_PROP_INTEGER property) { return ( property==ACCOUNT_PROP_LOGIN ? TextByLanguage("Номер счёта","Account number")+": "+(string)this.GetProperty(property) : property==ACCOUNT_PROP_TRADE_MODE ? TextByLanguage("Тип торгового счета","Account trade mode")+": "+this.TradeModeDescription() : property==ACCOUNT_PROP_LEVERAGE ? TextByLanguage("Размер предоставленного плеча","Account leverage")+": "+(string)this.GetProperty(property) : property==ACCOUNT_PROP_LIMIT_ORDERS ? TextByLanguage("Максимально допустимое количество действующих отложенных ордеров","Maximum allowed number of active pending orders")+": "+ (string)this.GetProperty(property) : property==ACCOUNT_PROP_MARGIN_SO_MODE ? TextByLanguage("Режим задания минимально допустимого уровня залоговых средств","Mode for setting the minimal allowed margin")+": "+ this.MarginSOModeDescription() : property==ACCOUNT_PROP_TRADE_ALLOWED ? TextByLanguage("Разрешенность торговли для текущего счета","Allowed trade for the current account")+": "+ (this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) : property==ACCOUNT_PROP_TRADE_EXPERT ? TextByLanguage("Разрешенность торговли для эксперта","Allowed trade for an Expert Advisor")+": "+ (this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) : property==ACCOUNT_PROP_MARGIN_MODE ? TextByLanguage("Режим расчета маржи","Margin calculation mode")+": "+ this.MarginModeDescription() : property==ACCOUNT_PROP_CURRENCY_DIGITS ? TextByLanguage("Количество знаков после запятой для валюты счета","The number of decimal places in the account currency")+": "+ (string)this.GetProperty(property) : property==ACCOUNT_PROP_SERVER_TYPE ? TextByLanguage("Тип торгового сервера","Type of trading server")+": "+ (string)this.GetProperty(property) : "" ); } //+------------------------------------------------------------------+
Напишем реализацию метода, возвращающего наименование типа торгового сервера:
//+------------------------------------------------------------------+ //| Возвращает наименование типа торгового сервера | //+------------------------------------------------------------------+ string CAccount::ServerTypeDescription(void) const { return(this.ServerType()==5 ? "MetaTrader5" : "MetaTrader4"); } //+------------------------------------------------------------------+
Доработка класса CAccount завершена.
Теперь внесём необходимые изменения в класс-коллекцию аккаунтов, так как мы решили, что отслеживание событий будем осуществлять из класса CAccountCollection. Все найденные изменения, произошедшие одновременно, мы будем записывать в int-массив. Для этого воспользуемся готовым классом динамического массива переменных типа int или uint стандартной библиотеки CArrayInt.
Для его использования, подключим файл класса к файлу библиотеки AccountsCollection.mqh:
//+------------------------------------------------------------------+ //| AccountsCollection.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\ArrayInt.mqh> #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Accounts\Account.mqh" //+------------------------------------------------------------------+ //| Коллекция аккаунтов | //+------------------------------------------------------------------+ class CAccountsCollection : public CListObj {
В качестве небольшого отступления определимся— что же мы хотим получить. Мы хотим знать моменты, когда изменились некоторые свойства счёта. Какое-то свойство может быть включено или выключено — например, разрешение/запрет торговли на счёте в общем, или только разрешение/запрет торговли советниками. О факте изменения данного свойства нам необходимо знать. Так же и уровень наступления MarginCall или StopOut — их изменение может повлиять на успешность выдерживания просадки средств, и т.п. Так же нам необходимо отслеживать прирост и уменьшение средств и баланса для принятия тех или иных решений в советнике.
Если, например, есть некоторое количество открытых позиций, и мы хотим закрывать какие-либо из них при превышении положительной или отрицательной величины средств, то нам нужно сперва задать некий порог, при превышении которого будет сгенерировано событие, и далее уже принимать решение — в зависимости от того прирост это, или падение средств выше заданной величины. Такая же логика применима к текущей прибыли на счёте, размеру баланса, свободной маржи, или к загрузке депозита.
Таким образом, для каких-то свойств нам необходимо иметь свои пороговые уровни прироста и падения и текущее значение свойства, а для других — только значение, которое может либо быть включенным/выключенным, либо измениться/не измениться.
Добавим в приватную секцию класса все необходимые переменные-члены класса для хрениния значений прироста/падения отслеживаемых свойств и их текущего значения, удалим оказавшийся ненужным метод SavePrevValues() и добавим методы инициализации отслеживаемых, и инициализации контролируемых данных аккаунта, метод, проверяющий изменения аккаунта и возвращающий код изменения, метод, устанавливающий тип события и заполняющий список событий, и наконец метод, возвращающий факт наличия флага в событии аккаунта:
//--- Сохраняет текущие значения состояния данных текущего аккаунта как прошлые
void SavePrevValues(void)
//+------------------------------------------------------------------+ //| Коллекция аккаунтов | //+------------------------------------------------------------------+ class CAccountsCollection : public CListObj { private: struct MqlDataAccount { double hash_sum; // Хэш-сумма данных аккаунта //--- Целочисленные свойства счёта long login; // ACCOUNT_LOGIN (Номер счёта) long leverage; // ACCOUNT_LEVERAGE (Размер предоставленного плеча) int limit_orders; // ACCOUNT_LIMIT_ORDERS (Максимально допустимое количество действующих отложенных ордеров) bool trade_allowed; // ACCOUNT_TRADE_ALLOWED (Разрешенность торговли для текущего счета со стороны сервера) bool trade_expert; // ACCOUNT_TRADE_EXPERT (Разрешенность торговли для эксперта со стороны сервера) //--- Вещественные свойства счёта double balance; // ACCOUNT_BALANCE (Баланс счета в валюте депозита) double credit; // ACCOUNT_CREDIT (Размер предоставленного кредита в валюте депозита) double profit; // ACCOUNT_PROFIT (Размер текущей прибыли на счете в валюте депозита) double equity; // ACCOUNT_EQUITY (Значение собственных средств на счете в валюте депозита) double margin; // ACCOUNT_MARGIN (Размер зарезервированных залоговых средств на счете в валюте депозита) double margin_free; // ACCOUNT_MARGIN_FREE (Размер свободных средств на счете в валюте депозита, доступных для открытия позиции) double margin_level; // ACCOUNT_MARGIN_LEVEL (Уровень залоговых средств на счете в процентах) double margin_so_call; // ACCOUNT_MARGIN_SO_CALL (Уровень залоговых средств, при котором происходит MarginCall) double margin_so_so; // ACCOUNT_MARGIN_SO_SO (Уровень залоговых средств, при достижении которого происходит StopOut) double margin_initial; // ACCOUNT_MARGIN_INITIAL (Размер средств, зарезервированных на счёте, для обеспечения гарантийной суммы по всем отложенным ордерам) double margin_maintenance; // ACCOUNT_MARGIN_MAINTENANCE (Размер средств, зарезервированных на счёте, для обеспечения минимальной суммы по всем открытым позициям) double assets; // ACCOUNT_ASSETS (Текущий размер активов на счёте) double liabilities; // ACCOUNT_LIABILITIES (Текущий размер обязательств на счёте) double comission_blocked; // ACCOUNT_COMMISSION_BLOCKED (Текущая сумма заблокированных комиссий по счёту) }; MqlDataAccount m_struct_curr_account; // Текущие данные счёта MqlDataAccount m_struct_prev_account; // Прошлые данные счёта MqlTick m_tick; // Структура тика string m_symbol; // Текущий символ long m_chart_id; // Идентификатор графика управляющей программы CListObj m_list_accounts; // Список объектов-аккаунтов CArrayInt m_list_changes; // Список изменений аккаунта string m_folder_name; // Имя папки хранения объектов-аккаунтов int m_index_current; // Индекс объекта-аккаунта с данными текущего счёта //--- Отслеживание изменений аккаунта bool m_is_account_event; // Флаг события в данных аккаунта int m_change_code; // Код изменения аккаунта //--- Плечо long m_changed_leverage_value; // Величина изменения плеча bool m_is_change_leverage_inc; // Флаг увеличения плеча bool m_is_change_leverage_dec; // Флаг уменьшения плеча //--- Количество действующих отложенных ордеров int m_changed_limit_orders_value; // Величина изменения максимально допустимого количества действующих отложенных ордеров bool m_is_change_limit_orders_inc; // Флаг увеличения максимально допустимого количества действующих отложенных ордеров bool m_is_change_limit_orders_dec; // Флаг уменьшения максимально допустимого количества действующих отложенных ордеров //--- Торговля на счёте bool m_is_change_trade_allowed_on; // Флаг разрешения торговли для текущего счета со стороны сервера bool m_is_change_trade_allowed_off; // Флаг запрета торговли для текущего счета со стороны сервера //--- Автоторговля на счёте bool m_is_change_trade_expert_on; // Флаг разрешения торговли для эксперта со стороны сервера bool m_is_change_trade_expert_off; // Флаг запрета торговли для эксперта со стороны сервера //--- Баланс double m_control_balance_inc; // Контролируемая величина прироста баланса double m_control_balance_dec; // Контролируемая величина уменьшения баланса double m_changed_balance_value; // Величина изменения баланса bool m_is_change_balance_inc; // Флаг изменения баланса больше, чем на величину прироста bool m_is_change_balance_dec; // Флаг изменения баланса больше, чем на величину уменьшения //--- Кредит double m_changed_credit_value; // Величина изменения кредита bool m_is_change_credit_inc; // Флаг увеличения кредита bool m_is_change_credit_dec; // Флаг уменьшения кредита //--- Профит double m_control_profit_inc; // Контролируемая величина прироста прибыли double m_control_profit_dec; // Контролируемая величина уменьшения прибыли double m_changed_profit_value; // Величина изменения прибыли bool m_is_change_profit_inc; // Флаг изменения прибыли больше, чем на величину прироста bool m_is_change_profit_dec; // Флаг изменения прибыли больше, чем на величину уменьшения //--- Средства double m_control_equity_inc; // Контролируемая величина прироста средств double m_control_equity_dec; // Контролируемая величина уменьшения средств double m_changed_equity_value; // Величина изменения средств bool m_is_change_equity_inc; // Флаг изменения средств больше, чем на величину прироста bool m_is_change_equity_dec; // Флаг изменения средств больше, чем на величину уменьшения //--- Маржа double m_control_margin_inc; // Контролируемая величина прироста залоговых средств double m_control_margin_dec; // Контролируемая величина уменьшения залоговых средств double m_changed_margin_value; // Величина изменения залоговых средств bool m_is_change_margin_inc; // Флаг изменения залоговых средств больше, чем на величину прироста bool m_is_change_margin_dec; // Флаг изменения залоговых средств больше, чем на величину уменьшения //--- Свободная маржа double m_control_margin_free_inc; // Контролируемая величина прироста свободных средств double m_control_margin_free_dec; // Контролируемая величина уменьшения свободных средств double m_changed_margin_free_value; // Величина изменения свободных средств bool m_is_change_margin_free_inc; // Флаг изменения свободных средств больше, чем на величину прироста bool m_is_change_margin_free_dec; // Флаг изменения свободных средств больше, чем на величину уменьшения //--- Уровень маржи double m_control_margin_level_inc; // Контролируемая величина прироста уровня свободных средств double m_control_margin_level_dec; // Контролируемая величина уменьшения уровня свободных средств double m_changed_margin_level_value; // Величина изменения уровня свободных средств bool m_is_change_margin_level_inc; // Флаг изменения уровня свободных средств больше, чем на величину прироста bool m_is_change_margin_level_dec; // Флаг изменения уровня свободных средств больше, чем на величину уменьшения //--- Margin Call double m_changed_margin_so_call_value; // Величина изменения уровня Margin Call bool m_is_change_margin_so_call_inc; // Флаг увеличения уровня Margin Call bool m_is_change_margin_so_call_dec; // Флаг уменьшения уровня Margin Call //--- MarginStopOut double m_changed_margin_so_so_value; // Величина изменения уровня Margin StopOut bool m_is_change_margin_so_so_inc; // Флаг увеличения уровня Margin StopOut bool m_is_change_margin_so_so_dec; // Флаг уменьшения уровня Margin StopOut //--- Гарантийная сумма по отложенным ордерам double m_control_margin_initial_inc; // Контролируемая величина прироста размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам double m_control_margin_initial_dec; // Контролируемая величина уменьшения размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам double m_changed_margin_initial_value; // Величина изменения размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам bool m_is_change_margin_initial_inc; // Флаг изменения размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам больше, чем на величину прироста bool m_is_change_margin_initial_dec; // Флаг изменения размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам больше, чем на величину уменьшения //--- Гарантийная сумма по открытым позициям double m_control_margin_maintenance_inc; // Контролируемая величина прироста зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям double m_control_margin_maintenance_dec; // Контролируемая величина уменьшения зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям double m_changed_margin_maintenance_value; // Величина изменения размера зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям bool m_is_change_margin_maintenance_inc; // Флаг изменения размера зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям bool m_is_change_margin_maintenance_dec; // Флаг изменения размера зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям //--- Активы double m_control_assets_inc; // Контролируемая величина прироста активов double m_control_assets_dec; // Контролируемая величина уменьшения активов double m_changed_assets_value; // Величина изменения активов bool m_is_change_assets_inc; // Флаг изменения активов больше, чем на величину прироста bool m_is_change_assets_dec; // Флаг изменения активов больше, чем на величину уменьшения //--- Обязательства double m_control_liabilities_inc; // Контролируемая величина прироста обязательств double m_control_liabilities_dec; // Контролируемая величина уменьшения обязательств double m_changed_liabilities_value; // Величина изменения обязательств bool m_is_change_liabilities_inc; // Флаг изменения обязательств больше, чем на величину прироста bool m_is_change_liabilities_dec; // Флаг изменения обязательств больше, чем на величину уменьшения //--- Заблокированные комиссии double m_control_comission_blocked_inc; // Контролируемая величина прироста заблокированных комиссий double m_control_comission_blocked_dec; // Контролируемая величина уменьшения заблокированных комиссий double m_changed_comission_blocked_value; // Величина изменения заблокированных комиссий bool m_is_change_comission_blocked_inc; // Флаг изменения заблокированных комиссий больше, чем на величину прироста bool m_is_change_comission_blocked_dec; // Флаг изменения заблокированных комиссий больше, чем на величину уменьшения //--- Инициализирует переменные (1) отслеживаемых, (2) контролируемых данных аккаунта void InitChangesParams(void); void InitControlsParams(void); //--- Проверяет изменения аккаунта, возвращает код изменения int SetChangeCode(void); //--- Устанавливает тип события и заполняет список событий void SetTypeEvent(void); //--- возвращает факт наличия флага в событии аккаунта bool IsPresentEventFlag(constint change_code) const { return (this.m_change_code & change_code)==change_code; } //--- Записывает данные текущего счёта в свойства объекта-аккаунта void SetAccountsParams(CAccount* account); //--- Проверяет наличие объекта-аккаунта в списке-коллекции bool IsPresent(CAccount* account); //--- Находит и возвращает индекс объекта-аккаунта с данными текущего счёта int Index(void); public:
Метод SavePrevValues() оказался невостребованным, так как при определении факта изменения свойств аккаунта нам необходимо сразу же записывать в структуру, хранящую данные о прошлом состоянии изменённого свойства, новое значение свойства, и при этом оставить остальные свойства теми, которые были на прошлой проверке — до момента фактического их изменения. А метод SavePrevValues() сохранял сразу все свойства аккаунта как прошлые, тем самым нарушая отслеживание конкретной величины изменения, установленной по умолчанию для каждого из отслеживаемых свойств, и которые можно задать отдельно — каждый своим методом установки размера отслеживаемой величины.
За пределами тела класса напишем метод инициализации отслеживаемых данных:
//+------------------------------------------------------------------+ //| Инициализирует переменные отслеживаемых данных аккаунта | //+------------------------------------------------------------------+ void CAccountsCollection::InitChangesParams(void) { //--- Список и код изменений this.m_list_changes.Clear(); // Очищаем список изменений this.m_list_changes.Sort(); // Сортируем список изменений //--- Плечо this.m_changed_leverage_value=0; // Величина изменения плеча this.m_is_change_leverage_inc=false; // Флаг увеличения плеча this.m_is_change_leverage_dec=false; // Флаг уменьшения плеча //--- Количество действующих отложенных ордеров this.m_changed_limit_orders_value=0; // Величина изменения максимально допустимого количества действующих отложенных ордеров this.m_is_change_limit_orders_inc=false; // Флаг увеличения максимально допустимого количества действующих отложенных ордеров this.m_is_change_limit_orders_dec=false; // Флаг уменьшения максимально допустимого количества действующих отложенных ордеров //--- Торговля на счёте this.m_is_change_trade_allowed_on=false; // Флаг разрешения торговли для текущего счета со стороны сервера this.m_is_change_trade_allowed_off=false; // Флаг запрета торговли для текущего счета со стороны сервера //--- Автоторговля на счёте this.m_is_change_trade_expert_on=false; // Флаг разрешения торговли для эксперта со стороны сервера this.m_is_change_trade_expert_off=false; // Флаг запрета торговли для эксперта со стороны сервера //--- Баланс this.m_changed_balance_value=0; // Величина изменения баланса this.m_is_change_balance_inc=false; // Флаг изменения баланса больше, чем на величину прироста this.m_is_change_balance_dec=false; // Флаг изменения баланса больше, чем на величину уменьшения //--- Кредит this.m_changed_credit_value=0; // Величина изменения кредита this.m_is_change_credit_inc=false; // Флаг увеличения кредита this.m_is_change_credit_dec=false; // Флаг уменьшения кредита //--- Прибыль this.m_changed_profit_value=0; // Величина изменения прибыли this.m_is_change_profit_inc=false; // Флаг изменения прибыли больше, чем на величину прироста this.m_is_change_profit_dec=false; // Флаг изменения прибыли больше, чем на величину уменьшения //--- Средства this.m_changed_equity_value=0; // Величина изменения средств this.m_is_change_equity_inc=false; // Флаг изменения средств больше, чем на величину прироста this.m_is_change_equity_dec=false; // Флаг изменения средств больше, чем на величину уменьшения //--- Маржа this.m_changed_margin_value=0; // Величина изменения залоговых средств this.m_is_change_margin_inc=false; // Флаг изменения залоговых средств больше, чем на величину прироста this.m_is_change_margin_dec=false; // Флаг изменения залоговых средств больше, чем на величину уменьшения //--- Свободная маржа this.m_changed_margin_free_value=0; // Величина изменения свободных средств this.m_is_change_margin_free_inc=false; // Флаг изменения свободных средств больше, чем на величину прироста this.m_is_change_margin_free_dec=false; // Флаг изменения свободных средств больше, чем на величину уменьшения //--- Уровень маржи this.m_changed_margin_level_value=0; // Величина изменения уровня свободных средств this.m_is_change_margin_level_inc=false; // Флаг изменения уровня свободных средств больше, чем на величину прироста this.m_is_change_margin_level_dec=false; // Флаг изменения уровня свободных средств больше, чем на величину уменьшения //--- Уровень Margin Call this.m_changed_margin_so_call_value=0; // Величина изменения уровня Margin Call this.m_is_change_margin_so_call_inc=false; // Флаг увеличения уровня Margin Call this.m_is_change_margin_so_call_dec=false; // Флаг уменьшения уровня Margin Call //--- Уровень Margin StopOut this.m_changed_margin_so_so_value=0; // Величина изменения уровня Margin StopOut this.m_is_change_margin_so_so_inc=false; // Флаг увеличения уровня Margin StopOut this.m_is_change_margin_so_so_dec=false; // Флаг уменьшения уровня Margin StopOut //--- Гарантийная сумма по отложенным ордерам this.m_changed_margin_initial_value=0; // Величина изменения размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам this.m_is_change_margin_initial_inc=false; // Флаг изменения размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам больше, чем на величину прироста this.m_is_change_margin_initial_dec=false; // Флаг изменения размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам больше, чем на величину уменьшения //--- Гарантийная сумма по открытым позициям this.m_changed_margin_maintenance_value=0; // Величина изменения размера зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям this.m_is_change_margin_maintenance_inc=false; // Флаг изменения размера зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям this.m_is_change_margin_maintenance_dec=false; // Флаг изменения размера зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям //--- Активы this.m_changed_assets_value=0; // Величина изменения активов this.m_is_change_assets_inc=false; // Флаг изменения активов больше, чем на величину прироста this.m_is_change_assets_dec=false; // Флаг изменения активов больше, чем на величину уменьшения //--- Обязательства this.m_changed_liabilities_value=0; // Величина изменения обязательств this.m_is_change_liabilities_inc=false; // Флаг изменения обязательств больше, чем на величину прироста this.m_is_change_liabilities_dec=false; // Флаг изменения обязательств больше, чем на величину уменьшения //--- Заблокированные комиссии this.m_changed_comission_blocked_value=0; // Величина изменения заблокированных комиссий this.m_is_change_comission_blocked_inc=false; // Флаг изменения заблокированных комиссий больше, чем на величину прироста this.m_is_change_comission_blocked_dec=false; // Флаг изменения заблокированных комиссий больше, чем на величину уменьшения } //+------------------------------------------------------------------+
Метод инициализации контролируемых данных:
//+------------------------------------------------------------------+ //| Инициализирует переменные контролируемых данных аккаунта | //+------------------------------------------------------------------+ void CAccountsCollection::InitControlsParams(void) { //--- Баланс this.m_control_balance_inc=50; // Контролируемая величина прироста баланса this.m_control_balance_dec=50; // Контролируемая величина уменьшения баланса //--- Прибыль this.m_control_profit_inc=20; // Контролируемая величина прироста прибыли this.m_control_profit_dec=20; // Контролируемая величина уменьшения прибыли //--- Средства this.m_control_equity_inc=15; // Контролируемая величина прироста средств this.m_control_equity_dec=15; // Контролируемая величина уменьшения средств //--- Маржа this.m_control_margin_inc=1000; // Контролируемая величина прироста залоговых средств this.m_control_margin_dec=1000; // Контролируемая величина уменьшения залоговых средств //--- Свободная маржа this.m_control_margin_free_inc=1000; // Контролируемая величина прироста свободных средств this.m_control_margin_free_dec=1000; // Контролируемая величина уменьшения свободных средств //--- Уровень маржи this.m_control_margin_level_inc=10000; // Контролируемая величина прироста уровня свободных средств this.m_control_margin_level_dec=500; // Контролируемая величина уменьшения уровня свободных средств //--- Гарантийная сумма по отложенным ордерам this.m_control_margin_initial_inc=1000; // Контролируемая величина прироста размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам this.m_control_margin_initial_dec=1000; // Контролируемая величина уменьшения размера зарезервированных средств для обеспечения гарантийной суммы по отложенным ордерам //--- Гарантийная сумма по открытым позициям this.m_control_margin_maintenance_inc=1000; // Контролируемая величина прироста зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям this.m_control_margin_maintenance_dec=1000; // Контролируемая величина уменьшения зарезервированных средств для обеспечения минимальной суммы по всем открытым позициям //--- Активы this.m_control_assets_inc=1000; // Контролируемая величина прироста активов this.m_control_assets_dec=1000; // Контролируемая величина уменьшения активов //--- Обязательства this.m_control_liabilities_inc=1000; // Контролируемая величина прироста обязательств this.m_control_liabilities_dec=1000; // Контролируемая величина уменьшения обязательств //--- Заблокированные комиссии this.m_control_comission_blocked_inc=1000; // Контролируемая величина прироста заблокированных комиссий this.m_control_comission_blocked_dec=1000; // Контролируемая величина уменьшения заблокированных комиссий } //+------------------------------------------------------------------+
В данном методе мы просто инициализируем переменные значениями по умолчанию. При превышении свойствами значений, вписанных в эти переменные будет сгенерировано соответствующее событие аккаунта. Эти свойства можно будет также установить непосредственно вызовом соответствующих методов установки контролируемых свойств аккаунта.
Метод, проверяющий факт изменения свойств аккаунта, и заполняющий код события соответствующими изменению флагами:
//+------------------------------------------------------------------+ //| Проверяет изменения аккаунта, возвращает код изменения | //+------------------------------------------------------------------+ int CAccountsCollection::SetChangeCode(void) { this.m_change_code=ACCOUNT_EVENT_FLAG_NO_EVENT; if(this.m_struct_curr_account.trade_allowed!=this.m_struct_prev_account.trade_allowed) this.m_change_code+=ACCOUNT_EVENT_FLAG_TRADE_ALLOWED; if(this.m_struct_curr_account.trade_expert!=this.m_struct_prev_account.trade_expert) this.m_change_code+=ACCOUNT_EVENT_FLAG_TRADE_EXPERT; if(this.m_struct_curr_account.leverage-this.m_struct_prev_account.leverage!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_LEVERAGE; if(this.m_struct_curr_account.limit_orders-this.m_struct_prev_account.limit_orders!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_LIMIT_ORDERS; if(this.m_struct_curr_account.balance-this.m_struct_prev_account.balance!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_BALANCE; if(this.m_struct_curr_account.credit-this.m_struct_prev_account.credit!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_CREDIT; if(this.m_struct_curr_account.profit-this.m_struct_prev_account.profit!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_PROFIT; if(this.m_struct_curr_account.equity-this.m_struct_prev_account.equity!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_EQUITY; if(this.m_struct_curr_account.margin-this.m_struct_prev_account.margin!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN; if(this.m_struct_curr_account.margin_free-this.m_struct_prev_account.margin_free!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_FREE; if(this.m_struct_curr_account.margin_level-this.m_struct_prev_account.margin_level!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_LEVEL; if(this.m_struct_curr_account.margin_so_call-this.m_struct_prev_account.margin_so_call!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_SO_CALL; if(this.m_struct_curr_account.margin_so_so-this.m_struct_prev_account.margin_so_so!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_SO_SO; if(this.m_struct_curr_account.margin_initial-this.m_struct_prev_account.margin_initial!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_INITIAL; if(this.m_struct_curr_account.margin_maintenance-this.m_struct_prev_account.margin_maintenance!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_MARGIN_MAINTENANCE; if(this.m_struct_curr_account.assets-this.m_struct_prev_account.assets!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_ASSETS; if(this.m_struct_curr_account.liabilities-this.m_struct_prev_account.liabilities!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_LIABILITIES; if(this.m_struct_curr_account.comission_blocked-this.m_struct_prev_account.comission_blocked!=0) this.m_change_code+=ACCOUNT_EVENT_FLAG_COMISSION_BLOCKED; //--- returnthis.m_change_code; } //+------------------------------------------------------------------+
В методе сначала обнуляется код события, затем сравниваются значения контролируемых параметров аккаунта в структуре текущих данных и структуре прошлых данных. Если данные не равны, то к коду события добавляется соответствующий флаг.
Метод, устанавливающий тип события, и добавляющий событие в список изменений аккаунта:
//+------------------------------------------------------------------+ //| Устанавливает тип события объекта-аккаунта | //+------------------------------------------------------------------+ void CAccountsCollection::SetTypeEvent(void) { this.InitChangesParams(); ENUM_ACCOUNT_EVENT event=ACCOUNT_EVENT_NO_EVENT; //--- Изменение разрешения торговли на счёте if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_TRADE_ALLOWED)) { if(!this.m_struct_curr_account.trade_allowed) { this.m_is_change_trade_allowed_off=true; event=ACCOUNT_EVENT_TRADE_ALLOWED_OFF; this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed; } else { this.m_is_change_trade_allowed_on=true; event=ACCOUNT_EVENT_TRADE_ALLOWED_ON; this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed; } if(this.m_list_changes.Search(event)==WRONG_VALUE) this.m_list_changes.Add(event); } //--- Изменение разрешения автоторговли на счёте if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_TRADE_EXPERT)) { if(!this.m_struct_curr_account.trade_expert) { this.m_is_change_trade_expert_off=true; event=ACCOUNT_EVENT_TRADE_EXPERT_OFF; this.m_struct_prev_account.trade_expert=false; } else { this.m_is_change_trade_expert_on=true; event=ACCOUNT_EVENT_TRADE_EXPERT_ON; this.m_struct_prev_account.trade_expert=true; } if(this.m_list_changes.Search(event)==WRONG_VALUE) this.m_list_changes.Add(event); } //--- Изменение предоставленного плеча if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_LEVERAGE)) { this.m_changed_leverage_value=this.m_struct_curr_account.leverage-this.m_struct_prev_account.leverage; if(this.m_changed_leverage_value>0) { this.m_is_change_leverage_inc=true; event=ACCOUNT_EVENT_LEVERAGE_INC; } else { this.m_is_change_leverage_dec=true; event=ACCOUNT_EVENT_LEVERAGE_DEC; } if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.leverage=this.m_struct_curr_account.leverage; } //--- Изменение максимально допустимого количества действующих отложенных ордеров if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_LIMIT_ORDERS)) { this.m_changed_limit_orders_value=this.m_struct_curr_account.limit_orders-this.m_struct_prev_account.limit_orders; if(this.m_changed_limit_orders_value>0) { this.m_is_change_limit_orders_inc=true; event=ACCOUNT_EVENT_LIMIT_ORDERS_INC; } else { this.m_is_change_limit_orders_dec=true; event=ACCOUNT_EVENT_LIMIT_ORDERS_DEC; } if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.limit_orders=this.m_struct_curr_account.limit_orders; } //--- Изменение размера предоставленного кредита в валюте депозита if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_CREDIT)) { this.m_changed_credit_value=this.m_struct_curr_account.credit-this.m_struct_prev_account.credit; if(this.m_changed_credit_value>0) { this.m_is_change_credit_inc=true; event=ACCOUNT_EVENT_CREDIT_INC; } else { this.m_is_change_credit_dec=true; event=ACCOUNT_EVENT_CREDIT_DEC; } if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.credit=this.m_struct_curr_account.credit; } //--- Изменение уровня залоговых средств, при котором происходит MarginCall if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_SO_CALL)) { this.m_changed_margin_so_call_value=this.m_struct_curr_account.margin_so_call-this.m_struct_prev_account.margin_so_call; if(this.m_changed_margin_so_call_value>0) { this.m_is_change_margin_so_call_inc=true; event=ACCOUNT_EVENT_MARGIN_SO_CALL_INC; } else { this.m_is_change_margin_so_call_dec=true; event=ACCOUNT_EVENT_MARGIN_SO_CALL_DEC; } if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_so_call=this.m_struct_curr_account.margin_so_call; } //--- Изменение уровня залоговых средств, при достижении которого происходит StopOut if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_SO_SO)) { this.m_changed_margin_so_so_value=this.m_struct_curr_account.margin_so_so-this.m_struct_prev_account.margin_so_so; if(this.m_changed_margin_so_so_value>0) { this.m_is_change_margin_so_so_inc=true; event=ACCOUNT_EVENT_MARGIN_SO_SO_INC; } else { this.m_is_change_margin_so_so_dec=true; event=ACCOUNT_EVENT_MARGIN_SO_SO_DEC; } if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_so_so=this.m_struct_curr_account.margin_so_so; } //--- Изменение баланса больше заданной величины в +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_BALANCE)) { this.m_changed_balance_value=this.m_struct_curr_account.balance-this.m_struct_prev_account.balance; if(this.m_changed_balance_value>this.m_control_balance_inc) { this.m_is_change_balance_inc=true; event=ACCOUNT_EVENT_BALANCE_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.balance=this.m_struct_curr_account.balance; } elseif(this.m_changed_balance_value<-this.m_control_balance_dec) { this.m_is_change_balance_dec=true; event=ACCOUNT_EVENT_BALANCE_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.balance=this.m_struct_curr_account.balance; } } //--- Изменение профита больше заданной величины в +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_PROFIT)) { this.m_changed_profit_value=this.m_struct_curr_account.profit-this.m_struct_prev_account.profit; if(this.m_changed_profit_value>this.m_control_profit_inc) { this.m_is_change_profit_inc=true; event=ACCOUNT_EVENT_PROFIT_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.profit=this.m_struct_curr_account.profit; } elseif(this.m_changed_profit_value<-this.m_control_profit_dec) { this.m_is_change_profit_dec=true; event=ACCOUNT_EVENT_PROFIT_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.profit=this.m_struct_curr_account.profit; } } //--- Изменение собственных средств больше заданной величины в +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_EQUITY)) { this.m_changed_equity_value=this.m_struct_curr_account.equity-this.m_struct_prev_account.equity; if(this.m_changed_equity_value>this.m_control_equity_inc) { this.m_is_change_equity_inc=true; event=ACCOUNT_EVENT_EQUITY_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.equity=this.m_struct_curr_account.equity; } elseif(this.m_changed_equity_value<-this.m_control_equity_dec) { this.m_is_change_equity_dec=true; event=ACCOUNT_EVENT_EQUITY_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.equity=this.m_struct_curr_account.equity; } } //--- Изменение размера зарезервированных залоговых средств на счете в валюте депозита больше заданной величины в +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN)) { this.m_changed_margin_value=this.m_struct_curr_account.margin-this.m_struct_prev_account.margin; if(this.m_changed_margin_value>this.m_control_margin_inc) { this.m_is_change_margin_inc=true; event=ACCOUNT_EVENT_MARGIN_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin=this.m_struct_curr_account.margin; } elseif(this.m_changed_margin_value<-this.m_control_margin_dec) { this.m_is_change_margin_dec=true; event=ACCOUNT_EVENT_MARGIN_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin=this.m_struct_curr_account.margin; } } //--- Изменение размера средств на счете в валюте депозита, доступных для открытия позиции больше заданной величины в +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_FREE)) { this.m_changed_margin_free_value=this.m_struct_curr_account.margin_free-this.m_struct_prev_account.margin_free; if(this.m_changed_margin_free_value>this.m_control_margin_free_inc) { this.m_is_change_margin_free_inc=true; event=ACCOUNT_EVENT_MARGIN_FREE_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_free=this.m_struct_curr_account.margin_free; } elseif(this.m_changed_margin_free_value<-this.m_control_margin_free_dec) { this.m_is_change_margin_free_dec=true; event=ACCOUNT_EVENT_MARGIN_FREE_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_free=this.m_struct_curr_account.margin_free; } } //--- Изменение уровня залоговых средств на счете в процентах больше заданной величины в +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_LEVEL)) { this.m_changed_margin_level_value=this.m_struct_curr_account.margin_level-this.m_struct_prev_account.margin_level; if(this.m_changed_margin_level_value>this.m_control_margin_level_inc) { this.m_is_change_margin_level_inc=true; event=ACCOUNT_EVENT_MARGIN_LEVEL_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_level=this.m_struct_curr_account.margin_level; } elseif(this.m_changed_margin_level_value<-this.m_control_margin_level_dec) { this.m_is_change_margin_level_dec=true; event=ACCOUNT_EVENT_MARGIN_LEVEL_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_level=this.m_struct_curr_account.margin_level; } } //--- Изменение размера средств, зарезервированных на счёте, для обеспечения гарантийной суммы по всем отложенным ордерам больше заданной величины в +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_INITIAL)) { this.m_changed_margin_initial_value=this.m_struct_curr_account.margin_initial-this.m_struct_prev_account.margin_initial; if(this.m_changed_margin_initial_value>this.m_control_margin_initial_inc) { this.m_is_change_margin_initial_inc=true; event=ACCOUNT_EVENT_MARGIN_INITIAL_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_initial=this.m_struct_curr_account.margin_initial; } elseif(this.m_changed_margin_initial_value<-this.m_control_margin_initial_dec) { this.m_is_change_margin_initial_dec=true; event=ACCOUNT_EVENT_MARGIN_INITIAL_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_initial=this.m_struct_curr_account.margin_initial; } } //--- Изменение размера средств, зарезервированных на счёте, для обеспечения минимальной суммы по всем открытым позициям больше заданной величины в +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_MARGIN_MAINTENANCE)) { this.m_changed_margin_maintenance_value=this.m_struct_curr_account.margin_maintenance-this.m_struct_prev_account.margin_maintenance; if(this.m_changed_margin_maintenance_value>this.m_control_margin_maintenance_inc) { this.m_is_change_margin_maintenance_inc=true; event=ACCOUNT_EVENT_MARGIN_MAINTENANCE_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_maintenance=this.m_struct_curr_account.margin_maintenance; } elseif(this.m_changed_margin_maintenance_value<-this.m_control_margin_maintenance_dec) { this.m_is_change_margin_maintenance_dec=true; event=ACCOUNT_EVENT_MARGIN_MAINTENANCE_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.margin_maintenance=this.m_struct_curr_account.margin_maintenance; } } //--- Изменение текущего размера активов на счёте больше заданной величины в +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_ASSETS)) { this.m_changed_assets_value=this.m_struct_curr_account.assets-this.m_struct_prev_account.assets; if(this.m_changed_assets_value>this.m_control_assets_inc) { this.m_is_change_assets_inc=true; event=ACCOUNT_EVENT_ASSETS_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.assets=this.m_struct_curr_account.assets; } elseif(this.m_changed_assets_value<-this.m_control_assets_dec) { this.m_is_change_assets_dec=true; event=ACCOUNT_EVENT_ASSETS_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.assets=this.m_struct_curr_account.assets; } } //--- Изменение текущего размера обязательств на счёте больше заданной величины в +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_LIABILITIES)) { this.m_changed_liabilities_value=this.m_struct_curr_account.liabilities-this.m_struct_prev_account.liabilities; if(this.m_changed_liabilities_value>this.m_control_liabilities_inc) { this.m_is_change_liabilities_inc=true; event=ACCOUNT_EVENT_LIABILITIES_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.liabilities=this.m_struct_curr_account.liabilities; } elseif(this.m_changed_liabilities_value<-this.m_control_liabilities_dec) { this.m_is_change_liabilities_dec=true; event=ACCOUNT_EVENT_LIABILITIES_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.liabilities=this.m_struct_curr_account.liabilities; } } //--- Изменение текущей суммы заблокированных комиссий по счёту больше заданной величины в +/- if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_COMISSION_BLOCKED)) { this.m_changed_comission_blocked_value=this.m_struct_curr_account.comission_blocked-this.m_struct_prev_account.comission_blocked; if(this.m_changed_comission_blocked_value>this.m_control_comission_blocked_inc) { this.m_is_change_comission_blocked_inc=true; event=ACCOUNT_EVENT_COMISSION_BLOCKED_INC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.comission_blocked=this.m_struct_curr_account.comission_blocked; } elseif(this.m_changed_comission_blocked_value<-this.m_control_comission_blocked_dec) { this.m_is_change_comission_blocked_dec=true; event=ACCOUNT_EVENT_COMISSION_BLOCKED_DEC; if(this.m_list_changes.Search(event)==WRONG_VALUE && this.m_list_changes.Add(event)) this.m_struct_prev_account.comission_blocked=this.m_struct_curr_account.comission_blocked; } } } //+------------------------------------------------------------------+
В методе есть два типа логики определения событий:
- простое отслеживание разрешения/запрета или изменения/неизменения свойства,
- отслеживание изменения больше заданной величины как в сторону увеличения значения, так и в сторону его уменьшения.
Так как метод дотаточно объёмен, то рассмотрим его работу на примере двух типов определения событий аккаунта:
Сначала обнуляются все флаги и данные об изменениях и тип события устанавливается в ноль.
Затем для первого типа логики (на примере разрешения торговли на счёте):
- проверяем наличие флага изменения разрешения торговли на счёте в коде события
- если на данный момент торговля не разрешена — значит только что было отключено разрешение
- устанавливаем флаг запрета торговли на счёте
- устанавливаем событие "торговля на счёте запрещена"
- сохраняем в структуру прошлых данных текущее состояние данного свойства счёта для последующей проверки
- иначе, если на данный момент торговля разрешена
- устанавливаем флаг разрешения торговли на счёте
- устанавливаем событие "торговля на счёте разрешена"
- сохраняем в структуру прошлых данных текущее состояние данного свойства счёта для последующей проверки
- если такого события ещё нет в списке изменений
- добавляем событие в список
Для второго типа логики (на примере изменения суммы заблокированных комиссий):
- проверяем наличие флага изменения суммы заблокированных комиссий
- рассчитываем величину изменения суммы заблокированных комиссий
- если величина изменения больше контролируемой величины прироста
- устанавливаем флаг прироста суммы заблокированных комиссий
- устанавливаем событие "сумма заблокированных комиссий увеличена больше заданного значения"
- если такого события ещё нет в списке изменений и событие успешно добавлено в список
- сохраняем в структуру прошлых данных текущее состояние данного свойства счёта для последующей проверки
- иначе, если величина изменения больше контролируемой величины уменьшения
- устанавливаем флаг уменьшения суммы заблокированных комиссий
- устанавливаем событие "сумма заблокированных комиссий уменьшена больше заданного значения"
- если такого события ещё нет в списке изменений и событие успешно добавлено в список
- сохраняем в структуру прошлых данных текущее состояние данного свойства счёта для последующей проверки
В публичную секцию класса впишем методы, возвращающие код события аккаунта, список событий аккаунта, событие аккаунта по его индексу в списке; методы, устанавливающий и возвращающий символ, метод, возвращающий идентификатор графика управляющей программы, и метод, возвращающий описание события аккаунта. А так же добавим методы получения и установки параметров отслеживаемых изменений:
public: //--- Возвращает полный список-коллекцию аккаунтов "как есть" CArrayObj *GetList(void) { return &this.m_list_accounts; } //--- Возвращает список по выбранному (1) целочисленному, (2) вещественному и (3) строковому свойству, удовлетворяющему сравниваемому критерию CArrayObj *GetList(ENUM_ACCOUNT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByAccountProperty(this.GetList(),property,value,mode);} CArrayObj *GetList(ENUM_ACCOUNT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByAccountProperty(this.GetList(),property,value,mode);} CArrayObj *GetList(ENUM_ACCOUNT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByAccountProperty(this.GetList(),property,value,mode);} //--- Возвращает (1) индекс текущего объекта-аккаунта, (2) флаг произошедшего события в данных аккаунта, (3) тип события int IndexCurrentAccount(void) const { return this.m_index_current; } bool IsAccountEvent(void) const { return this.m_is_account_event; } //--- Возвращает (1) код события объекта-аккаунта, (2) список событий, (3) событие аккаунта по его номеру в списке int GetEventCode(void) const { return this.m_change_code; } CArrayInt *GetListChanges(void) { return &this.m_list_changes; } ENUM_ACCOUNT_EVENT GetEvent(constint shift=WRONG_VALUE); //--- (1) Устанавливает, (2) возвращает текущий символ void SetSymbol(conststring symbol) { this.m_symbol=symbol; } string GetSymbol(void) const { return this.m_symbol; } //--- Устанавливает идентификатор графика управляющей программы void SetChartID(constlong id) { this.m_chart_id=id; } //--- Конструктор, деструктор CAccountsCollection(); ~CAccountsCollection(); //--- Добавляет объект-аккаунт в список bool AddToList(CAccount* account); //--- (1) Сохраняет объекты-аккаунты из списка в файлы //--- (2) Загружает объекты-аккаунты из файлов в список bool SaveObjects(void); bool LoadObjects(void); //--- Возвращает описание события аккаунта string EventDescription(const ENUM_ACCOUNT_EVENT event); //--- Обновляет данные текущего аккаунта void Refresh(void); //--- Получение и установка параметров отслеживаемых изменений //--- Плечо: //--- (1) Величина изменения плеча, (2) Флаг увеличения плеча, (3) Флаг уменьшения плеча long GetValueChangedLeverage(void) const { return this.m_changed_leverage_value; } bool IsIncreaseLeverage(void) const { return this.m_is_change_leverage_inc; } bool IsDecreaseLeverage(void) const { return this.m_is_change_leverage_dec; } //--- Количество действующих отложенных ордеров: //--- (1) Величина изменения, (2) Флаг увеличения, (3) Флаг уменьшения int GetValueChangedLimitOrders(void) const { return this.m_changed_limit_orders_value; } bool IsIncreaseLimitOrders(void) const { return this.m_is_change_limit_orders_inc; } bool IsDecreaseLimitOrders(void) const { return this.m_is_change_limit_orders_dec; } //--- Торговля на счёте: //--- (1) Флаг разрешения торговли для текущего счета, (2) Флаг запрета торговли для текущего счета со стороны сервера bool IsOnTradeAllowed(void) const { return this.m_is_change_trade_allowed_on; } bool IsOffTradeAllowed(void) const { return this.m_is_change_trade_allowed_off; } //--- Автоторговля на счёте: //--- (1) Флаг разрешения торговли для эксперта, (2) Флаг запрета торговли для эксперта со стороны сервера bool IsOnTradeExpert(void) const { return this.m_is_change_trade_expert_on; } bool IsOffTradeExpert(void) const { return this.m_is_change_trade_expert_off; } //--- Баланс: //--- установка контролируемой величины (1) прироста, (2) уменьшения баланса //--- получение (3) величины изменения баланса, //--- получение флага изменения баланса больше, чем на величину (4) прироста, (5) уменьшения void SetControlBalanceInc(const double value) { this.m_control_balance_inc=::fabs(value); } void SetControlBalanceDec(const double value) { this.m_control_balance_dec=::fabs(value); } double GetValueChangedBalance(void) const { return this.m_changed_balance_value; } bool IsIncreaseBalance(void) const { return this.m_is_change_balance_inc; } bool IsDecreaseBalance(void) const { return this.m_is_change_balance_dec; } //--- Кредит: //--- получение (1) величины изменения кредита, (2) флага увеличения кредита, (3) флага уменьшения кредита double GetValueChangedCredit(void) const { return this.m_changed_credit_value; } bool IsIncreaseCredit(void) const { return this.m_is_change_credit_inc; } bool IsDecreaseCredit(void) const { return this.m_is_change_credit_dec; } //--- Профит: //--- установка контролируемой величины (1) прироста, (2) уменьшения прибыли //--- получение (3) величины изменения прибыли, //--- получение флага изменения прибыли больше, чем на величину (4) прироста, (5) уменьшения void SetControlProfitInc(const double value) { this.m_control_profit_inc=::fabs(value); } void SetControlProfitDec(const double value) { this.m_control_profit_dec=::fabs(value); } double GetValueChangedProfit(void) const { return this.m_changed_profit_value; } bool IsIncreaseProfit(void) const { return this.m_is_change_profit_inc; } bool IsDecreaseProfit(void) const { return this.m_is_change_profit_dec; } //--- Средства: //--- установка контролируемой величины (1) прироста, (2) уменьшения средств //--- получение (3) величины изменения средств, //--- получение флага изменения средств больше, чем на величину (4) прироста, (5) уменьшения void SetControlEquityInc(const double value) { this.m_control_equity_inc=::fabs(value); } void SetControlEquityDec(const double value) { this.m_control_equity_dec=::fabs(value); } double GetValueChangedEquity(void) const { return this.m_changed_equity_value; } bool IsIncreaseEquity(void) const { return this.m_is_change_equity_inc; } bool IsDecreaseEquity(void) const { return this.m_is_change_equity_dec; } //--- Маржа: //--- установка контролируемой величины (1) прироста, (2) уменьшения залоговых средств //--- получение (3) величины изменения залоговых средств, //--- получение флага изменения залоговых средств больше, чем на величину (4) прироста, (5) уменьшения void SetControlMarginInc(const double value) { this.m_control_margin_inc=::fabs(value); } void SetControlMarginDec(const double value) { this.m_control_margin_dec=::fabs(value); } double GetValueChangedMargin(void) const { return this.m_changed_margin_value; } bool IsIncreaseMargin(void) const { return this.m_is_change_margin_inc; } bool IsDecreaseMargin(void) const { return this.m_is_change_margin_dec; } //--- Свободная маржа: //--- установка контролируемой величины (1) прироста, (2) уменьшения свободных средств //--- получение (3) величины изменения свободных средств, //--- получение флага изменения свободных средств больше, чем на величину (4) прироста, (5) уменьшения void SetControlMarginFreeInc(const double value) { this.m_control_margin_free_inc=::fabs(value); } void SetControlMarginFreeDec(const double value) { this.m_control_margin_free_dec=::fabs(value); } double GetValueChangedMarginFree(void) const { return this.m_changed_margin_free_value; } bool IsIncreaseMarginFree(void) const { return this.m_is_change_margin_free_inc; } bool IsDecreaseMarginFree(void) const { return this.m_is_change_margin_free_dec; } //--- Уровень маржи: //--- установка контролируемой величины (1) прироста, (2) уменьшения уровня свободных средств //--- получение (3) величины изменения уровня свободных средств, //--- получение флага изменения уровня свободных средств больше, чем на величину (4) прироста, (5) уменьшения void SetControlMarginLevelInc(const double value) { this.m_control_margin_level_inc=::fabs(value); } void SetControlMarginLevelDec(const double value) { this.m_control_margin_level_dec=::fabs(value); } double GetValueChangedMarginLevel(void) const { return this.m_changed_margin_level_value; } bool IsIncreaseMarginLevel(void) const { return this.m_is_change_margin_level_inc; } bool IsDecreaseMarginLevel(void) const { return this.m_is_change_margin_level_dec; } //--- Margin Call: //--- получение (1) величины изменения Margin Call, (2) флага увеличения уровня Margin Call, (3) флага уменьшения уровня Margin Call double GetValueChangedMarginCall(void) const { return this.m_changed_margin_so_call_value; } bool IsIncreaseMarginCall(void) const { return this.m_is_change_margin_so_call_inc; } bool IsDecreaseMarginCall(void) const { return this.m_is_change_margin_so_call_dec; } //--- Margin StopOut: //--- получение (1) величины изменения Margin StopOut, (2) флага увеличения уровня Margin StopOut, (3) флага уменьшения уровня Margin StopOut double GetValueChangedMarginStopOut(void) const { return this.m_changed_margin_so_so_value; } bool IsIncreaseMarginStopOut(void) const { return this.m_is_change_margin_so_so_inc; } bool IsDecreasMarginStopOute(void) const { return this.m_is_change_margin_so_so_dec; } //--- Гарантийная сумма по отложенным ордерам: //--- установка контролируемой величины (1) прироста, (2) уменьшения размера зарезервированных средств гарантийной суммы по отложенным ордерам //--- получение (3) величины изменения уровня зарезервированных средств, //--- получение флага изменения уровня зарезервированных средств больше, чем на величину (4) прироста, (5) уменьшения void SetControlMarginInitialInc(const double value) { this.m_control_margin_initial_inc=::fabs(value); } void SetControlMarginInitialDec(const double value) { this.m_control_margin_initial_dec=::fabs(value); } double GetValueChangedMarginInitial(void) const { return this.m_changed_margin_initial_value; } bool IsIncreaseMarginInitial(void) const { return this.m_is_change_margin_initial_inc; } bool IsDecreaseMarginInitial(void) const { return this.m_is_change_margin_initial_dec; } //--- Гарантийная сумма по открытым позициям: //--- установка контролируемой величины (1) прироста, (2) уменьшения размера зарезервированных средств гарантийной суммы по открытым позициям //--- получение (3) величины изменения уровня зарезервированных средств, //--- получение флага изменения уровня зарезервированных средств больше, чем на величину (4) прироста, (5) уменьшения void SetControlMarginMaintenanceInc(const double value) { this.m_control_margin_maintenance_inc=::fabs(value); } void SetControlMarginMaintenanceDec(const double value) { this.m_control_margin_maintenance_dec=::fabs(value); } double GetValueChangedMarginMaintenance(void) const { return this.m_changed_margin_maintenance_value; } bool IsIncreaseMarginMaintenance(void) const { return this.m_is_change_margin_maintenance_inc; } bool IsDecreaseMarginMaintenance(void) const { return this.m_is_change_margin_maintenance_dec; } //--- Активы: //--- установка контролируемой величины (1) прироста, (2) уменьшения активов //--- получение (3) величины изменения уровня активов, //--- получение флага изменения уровня активов больше, чем на величину (4) прироста, (5) уменьшения void SetControlAssetsInc(const double value) { this.m_control_assets_inc=::fabs(value); } void SetControlAssetsDec(const double value) { this.m_control_assets_dec=::fabs(value); } double GetValueChangedAssets(void) const { return this.m_changed_assets_value; } bool IsIncreaseAssets(void) const { return this.m_is_change_assets_inc; } bool IsDecreaseAssets(void) const { return this.m_is_change_assets_dec; } //--- Обязательства: //--- установка контролируемой величины (1) прироста, (2) уменьшения обязательств //--- получение (3) величины изменения уровня обязательств, //--- получение флага изменения уровня обязательств больше, чем на величину (4) прироста, (5) уменьшения void SetControlLiabilitiesInc(const double value) { this.m_control_liabilities_inc=::fabs(value); } void SetControlLiabilitiesDec(const double value) { this.m_control_liabilities_dec=::fabs(value); } double GetValueChangedLiabilities(void) const { return this.m_changed_liabilities_value; } bool IsIncreaseLiabilities(void) const { return this.m_is_change_liabilities_inc; } bool IsDecreaseLiabilities(void) const { return this.m_is_change_liabilities_dec; } //--- Заблокированные комиссии: //--- установка контролируемой величины (1) прироста, (2) уменьшения заблокированных комиссий //--- получение (3) величины изменения уровня заблокированных комиссий, //--- получение флага изменения уровня заблокированных комиссий больше, чем на величину (4) прироста, (5) уменьшения void SetControlComissionBlockedInc(const double value) { this.m_control_comission_blocked_inc=::fabs(value); } void SetControlComissionBlockedDec(const double value) { this.m_control_comission_blocked_dec=::fabs(value); } double GetValueChangedComissionBlocked(void) const { return this.m_changed_comission_blocked_value; } bool IsIncreaseComissionBlocked(void) const { return this.m_is_change_comission_blocked_inc; } bool IsDecreaseComissionBlocked(void) const { return this.m_is_change_comission_blocked_dec; } }; //+------------------------------------------------------------------+
За пределами тела класса напишем реализацию метода, возвращающего событие аккаунта по его номеру в списке:
//+------------------------------------------------------------------+ //| Возвращает событие аккаунта по его номеру в списке | //+------------------------------------------------------------------+ ENUM_ACCOUNT_EVENT CAccountsCollection::GetEvent(constint shift=WRONG_VALUE) { int total=this.m_list_changes.Total(); if(total==0) return ACCOUNT_EVENT_NO_EVENT; int index=(shift<0 || shift>total-1 ? total-1 : total-shift-1); int event=this.m_list_changes.At(index); return ENUM_ACCOUNT_EVENT(event!=NULL ? event : ACCOUNT_EVENT_NO_EVENT); } //+------------------------------------------------------------------+
События в списке изменений свойств аккаунта располагаются в порядке их добавления — самое первое находится по индексу 0, а самое последнее — по индексу (размер_списка-1). Нам же нужно, чтобы пользователь мог получить искомое событие как в таймсерии — в нулевом индексе должно находиться самое последнее событие. Для этого в методе сделан расчёт индекса: index = (размер_списка - номер_искомого_события-1). При таком расчёте, если передать 0, то будет возвращено последнее событие в списке, если 1, то предпоследнее, если передать число, превышающее размер списка, то будет возвращено последнее событие.
Итак: в метод передаётся индекс искомого события.
Сначала проверяем количество событий в списке, и если их нет, то возвращаем отсутствие события.
Далее проверяем индекс искомого события, и если переданное значение меньше нуля, или выходит за пределы размера массива, то индекс будет указывать на последнее событие в списке, иначе — рассчитываем индекс события в списке в соответствии с правилом: если в метод передан 0, то значит хотим получить последнее событие (как в таймсерии), если 1 — то предпоследнее, и т.д. Либо, если необходимо получить последнее событие, то можно передать в качестве входного параметра индекса значение -1.
Далее получаем событие из списка по рассчитанному индексу и возвращаем его.
Если событие получить не удалось, то возвращается NULL, а это значит, что прежде, чем использовать результат работы метода, необходимо проверить его на валидность.
Напишем реализацию метода, возвращающего описание события аккаунта:
//+------------------------------------------------------------------+ //| Возвращает описание события аккаунта | //+------------------------------------------------------------------+ string CAccountsCollection::EventDescription(const ENUM_ACCOUNT_EVENT event) { int total=this.m_list_accounts.Total(); if(total==0) return(DFUN+TextByLanguage("Ошибка. Список изменений пуст","Error. List of changes is empty")); CAccount* account=this.m_list_accounts.At(this.m_index_current); if(account==NULL) return(DFUN+TextByLanguage("Ошибка. Не удалось получить данные аккаунта","Error. Failed to get account data")); constint dg=(account.MarginSOMode()==ACCOUNT_STOPOUT_MODE_MONEY ? (int)account.CurrencyDigits() : 2); conststring curency=" "+account.Currency(); conststring mode_lev=(account.IsPercentsForSOLevels() ? "%" : " "+curency); return ( event==ACCOUNT_EVENT_NO_EVENT ? TextByLanguage("Нет события","No event") : event==ACCOUNT_EVENT_TRADE_ALLOWED_ON ? TextByLanguage("Торговля на счёте разрешена","Trading on the account is allowed now") : event==ACCOUNT_EVENT_TRADE_ALLOWED_OFF ? TextByLanguage("Торговля на счёте запрещена","Trading on the account is prohibited now") : event==ACCOUNT_EVENT_TRADE_EXPERT_ON ? TextByLanguage("Автоторговля на счёте разрешена","Autotrading on the account is allowed now") : event==ACCOUNT_EVENT_TRADE_EXPERT_OFF ? TextByLanguage("Автоторговля на счёте запрещена","Autotrade on the account is prohibited now") : event==ACCOUNT_EVENT_LEVERAGE_INC ? TextByLanguage("Плечо увеличено на ","Leverage increased by ")+(string)this.GetValueChangedLeverage()+" (1:"+(string)account.Leverage()+")" : event==ACCOUNT_EVENT_LEVERAGE_DEC ? TextByLanguage("Плечо уменьшено на ","Leverage decreased by ")+(string)this.GetValueChangedLeverage()+" (1:"+(string)account.Leverage()+")" : event==ACCOUNT_EVENT_LIMIT_ORDERS_INC ? TextByLanguage("Максимально допустимое количество действующих отложенных ордеров увеличено на","Maximum allowable number of active pending orders increased by ")+(string)this.GetValueChangedLimitOrders()+" ("+(string)account.LimitOrders()+")" : event==ACCOUNT_EVENT_LIMIT_ORDERS_DEC ? TextByLanguage("Максимально допустимое количество действующих отложенных ордеров уменьшено на","Maximum allowable number of active pending orders decreased by ")+(string)this.GetValueChangedLimitOrders()+" ("+(string)account.LimitOrders()+")" : event==ACCOUNT_EVENT_BALANCE_INC ? TextByLanguage("Баланс счёта увеличен на ","Account balance increased by ")+::DoubleToString(this.GetValueChangedBalance(),dg)+curency+" ("+::DoubleToString(account.Balance(),dg)+curency+")" : event==ACCOUNT_EVENT_BALANCE_DEC ? TextByLanguage("Баланс счёта уменьшен на ","Account balance decreased by ")+::DoubleToString(this.GetValueChangedBalance(),dg)+curency+" ("+::DoubleToString(account.Balance(),dg)+curency+")" : event==ACCOUNT_EVENT_EQUITY_INC ? TextByLanguage("Средства увеличены на ","Equity increased by ")+::DoubleToString(this.GetValueChangedEquity(),dg)+curency+" ("+::DoubleToString(account.Equity(),dg)+curency+")" : event==ACCOUNT_EVENT_EQUITY_DEC ? TextByLanguage("Средства уменьшены на ","Equity decreased by ")+::DoubleToString(this.GetValueChangedEquity(),dg)+curency+" ("+::DoubleToString(account.Equity(),dg)+curency+")" : event==ACCOUNT_EVENT_PROFIT_INC ? TextByLanguage("Текущая прибыль счёта увеличена на ","Account current profit increased by ")+::DoubleToString(this.GetValueChangedProfit(),dg)+curency+" ("+::DoubleToString(account.Profit(),dg)+curency+")" : event==ACCOUNT_EVENT_PROFIT_DEC ? TextByLanguage("Текущая прибыль счёта уменьшена на ","Account current profit decreased by ")+::DoubleToString(this.GetValueChangedProfit(),dg)+curency+" ("+::DoubleToString(account.Profit(),dg)+curency+")" : event==ACCOUNT_EVENT_CREDIT_INC ? TextByLanguage("Предоставленный кредит увеличен на ","Credit increased by ")+::DoubleToString(this.GetValueChangedCredit(),dg)+curency+" ("+::DoubleToString(account.Credit(),dg)+curency+")" : event==ACCOUNT_EVENT_CREDIT_DEC ? TextByLanguage("Предоставленный кредит уменьшен на ","Credit decreased by ")+::DoubleToString(this.GetValueChangedCredit(),dg)+curency+" ("+::DoubleToString(account.Credit(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_INC ? TextByLanguage("Залоговые средства увеличены на ","Margin increased by ")+::DoubleToString(this.GetValueChangedMargin(),dg)+curency+" ("+::DoubleToString(account.Margin(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_DEC ? TextByLanguage("Залоговые средства уменьшены на ","Margin decreased by ")+::DoubleToString(this.GetValueChangedMargin(),dg)+curency+" ("+::DoubleToString(account.Margin(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_FREE_INC ? TextByLanguage("Свободные средства увеличены на ","Free margin increased by ")+::DoubleToString(this.GetValueChangedMarginFree(),dg)+curency+" ("+::DoubleToString(account.MarginFree(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_FREE_DEC ? TextByLanguage("Свободные средства уменьшены на ","Free margin decreased by ")+::DoubleToString(this.GetValueChangedMarginFree(),dg)+curency+" ("+::DoubleToString(account.MarginFree(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_LEVEL_INC ? TextByLanguage("Уровень залоговых средств увеличен на ","Margin level increased by ")+::DoubleToString(this.GetValueChangedMarginLevel(),dg)+"%"+" ("+::DoubleToString(account.MarginLevel(),dg)+"%)" : event==ACCOUNT_EVENT_MARGIN_LEVEL_DEC ? TextByLanguage("Уровень залоговых средств уменьшен на ","Margin level decreased by ")+::DoubleToString(this.GetValueChangedMarginLevel(),dg)+"%"+" ("+::DoubleToString(account.MarginLevel(),dg)+"%)" : event==ACCOUNT_EVENT_MARGIN_INITIAL_INC ? TextByLanguage("Гарантийная сумма по отложенным ордерам увеличена на ","Guarantee summ for pending orders increased by ")+::DoubleToString(this.GetValueChangedMarginInitial(),dg)+curency+" ("+::DoubleToString(account.MarginInitial(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_INITIAL_DEC ? TextByLanguage("Гарантийная сумма по отложенным ордерам уменьшена на ","Guarantee summ for pending orders decreased by ")+::DoubleToString(this.GetValueChangedMarginInitial(),dg)+curency+" ("+::DoubleToString(account.MarginInitial(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_MAINTENANCE_INC ? TextByLanguage("Гарантийная сумма по позициям увеличена на ","Guarantee summ for positions increased by ")+::DoubleToString(this.GetValueChangedMarginMaintenance(),dg)+curency+" ("+::DoubleToString(account.MarginMaintenance(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_MAINTENANCE_DEC ? TextByLanguage("Гарантийная сумма по позициям уменьшена на ","Guarantee summ for positions decreased by ")+::DoubleToString(this.GetValueChangedMarginMaintenance(),dg)+curency+" ("+::DoubleToString(account.MarginMaintenance(),dg)+curency+")" : event==ACCOUNT_EVENT_MARGIN_SO_CALL_INC ? TextByLanguage("Увеличен уровень Margin Call на ","Increased Margin Call level by ")+::DoubleToString(this.GetValueChangedMarginCall(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOCall(),dg)+mode_lev+")" : event==ACCOUNT_EVENT_MARGIN_SO_CALL_DEC ? TextByLanguage("Уменьшен уровень Margin Call на ","Decreased Margin Call level by ")+::DoubleToString(this.GetValueChangedMarginCall(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOCall(),dg)+mode_lev+")" : event==ACCOUNT_EVENT_MARGIN_SO_SO_INC ? TextByLanguage("Увеличен уровень Stop Out на ","Increased Margin Stop Out level by ")+::DoubleToString(this.GetValueChangedMarginStopOut(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOSO(),dg)+mode_lev+")" : event==ACCOUNT_EVENT_MARGIN_SO_SO_DEC ? TextByLanguage("Уменьшен уровень Stop Out на ","Decreased Margin Stop Out level by ")+::DoubleToString(this.GetValueChangedMarginStopOut(),dg)+mode_lev+" ("+::DoubleToString(account.MarginSOSO(),dg)+mode_lev+")" : event==ACCOUNT_EVENT_ASSETS_INC ? TextByLanguage("Размер активов увеличен на ","Assets increased by ")+::DoubleToString(this.GetValueChangedAssets(),dg)+" ("+::DoubleToString(account.Assets(),dg)+")" : event==ACCOUNT_EVENT_ASSETS_DEC ? TextByLanguage("Размер активов уменьшен на ","Assets decreased by ")+::DoubleToString(this.GetValueChangedAssets(),dg)+" ("+::DoubleToString(account.Assets(),dg)+")" : event==ACCOUNT_EVENT_LIABILITIES_INC ? TextByLanguage("Размер обязательств увеличен на ","Liabilities increased by ")+::DoubleToString(this.GetValueChangedLiabilities(),dg)+" ("+::DoubleToString(account.Liabilities(),dg)+")" : event==ACCOUNT_EVENT_LIABILITIES_DEC ? TextByLanguage("Размер обязательств уменьшен на ","Liabilities decreased by ")+::DoubleToString(this.GetValueChangedLiabilities(),dg)+" ("+::DoubleToString(account.Liabilities(),dg)+")" : event==ACCOUNT_EVENT_COMISSION_BLOCKED_INC ? TextByLanguage("Размер заблокированных комиссий увеличен на ","Blocked comissions increased by ")+::DoubleToString(this.GetValueChangedComissionBlocked(),dg)+" ("+::DoubleToString(account.ComissionBlocked(),dg)+")" : event==ACCOUNT_EVENT_COMISSION_BLOCKED_DEC ? TextByLanguage("Размер заблокированных комиссий уменьшен на ","Blocked comissions decreased by ")+::DoubleToString(this.GetValueChangedComissionBlocked(),dg)+" ("+::DoubleToString(account.ComissionBlocked(),dg)+")" : ::EnumToString(event) ); } //+------------------------------------------------------------------+
Здесь: в метод передаётся событие аккаунта, описание которого необходимо получить. Проверяем размер списка объектов-аккаунтов, и если он пуст, то возвращаем описание ошибки. Так как мы можем отслеживать только события текущего аккаунта, то получаем текущий объект-аккаунт из списка аккаунтов по индексу текущего объекта-аккаунта. Если объект получить не удалось, то так же возвращаем описание ошибки.
Далее получаем необходимые свойства аккаунта для корректного вывода описания события, проверяем событие и возвращаем его описание.
В конструкторе класса, в его списке инициализации инициализируем переменные символа и идентификатора графика управляющей программы значениями по умолчанию — текущий символ и текущий график, очищаем структуру тика, которая потребуется нам для определения времени события, и инициализируем изменяемые и контролируемые параметры аккаунта:
//+------------------------------------------------------------------+ //| Конструктор | //+------------------------------------------------------------------+ CAccountsCollection::CAccountsCollection(void) : m_folder_name(DIRECTORY+"Accounts"), m_is_account_event(false), m_symbol(::Symbol()), m_chart_id(::ChartID()) { this.m_list_accounts.Clear(); this.m_list_accounts.Sort(SORT_BY_ACCOUNT_LOGIN); this.m_list_accounts.Type(COLLECTION_ACCOUNT_ID); ::ZeroMemory(this.m_struct_prev_account); ::ZeroMemory(this.m_tick); this.InitChangesParams(); this.InitControlsParams(); //--- Создание папки хранения файлов аккаунтов ::ResetLastError(); if(!::FolderCreate(this.m_folder_name,FILE_COMMON)) Print(DFUN,TextByLanguage("Не удалось создать папку хранения файлов. Ошибка ","Could not create file storage folder. Error "),::GetLastError()); //--- Создание и добавление в список объекта-аккаунта текущего счёта CAccount* account=new CAccount(); if(account!=NULL) { if(!this.AddToList(account)) { Print(DFUN_ERR_LINE,TextByLanguage("Ошибка. Не удалось добавить текущий объект-аккаунт в список-коллекцию.","Error. Failed to add current account object to collection list.")); delete account; } else account.PrintShort(); } else Print(DFUN,TextByLanguage("Ошибка. Не удалось создать объект-аккаунт с данными текущего счёта.","Error. Failed to create an account object with current account data.")); //--- Загрузка объектов-аккаунтов из файлов в коллекцию this.LoadObjects(); //--- Сохранение индекса текущего аккаунта this.m_index_current=this.Index(); } //+------------------------------------------------------------------+
И наконец, впишем в метод обновления данных аккаунта отслеживание изменений его свойств:
//+------------------------------------------------------------------+ //| Обновляет данные текущего аккаунта | //+------------------------------------------------------------------+ void CAccountsCollection::Refresh(void) { this.m_is_account_event=false; if(this.m_index_current==WRONG_VALUE) return; CAccount* account=this.m_list_accounts.At(this.m_index_current); if(account==NULL) return; ::ZeroMemory(this.m_struct_curr_account); this.SetAccountsParams(account); //--- Первый запуск if(!this.m_struct_prev_account.login) { this.m_struct_prev_account=this.m_struct_curr_account; return; } //--- Если хэш-сумма аккаунта изменилась if(this.m_struct_curr_account.hash_sum!=this.m_struct_prev_account.hash_sum) { this.m_change_code=this.SetChangeCode(); this.SetTypeEvent(); int total=this.m_list_changes.Total(); if(total>0) { this.m_is_account_event=true; for(int i=0;i<total;i++) { ENUM_ACCOUNT_EVENT event=this.GetEvent(i); if(event==NULL || !::SymbolInfoTick(this.m_symbol,this.m_tick)) continue; string sparam=TimeMSCtoString(this.m_tick.time_msc)+": "+this.EventDescription(event); Print(sparam); ::EventChartCustom(this.m_chart_id,(ushort)event,this.m_tick.time_msc,(double)i,sparam); } } this.m_struct_prev_account.hash_sum=this.m_struct_curr_account.hash_sum; } } //+------------------------------------------------------------------+Первым делом сбросим флаг события аккаунта. Так как мы удалили метод SavePrevValues(), то вместо него впишем строку, которая была прописана в удалённом методе — сохранение структуры текущих данных в структуре прошлых данных при первом запуске. При изменении хеш-суммы, сразу же проверим и установим код события и тип произошедшего события.
В методе установки типа события, в список изменений вносятся сразу все события, которые произошли одновременно в свойствах счёта. Поэтому мы сначала проверим размер списка изменений, и если он не пустой, то установим флаг произошедшего изменения, и далее в цикле по данным списка получаем событие, устанавливаем его строковое описание, состоящее из времени в милисекундах и описания события, затем временно, и только для проверки (далее заменим это, и все остальные системные сообщения библиотеки на вывод в журнал только при разрешении логирования) распечатываем в журнал описание события, и наконец, отправляем событие в управляющую программу при помощи EventChartCustom().
В параметрах функции EventChartCustom() передаём:
- в event_id передаём событие,
- в lparam — время события в милисекундах
- в dparam передаём индекс события в списке одновременно произошедших изменений аккаунта
- в sparam — строковое описание события
В самом конце метода обязательно сохраняем текущую хеш-сумму как прошлую для последующей проверки.
Доработка класса CAccountsCollection на этом завершена.
Теперь перейдём к классу CEngine — всё у нас управляется и начинается из него, и впишем всё необходимое для работы с событиями аккаунта.
В приватной секции класса впишем переменные для хранения флага события изменения свойств аккаунта и для хранения последнего события, произошедшего на счёте. А в публичной секции впишем методы, возвращающие список событий аккаунта, произошедших одновременно, и последнее событие аккаунта:
//+------------------------------------------------------------------+ //| Класс-основа библиотеки | //+------------------------------------------------------------------+ class CEngine : public CObject { private: CHistoryCollection m_history; // Коллекция исторических ордеров и сделок CMarketCollection m_market; // Коллекция рыночных ордеров и сделок CEventsCollection m_events; // Коллекция событий CAccountsCollection m_accounts; // Коллекция аккаунтов CArrayObj m_list_counters; // Список счётчиков таймера 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(constint id) const; //--- Возвращает (1) флаг первого запуска, (2) факт наличия флага в торговом событии bool IsFirstStart(void); //--- Работа с событиями (1) ордеров, сделок и позиций, (2) аккаунтов void TradeEventsControl(void); void AccountEventsControl(void); //--- Возвращает последний (1) рыночный отложенный ордер, (2) маркет-ордер, (3) последнюю позицию, (4) позицию по тикету COrder* GetLastMarketPending(void); COrder* GetLastMarketOrder(void); COrder* GetLastPosition(void); COrder* GetPosition(constulong ticket); //--- Возвращает последний (1) удалённый отложенный ордер, (2) исторический маркет-ордер, (3) исторический ордер (маркет или отложенный) по его тикету COrder* GetLastHistoryPending(void); COrder* GetLastHistoryOrder(void); COrder* GetHistoryOrder(constulong ticket); //--- Возвращает (1) первый и (2) последний исторический маркет-ордер из списка всех ордеров позиции, (3) последнюю сделку COrder* GetFirstOrderPosition(constulong position_id); COrder* GetLastOrderPosition(constulong 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(constulong position_id); //--- Возвращает список (1) аккаунтов, (2) событий аккаунтов CArrayObj* GetListAllAccounts(void) { returnthis.m_accounts.GetList(); } CArrayInt* GetListAccountEvents(void) { returnthis.m_accounts.GetListChanges(); } //--- Возвращает список событий ордеров, сделок и позиций CArrayObj* GetListAllOrdersEvents(void) { returnthis.m_events.GetList(); } //--- Сбрасывает последнее торговое событие void ResetLastTradeEvent(void) { this.m_events.ResetLastTradeEvent(); } //--- Возвращает (1) последнее торговое событие, (2) последнее событие в свойствах счёта, (3) флаг счёта-хедж, (4) флаг работы в тестере ENUM_TRADE_EVENT LastTradeEvent(void) const { returnthis.m_last_trade_event; } ENUM_ACCOUNT_EVENT LastAccountEvent(void) const { returnthis.m_last_account_event; } bool IsHedge(void) const { returnthis.m_is_hedge; } bool IsTester(void) const { returnthis.m_is_tester; } //--- Создаёт счётчик таймера void CreateCounter(constint id,constulong frequency,constulong pause); //--- Таймер void OnTimer(void); //--- Конструктор/Деструктор CEngine(); ~CEngine(); }; //+------------------------------------------------------------------+
В конструкторе класса, в его списке инициализации пропишем инициализацию последнего события аккаунта:
//+------------------------------------------------------------------+ //| CEngine конструктор | //+------------------------------------------------------------------+ CEngine::CEngine() : m_first_start(true),m_last_trade_event(TRADE_EVENT_NO_EVENT),m_last_account_event(ACCOUNT_EVENT_NO_EVENT) {
Допишем метод AccountEventsControl(), который ранее у нас лишь вызывал метод Refresh() класса-коллекции аккаунтов:
//+------------------------------------------------------------------+ //| Проверка событий аккаунта | //+------------------------------------------------------------------+ void CEngine::AccountEventsControl(void) { //--- Проверка изменений свойств аккаунта и установка флага событий изменения аккаунта this.m_accounts.Refresh(); this.m_is_account_event=this.m_accounts.IsAccountEvent(); //--- Если есть изменения свойств аккаунта if(this.m_is_account_event) { //--- Получаем последнее событие изменения свойств аккаунта this.m_last_account_event=this.m_accounts.GetEvent(); } } //+------------------------------------------------------------------+
Здесь всё просто — сначала обновляем данные аккаунта, и если есть какое-либо изменение свойств аккаунта, просто записываем в переменную последнее событие. Все остальные данные о событии будем извлекать в управляющей программе, работающей на основе библиотеки.
Тест событий аккаунта
Для тестирования событий аккаунта, в принципе, мы можем использовать советник из прошлой статьи, так как библиотека сама находит все изменения свойств аккаунта, отправляет об этом сообщение в события графика и распечатывает в журнале описание произошедшего события аккаунта.
Но давайте попробуем немного выйти из "песочницы" библиотеки и обработать некоторые события аккаунта в программе, например — увеличение размера собственных средств.
Да, сейчас библиотека пока является "программой в самой себе", и доступ к её возможностям извне сильно ограничен. Но это лишь до той поры, пока мы занимаемся сбором и обработкой необходимых данных — библиотека распечатывает в журнал различные события лишь для тестовых проверок правильности работы создаваемых классов и собираемых данных и отслеживаемых ею событий. Далее мы организуем простой и удобный доступ к любым имеющимся данным библиотеки, и тогда возможности их получения из программы сильно облегчатся.
Для возможности получения данных об изменениях свойств аккаунта уже сейчас, внесём небольшие правки в класс CEngine — нам потребуется получить доступ к объекту текущего аккаунта и к событиям текущего аккаунта.
Для этого допишем в файле Engine.mqh, в публичной секции класса CEngine необходимые методы:
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(constulong 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);
Здесь мы добавили метод получения события аккаунта по его индексу в списке изменений, метод получения текущего объекта-аккаунта и метод получения описания события аккаунта.
Метод получения события аккаунта по индексу просто возвращает результат работы метода GetEvent() класса-коллекции аккаунтов (ранее мы его рассматривали).
В конце листинга впишем реализацию метода получения текущего объекта-аккаунта:
//+------------------------------------------------------------------+ //| Возвращает текущий аккаунт | //+------------------------------------------------------------------+ CAccount* CEngine::GetAccountCurrent(void) { int index=this.m_accounts.IndexCurrentAccount(); if(index==WRONG_VALUE) return NULL; CArrayObj* list=this.m_accounts.GetList(); return(list!=NULL ? (list.At(index)!=NULL ? list.At(index) : NULL) : NULL); } //+------------------------------------------------------------------+
Сначала получаем индекс текущего аккаунта из класса-коллекции аккаунтов. Если индекс не получен, то возвращаем NULL. Затем получаем полный список аккаунтов и возвращаем нужный нам текущий аккаунт по его индексу в списке аккаунтов. При ошибке получения списка или аккаунта — возвращаем NULL.
И напишем реализацию метода, возвращающего описание события аккаунта:
//+------------------------------------------------------------------+ //| Возвращает описание события аккаунта | //+------------------------------------------------------------------+ string CEngine::GetAccountEventDescription(ENUM_ACCOUNT_EVENT event) { return this.m_accounts.EventDescription(event); } //+------------------------------------------------------------------+
Метод возвращает результат работы метода класса-коллекции аккаунтов, возвращающего описание события аккаунта.
Для тестирования событий аккаунта возьмём советник из прошлой статьи \MQL5\Experts\TestDoEasy\Part12\TestDoEasyPart12_2.mq5 и сохраним его под именем TestDoEasyPart13.mq5 в новой папке \MQL5\Experts\TestDoEasy\Part13.
Сразу же удалим входной параметр
inputbool InpFullProperties = false;// Show full accounts properties
и из обработчика OnInit() удалим быструю проверку коллекции аккаунтов:
//--- Быстрая проверка коллекции объектов-аккаунтов CArrayObj* list=engine.GetListAllAccounts(); if(list!=NULL) { int total=list.Total(); if(total>0) Print("\n",TextByLanguage("=========== Список сохранённых аккаунтов ===========","=========== List of saved accounts ===========")); for(int i=0;i<total;i++) { CAccount* account=list.At(i); if(account==NULL) continue; Sleep(100); if(InpFullProperties) account.Print(); else account.PrintShort(); } } //---
К сведению:
так как мы изменили структуру объекта-аккаунта (изменили размеры uchar-массивов для хранения строковых свойств аккаунта и добавили ещё одно целочисленное свойство), то все ранее сохранённые файлы объектов-аккаунтов теперь не будут загружаться правильно. Если они есть в общей папке терминалов в каталоге \Files\DoEasy\Accounts\, то их все необходимо удалить перед запуском этого тестового советника — они будут созданы заново при переключениях со счёта на счёт с уже новым размером структуры объектов.
Обработчик OnInit() теперь выглядит так:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Вызов данной функции выводит в журнал список констант перечисления, //--- заданного в файле DELib.mqh в строках 22 и 25, для проверки корректности констант //EnumNumbersTest(); //--- Установка глобальных переменных советника prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_"; for(int i=0;i<TOTAL_BUTT;i++) { butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i); butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i); } lot=NormalizeLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0)); magic_number=InpMagic; stoploss=InpStopLoss; takeprofit=InpTakeProfit; distance_pending=InpDistance; distance_stoplimit=InpDistanceSL; slippage=InpSlippage; trailing_stop=InpTrailingStop*Point(); trailing_step=InpTrailingStep*Point(); trailing_start=InpTrailingStart; stoploss_to_modify=InpStopLossModify; takeprofit_to_modify=InpTakeProfitModify; //--- Проверка и удаление неудалённых графических объектов советника if(IsPresentObects(prefix)) ObjectsDeleteAll(0,prefix); //--- Создание панели кнопок if(!CreateButtons(InpButtShiftX,InpButtShiftY)) returnINIT_FAILED; //--- Установка состояния кнопки активизации трейлингов ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on); //--- Установка параметров торгового класса CTrade #ifdef __MQL5__ trade.SetDeviationInPoints(slippage); trade.SetExpertMagicNumber(magic_number); trade.SetTypeFillingBySymbol(Symbol()); trade.SetMarginMode(); trade.LogLevel(LOG_LEVEL_NO); #endif //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
Для обработки всех событий, приходящих от библиотеки в программу, и чтобы не засорять штатный OnChartEvent(), сделаем отдельный обработчик: OnDoEasyEvent(), и уже в нём будем разбирать все полученные события. В чём ещё плюс — код станет более читаем и, что не менее важно — мы сможем обрабатывать события в тестере, что нам сейчас как раз и нужно — мы собрались обрабатывать событие аккаунта "увеличение собственных средств выше заданного значения прироста", а для этого — куда быстрее и проще всё проверить в тестере.
Но по порядку.
Допишем в обработчике OnTick() необходимый функционал для обработки событий аккаунта:
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Инициализация последних событий static ENUM_TRADE_EVENT last_trade_event=WRONG_VALUE; static ENUM_ACCOUNT_EVENT last_account_event=WRONG_VALUE; //--- Если работа в тестере if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(); PressButtonsControl(); } //--- Если последнее торговое событие изменилось if(engine.LastTradeEvent()!=last_trade_event) { last_trade_event=engine.LastTradeEvent(); Comment("\nLast trade event: ",EnumToString(last_trade_event)); } //--- Если последнее событие аккаунта изменилось if(engine.LastAccountEvent()!=last_account_event) { last_account_event=engine.LastAccountEvent(); //--- Если это тестер if(MQLInfoInteger(MQL_TESTER)) { //--- Получим список всех событий аккаунта, произошедших одновременно CArrayInt* list=engine.GetListAccountEvents(); if(list!=NULL) { //--- В цикле получаем очередное событие int total=list.Total(); for(int i=0;i<total;i++) { ENUM_ACCOUNT_EVENT event=(ENUM_ACCOUNT_EVENT)list.At(i); if(event==NULL) continue; string sparam=engine.GetAccountEventDescription(event); long lparam=TimeCurrent()*1000; double dparam=(double)i; //--- Отправляем событие в обработчик событий OnDoEasyEvent(CHARTEVENT_CUSTOM+event,lparam,dparam,sparam); } } } Comment("\nLast account event: ",EnumToString(last_account_event)); } //--- Если установлен флаг трейлинга if(trailing_on) { TrailingPositions(); TrailingOrders(); } } //+------------------------------------------------------------------+
Здесь: мы ввели новую переменную, хранящую тип последнего события аккаунта. Проверяем её текущее состояние по отношению к типу последнего события, возвращаемого классом CAccountsCollection. Если состояние изменилось — значит было событие аккаунта. Далее только для тестера — получаем в цикле по списку событий аккаунта, произошедших одновременно, очередное событие и отправляем его в обработчик событий библиотеки. В листинге прописаны в комментариях все действия по получению событий и отправке их в обработчик. Отличием работы для тестера является то, что здесь мы не можем получить доступ к данным о времени события в милисекундах. Поэтому просто отправляем текущее время * 1000.
Теперь допишем обработчик событий OnChartEvent():
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { if(MQLInfoInteger(MQL_TESTER)) return; if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,"BUTT_")>0) { PressButtonEvents(sparam); } //--- Событие библиотеки DoEasy if(id>=CHARTEVENT_CUSTOM) { OnDoEasyEvent(id,lparam,dparam,sparam); } } //+------------------------------------------------------------------+
Здесь мы дописали вызов обработчика событий библиотеки в случае, если идентификатор события указывает на событие, пришедшее из библиотеки.
И наконец, напишем обработчик событий библиотеки:
//+------------------------------------------------------------------+ //| Обработка событий библиотеки DoEasy | //+------------------------------------------------------------------+ void OnDoEasyEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { int idx=id-CHARTEVENT_CUSTOM; string event="::"+string(idx); int digits=Digits(); //--- Обработка торговых событий if(idx<TRADE_EVENTS_NEXT_CODE) { event=EnumToString((ENUM_TRADE_EVENT)ushort(idx)); digits=(int)SymbolInfoInteger(sparam,SYMBOL_DIGITS); } //--- Обработка событий аккаунта else if(idx<ACCOUNT_EVENTS_NEXT_CODE) { event=EnumToString((ENUM_ACCOUNT_EVENT)ushort(idx)); digits=0; //--- если это увеличение средств if((ENUM_ACCOUNT_EVENT)idx==ACCOUNT_EVENT_EQUITY_INC) { Print(DFUN,sparam); //--- Закроем позицию с самой большой прибылью при увеличении средств больше, //--- чем задано в методе CAccountsCollection::InitControlsParams() для //--- переменной m_control_equity_inc, контролирующей прирост средств на 15 единиц (по умолчанию) //--- Файл AccountCollection, метод InitControlsParams(), строка 1199 //--- Получаем список всех открытых позиций CArrayObj* list_positions=engine.GetListMarketPosition(); //--- Сортируем список по прибыли с учётом комиссии и свопа list_positions.Sort(SORT_BY_ORDER_PROFIT_FULL); //--- Получаем индекс позиции с наибольшей прибылью int index=CSelect::FindOrderMax(list_positions,ORDER_PROP_PROFIT_FULL); if(index>WRONG_VALUE) { COrder* position=list_positions.At(index); if(position!=NULL) { //--- Получаем тикет позиции с наибольшей прибылью и закрываем позицию по тикету #ifdef __MQL5__ trade.PositionClose(position.Ticket()); #else PositionClose(position.Ticket(),position.Volume()); #endif } } } } } //+------------------------------------------------------------------+
Так как при отправке события на график управляющей программы, к коду события добавляется значение CHARTEVENT_CUSTOM, равное 1000, то для получения истинного кода, нам необходимо из полученного кода события вычесть значение CHARTEVENT_CUSTOM. Если событие — его числовое значение, находится в пределах от TRADE_EVENTS_NEXT_CODE до ACCOUNT_EVENTS_NEXT_CODE-1, то то значит, что пришло событие изменения свойств аккаунта. Так как по нашей задумке мы хотим закрывать самую прибыльную позицию при увеличении размера средств больше, чем задано в настройках (а по умолчанию у нас задано значение прироста от 15), то проверяем событие "увеличение размера средств выше заданной величины", и далее распечатываем в журнал описание события и закрываем самую прибыльную позицию — всё описано в комментариях к коду.
Если теперь просто запустить советник на графике, то спустя некоторое время мы можем получить в журнале записи о запрете торговли на счёте, а делее — о разрешении:
2019.06.1010:56:33.8772019.06.1006:55:29.279: Trading on the account is prohibited now 2019.06.1011:08:56.5492019.06.1007:08:51.900: Trading on the account is allowed now
На MetaQuotes-Demo такое отключение/включение разрешения торговли можно наблюдать несколько раз в день, что даёт нам возможность проверить работу библиотеки по определению таких событий на демо-счёте.
Теперь запустим советник в тестере и откроем побольше позиций — чтобы быстро поймать событие увеличения средств и написанную нами обработку данного события — закрытие самой прибыльной позиции:
Видно, что при увеличении средств больше заданной величины, автоматически закрывается самая прибыльная позиция. В журнал выводятся сообщения об отслеживаемом нами событии аккаунта.
Что дальше
В следующей части начнём делать работу с символами. У нас запланированы к реализации объекты-символы, коллекция объектов-символов и события символов.
Ниже прикреплены все файлы текущей версии библиотеки и файлы тестового советника. Их можно скачать и протестировать всё самостоятельно.
При возникновении вопросов, замечаний и пожеланий, вы можете озвучить их в комментариях к статье.
Статьи этой серии:
Часть 1. Концепция, организация данных.
Часть 2. Коллекция исторических ордеров и сделок.
Часть 3. Коллекция рыночных ордеров и позиций, организация поиска.
Часть 4. Торговые события. Концепция.
Часть 5. Классы и коллекция торговых событий. Отправка событий в программу.
Часть 6. События на счёте с типом неттинг.
Часть 7. События срабатывания StopLimit-ордеров, подготовка функционала для регистрации событий модификации ордеров и позиций.
Часть 8. События модификации ордеров и позиций.
Часть 9. Совместимость с MQL4 - Подготовка данных.
Часть 10. Совместимость с MQL4 - События открытия позиций и активации отложенных ордеров.
Часть 11. Совместимость с MQL4 - События закрытия позиций.
Часть12. Класс объекта "аккаунт", коллекция объектов-аккаунтов.





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Небольшое уточнение по поводу определения типа терминала в конструкторе:
this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE] = (::TerminalInfoString(TERMINAL_NAME)=="MetaTrader 5" ? 5 : 4);
Наверное более корректно было бы так написать:
this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE] = (::StringFind(TerminalInfoString(TERMINAL_NAME),"MetaTrader 5") != -1 ? 5 : 4);
Поскольку там может ещё и имя брокера фигурировать..
Небольшое уточнение по поводу определения типа терминала в конструкторе:
Наверное более корректно было бы так написать:
this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE] = (::StringFind(TerminalInfoString(TERMINAL_NAME),"MetaTrader 5") != -1 ? 5 : 4);
Поскольку там может ещё и имя брокера фигурировать..
Киньте в личку ссылку на брокера, у которого такое происходит, пожалуйста