Beispiel #1
0
        /// <summary>
        /// Обработка неудачной транзакции
        /// </summary>
        /// <param name="message"></param>
        private void ProcessFailedTransactionReply(QLTransactionReply message)
        {
            var newOrderTransaction    = container.GetNewOrderTransaction(message.trans_id);
            var killOrderTransaction   = container.GetKillOrderTransactionByTransId(message.trans_id);
            var modifyOrderTransaction = container.GetModifyOrderTransactionByTransId(message.trans_id);

            switch (message.status)
            {
            case 13:     // отвергнута как кросс сделка
                Logger.Error().Print("Transaction failed, due to potential cross trade", LogFields.Message(message));
                break;

            default:
                Logger.Error().Print("Transaction failed", LogFields.Message(message));
                break;
            }

            OnMessageReceived(message: new TransactionReply
            {
                Success       = message.Successful,
                Message       = message.result_msg,
                TransactionId = newOrderTransaction?.TransactionId
                                ?? killOrderTransaction?.TransactionId
                                ?? modifyOrderTransaction?.TransactionId
                                ?? Guid.Empty
            });

            container.RemoveProcessedPendingReply(message);
        }
Beispiel #2
0
        /// <summary>
        ///     Обработка отказа по заявке
        /// </summary>
        private void OrderRequestRejectReceived(AdapterEventArgs <OrderRequestReject> args)
        {
            args.MarkHandled();

            var message = $"[{args.Message.reject_code}] {args.Message.text_message}";

            Logger.Error().Print("CQG order rejected", LogFields.Message(message));

            TrySendTransactionReplyRejected(args.Message.request_id, message);
        }
Beispiel #3
0
        /// <summary>
        ///     Обработчик события изменения статуса подписки
        /// </summary>
        private void TradeSubscriptionStatusReceived(AdapterEventArgs <TradeSubscriptionStatus> args)
        {
            args.MarkHandled();

            Logger.Debug().Print(
                "Trade subscription status received",
                LogFields.Id(args.Message.id),
                LogFields.Status((TradeSubscriptionStatus.StatusCode)args.Message.status_code),
                LogFields.Message(args.Message.text_message)
                );
        }
Beispiel #4
0
        private static void MarketDataSubscriptionStatusReceived(AdapterEventArgs <MarketDataSubscriptionStatus> args)
        {
            args.MarkHandled();

            _Log.Debug().Print(
                $"Subscription status for contract #{args.Message.contract_id}: Level={1}, Status={2}. {3}",
                LogFields.Level((MarketDataSubscription.Level)args.Message.level),
                LogFields.Status((MarketDataSubscriptionStatus.StatusCode)args.Message.status_code),
                LogFields.Message(args.Message.text_message)
                );
        }
Beispiel #5
0
        private async Task HandleAsync(QLFill message)
        {
            try
            {
                Logger.Debug().Print($"Handle(QLFill): {message}");

                var instrument = await adapter.ResolveInstrumentAsync(message.sec_code);

                if (instrument == null)
                {
                    Logger.Error().Print($"Unable to resolve instrument for {message.sec_code}");
                    return;
                }

                // если заявка отправлялась в текущей сессии работы программы, то нужно убедиться, что oscm по ней уже отправлялся
                if (container.IsCurrentSessionOrder(message.order_num))
                {
                    var lastOscm = container.GetLastOrderStateChangeForOrderId(message.order_num);
                    if (lastOscm == null)
                    {
                        Logger.Debug()
                        .Print("Handle(QLFill): Fill will be processed later, no OSCM received",
                               LogFields.Message(message));
                        container.PutPendingFill(message);
                        return;
                    }
                }
                else if (container.HasUnrepliedTransactions())
                {
                    Logger.Debug()
                    .Print($"Handle(QLFill): Fill will be processed later, there are unreplied transactions",
                           LogFields.Message(message));
                    container.PutPendingFill(message);
                    return;
                }

                OnMessageReceived(new FillMessage
                {
                    Instrument      = instrument,
                    Account         = message.account,
                    Quantity        = (uint)message.qty,
                    ClientCode      = message.account,
                    ExchangeId      = message.trade_num.ToString(),
                    ExchangeOrderId = message.order_num.ToString(),
                    Price           = message.price,
                    Operation       = message.Operation,
                    DateTime        = message.Time
                });
            }
            catch (Exception e)
            {
                Logger.Error().Print(e, $"Failed to handle {message}");
            }
        }
