Оптимальный алгоритм - страница 2

 

Ок. Попробую еще более детально.
Имеем подписки (и я отметил важные моменты в них):

1. protected override void OnTick(object sender, TickEventArgs e) {        //событие прихода тика

      for (int i = 0; i < Symbols; i++)                                                       //перебираем символы

      {....                                                                                              //здесь алгоритм расчета
           if (TradeFlag[i,0]==2 && openposition[i]==0)  //условие входа, openposition та самая переменная, в которой хранится инфо об ордере.

          {TradeRecord record = this.Trade.Server.SendOrder(symb[i], ...................);...}}}     //точка входа

 

2. protected override void OnFinancialInfoChanged(Object sender, FinancialInfoChangedEventArgs e) { //событие изменения информации о счете

                                      OnPositionReport(Object sender, PositionReportEventArgs e)}                            //есть ли открытые позиции

 

3. protected override void OnExecutionReport(object sender, ExecutionReportEventArgs e) {                  //событие действия с ордером

          e.Report.OrderStatus .... }        //изменение статуса

Считайте, больше ничего нет. Максимально упрощаем.

Корень проблемы: при отправке SendOrder, информация в подписчики поступает не мгновенно. Это за собой тянет все.

Таким образом, SendOrder может наступить множество раз, пока будем ждать OnExecutionReport. Логично, что нужно где-то записывать, что ордер отправлен - я записываю (считайте - учитываю) в переменной.

Далее, с приходом OnExecutionReport, я модифицирую запись в переменной, меняя число в ней (и тем самым смысловую нагрузку) при смене возвращаемых e.Report.OrderStatus. При наступлении Filled ожидаем нужного момента и запускается схожий процесс отправки ордера на закрытие позиции. Жизненный статус ордера закрытия так же отслеживается в той же самой переменной. Вплоть до 0 при e.Report.OrderStatus== OrderStatus.Filled. В итоге, мы приходим в отправную точку.

Как вам алгоритм? Где косяки и что можно улучшить?

 
Heroix:

Ок. Попробую еще более детально.
Имеем подписки (и я отметил важные моменты в них):

...

Как вам алгоритм? Где косяки и что можно улучшить?

Теперь кажется понял)

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

1. Каждый торговый интерфейс будь то API биржи или API MetaTrader имеет свой торговый интерфейс и свои торговые функции, включая событийную модель.  На основе этих торговых функций создается набор распространненных торговых методов - специальных классов, содержащие простые торговые примитивы. Например, у меня есть класс, покупающий или продающий по рынку заданный объем, есть класс, который просто выставляет отложенный ордер с заданными параметрами и т.д. Этих торговых примитивов много, на все случаи жизни. По сути это объекты-обертки в основе которых лежит определенный API зависимый торговый метод. Благодаря тому, что каждый метод обернут в классы, можно объединять методы с списки. Список методов может быть произвольным, каждый такой список образует простое логическое действие, оно называется таргетом и выглядит как класс.

2. Таргет, по мимо торговых примитивов, вроде открытия по рынку или удаления отложенного ордера, содержит обработчик событий приходящих в OnTradeTransaction(). Таргет, получив управление на себя, вызывает исполнение первого торгового метода в своем списке, запоминает указатель на этом методе и возвращает управление основному потоку. Через некоторое время вызывается событие OnTradeTransaction, это событие информирует о произошедших изменениях, что логично, так как метод запушенный таргетом совершил некоторое торговое действие. Это событие упаковывается в специальный класс и передается таргету, иполняющему текущую задачу. Так как таргет всегда содержит конкретную задачу, он знает, какой ответ от сервера необходимо ожидать. Также анализируя ответ от OnTradeTransaction он сможет понять, что что-то пошло не так. Если полученное событие подтвердило успешное завершение метода, таргет переходит к следующему по списку методу. Если произошел какой-либо сбой, таргет устанавливает флаг FAILED_TASK, и прекращает дальнейшее выполнение сценария. После того, как все методы в таргете исполняются, таргет завершает свою работу и получает соответствующий статус. Раз исполненный таргет (успешно или нет) уже никогда не станет исполняться вновь. Благодаря этому мы огорожены от ужасных ошибок вроде вечного цикла с OrderSend.

3. В случае неудачи выполнения торгового запроса, можно написать специальный сценарий восстановления. Допустим торговый запрос состоит из нескольких действий, скажем, что бы закрыть открытую позицию защищенную отложенным ордером выполняющим роль стоп-лосса необходимо вначале удалить этот отложенный ордер, а затем выставить ордер по рынку, закрывающий открытую позицию. Таргет, совершающий закрытие позиции будет содержать два торговых метода-примитива: удалить заданный отложенный ордер и выставить ордер по рынку. Допустим первый метод отработал удачно, а вот второй по каким-то причинами не сработал. В этом случае произойдет сбой и задача не сможет завершиться успешно. Однако защитная остановка в виде отложенного ордера уже будет снята. Для таких целей таргет может содержать сценарий восстановления. Конкретно для этого таргета он будет содержаться в том, что в случае неудачи с отсылкой ордера по рынку, будет запускаться альтернативный метод, устанавливающий отложенный ордер и тем самым восстанавливающий защитную остановку.

Решение не совсем простое, зато надежное и не накладывает ни каких ограничений на длину цепочки Запрос-Ответ-Запрос-Ответ... а также позволяет работать в асинхронном режиме. 

 
papaklass:

 Интересно время обработки одного торгового приказа таким алгоритмом.

Еще интересно время работы программы, если она состоит из таких блоков, на одном тике.

Достоверно менее одной миллисекунды (зеленый прямоугольник). Более точно сказать трудно, из-за ограниченной разрешающей способности таймера и накладок фактического исполнения ордера сервером (сотни миллисекунд, синий прямоугольник).

 

Сравнительное время исполнение торгового приказа и его обработка внутренними алгоритмами. Пропорции рисунка соответствуют времени.

 
papaklass:

Хорошее время.

Написали бы статейку на тему Вашего предыдущего поста. У Вас статьи интересные получаются. Да и чайникам было бы полезно прочитать про эти "таргеты, примитивы, обертки, списки и т.д." Как это все собрать воедино?

Поделитесь опытом программирования.

А если бы статья да еще и на C#, цены бы Вам не было. :)

Да, надо бы статейку на эту тему написать. Но не для чайников точно получиться. Асинхронные операции весьма сложная вещь, как их не упрощай, все равно в том или ином виде придешь к сложным ООП конструкциям.
Причина обращения: