Пишем Сервер

Пишем Сервер

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




0. Глоссарий и общие сведения


Коннектор в Os.Engine это не тоже самое что коннектор в СтокШарп. Коннектором здесь называется класс инкапсулирующий в себе обмен данными между BotTabSimple/BotTabIndex и определённой реализацией сервера(IServer). IServer в свою очередь это и есть то, что нужно делать чтобы добавить в систему новый тип подключения.


1 Сервер ( IServer) - сервер подключения к какой-либо бирже. Реализует в себе обмен данными между Os.Engine и биржей. Может быть развёрнут только один сервер одного типа. Могут быть развёрнуты множество серверов к разным подключениям. Например одновременно можно развернуть сервер Плаза 2 и Квик и т.д.


2 ServerMaster - класс для менеджмента реализации Серверов.


3 ServerMasterUi - окно менеджмента Серверов.


4 Коннектор - (Connector) - класс для подключения BotTabSimple/BotTabIndex к уже развёрнутому и готовому IServer. Connector есть у каждого бота. По нескольку штук бывает, когда роботу нужно получить несколько бумаг.

BotTabSimple/BotTabIndex - вкладки у робота. Через BotTabSimple осуществляется торговля. Эта вкладка специально созданная для торговли одного инструмента. Если нужно 2, то создаём две BotTabSimple. Вкладки храняться в BotPanel.

BotPanel - интерфейс создания робота. Это то что мы перегружаем в PanelCreator чтобы создать робота. Отвечает за менеджмент вкладок.

1. Что такое сервер и где он нужен


Сервер для платформы это вот этот интерфейс



Этот интерфейс используется:


1) в ServerMaster, где создаются подключения.
2) в Connector, объекте который представляет для роботов данные для торговли.


2. С чего начать


2.1 добавляем папку рядом с другими серверами



И создаём в этой вкладке соответствующий Класс.


Вот так вот:


namespace OsEngine.Market.Servers.NewFolder1
{
class NewServer
{
}
}


Затем сюда надо подключить интерфейс IServer:


namespace OsEngine.Market.Servers.NewFolder1
{
class NewServer: IServer
{
}
}


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



После этого соглашаемся на всё и у нас появяться 120 строк с не реализованными функциями.



Эти методы, поля и события надо оживить. Надо чтобы все эти методы работали как нужно. Как в других серверах.

2.2 Теперь открываем класс IServer


В нём есть структура и мы её забираем.
Во первых: из класса IServer переносим все названия методов, событий и полей - в новый класс. Это поможет понять что и за что отвечает.
Во вторых: В IServer кроме комментариев код разбит на блоки. Делаем точно также. Эти блоки будут далее помогать нам разбить работу на этапы. Это и есть наши этапы.
Переписывайте комментарии и разбиваем код на логические блоки. Вот в таком же порядке как в IServer.



2.3 После этого останавливаемся и изучаем SmartComServer


Прежде чем писать свою реализацию, надо изучить работу этого сервера. И в дальнейшем ровняться именно на эту реализацию.
Смотрим блоками.
Кроме блоков которые есть в IServer здесь ещё есть два дополнительных:
// работа основного потока !!!!!!
// работа потока рассылки !!!!!
Эти блоки - краеугольный камень любого коннектора. Но об этом ниже.
Прямо регистрируйтесь на учебный сервер ItInvest и подключите его. Посмотрите как он работает. Поторгуйте. Разберите через какие методы он получает данные, через какие высылает. В общем. Потратьте на это пару дней.


3. Сервер и реализация


Сервер разделён на логические блоки. И в таком же порядке их надо делать. Не ленитесь плз. Начинайте с разметки и потом спокойно блок за блоком заставляйте коннектор оживать.
В этой главе опишу каждый из этих блоков как смогу. Но лучше смотреть в код. Реализация есть в других серверах. Я рекомендую воровать у СмартКом. SmartComServer


3.0. Потоки


