← Zurück

Серьезный трабл с ассинхронным режимом

Михаил, у меня сложилось ощущение что ассинхронный режим работает иногда некорректно. поппытаюсь сейчас объяснить. Я пишу арбитражера, сут ье го работы - выставить заявку при появлении определенного сигнала и дальше 2 варианта - либо по исполнении ее выброзить еще одну заявку, либо , если сигнал ушел - снять первую заявку.

Это преамбула. (бага на версии 2.0.1, т.к. с 2.1 у меня известные вам траблы)

Амбула - т.к. режим асинхронный, когда уходит сигнал, успевает пройти запрос на снятие раз 15, прежде чем заявка снимется и поменяет статус на Canceled, у меня как только заявка становится Canceled или Matched срабатывает ветка в коде, кторая проверяет Volume-Blance и на эту разницу выкидывает вторую заявку (если Canceled), либо (если Matched) выкидывают вторую заявку на Volume первой.И у меня складывается ощущения, что в какой то момент сбивается или нарушается (не знаю как скзаать) процесс обновления полей в экземпляре заявки. Как эт овыглядит (в прилагаемом скрине, я далее для удобства буду давать только послдение 4 цифры номера заявки)

Сработал сигнал, выставилась заявка 6984, сигнал ушел, я отправляю trader.CancelOrder(order) до тех пор пока order.State != Canceled. как только Canceled, делаю order = null и дальше слушать сигнал.В логах так и написано - заявка стала Canceled, Balance = 2

Сигнал срабатывает второй раз, выставялю снвоа заявку order = new Order () .... (перменная та же самая), trader.RegisterOrder(order). Высталяется заявка (номер у нее 8248) Что происходит далее - на бирже заявка исполняется, но сигнал уходит. Робот честно пытается ее отменить до тех пор, пока статус у нее Active. как только статус заявки меняется на Исполнена(в квике), робот видит изменение статуса, но! в логах пишет мне что заявка Canceled, и Balance у нее 2. (то есть данные из заявки 6984). ну и соответсвенно не выкидаывает правую часть. и другая бага (наверно изза тгого, что уходит 10-15 запросов на снятие заявки до тех пора пока она станет Canceled - были случаи ,когда аявки часто тсавилис снимались, что например идут заявки 1,2,3,4,5,6 , они выставляются- снимают, но по логам заявка под номером например 4 вообще не снималась.То есть робот ее не снимал.Может быть это изза тго, что между первым запросом на снятие и реальным изменением ее статуса на Canceled на сервер уходит штук 15 транзакций на снятие?

скрин списка заявок - файл 07.07.png

War dieses Thema hilfreich?

Thema teilen

Kommentare (34)

Anmelden oder Konto erstellen, Melden Sie sich an oder registrieren Sie sich, um einen Kommentar zu hinterlassen

Mikhail Sukhov
Mikhail Sukhov

По скрину. Пустые номера транзакций - это ручками? Номера транзакций уникальны? А то я смотрю у Вас с 1 начинается. До этого 1 не встречался? Уникальность должна быть в пределах всей таблицы (тоесть, робот запускали несколько раз и между запусками должна сохраняться уникальность). Заявки никак не меняются в коде? Если выставили заявку, то ее уже никак нельзя менять. Это иногда вводит в путаницу, когда используют ФОРЦ мув. Даже при нем нельзя менять заявку.

Tauler
Tauler Autor

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

public Order MoveOrder(Order order, decimal price) { var newOrder = makeOrder(order.Direction, order.Security, order.Volume, order.Security.ShrinkPrice((double)price), order.Account); if (order.Price != newOrder.Price) { bool succes = CancelOrder(order); if (succes) {

TradeBasketHelperLogger.Logger.Debug(String.Format("Try moving order ID = {0}", order.Id)); trader.RegisterOrder(newOrder);

TradeBasketHelperLogger.Logger.Debug(String.Format("Moving order succes. New order ID = {0}", newOrder.Id)); return newOrder; } return order; } return order; }

Mikhail Sukhov
Mikhail Sukhov

В Вашем случае такое не подойдет (надо в доке отразить). Сделайте свой генератор (по сути там только один метод реализовать). Который такты проца берет. Уж он то точно будет уникью =)

Tauler
Tauler Autor

Если затык тока в генераторе - поставлю вам памятник нерукотворный :)

Mikhail Sukhov
Mikhail Sukhov