Beispiel #6
0
        /// <summary>
        ///     Обработка результата логина
        /// </summary>
        private void Handle(LogonResult msg)
        {
            var resultCode = (LogonResult.ResultCode)msg.result_code;

            switch (resultCode)
            {
            case LogonResult.ResultCode.SUCCESS:
                Log.Info().Print($"Connected to CQG with login {settings?.Username}");
                if (!DateTime.TryParseExact(
                        msg.base_time,
                        "yyyy-MM-ddTHH:mm:ss",
                        CultureInfo.InvariantCulture,
                        DateTimeStyles.AssumeUniversal,
                        out baseTime))
                {
                    baseTime = DateTime.UtcNow;
                    Log.Warn().Print($"Unable to parse base_time = msg.base_time. Order and fill timestamps might be corrupted. Historical data won't work at all.");
                }

                //[ENABLE_CQGC_TRACE]WebApiTrace.SetBaseTime(baseTime);
                connectionStatus = ConnectionStatus.Connected;
                OnConnectionStatusChanged(connectionStatus);
                logoffEfent.Reset();
                RequestInitializingData();

                return;

            case LogonResult.ResultCode.FAILURE:
                break;

            case LogonResult.ResultCode.NO_ONETIME_PASSWORD:
                break;

            case LogonResult.ResultCode.PASSWORD_EXPIRED:
                return;

            case LogonResult.ResultCode.CONCURRENT_SESSION:
                break;

            case LogonResult.ResultCode.REDIRECTED:
                break;
            }

            Log.Error().Print("Unable to log in", LogFields.Result(resultCode), LogFields.Message(msg.text_message));
            connectionStatus = ConnectionStatus.Terminated;
            OnConnectionStatusChanged(connectionStatus);

            using (socketLock.Lock())
            {
                Log.Debug().Print("Closing CQG socket");
                socket?.Close();
            }
        }
Beispiel #7
0
        /// <summary>
        /// Сохранить сделку, требующую отложенной обработки
        /// </summary>
        /// <param name="message"></param>
        public void PutPendingFill(QLFill message)
        {
            log.Debug().Print("Postpone fill processing", LogFields.Message(message));
            using (locker.WriteLock())
            {
                if (pendingFills.ContainsKey(message.trade_num))
                {
                    log.Warn().Print($"Fill duplicate received", LogFields.Id(message.trade_num));
                    return;
                }

                pendingFills[message.trade_num] = message;
            }
        }
Beispiel #8
0
 /// <summary>
 /// Предварительная обработка ответа на транзакцию
 /// </summary>
 /// <param name="message"></param>
 private void PreprocessTransactionReply(QLTransactionReply message)
 {
     if (!string.IsNullOrEmpty(message.result_msg) &&
         (
             message.result_msg.Contains("Вы не можете снять данную заявку") ||
             message.result_msg.Contains("Не найдена заявка для удаления")
         ))
     {
         Logger.Warn().Print(
             $"Failed kill transaction will be treated as successfull, status will be changed from {message.status} to 3",
             LogFields.Message(message)
             );
         message.status = 3;
     }
 }
 public void Send(Transaction transaction)
 {
     try
     {
         transaction.Accept(this);
     }
     catch (TransactionRejectedException exception)
     {
         Reject(transaction, exception.Message);
     }
     catch (Exception exception)
     {
         _Log.Error()
         .Print(exception, "Unable to send transaction", LogFields.Transaction(transaction),
                LogFields.Message(exception.Message));
         Reject(transaction, "Transaction execution failed: {0}", exception.Message);
     }
 }
