Создание торгового робота на Plaza2
Atom
13.03.2013


Введение.

В последнее время широкую популярность приобретает разработка торговых роботов с использованием платформы Plaza2. Основной причиной популярности этой платформы является минимальное количество звеньев между торговым роботом и серверами биржи, что позволяет добиться более высокой надежности системы, высокой скорости передачи рыночных данных и обработки транзакций. Таким образом, робот, использующий протокол Plaza2, имеет более реальную картинку торгов и может оценивать рынок более точно, чем роботы, подключенные через Quik, SmartCom и т.д. Описание протокола и набора транслируемых данных можно найти на сайте Московской биржи, а так же по следующим ссылкам здесь и здесь.

Роутер.

При использовании торгового терминала Quik подключение производится непосредственно к терминалу на локальной машине. Когда используется Plaza2, то подключение происходит к клиентскому роутеру, который может находить как на локальной машине, так и на удаленной. Роутер позволяется подключаться к нему из нескольких приложений одновременно, что является большим преимуществом. Например, можно упростить инфраструктуру торгового робота и запускать каждую стратегию в виде отдельного приложения, это так же позволит повысить устойчивость каждого отдельного робота.

Из недостатков можно выделить отсутствие, какого бы то ни было, пользовательского интерфейса, т.е. невозможность ручного управления позициями при работе робота. Для этих целей можно использовать простой «самописный терминал», с помощью которого можно будет просматривать стаканы, списки заявок и сделок, портфели и лимиты, а так же выставлять заявки в случае необходимости. В качестве каркаса подобного терминала может служить S# пример Plaza\SampleGUI.

Роутер представляет собой самостоятельное приложение, единственной функцией которого является передача данных от биржи клиенту и наоборот. Есть два варианта запуска локального роутера: в виде службы и консольного приложения. Способ запуска роутера выбирается при его установке. При использовании консольного приложения, пользователь может сделать несколько конфигурационных файлов и запускать роутеры для разных логинов или серверов с помощью простых командных файлов. Полное детальное описание процесса установки и настройки роутера вы можете найти в файлах документации здесь и здесь.

Подключение к роутеру.

В настоящее время роутером поддерживаются два вида соединений:
  1. Соединение посредством протокола TCP/IP. Медленнее, удобно для отладки, может связываться с роутером, установленным на другой машине
  2. Соединение посредством разделяемой памяти (lrpcq). Быстрее, оптимально для боевых систем, работает исключительно в рамках одной машины.

Платформа S# поддерживает оба типа соединение и по умолчанию используется TCP/IP соединение. Для использования lrpcq подключения необходимо до подключения к роутеру выставить флаг:
Код
Trader.UseLocalProtocol = true;


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

Для подключения к роутеру, установленному на другой машине, необходимо внести дополнительные изменения в конфигурацию роутера. По умолчанию, конфигурация роутера хранится в файле client_router.ini в директории, куда был установлен роутер. Чтобы иметь возможность подключаться к роутеру удаленно, необходимо указать имена приложений, с помощью которых будет выполняться удаленное подключение и пароль для каждого из имен, для этого в файл конфигурации необходимо добавить следующие строки:
Цитата:
[AS:Local]
префикс_0=пароль
префикс_1=пароль
префикс_2=пароль

Т.к. одно приложение может одновременно использовать несколько подключений к роутеру, то к имени, указанному в AppName добавляется его номер, таким образом, соединения именуются как {префикс_номер}, поэтому в конфигурации роутера необходимо указать все названия имен с учетом их номеров.
После настройки роутера, необходимо дополнительно указать пароль для S# коннектора, который был сохранен в файле конфигурации роутера. Для указания сетевого пароля используется поле Password, которое может использоваться в двух вариациях:
  1. в случае если было задано поле Login, то поле Password используется для указания пароля для подключения серверам биржи или брокера;
  2. если поле Login задано не было, тогда Password будет использоваться как пароль для локального соединения.

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

Схемы данных.

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

Для определения набора полей, которые будут транслироваться в каждой таблице, используются схемы данных. Протокол Plaza2 позволяет использовать два варианта схем данных:
  1. Серверная схема данных
    При открытии потока пользователю не требуется задавать какое-либо описание получаемых данных, в момент подключения роутер получит схему данных с сервера, и все данные будут приходить согласно полученной схеме. Таким образом, перед пользователем не стоит задача поддержания схемы в валидном состоянии, т.к. набор доступных полей для каждой таблицы может меняться с течением времени.
  2. Пользовательская схема данных
    В случае, когда стандартный набор полей в таблицах содержит лишние или не содержит необходимых полей, пользователь может задать свои схемы данных для каждого потока и таблицы отдельно. Пользовательские схемы описываются с помощью ini-файлов, в которых указывается название схемы данных, названия таблиц и список полей для каждой таблицы. Далее, при открытии потока данных, передается путь к соответствующему файлу с настройками схемы и ее название, и роутер отправляет схему на сервер для согласования. В случае если схема была принята на серверной стороне, все данные будут приходить с указанным набором полей. Если в схеме есть недопустимые поля или типы полей, то с сервера придет соответствующее сообщение, поток данных при этом открыт не будет, более детальное описание ошибки будет записано в клиентский лог-файл, который располагается в папке \StockSharp_Plaza\Logs\.
    Полное описание формата данных для всех транслируемых таблиц можно найти в файле документации 2, а так же в описании схем данных, которое устанавливается вместе с роутером.

