Ejemplo n.º 1
0
        /// <summary>
        ///     Возвращает фолс, если такой статус уже приходил
        ///     (иногда квик присылает один и тот же QLOrderStateChange по нескольку раз, зафиксированы случаи по три присыла).
        ///
        /// ВАЖНО: этот метод также расчитывает реально исполненное количество в текущем PartiallyFilled изменение
        /// </summary>
        public bool PutOrderStateChange(QLOrderStateChange osc)
        {
            List <QLOrderStateChange> changes;

            using (locker.WriteLock())
            {
                if (!orderStateChanges.TryGetValue(osc.order_num, out changes))
                {
                    orderStateChanges.Add(osc.order_num, (changes = new List <QLOrderStateChange>()));
                }

                if (changes.Contains(osc))
                {
                    return(false);
                }

                var prevFilledQuantity  = changes.Sum(_ => _.State == OrderState.PartiallyFilled ? _.filled : 0);
                var totalFilledQuantiry = osc.qty - osc.balance;
                osc.filled = totalFilledQuantiry - prevFilledQuantity;

                changes.Add(osc);

                if (currentSeccionTransactionIds.Contains(osc.trans_id))
                {
                    mapQuikTransIdOnOrderExchangeId[osc.trans_id] = osc.order_num;
                }
            }

            return(true);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Положить OSCM в отложенную обработку
        /// </summary>
        /// <param name="oscm"></param>
        public void PutPendingOrderStateChange(QLOrderStateChange oscm)
        {
            log.Info().Print("Postpone OSCM processing, there are transactions without replies.", LogFields.Message(oscm));
            List <QLOrderStateChange> oscms;

            using (locker.WriteLock())
            {
                if (!mapOrderIdOnPendingOrderStateChange.TryGetValue(oscm.order_num, out oscms))
                {
                    mapOrderIdOnPendingOrderStateChange[oscm.order_num] = oscms = new List <QLOrderStateChange>();
                }

                oscms.Add(oscm);
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Обработка статуса по заявке, которая была выставлена транзакцией из прикладного приложения из текущей сессии
        /// </summary>
        /// <param name="message">Изменения</param>
        /// <param name="newTransactionId">ID связанной с заявкой транзакции на постановку</param>
        /// <param name="killTransactionId">ID связанной с заявкой транзакции на снятие</param>
        /// <param name="modifyTransactionId">ID связанной с заявок транзакции на изменение заявки</param>
        private void ProcessKnownOrderStateChange(QLOrderStateChange message, Guid?newTransactionId, Guid?killTransactionId, Guid?modifyTransactionId)
        {
            Guid transactionId = Guid.Empty;

            // если есть и new и kill транзакция для этого номера заявки, то нужно понять, результатом какой из транзакицй
            // является конкретно это изменение ордера
            if (newTransactionId.HasValue && killTransactionId.HasValue)
            {
                // если заявка снялась, то это результат килл транзакции и именно её transId мы проставляем в OSCM, чтобы правильно запроцессить в TransactionMessageHandler-е
                transactionId = message.State == OrderState.Cancelled
                    ? killTransactionId.Value
                    : newTransactionId.Value;
                Logger.Debug().PrintFormat(
                    "OSCM with two associated transactions received: not={0}, kot={1}. State is {2}, select {3} for further OSCM processing.",
                    newTransactionId,
                    killTransactionId,
                    message.State,
                    transactionId
                    );
            }
            // если есть только одна транзакция, то выбираем её
            else
            {
                transactionId = (Guid)(newTransactionId ?? killTransactionId);
            }

            OnMessageReceived(new OrderStateChangeMessage
            {
                TransactionId   = transactionId,
                ActiveQuantity  = (uint)message.balance,
                OrderExchangeId = message.order_num.ToString(),
                FilledQuantity  = (uint)(message.filled),
                State           = message.State,
                Price           = message.price,
                Quantity        = (uint?)message.qty,
                ChangeTime      = message.Time
            });
        }
Ejemplo n.º 4
0
        /// <summary>
        ///     Обработка статуса по заявке, которая либо была выставлена не из прикладного приложения или из другой сессии, либо по которой пока не пришёл ответ на транзакцию
        /// </summary>
        private void ProcessUnknownOrderStateChange(QLOrderStateChange message)
        {
            try
            {
                var order = container.GetOrder(message.order_num);

                // если это первый статус по заявке, то отправляем ExternalOrderMessage
                if (order == null)
                {
                    var instrument = adapter.ResolveInstrumentAsync(message.sec_code).Result;
                    if (instrument == null)
                    {
                        Logger.Error().Print($"Unable to resolve instrument for {message.sec_code}");
                        return;
                    }

                    order = new Order
                    {
                        OrderExchangeId = message.order_num.ToString(),
                        Instrument      = instrument,
                        Account         = message.account,
                        ActiveQuantity  = (uint)message.balance,
                        Quantity        = (uint)message.qty,
                        State           = message.State,
                        Price           = message.price,
                        ClientCode      = message.account,
                        Comment         = ExtractCommentFromBrokerref(message.brokerref),
                        // TODO Тут проставляется 4100Y2b//00007, а мы для кодирования стратегий используется только то, что после //
                        Operation     = message.Operation,
                        DateTime      = message.Time,
                        TransactionId = Guid.NewGuid()
                    };

                    container.PutOrder(message.order_num, order);

                    OnMessageReceived(new ExternalOrderMessage {
                        Order = order
                    });

                    OnMessageReceived(new OrderStateChangeMessage
                    {
                        ActiveQuantity  = (uint)message.balance,
                        OrderExchangeId = message.order_num.ToString(),
                        FilledQuantity  = (uint)(message.filled),
                        State           = message.State,
                        Price           = message.price,
                        Quantity        = (uint?)message.qty,
                        ChangeTime      = message.Time,
                        TransactionId   = order.TransactionId
                    });
                }
                // иначе мы уже отправляли информацию о внешней заявке и теперь должны слать статусы
                else
                {
                    OnMessageReceived(new OrderStateChangeMessage
                    {
                        ActiveQuantity  = (uint)message.qty,
                        OrderExchangeId = message.order_num.ToString(),
                        FilledQuantity  = (uint)(message.filled),
                        State           = message.State,
                        Price           = message.price,
                        Quantity        = (uint?)message.balance,
                        ChangeTime      = message.Time,
                        TransactionId   = order.TransactionId
                    });
                }
            }
            catch (Exception e)
            {
                Logger.Error().Print(e, $"Failed to process {message}");
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Обработка сообщения об изменении статуса заявки
        /// </summary>
        /// <param name="message"></param>
        private void Handle(QLOrderStateChange message)
        {
            Logger.Debug().PrintFormat("Handle: {0}", message);

            // если у нас есть транзакции без ответа, то откладываем обратку статуса заявки, будем процессить их после получения transReply
            if (container.HasUnrepliedTransactions())
            {
                // бывает квик присылает и такое
                if (message.trans_id == 0)
                {
                    container.PutPendingOrderStateChange(message);
                    return;
                }

                // если есть неотвеченные транзакции, то по OSCM можно создать ответ на транзакцию
                if (container.IsTransactionUnreplied(message.trans_id))
                {
                    if (message.State == OrderState.Active || message.State == OrderState.PartiallyFilled || message.State == OrderState.Filled)
                    {
                        Logger.Info().Print($"Handle(OSCM): transaction with trans_id = {message.trans_id} is pending and order state {message.State} received. Create and handle artifitial QLTransactionReply");
                        Handle(new QLTransactionReply
                        {
                            status     = 3,
                            result_msg = message.reject_reason,
                            trans_id   = message.trans_id,
                            account    = message.account,
                            order_num  = message.order_num,
                            price      = message.price,
                            balance    = message.balance,
                            quantity   = message.qty
                        });
                    }
                }
            }

            // Сохраняем сообщение. Если такое сообщение уже приходило, не обрабатываем его.
            if (!container.PutOrderStateChange(message))
            {
                Logger.Debug().PrintFormat("Handle: {0} - skip duplicate event", message);
                return;
            }

            // пробуем получить транзакцию, в результате которой была создана заявка, по которой мы получили данный OSCM

            // TODO Нужно пытаться получить newOrderTransaction не только по trans_id, но и по номеру заявки
            var newOrderTransaction    = container.GetNewOrderTransaction(message.trans_id, message.order_num);
            var killOrderTransaction   = container.GetKillOrderTransactionByOrderId(message.order_num);
            var modifyOrderTransaction = container.GetModifyOrderTransactionByOrderId(message.order_num);

            if (newOrderTransaction != null || killOrderTransaction != null)
            {
                ProcessKnownOrderStateChange(message, newOrderTransaction?.TransactionId,
                                             killOrderTransaction?.TransactionId, modifyOrderTransaction?.TransactionId);
            }
            else
            {
                ProcessUnknownOrderStateChange(message);
            }

            processPendingMessagesEvent.Set();
        }