В любом сервере есть три потока. Они создаются в конструкторе.
Поток 1 - занимается обработкой запросов пользователя к серверу. Как то подключается,/отключается, требует бумаги от коннектора и проч. Для чего: нельзя трогать сторонние Апи из разных потоков. Ни разу я не встречал чтобы Апи было потокобезопасным. Поэтому все запросы и действия надо делать через Флаги. Смотря на которые, этот поток будет совершать действия с Апи. Блок: "Работа основного потока"
Поток 2 - поток высылающий наверх входящие данные. Когда из сервера приходят новые данные, эти данные нельзя сразу отправить наверх. Данные нужно ставить в очереди(ConcurrentQueue). Далее поток2 в бесконечном цикле проверяет очереди данных и если что-то есть - высылает наверх через события. Блок: " работа потока рассылки !!!!!"
Поток 3 - поток обрабатывающий Ордера которые нужно снять или выставить. Точно так же. Нельзя напрямую зайти в этот класс через метод и тут же отправить заявку в терминал. Это надо делать через очередь. Блок: исполнение ордеров
Важно!
Поток 1 и поток 3 не должны ни в коем случае получить доступ к Апи в один момент времени. Поэтому надо использовать блокировку многопоточного доступа к нему. Реализацию смотрим в SmartComServer. Метод ExecutorOrdersThreadArea и PrimeThreadArea
lock (_smartComServerLocker)
{
// Внутри этого блока работает только поток 1 в ExecutorOrdersThreadArea
// или поток 3 в ExecutorOrdersThreadArea
// одновременно они сюда не попадают
}


3.1. Сервис


Это первый блок который надо реализовать. В момент его создания мы:
1) даём серверу название. это поле: public ServerType ServerType
2) в перечисление ServerType нужно добавить новый тип сервера. Допустим у нас это будет "NewServer"
3) выделяем настройки для коннектора. Обычно это логин и пароль. Делаем методы Load() и Save().
4) делаем конструктор класса. в конструкторе присваиваем серверу наше имя и вызываем Load(). Смотрим SmartCom. Там ещё много чего.


3.2. Статус сервера


Текущий статус сервера. Весь блок можно своровать из SmartComServer. Работает всё очень просто. Изначально надо установить статус в Disconnect. Затем, когда придёт коллбек во время соединения, нужно изменить статус и сетор ServerStatus сам вышлет оповещение наверх.
На колбек для статуса подписываемся из потока1.


3.3. Работа основного потока


Это один из двух блоков которых нет в IServer. Здесь у нас происходит важная работа.
Создаём метод:
PrimeThreadArea(). Внутри него бесконечный цикл с ожиданием 1 секунда. И посылаем в этот метод новый поток из конструктора.
Здесь, ориентируясь на статус сервера и флаги от пользователя мы:
1) создаём подключение Апи
2) пробуем к нему подключиться если пользователь запросил
3) создаём менеджер свечей, если его ещё нет
4) запрашиваем бумаги у Апи, если их ещё нет
5) запрашиваем портфели у Апи, запрашиваем их если ещё нет
6) подписываемся на обновления бумаг, портфеля, ордеров, моих Сделок(MyTrade). Свечки, тики и стаканы подписываются в другом месте! Только те которые нужны.
7) отключаемся от всего этого хозяйства, если пользователь запросил.
Иногда, этот же поток у меня рассылает и заявки. Таким образом я делал в ASTS Bridge и далее буду так делать. Но это не принципиально.


3.4. подключение / отключение


Два метода: StartServer и StopServer. Через них мы указываем влаг о желании пользователя. Что он хочет. Через них не нужно подключаться к Апи!
Эти флаги читает основной поток из PrimeThreadArea и уже делает всё сам.


3.5. работа потока рассылки


Из метода SenderThreadArea поток следит за очередями, и если есть какие-то данные то он высылает их на верх через события.
В очереди данные нужно ложить из Коллбеков Апи. Нельзя вызывать события с данными нигде!!! кроме метода SenderThreadArea.


3.6. время сервера


Надо просто копировать реализацию этого блока из SmartComServer. В ней всё идеально.
Когда заносяться данные в ServerTime, то если время новое, то у нас время заноситься в очередь на отправку.
Устанавливать ServerTime можно непосредственно подписавшись на время сервера. Если такого коллбека нет, то устанавливаем ServerTime во время приёма тиков из Апи. SmartServer_AddTick


3.7. Портфели