Beispiel #10
0
        private void MarketDataNotResolved(AdapterEventArgs <InformationReport> args)
        {
            ResolutionRequest request;

            using (resolutionRequestsLock.Lock())
            {
                if (!resolutionRequestsById.TryGetValue(args.Message.id, out request))
                {
                    return;
                }

                resolutionRequestsById.Remove(request.Id);
                resolutionRequestsByInstrument.Remove(request.Instrument);
            }

            request.Reject();
            args.MarkHandled();

            _Log.Error().Print("Failed to resolve instrument", LogFields.RequestId(request.Id), LogFields.Message(args.Message.text_message));
        }
        /// <summary>
        ///     Обработать транзакцию <see cref="NewOrderTransaction"/>
        /// </summary>
        /// <param name="transaction">
        ///     Транзакция для обработки
        /// </param>
        async void ITransactionVisitor.Visit(NewOrderTransaction transaction)
        {
            try
            {
                var order = new IBOrder
                {
                    Account       = transaction.Account,
                    ClientId      = connector.ClientId,
                    Action        = transaction.Operation == OrderOperation.Buy ? "BUY" : "SELL",
                    TotalQuantity = (int)transaction.Quantity,
                    OrderRef      = !string.IsNullOrWhiteSpace(transaction.Comment)
                        ? connector.IBOrderRouter.SessionUidInternal + transaction.Comment
                        : connector.IBOrderRouter.SessionUidInternal,
                    Transmit = true
                };

                switch (transaction.Type)
                {
                case OrderType.Limit:
                    order.OrderType = "LMT";
                    order.LmtPrice  = (double)transaction.Price;
                    break;

                case OrderType.Market:
                    order.OrderType = "MKT";
                    break;

                default:
                    throw new ArgumentOutOfRangeException("transaction.Type");
                }

                switch (transaction.ExecutionCondition)
                {
                case OrderExecutionCondition.PutInQueue:
                    order.Tif = "GTC";     /* Good till cancelled */
                    break;

                case OrderExecutionCondition.FillOrKill:
                    order.Tif = "FOC";     /* Fill or cancel */
                    break;

                case OrderExecutionCondition.KillBalance:
                    order.Tif = "IOC";     /* Immediate or cancel */
                    break;

                default:
                    throw new ArgumentOutOfRangeException("transaction.ExecutionCondition");
                }

                await connector.Adapter.PlaceOrderAsync(transaction, order);
            }
            catch (TransactionRejectedException exception)
            {
                Reject(transaction, exception.Message);
            }
            catch (Exception exception)
            {
                _Log.Error()
                .Print(exception, "Unable to send transaction", LogFields.Transaction(transaction),
                       LogFields.Message(exception.Message));
                Reject(transaction, "Transaction execution failed: {0}", exception.Message);
            }
        }
Beispiel #12
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);
            }
        }