Для того чтобы исключить необходимость постоянного обращения к документации Plaza2, возможные опечатки при задании схем данных, не оперировать непонятными сокращениями в названиях полей и их типами, в S# было введено понятие метаданных, которые содержат описания всех доступных таблиц и полей, которые могут быть в этих таблицах. Описание метаданных находится в пространстве имен StockSharp.Plaza.Metadata. Например, все доступные таблицы представлены полями класса PlazaTableRegistry, а все доступные поля для таблицы сделок по фьючерсам - ColumnRegistry.TradeFuture.
Набор таблиц, данные из которых необходимо будет получать при подключении к серверу, задается с помощью свойства PlazaTrader.Tables, куда необходимо добавить нужные таблицы и удалить ненужные. Для ручного добавления и удаления таблиц можно необходимо вызвать соответствующую функцию у PlazaTrader.Tables и передать в качестве параметра одно из полей PlazaTrader.TableRegistry, например, для добавления полного ордерлога необходимо выполнить:
Код
PlazaTrader.Tables.Add(PlazaTrader.TableRegistry. AnonymousOrdersLog);

В определенных ситуациях, выбор необходимого набора таблиц для получения данных можно оставить конечному пользователю, для этого в S# присутствует специальный графический компонент PlazaTableListComboBox, который представляет собой выпадающий список с набором всех доступных таблиц (рис. 1). Каждая строка представлена в виде трех столбцов: описания таблицы, названия потока репликации, в котором транслируется таблица и названия самой таблицы, последние два столбца соответствуют названиям потока и таблицы в документации по Plaza2.
Рис. 1 - Выбор таблиц репликации данных.

Для того чтобы передать список выбранных таблиц в PlazaTrader, в библиотеке S# присутствует специальный метод расширения SyncTables, который можно использовать следующим образом:
Код
PlazaTrader.SyncTables(Tables.SelectedTables);

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

Поля таблицы, для которых нет соответствующих полей у объектов S#, будут записываться в специальный словарь ExtensionInfo объекта S#. Например, если нам необходимо получать данные по сбору по сделке продавца, то в таблицу TradeFuture необходимо добавить столбец SellFee:
Код
PlazaTrader.TableRegistry.TradeFuture.Columns.Add(PlazaTrader.TableRegistry.ColumnRegistry.TradeFuture.SellFee);

далее, в момент обработки данных по сделке, данное поле можно будет получить следующим образом:
Код
var fee = trade.ExtensionInfo[PlazaTrader.TableRegistry.ColumnRegistry.TradeFuture.SellFee];

Подробное описание работы с дополнительными полями и произвольными таблицами можно найти в документации по S# в разделе Российские коннекторы - Plaza2.

После того как были выбраны все необходимые таблицы и их поля, в момент подключения к серверу будут сгенерированы соответствующие файлы схем данных, которые будут записаны в .\StockSharp_Plaza\Configs\ и будут использоваться при открытии соответствующих потоков. Нет необходимости в ручном изменении этих файлов, т.к. при следующем подключении они снова будут перезаписаны данными, сгенерированными по набору таблиц и их полей. Но эти файлы могут быть использованы в случае ошибки при открытии потока, чтобы понять, где была допущена ошибка.

При подключении к роутеру, все выбранные таблицы группируются по потокам, которые, в свою очередь, группируются по разным соединениям. Каждое подключение к роутеру может использоваться для передачи данных по одному и более потоку репликации. Разделение потоков по разным соединениям необходимо для уменьшения влияния процесса обработки одних данных на другие, например, разделение потоков с таблицами сделок и агрегированных заявок по разным подключениям, позволяется обрабатывать стаканы, не дожидаясь пока будут обработаны все пришедшие сделки. В библиотеке S#, все получаемые потоки изначально сгруппированы таким образом, что наиболее нагруженные потоки репликации обрабатываются в различных подключениях. Если, по каким-либо причинам, стандартная группировка потоков не подходит для решения поставленных задач, ее можно изменить с помощью ConnectionGroupping. Например, если необходимо получать все потоки репликации в одном подключении, то необходимо для каждого потока указать одинаковый индекс подключения:
Код
var streamRegistry = PlazaTrader.TableRegistry.StreamRegistry;
var groupping = PlazaTrader.StreamManager.ConnectionGroupping;

groupping[streamRegistry.Aggregation5Future] = 0;
groupping[streamRegistry.Aggregation5Option] = 0;
groupping[streamRegistry.Aggregation20Future] = 0;
groupping[streamRegistry.Aggregation20Option] = 0;
groupping[streamRegistry.Aggregation50Future] = 0;
groupping[streamRegistry.Aggregation50Option] = 0;
...
groupping[streamRegistry.TradeFuture] = 0;
groupping[streamRegistry.TradeOption] = 0;