Приём и хранение портфелей и позиции по ним.
На портфель подписывается поток1, в момент подключения.
Тут реализация раз от раза отличается, скопировать врятли удастся.
Позиция храниться в портфеле. Смотрим класс OsEngine.Entity.Portfolio и OsEngine.Entity. PositionOnBoard
В общем случае требуется следущее:
1) нужно портфели принять, сохранить и поставить в очередь на отправку.
2) нужно позиции принять, прогрузить ими портфели, сохранить и поставить в очередь на отправку.
3) оживить метод GetPortfolioForName(string name). Тут не будет проблем.
4) оживить public List
Portfolios. По этому запросу нужно выдавать все(без дублей и проч.) ранее принятые портфели.


3.8. Бумаги


Приём и хранение инструментов.
На бумаги подписывается поток1, в момент подключения.
Тут реализация раз от раза отличается, скопировать врятли удастся.
Класс: OsEngine.Entity. Security
В общем случае требуется следущее:
1) нужно бумаги принять, сохранить и поставить в очередь на отправку.
3) оживить метод GetSecurityForName(string name)
4) оживить public List
Securities. По этому запросу нужно выдавать все(без дублей и проч.) ранее принятые бумаги.


3.9. Подпись на данные и тут же Свечи


Так же раз от раза приходиться делать по разному.
В общем случае требуется:
1) оживить вот этот метод CandleSeries StartThisSecurity(string namePaper, TimeFrame timeFrame) . Со всеми костылями из СмартКОМ!!!
Так чтобы после этого CandleSeries начал выдвать свечи по этому инструменту и ТаймФрейму. Кроме того в этом методе нужно подписаться на тики и стакан этого инструмента.
CandleManager - в каждом сервере есть эта штука. Она отвечает за создание свечек из ТИКОВ. Эта штука создаётся в конструкторе сервера. Чтобы она начала создавать свечи по какомуто инструменту, в неё надо передать CandleSeries.
CandleSeries - место сбора конкретного ТФ свечек по конкретному инструменту.
Смотрим OsEngine.Entity.CandleManager OsEngine.Entity.CandleSeries. И реализацию StartThisSecurity в SmartComServer.


3.10. Стакан


Подписываемся на стакан в предыдущем блоке. Здесь его принимаем, разбираем и ставим в очередь на рассылку.


3.11. Тики


Подписываемся на тики определённого инструмента в блоке "Подпись на данные".
Здесь их принимаем, разбираем, сохраняем и ставим в очередь на рассылку.
+ Оживляем List
[] AllTrades.
Отдельно следует отметить, что если Апи не выдаёт тики хотябы за 5 дней, то появляется необходимость сохранять тики на своей стороне. Реализацию этой штуки нужно смотреть в этом же блоке но в сервере QuikServer. За это отвечает класс: OsEngine.Market.Servers.ServerTickStorage


3.12. Мои сделки


На событие моих сделок подписывается поток1, в момент подключения к Апи.
Здесь их принимаем, разбираем, сохраняем и ставим в очередь на рассылку.
оживляем public List
MyTrades.


3.13. Работа с ордерами


В этом блоке две части. Одна принимает ордера, вторая для их выставления/снятия.
Блок один. Приём ордеров из Апи
Подписываемся на это в потоке 1.
Принимаем ордера которые приходят через апи, разбираем, сохраняем/обновляем, ставим в очередь на отправку.
Блок два. Исполнение ордеров.
Здесь работает поток номбер 3, в методе ExecutorOrdersThreadArea. Исполняет / отзывает ордера если пользователь такоевые передал ему через методы ExecuteOrder/CanselOrder.
Ничего не исполняется на прямую! Только через очереди. Не забываем про многопоточный доступ к Апи и lock. Про это есть в разделе про потоки.


3.14. Обработка лога


Копируем полностью из СмартКом этот блок. _logMaster создаётся в конструкторе. Обычно я делаю это в последнюю очередь, т.к. удобнее при написании кода чтобы всё падало прямо и VS отправляет к месту проишествия. Вы не как хотите.


4. Сначала ордер, потом моя сделка


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


В заключении


Это конечно сложная задача, но вполне реализуемая. На каждый у меня уходит времени от 3 недель до шести.
Начать можно с TWIME, ЛУА(используйте Quik Sharp), Транзака или OEC. Работы много на самом деле.
Если соберётесь писать и чувствуете в себе силы джедая, напишите мне чтобы не вышло так что несколько человек работает над одним подключением.
Удачных алгоритмов!

07:29
699

Комментарии

Нет комментариев. Ваш будет первым!