Все статьи «Plaza2 и МТС»
Задача обработки собственных заявок состоит в том, чтобы как можно более актуально хранить динамические данные о ранее выставленных заявках и максимально быстро получать информацию о любой ранее отправленной заявке. При этом необходимо учесть, что торговый алгоритм (или несколько одновременно работающих торговых алгоритмов) может быть высокочастотным, т.е. количество заявок за сессию может достигать сотен тысяч.
Непосредственно информация о изменении состояния заявок поступает клиенту в виде реплик таблицы orders_log потоков FORTS_FUTTRADE_REPL и FORTS_OPTTRADE_REPL, но для того, чтобы клиент мог реагировать на изменение ситуации максимально быстро, не стоит игнорировать и косвенную информацию о состоянии заявок из таблицы сделок (собственных сделок) deal(user_ deal) потоков FORTS_FUTTRADE_REPL(FORTS_OPTTRADE_REPL), а также, если подключен а полный лог заявок, то соответственно данные и из таблицы FORTS_ORDLOG_REPL.orders_log,. Так как поступление данных в таблицах не синхронно – предсказать заранее в каком порядке будут получены данные невозможно. Реплики не несут полной информации о состоянии заявок, данные реплик различных потоков сообщают об изменении их состояния. Кроме того, источником информации о состоянии заявки является ответ на транзакцию добавления/удаления/перемещения заявки, в котором содержится результат выполнения транзакции (заявка принята/отвергнута/перемещена/снята) и номер заявки, присвоенный ядром.
Заявка может быть описана в виде структуры с полями, которые заполняются при добавлении заявки методом FutAddOrder, а также остатком (не сведенной частью заявки) и локальным идентификатором –порядковым номером в локальной таблице заявок. Локальный идентификатор заявки обычно присваивается заявке локальным алгоритмом торгового робота, в момент принятия решения торговым алгоритмом о добавлении новой заявки. Как правило, это целый положительный уникальный номер, равный текущему количеству собственных заявок плюс один. Он необходим для идентификации заявки до того, как её биржевой номер, присвоенный ядром, станет известен локальной системе. Позже, когда это произойдет, необходимо связать биржевой и локальный номер заявки, записав биржевой номер в структуру, соответствующую этой заявке. Метод Plaza2 FutAddOrder для отправки заявки содержит «необязательное» поле ext_id. Значение этого поля при сведении в сделки переносится в таблицу сделок при сведении (также поле ext_id у сделок). Поле ext_id предназначено для заполнения внешним (относительно биржевой инфраструктуры) номером, в которое следует поместить локальный идентификатор при добавлении/перемещении заявкт. Хотя поле является необязательным, его использование сильно упрощает жизнь, а не использование будет приводить к неэффективностям и «потере» собственных заявок в некоторых ситуациях.
При использовании косвенной информации о заявках следует учитывать только записи с собственным кодом клиента и только те записи, результат которых либо очевидное полное сведение заявки, либо ее снятие. Использование реплик о частичном сведении приведет к путанице и неверному обновлению данных о заявке. Посчитаем скорость выполнения запросов к информации о заявке при использовании локального номера добавляемой заявки в качестве ext_id:
- Со стороны алгоритмической части МТС – в момент добавление заявки локальный идентификатор известен сразу. Обращение по локальному идентификатору к заявке в таблице — это фактически обращение по индексу, операция поиска отсутствует, т.е. мгновенный доступ, вне зависимости от размера локальной таблицы заявок
- Со стороны Plaza2 необходимые реплики с приходят с заполненным ext_id, так как в нашем алгоритме ext_id был заполнен при добавлении(перемещении) заявки. Ext_id – это локальный идентификатор — мгновенный доступ, вне зависимости от размера локальной таблицы заявок
- Удаление заявки. Если удалять заявку методом FutDelOrder, то потребуется ее биржевой номер, который можно извлечь из структуры заявки, обратившись по локальному идентификатору- также мгновенный доступ. Здесь может возникнуть проблема: возможно, понадобится снять заявку до того, как локаольной стороне будет известен ее биржевой номер. В этом случае на помощь придет метод FutDelUserOrders, который в качестве аргумента принимает ext_id – внешний номер заявки. Есть важный момент: если робот будет упорно удалять одну и ту же заявку подряд на каждом до тех пор пока не будет получена реплика о снятии заявки – это и очень плохо, скорее всего робот-спамер будет регулярно получать пенальти за такие действия. Поэтому имеет смысл структуру заявки дополнить еще одним полем – булевым признаком, была ли отправлена транзакция на снятие заявки или нет. Случай применения FutDelUserOrders до того, как получен биржевой номер особый. Дело в том, что транзакция о снятии заявки может быть получена ядром до того как заявка будет выставлена, тогда заявка попадет в систему, не смотря на то что согласно торговому алгоритму она должна быть снята. Здесь нужно внимательно следить за ответом на эту транзакцию, а конкретно за полем num_orders (количество удалённых заявок), и, если это 0 придется удалить заявку еще раз. В любой из этих операций доступ мгновенный, поиск отсутствует.
- Получение ответа биржи на транзакцию добавление/ перемещение заявки. Основной целью получения ответа является связывание биржевого и локального номера заявки. Также этот ответ можно использовать для корректировки синхронизации серверного и локального времени ( предыдущая статья «Plaza2 и МТС #4. Время»). Здесь при подписке на ответ в качестве аргумента можно указать локальный номер заявки, тогда при получении реплики-ответа будет также получен локальный идентификатор заявки, по которому и будет получен доступ к структуре нужной заявки – мгновенно.
Может показаться, что в статье описан простой и очевидный алгоритм обработки заявки, возможно вы уже реализовали свой, и считаете, что он гораздо лучше (давайте обсудим в комментариях)… На всякий случай ответьте для себя на 3 ключевых вопроса:
- Ваш робот использует поле ext_id при добавлении и перемещении заявок?
- Ваш робот не запускает алгоритм поиска при доступе к структуре информации о заявке?
- Ваш робот отправляет транзакцию удаления для одной заявки 1 раз ?
Если на один из вопросов ответ «нет», значит, чей-то алгоритм оптимальнее и он зарабатывает вместо (а может и за счет) вас при тех же расходах инфраструктуру.