Посмотреть сколько открывается соединений, и с какими названиями, можно в логе PlazaTrader-а в момент подключения:
Цитата:
PlazaTrader | 30.01.2013 15:10:21.761 | | Attempted to connect Webinar_0.
PlazaTrader | 30.01.2013 15:10:21.819 | | Attempted to connect Webinar_1.
PlazaTrader | 30.01.2013 15:10:21.820 | | Attempted to connect Webinar_2.


Управление ревизиями.

Каждая реплицируемая таблица имеет в своей структуре несколько служебных полей, предназначенных для обеспечения механизма репликации. Одним из полей является уникальный номер изменения в таблице. При любом изменении в таблице (вставке, редактировании, удалении записи) затронутая запись получает значение replRev, равное максимальному replRev в таблице до изменения +1. После согласования схем данных, клиент отсылает на сервер максимальные значения номера ревизии для каждой таблицы. Начальная синхронизация заключается в том, что сервер присылает клиенту все данные с номерами, большими, чем те, что указал клиент. Если клиент не указал номер ревизии для таблицы, то данные по этой таблице будут приходить в полном объеме.

Для того чтобы получение данных начиналось с последних сохраненных ревизий, необходимо добавить нужные таблицы в PlazaRevisionManager.Tables:
Код
var revisionManager = PlazaTrader.StreamManager.RevisionManager;

revisionManager.Tables.Add(Trader.TableRegistry.TradeFuture);
revisionManager.Tables.Add(Trader.TableRegistry.TradeOption);

При первом подключении, после добавления таблиц в RevisionManager, данные так же будут получены в полном объеме, т.к. информация о сохраненных номерах ревизий еще отсутствует. После переподключения, данные будут скачиваться с номера последней сохраненной ревизии.
Интервал, через который сохраняется номер последней ревизии, доступен через PlazaRevisionManager.Interval. По умолчанию файл с номером последней ревизии по выбранной таблице сохраняется в папку \StockSharp_Plaza\Revisions. Для того чтобы перезакачать все данные, достаточно удалить файлы из папки Revisions.

Полный ордерлог.

Полный журнал заявок – сервис Московской биржи, который позволяет получать список всех торговых транзакций, принятых торговой системой в текущую торговую сессию с указанием текущего статуса заявок (поставлена/удалена) и изменений параметров транзакции (частичных исполнений, передвижений заявки). Также в журнале отображается запись о сделке, с указанием номера сведенной в данную сделку заявки. Ордерлог - самый глубокий и детальный уровень биржевых данных, который доступен трейдеру. По данным ордерлога можно построить стаканы, получить тики и многое другое.

Для получения и обработки всех данных по ордерлогу необходимо добавить таблицу AnonymousOrdersLog:
Код
PlazaTrader.Tables.Add(PlazaTrader.TableRegistry. AnonymousOrdersLog);

и подписаться на обработку события NewOrderLogItems.
Ордерлог, в отличие от потока агрегированных заявок, содержит информацию по всем заявкам, таким образом, по ордерлогу может быть построен стакан полной глубины. Библиотека S# предоставляет функционал, позволяющий автоматически строить стаканы и тики по данным ордерлога.
  1. Для построения стаканов по журналу заявок необходимо выставить соответствующий флаг
    Код
    PlazaTrader.CreateDepthFromOrdersLog = true;

    при установке этого флага автоматически отключается обработка потоков агрегированных заявок и для получения данных добавляется таблица AnonymousOrdersLog.
  2. Для построения тиков по журналу заявок необходимо выставить флаг
    Код
    PlazaTrader.CreateTradesFromOrdersLog = true;

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


Сохранение и восстановление настроек.

S# Plaza2 коннектор предоставляет широкие возможности для управления настройками подключения, списком выбранных таблиц, группировкой потоков по соединениям и другими настройками. В одних случаях, эти настройки могут быть зашиты в торговом роботе, в других, может возникнуть необходимость предоставить возможность редактировать эти настройки конечному пользователю. Для удобства, все коннекторы S# содержат встроенные механизмы сохранения и загрузки настроек с помощью методов Save и Load.

Для сохранения и загрузки настроек из внешнего файла можно воспользоваться соответственно сериализацией и десериализацией, реализованной в S#:
  1. Загрузка
    Код
    var trader = new PlazaTrader();
    if (File.Exists("trader.xml"))
    {
    //Загрузка настроек из существующего конфигурационного файла
    var settingsStorage = new XmlSerializer<SettingsStorage>().Deserialize("trader.xml");
    trader.Load(settingsStorage);
    }

  2. Сохранение
    Код
    //Сохраняем настройки в файл
    var settings = new SettingsStorage();
    trader.Save(settings);
    new XmlSerializer< SettingsStorage >().Serialize(settings, " trader.xml");


Белич Александр © 2013


Moadip

Фотография
Дата: 13.03.2013
Ответить


Классная статья.[thumbup] Все четко и по теме. И без лишней воды.
Спасибо:


Добавить файлы через драг-н-дроп, , или вставить из буфера обмена.

loading
clippy