Beispiel #13
0
        /// <summary>
        /// Обработка успешной транзакции
        /// </summary>
        private void ProcessSuccessfulTransactionReply(QLTransactionReply message)
        {
            var newOrderTransaction    = container.GetNewOrderTransaction(message.trans_id);
            var killOrderTransaction   = container.GetKillOrderTransactionByTransId(message.trans_id);
            var modifyOrderTransaction = container.GetModifyOrderTransactionByTransId(message.trans_id);

            if (newOrderTransaction == null && killOrderTransaction == null && modifyOrderTransaction == null)
            {
                Logger.Warn().Print("TRANS_REPL received for transaction which wasn't sent from application", LogFields.Message(message));
                container.RemoveProcessedPendingReply(message);
                return;
            }

            QLOrderStateChange lastState;

            if ((lastState = container.GetLastOrderStateChangeForTransactionId(message)) == null)
            {
                Logger.Debug().Print("Postpone TrRepl processing, no last OSCM found", LogFields.Message(message));
                container.PutPendingTransactionReply(message);
                return;
            }

            // проверка соответствия последнего статуса типу транзакции
            // kill транзакция считатется завершённой, если заявка находится в одном из статусов ниже
            if (killOrderTransaction != null && lastState.State == OrderState.New)
            {
                Logger.Debug().Print($"Postpone KillTrRepl processing. Last ord state is {lastState.State}", LogFields.Message(message));
                container.PutPendingTransactionReply(message);
                return;
            }

            // new транзакция считатется завершённой, если заявка не находится в одном из статусов ниже
            if (newOrderTransaction != null &&
                (lastState.State == OrderState.New || lastState.State == OrderState.Undefined))
            {
                Logger.Debug().Print($"Postpone NewTrRepl processing. Last ord state is {lastState.State}", LogFields.Message(message));
                container.PutPendingTransactionReply(message);
                return;
            }

            if (modifyOrderTransaction != null &&
                (lastState.State == OrderState.New || lastState.State == OrderState.Undefined ||
                 lastState.trans_id != message.trans_id))
            {
                Logger.Debug().Print($"Postpone ModifyTrRepl processing. Last ord state is {lastState.State}", LogFields.Message(message));
                Logger.Error().Print("Handle(TR): for modify transaction not implemented");
                container.PutPendingTransactionReply(message);
                return;
            }

            if (killOrderTransaction != null)
            {
                var unfilledQuantity = ParseUnfilledQuantityFromTransactionReply(message);
                Logger.Debug().Print($"Handle(TR)[{message.trans_id}]: Create artifitial OSCM from successful kill transaction reply", LogFields.Message(message));

                OnMessageReceived(new OrderStateChangeMessage
                {
                    TransactionId   = killOrderTransaction.TransactionId,
                    ActiveQuantity  = (uint)unfilledQuantity,
                    OrderExchangeId = message.order_num.ToString(),
                    //FilledQuantity = (uint)(message.filled),
                    State    = OrderState.Cancelled,
                    Price    = message.price,
                    Quantity = (uint?)message.quantity
                });
            }

            OnMessageReceived(new TransactionReply
            {
                Success       = message.Successful,
                Message       = message.result_msg,
                TransactionId = newOrderTransaction?.TransactionId
                                ?? killOrderTransaction?.TransactionId
                                ?? modifyOrderTransaction?.TransactionId
                                ?? Guid.Empty
            });

            container.RemoveProcessedPendingReply(message);
        }
Beispiel #14
0
        private void Handle(QLTransactionReply message)
        {
            Logger.Debug().PrintFormat("Handle: {0}", message);

            var orderExchangeId = ParseOrderIdFromTransactionReply(message);

            if (orderExchangeId > 0)
            {
                container.PutOrderExchangeId(orderExchangeId);
            }

            var pendingOscmsToProcess = container.PutTransactionReply(message, orderExchangeId);

            if (pendingOscmsToProcess != null)
            {
                Logger.Debug().Print($"Handle(TR) fires {pendingOscmsToProcess.Count} pending OSCMs to process", LogFields.Message(message));
                foreach (var oscm in pendingOscmsToProcess)
                {
                    // если у нас был получен oscm по данному номеру заявки, но с нулевым trans_id (да да, такое бывает), то тут
                    // у нас есть прекрасная возможность проставить oscm.trans_id и запроцессить oscm по нормальному алгоритму
                    if (oscm.order_num == orderExchangeId && oscm.trans_id == 0)
                    {
                        oscm.trans_id = message.trans_id;
                    }

                    Handle(oscm);
                }
            }

            PreprocessTransactionReply(message);

            if (message.Successful)
            {
                ProcessSuccessfulTransactionReply(message);
            }
            else
            {
                ProcessFailedTransactionReply(message);
            }
        }