Я не знаю. По картинке выше не видно, были еще заявки с таким номером или нет.

Tauler
Tauler Autor

наверняка были - робот несколько раз запускался

Tauler
Tauler Autor

IncrementTransactionIdGenerator tranGen = new IncrementTransactionIdGenerator

; trader.TransactionIdGenerator = tranGen;

вот так я думаю прокатывать будет всегда :)

Tauler
Tauler Autor

нет, не катит - пишет что превышен размер . щас буду думать. я хрен знает как тики проца взять, и разбираться лень.

Mikhail Sukhov
Mikhail Sukhov

Да, дилема... Штука в том, что транзакция не может превышать int.MaxValue. А если брать тики (+такты) то без разрядности long ну никак. Есть обходной маневр. Попробовать в начале инициализировать не количество тиков, а количество секунд с начала дня. Как то так:

{CurrentTransactionId = (DateTime.Now - DateTime.Today).TotalSeconds};

Tauler
Tauler Autor

Ну вполне рабочий такой work around.Надеюсь в версии 2.2 будет еще один генератор транзакций, для таких как я :)

Mikhail Sukhov
Mikhail Sukhov

... если этот поможет.

Tauler
Tauler Autor

Блин опять то же самое :( не помогла генерация транзакций.

Mikhail Sukhov
Mikhail Sukhov

Тогда где-то проблема в другом месте. ITrader.OrdersChanged по этим заявкам выводит событие, что в них что-то поменялось?

Tauler
Tauler Autor

в сделке кторая пришла по событию баланс - 0, а в переменной - 4.

вот лог из консоли

Done branch, Order Id = 1882934524, Balance = 4 - эт ов основном цикле, ветка Status = Done

а это лог из OrderChanged 15:27:03,968 - OrderId = 1882934524 State = Done Bal = 0 TrId = 55471 Time = 15:27:03 15:27:03,968 - OrderId = 1882934524 State = Done Bal = 0 TrId = 55471 Time = 15:27:03 15:27:03,968 - OrderId = 1882934524 State = Done Bal = 0 TrId = 55471 Time = 15:27:03

Tauler
Tauler Autor

Переменная эта используется в Workflow, а воркфолоу работает в своем потоке. может изза этого?

Tauler
Tauler Autor

смотрите как интересно - как будто заявка сразу считается снята. это может быть отго, что бросается масса заявок на снятие?

он выполняет ветку кторая if (State == Done), а потом еще приходит 3 события OrderChaged.

15:47:52,656 - OrderId = 1883161388 State = Active Bal = 4 TrId = 56280 Time = 15:47:51 15:47:52,656 - OrderId = 1883161388 State = Active Bal = 4 TrId = 56280 Time = 15:47:51 15:47:52,765 - OrderId = 1883161388 State = Done Bal = 4 TrId = 56280 Time = 15:47:51

Tauler
Tauler Autor

в общем щас еще раз поймаю - напишу сюда последовательность.

Tauler
Tauler Autor

Забрела ко мне в голову идея - может вы сперва в заявке статус обновляете, а потом баланс?

Tauler
Tauler Autor

Поймал. вот что мы имеем

16:59:23,578 - Buy left part spread start. SRU0 BA = 7567, SBER03 BB = 75,4 16:59:23,578 - Buy left part spread end. SRU0 BA = 7567, SBER03 BB = 75,4 Это вставил заявку в результате срабатывания сигнала

16:59:24,093 - Check open long spread order. A = 35,125000, ? = 39,0, (A-?*?) = 41,125000, signal is 0 < 39,0 - 41,125000 <= 2, alpha = 6, sigma = 1 16:59:24,093 - Prices: SRU0 BA = 7570, SBER03 BB = 75,3 16:59:24,093 - Try cancel order 1883929777, State = Active, Status = Done 16:59:24,093 - Canceling succesful это проверка сигнала. в данном случае сигнал ушел, поэтому мы отменяем заявку.Проверяем и отменяем в цикле до тех пор, пока статус не станет Done. Canceling succesful - т.к. режим ассинхронный, и CancelOrder не вызывает исключений

16:59:24,109 - Check open long spread order. A = 35,125000, ? = 39,0, (A-??) = 41,125000, signal is 0 < 39,0 - 41,125000 <= 2, alpha = 6, sigma = 1 16:59:24,109 - Prices: SRU0 BA = 7570, SBER03 BB = 75,3 16:59:24,109 - Try cancel order 1883929777, State = Active, Status = Done 16:59:24,109 - Canceling succesful 16:59:24,125 - Check open long spread order. A = 35,125000, ? = 39,0, (A-??) = 41,125000, signal is 0 < 39,0 - 41,125000 <= 2, alpha = 6, sigma = 1 16:59:24,125 - Prices: SRU0 BA = 7570, SBER03 BB = 75,3 16:59:24,125 - Try cancel order 1883929777, State = Active, Status = Done 16:59:24,125 - Canceling succesful 16:59:24,140 - Check open long spread order. A = 35,125000, ? = 39,0, (A-??) = 41,125000, signal is 0 < 39,0 - 41,125000 <= 2, alpha = 6, sigma = 1 16:59:24,140 - Prices: SRU0 BA = 7570, SBER03 BB = 75,3 16:59:24,140 - Try cancel order 1883929777, State = Active, Status = Done 16:59:24,140 - Canceling succesful 16:59:24,156 - Check open long spread order. A = 35,125000, ? = 39,0, (A-??) = 41,125000, signal is 0 < 39,0 - 41,125000 <= 2, alpha = 6, sigma = 1 16:59:24,156 - Prices: SRU0 BA = 7570, SBER03 BB = 75,3 16:59:24,156 - Try cancel order 1883929777, State = Active, Status = Done 16:59:24,156 - Canceling succesful 16:59:24,171 - Check open long spread order. A = 35,125000, ? = 39,0, (A-??) = 41,125000, signal is 0 < 39,0 - 41,125000 <= 2, alpha = 6, sigma = 1 16:59:24,171 - Prices: SRU0 BA = 7570, SBER03 BB = 75,3 16:59:24,171 - Try cancel order 1883929777, State = Active, Status = Done 16:59:24,171 - Canceling succesful 16:59:24,187 - Check open long spread order. A = 35,125000, ? = 39,0, (A-??) = 41,125000, signal is 0 < 39,0 - 41,125000 <= 2, alpha = 6, sigma = 1 16:59:24,187 - Prices: SRU0 BA = 7570, SBER03 BB = 75,3 16:59:24,187 - Try cancel order 1883929777, State = Active, Status = Done 16:59:24,187 - Canceling succesful 16:59:24,203 - Check open long spread order. A = 35,125000, ? = 39,0, (A-??) = 41,125000, signal is 0 < 39,0 - 41,125000 <= 2, alpha = 6, sigma = 1 16:59:24,203 - Prices: SRU0 BA = 7570, SBER03 BB = 75,3 16:59:24,203 - Try cancel order 1883929777, State = Active, Status = Done 16:59:24,203 - Canceling succesful 16:59:24,218 - Check open long spread order. A = 35,125000, ? = 39,0, (A-??) = 41,125000, signal is 0 < 39,0 - 41,125000 <= 2, alpha = 6, sigma = 1 16:59:24,218 - Prices: SRU0 BA = 7570, SBER03 BB = 75,3 16:59:24,218 - Try cancel order 1883929777, State = Active, Status = Done 16:59:24,218 - Canceling succesful

и вот на этом месте статус меняется, но баланс все равно 4, и робот уходит в ветку, где статус = Done и IsFilledEmpty = true. Хотя на деле баланс = 0.

А дальше идет лог из OrderChaged:

16:59:24,546 - OrderId = 1883929777 State = Done Bal = 0 TrId = 60554 Time = 16:59:23 Now = 16:59:24.5468750 16:59:24,546 - OrderId = 1883929777 State = Done Bal = 0 TrId = 60554 Time = 16:59:23 Now = 16:59:24.5468750 16:59:24,546 - OrderId = 1883929777 State = Done Bal = 0 TrId = 60554 Time = 16:59:23 Now = 16:59:24.5468750

Mikhail Sukhov
Mikhail Sukhov

Кажется я начинаю понимать. У Вас случаем не такой код?

while (order.Type != Done) { WriteLog(); }

if (order.Balance > 0) {

Тут дело не в 2.1 и не в асинхронности. Такое бы не прокатило ни на одной вресии. Вы своим кодом предполагаете, что все свойства меняются одновременное. А такое невозможно. Я даже предполжить не могу, на что можно блокироваться. Так просто не делается, и я не знаю подхода, который бы такое делал.

А почему Вы не работаете стандартным путем - через события. У Вас везде вечные циклы. Зачем все так сложно?

Tauler
Tauler Autor

потому что робот у меня в WorkFlow нарисован. А там - детерменированый подход. А предполагаю что свойства меняются не одновременно, а что сперва баланс, а потом - состояние заявки.

Mikhail Sukhov
Mikhail Sukhov

у Вас sequential?

Tauler
Tauler Autor

в 4м дотнете нет такого понятия. там один вид воркфлоу.

Tauler
Tauler Autor

а никак нельзя лочить объект во время его апдейта?

Tauler
Tauler Autor

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

On 7 июл, 17:51, Tauler <vladimir_igo...@mail.ru> wrote:

Tauler
Tauler Autor

Короче придумал я костыль - класс-репозиторий, кторый подписывается на NewOrder и OrderChanged, и оттуда форкфлоу запрашивает заявку перед ее проверкой.

On 7 июл, 17:54, Tauler <vladimir_igo...@mail.ru> wrote:

Mikhail Sukhov
Mikhail Sukhov

Да, я еще вчера посмотрел как идет обновлением. Статус обновляется последним.

On 8 июл, 12:37, Tauler <vladimir_igo...@mail.ru> wrote:

Tauler
Tauler Autor

Тогда вообще не понятно, почему у меня был статус Done, но баланс ненулевой на целиком закрытой заявке.

On 8 июл, 12:38, Mikhail Sukhov <msou...@gmail.com> wrote:

Mikhail Sukhov
Mikhail Sukhov

OrdersChanged должен был помочь разгадать загадку.

On 8 июл, 13:26, Tauler <vladimir_igo...@mail.ru> wrote:

Tauler
Tauler Autor

Не прокатывает мое решение с репозиторием - такая же фигня.

икак не пойму как так получется

вот класс репозитория

public class OrderRepository { private ITrader trader; private List<Order> orders = new List<Order>();

   private object locker = new object();

   public OrderRepository(ITrader trader)
    {
        this.trader = trader;
        trader.OrdersChanged += new

Action<IEnumerable<Order>>(trader_OrdersChanged); trader.NewOrders += new Action<IEnumerable<Order>>(trader_NewOrders); }

   public Order GetOrderById(long id)
    {
        lock (locker)
        {
            Order order = orders.LastOrDefault(ord => ord.Id ==

id); if (order != null) { orders.RemoveAll(ord => ord.Id == id); orders.Add(order); }

           return order;
        }
    }

   public Order GetOrderByTransId(long id)
    {
        lock (locker)
        {
            Order order = orders.LastOrDefault(ord =>

ord.TransactionId == id); if (order != null) { orders.RemoveAll(ord => ord.TransactionId == id); orders.Add(order); Console.WriteLine(String.Format("GetOrderByTransId TRID = {0} St = {1} bal = {2} ID = {3}",

order.TransactionId, order.State, order.Balance, order.Id)); }

           return order;
        }
    }

   void trader_NewOrders(IEnumerable<Order> obj)
    {
        lock (locker)
        {
            orders.AddRange(obj);
        }

   }

   void trader_OrdersChanged(IEnumerable<Order> obj)
    {
        lock (locker)
        {
            orders.AddRange(obj);
        }
    }
}

воркфлоу перед какждыйм циклом проверки заявки лезет сюда за заявкой

но каким то чудом он получает из репозиторя заявку со стутусом Done, но с целым балансом. И тут же вылетает лог события что заявка изменилась, статус Доне, и баланс 0. Ваще ничего не понимаю :(

On 8 июл, 13:31, Mikhail Sukhov <msou...@gmail.com> wrote:

Tauler
Tauler Autor

В событии вы выбрасываете новый экземпляр заявки , или все время один и тот же? кторый сформировался на NewOrder?

On 8 июл, 13:31, Mikhail Sukhov <msou...@gmail.com> wrote:

Mikhail Sukhov
Mikhail Sukhov

Всегда один и тот же.

On 8 июл, 17:19, Tauler <vladimir_igo...@mail.ru> wrote:

Tauler
Tauler Autor

Интерфес IClonable реализован?

On 8 июл, 17:35, Mikhail Sukhov <msou...@gmail.com> wrote:

Mikhail Sukhov
Mikhail Sukhov

Это для ReRegister. В перегруженом методе, где передается не новая заявка, а только новые цена и объем, сначала клонируется текущая заявка, а затем ей заполняются новые параметры.

On 8 июл, 17:44, Tauler <vladimir_igo...@mail.ru> wrote: