示例#1
0
        private void InfoClient_OnInfoTrade(InfoTrade trade)
        {
            if (trade.acc_id == 0 || !mapAccountIdToAccount.ContainsKey(trade.acc_id))
            {
                return;
            }

            var code       = trade.security + "|" + trade.board;
            var instrument = connector.ResolveSymbolAsync(code).Result;

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

            var fill = new FillMessage
            {
                Account         = mapAccountIdToAccount[trade.acc_id].code,
                Instrument      = instrument,
                ExchangeId      = trade.code,
                Operation       = trade.buy_sell == BuySell.BUY ? OrderOperation.Buy : OrderOperation.Sell,
                Price           = PriceHelper.ToPrice(trade.price),
                Quantity        = trade.qty,
                DateTime        = DateTime.FromFileTime((long)trade.trade_time),
                ExchangeOrderId = trade.order_id
            };

            OnMessageReceived(fill);
        }
示例#2
0
        public async Task <List <AssetModel> > HarvestAssetList(string strServiceUri)
        {
            var objMessage = new FillMessage();
            var lstUris    = new List <Uri>();
            var lstAssets  = new List <AssetModel>();

            try
            {
                var resultObject = await GetHarvestList(strServiceUri);

                var bulkUpdates = resultObject.Products.FirstOrDefault()?.BulkUpdates;
                bulkUpdates.ForEach(
                    bf => bf.BulkFiles.ForEach(
                        harvest => Helpers.ExtractFileInformation(harvest.Location, lstUris, lstAssets)
                        ));

                return(lstAssets);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            return(null);
        }
示例#3
0
        public override void execDetails(int reqId, Contract contract, Execution execution)
        {
            //Сделки с нулевым количеством
            //Пропускаем BAG, т.к. это контракт для конструкций. Сейчас мы его не используем.
            //BAG is the security type for COMBO order
            //https://www.interactivebrokers.com/en/software/api/apiguide/c/placing_a_combination_order.htm
            //https://www.interactivebrokers.com/en/software/api/apiguide/tables/api_message_codes.htm
            if (contract.SecType == "BAG")
            {
                return;
            }

            Log.Debug().PrintFormat("< execDetails {0} {1} {2} {3}", reqId, contract.ConId, execution.ExecId);

            connector.ContractContainer.GetInstrumentAsync(
                contract,
                string.Format("A fill on order \"{0}\", account \"{1}\"", execution.ExecId, execution.AcctNumber),
                async instrument =>
            {
                var fill = new FillMessage
                {
                    Account         = execution.AcctNumber,
                    Instrument      = instrument,
                    DateTime        = ParseExecutionTime(execution.Time),
                    ExchangeId      = execution.ExecId,
                    ExchangeOrderId = execution.PermId.ToString(CultureInfo.InvariantCulture),
                    Operation       = execution.Side == "BOT" ? OrderOperation.Buy : OrderOperation.Sell,
                    Price           = (decimal)execution.Price,
                    Quantity        = (uint)execution.CumQty
                };

                // В случае частичного исполнения заявки мы запоминаем прежнее значение CumQty
                // и в соответствии с ним пересчитываем fill.Quantity
                using (lastExecCumQtiesLock.Lock())
                {
                    var orderKey = new Tuple <Instrument, int>(instrument, execution.PermId);
                    int lastQty;
                    if (lastExecCumQties.TryGetValue(orderKey, out lastQty))
                    {
                        fill.Quantity = (uint)(execution.CumQty - lastQty);
                    }

                    lastExecCumQties[orderKey] = execution.CumQty;
                }

                // Ждём пока в наш адаптер не придут данные по заявке
                await orderInfoContainer.WaitOrderForFill(execution);

                // Выплевываем наружу сообщение
                connector.IBOrderRouter.Transmit(fill);
            });
        }
示例#4
0
        /// <summary>
        ///     Сгенерировать <see cref="FillMessage"/>
        /// </summary>
        private void TryEmitFills(OrderStatus orderStatus, Order order)
        {
            if (orderStatus.transaction_status != null)
            {
                foreach (var transactionStatus in orderStatus.transaction_status)
                {
                    switch ((TransactionStatus.Status)transactionStatus.status)
                    {
                    case TransactionStatus.Status.FILL:
                        if (transactionStatus.trade == null)
                        {
                            continue;
                        }

                        foreach (var trade in transactionStatus.trade)
                        {
                            if (trade != null)
                            {
                                using (processedFillsLock.Lock())
                                {
                                    if (!processedFillIds.Add(trade.trade_id))
                                    {
                                        // Сделка уже обработана
                                        continue;
                                    }
                                }

                                var fill = new FillMessage
                                {
                                    Instrument      = order.Instrument,
                                    DateTime        = adapter.ResolveDateTime(trade.trade_utc_time),
                                    Account         = order.Account,
                                    Operation       = ConvertionHelper.GetOrderOperation((WebAPI.Order.Side)trade.side),
                                    Price           = instrumentResolver.ConvertPriceBack(trade.contract_id, trade.price),
                                    Quantity        = trade.qty,
                                    ExchangeId      = trade.trade_id,
                                    ExchangeOrderId = order.OrderExchangeId
                                };

                                OnMessageReceived(fill);
                            }
                        }
                        break;
                    }
                }
            }
        }
示例#5
0
        /// <summary>
        /// Сохраняет свою сделку.
        /// </summary>
        /// <param name="fill">Данные своей сделки.</param>
        protected void AddFill(FillMessage fill)
        {
            if (!storeFillsInMemory)
            {
                return;
            }

            if (!IsPermittedAccount(fill.Account))
            {
                return;
            }

            using (SyncRoot.Lock())
            {
                Dictionary <Instrument, List <FillMessage> > accountFills;

                if (!AvailableAccounts.Contains(fill.Account))
                {
                    AvailableAccounts.Add(fill.Account);
                    accountFills = new Dictionary <Instrument, List <FillMessage> >();
                    Fills.Add(fill.Account, accountFills);
                }
                else
                {
                    accountFills = Fills[fill.Account];
                }

                List <FillMessage> instrumentFills;

                if (!accountFills.TryGetValue(fill.Instrument, out instrumentFills))
                {
                    instrumentFills = new List <FillMessage>();
                    accountFills.Add(fill.Instrument, instrumentFills);
                }

                instrumentFills.Add(fill);
            }
        }
示例#6
0
 /// <summary>
 ///     Выплюнуть из раутера сообщение
 /// </summary>
 /// <param name="message">
 ///     Сообщение
 /// </param>
 internal void Transmit(FillMessage message)
 {
     OnMessageReceived(message);
 }
示例#7
0
        private async void Handle(ExecutionReport msg)
        {
            var    clOrderId     = msg.ClOrdID.Obj;
            string origClOrderId = null;

            if (msg.IsSetOrigClOrdID())
            {
                origClOrderId = msg.OrigClOrdID.Obj;
            }

            var state = msg.IsSetOrdStatus() ? ConvertOrderState(msg.OrdStatus) : null;
            var price = msg.IsSetPrice() ? msg.Price.Obj : (decimal?)null;

            price = price != 0M ? price : null;
            var qty             = msg.IsSetOrderQty() ? (uint)msg.OrderQty.Obj : (uint?)null;
            var filledQty       = msg.IsSetLastQty() ? (uint)msg.LastQty.Obj : (uint?)null;
            var activeQty       = msg.IsSetLeavesQty() ? (uint)msg.LeavesQty.Obj : (uint?)null;
            var time            = msg.IsSetTransactTime() ? ParseTransactTime() : DateTime.Now;
            var orderExchangeId = msg.IsSetOrderID() ? msg.OrderID.Obj : null;

            var transactionId = _orders.GetOrCreateOrderTransactionId(origClOrderId ?? clOrderId);

            var oscm = new OrderStateChangeMessage
            {
                TransactionId   = transactionId,
                State           = state,
                Price           = price,
                Quantity        = qty,
                FilledQuantity  = filledQty,
                ActiveQuantity  = activeQty,
                ChangeTime      = time,
                OrderExchangeId = orderExchangeId
            };

            switch (msg.ExecType.Obj)
            {
            case ExecType.NEW:
                _newOrderTransactions.Accept(clOrderId);
                _orders.SaveOrderExchangeId(transactionId, orderExchangeId);
                SendMessage(oscm);
                break;

            case ExecType.TRADE:
                _newOrderTransactions.Accept(clOrderId);
                _orders.SaveOrderExchangeId(transactionId, orderExchangeId);

                SendMessage(oscm);
                await EmitFillAsync();

                if (oscm.State == OrderState.Filled)
                {
                    _newOrderTransactions.Forget(transactionId);
                    _killOrderTransactions.Forget(msg.ClOrdID.Obj);
                    _orders.ForgetOrder(transactionId);
                }
                break;

            case ExecType.FILL:
                _newOrderTransactions.Accept(clOrderId);

                _orders.SaveOrderExchangeId(transactionId, orderExchangeId);
                SendMessage(oscm);
                await EmitFillAsync();

                if (oscm.State == OrderState.Filled)
                {
                    _newOrderTransactions.Forget(transactionId);
                    _killOrderTransactions.Forget(msg.ClOrdID.Obj);
                    _orders.ForgetOrder(transactionId);
                }
                break;

            case ExecType.PARTIAL_FILL:
                _newOrderTransactions.Accept(clOrderId);
                _orders.SaveOrderExchangeId(transactionId, orderExchangeId);
                SendMessage(oscm);
                await EmitFillAsync();

                break;

            case ExecType.REJECTED:
                string rejectReason;
                switch (msg.OrdRejReason.Obj)
                {
                case OrdRejReason.UNKNOWN_SYMBOL:
                    rejectReason = "Unknown symbol";
                    break;

                case OrdRejReason.EXCHANGE_CLOSED:
                    rejectReason = "Exchange closed";
                    break;

                case OrdRejReason.ORDER_EXCEEDS_LIMIT:
                    rejectReason = "Order exceeds limit";
                    break;

                case OrdRejReason.DUPLICATE_ORDER:
                    rejectReason = "Duplicate order";
                    break;

                default:
                    rejectReason = $"#{msg.OrdRejReason.Obj}";
                    break;
                }
                if (!string.IsNullOrEmpty(msg.Text?.Obj))
                {
                    rejectReason = $"{rejectReason}. {msg.Text?.Obj}";
                }
                _newOrderTransactions.Reject(clOrderId, rejectReason);
                _orders.ForgetOrder(transactionId);
                break;

            case ExecType.PENDING_CANCEL:
                _killOrderTransactions.Accept(msg.ClOrdID.Obj);
                SendMessage(oscm);
                break;

            case ExecType.CANCELED:
                _killOrderTransactions.Accept(msg.ClOrdID.Obj);
                _newOrderTransactions.Forget(transactionId);
                _killOrderTransactions.Forget(msg.ClOrdID.Obj);
                _orders.ForgetOrder(transactionId);
                SendMessage(oscm);
                break;

            case ExecType.PENDING_REPLACE:
                _modifyOrderTransactions.Accept(clOrderId);
                break;

            case ExecType.REPLACED:
                _newOrderTransactions.Forget(origClOrderId);
                _killOrderTransactions.Forget(clOrderId);
                _orders.UpdateOrderParams(
                    orderExchangeId: orderExchangeId,
                    origClOrderId: origClOrderId,
                    clOrderId: clOrderId,
                    symbol: msg.Symbol.Obj,
                    qty: msg.OrderQty.Obj,
                    side: msg.Side.Obj);

                SendMessage(oscm);
                break;

            default:
                _Log.Warn().PrintFormat("Unknown ExecType: {0}", msg.ExecType.Obj);
                break;
            }

            OrderState?ConvertOrderState(OrdStatus field)
            {
                switch (field.Obj)
                {
                case OrdStatus.PENDING_NEW: return(OrderState.New);

                case OrdStatus.NEW: return(OrderState.Active);

                case OrdStatus.CANCELED: return(OrderState.Cancelled);

                case OrdStatus.FILLED: return(OrderState.Filled);

                case OrdStatus.PARTIALLY_FILLED: return(OrderState.PartiallyFilled);

                case OrdStatus.REJECTED: return(OrderState.Error);

                case OrdStatus.PENDING_CANCEL: return(null);

                case OrdStatus.PENDING_REPLACE: return(null);

                default:
                    _Log.Warn().PrintFormat("Unknown OrdStatus: {0}", field.Obj);
                    return(null);
                }
            }

            DateTime ParseTransactTime()
            {
                var maxLen = "20170912-09:39:57.2761221".Length;

                var str = msg.GetString(60 /*TransactTime*/);

                if (str.Length > maxLen)
                {
                    str = str.Substring(0, maxLen);
                }
                var t = DateTime.ParseExact(str, "yyyyMMdd-HH:mm:ss.fffffff", null, DateTimeStyles.AssumeUniversal);

                return(t);
            }

            async Task EmitFillAsync()
            {
                if (!msg.IsSetSecondaryExecID())
                {
                    return;
                }

                var fillExchangeId = msg.SecondaryExecID.Obj;
                var fillPrice      = msg.IsSetLastPx() ? msg.LastPx.Obj : (decimal?)null;

                price = price != 0M ? price : null;
                var fillQty = msg.IsSetLastQty() ? (uint)msg.LastQty.Obj : (uint?)null;

                if (fillPrice == null || fillQty == null)
                {
                    return;
                }

                Instrument instrument;

                try
                {
                    instrument = await _settings.InstrumentConverter.ResolveSymbolAsync(this, msg.Symbol.Obj);
                }
                catch (Exception e)
                {
                    _Log.Error().Print(e, $"Failed to resolve instrument {msg.Symbol.Obj}");
                    return;
                }

                var fill = new FillMessage
                {
                    Price           = fillPrice.Value,
                    Quantity        = fillQty.Value,
                    DateTime        = time,
                    Instrument      = instrument,
                    Account         = msg.Account.Obj,
                    Operation       = msg.Side.Obj == Side.BUY ? OrderOperation.Buy : OrderOperation.Sell,
                    ExchangeId      = fillExchangeId,
                    ExchangeOrderId = orderExchangeId
                };

                SendMessage(fill);
            }
        }