예제 #1
0
 public void Store(int tickerId, HistoryTaskCompletionSource tcs)
 {
     using (historyPointsLock.Lock())
     {
         tasks[tickerId] = tcs;
     }
 }
예제 #2
0
        /// <summary>
        ///     Выставить заявку
        /// </summary>
        /// <param name="transaction">
        ///     Транзакция
        /// </param>
        /// <param name="order">
        ///     IB-заявка
        /// </param>
        public async Task PlaceOrderAsync(NewOrderTransaction transaction, IBOrder order)
        {
            var instrument = transaction.Instrument;

            var contract = await connector.ContractContainer.GetContractAsync(instrument, null);

            if (contract == null)
            {
                throw new TransactionRejectedException($"Details of contract {instrument.Code} are not available");
            }

            using (orderInfoContainerLock.Lock())
            {
                var tickerId = NextTickerId();
                order.OrderId = tickerId;

                // Сохраняем заявку по ее тикеру
                var orderInfo = new OrderInfo(order, transaction.Instrument)
                {
                    State = OrderState.New,
                    NewOrderTransactionId = transaction.TransactionId
                };
                orderInfoContainer.StoreByTickerId(tickerId, orderInfo, true);

                Socket.placeOrder(tickerId, contract, order);
            }
        }
예제 #3
0
        /// <summary>
        ///     Останов адаптера
        /// </summary>
        public void Stop()
        {
            try
            {
                using (socketLock.Lock())
                {
                    if (socket == null || stopped)
                    {
                        return;
                    }
                }

                stopped = true;
                Log.Info().Print("Stopping CQGCAdapter");
                SendLogoff();
                cancellationTokenSource.Cancel();
                Log.Info().Print("Waiting for logoff reply");

                WaitHandle.WaitAny(new WaitHandle[] { socketClosedEvent, logoffEfent });
            }
            catch (CQGCAdapterConnectionException e)
            {
                // Адаптер не был подключен, logoff не нужен
                Log.Warn().Print(e, "No active connection on stop");
            }
        }
 public void Store(int tickerId, PendingTestResult testResult)
 {
     using (syncRoot.Lock())
     {
         testResultByTicker[tickerId] = testResult;
     }
 }
예제 #5
0
        internal async Task <IList <HistoryDataPoint> > FetchHistoryDataAsync(
            string instrumentSymbol,
            DateTime begin,
            DateTime end,
            HistoryProviderSpan span,
            CancellationToken cancellationToken)
        {
            // Создаем операцию для ожидания
            var operation = new HistoryRequest(span, begin, end);
            var requestId = HistorySocketWrapper.HistoryRequestIdPefix + Guid.NewGuid().ToString("N");

            using (historyRequestsLock.Lock())
            {
                historyRequests[requestId] = operation;
            }

            // Подписываемся на исторические данные
            historySocket.RequestHistoryData(instrumentSymbol, begin, end, span, requestId);

            // Разрешаем отмену операции
            cancellationToken.RegisterSafe(() => operation.TrySetCanceled());

            // Дожидаемся результатов
            var points = await operation.Task;

            return(points);
        }
예제 #6
0
        /// <summary>
        ///     Проверить подписку по вендорскому коду
        /// </summary>
        public async Task <Tuple <bool, string> > TrySubscribeAsync(string code, SecurityType type)
        {
            using (LogManager.Scope())
            {
                await securityTypeIndexCompleted.Task;

                int typeId;
                if (!securityTypeIndex.TryGetValue(type, out typeId))
                {
                    var message = LogMessage.Format($"Failed to find an identifier for {type}").ToString();
                    Logger.Warn().Print(message);
                    return(Tuple.Create(false, message));
                }

                var operation = new SubscriptionTest(code, type);
                var requestId = LookupSocketWrapper.RequestIdPrefix + Guid.NewGuid().ToString("N");
                using (subscriptionTestsLock.Lock())
                {
                    subscriptionTests[requestId] = operation;
                }

                lookupSocket.RequestSymbolLookup(code, typeId, requestId);

                var result = await operation.Task;
                return(Tuple.Create(result, operation.Message));
            }
        }
예제 #7
0
        /// <summary>
        ///     Получить исторические данные
        /// </summary>
        /// <param name="consumer">
        ///     Потребитель исторических данных
        /// </param>
        /// <param name="instrument">
        ///     Инструмент
        /// </param>
        /// <param name="begin">
        ///     Начало диапазона
        /// </param>
        /// <param name="end">
        ///     Конец диапазона
        /// </param>
        /// <param name="span">
        ///     Интервал свечей для исторических данных
        /// </param>
        /// <param name="cancellationToken">
        ///     Токен отмены
        /// </param>
        /// <returns>
        ///     Исторические данные
        /// </returns>
        /// <remarks>
        ///     Провайдер вправе переопределить параметры исторических графиков - диапазон, интервал,
        ///     если он не в состоянии предоставить запрошенные данные.
        /// </remarks>
        /// <exception cref="NoHistoryDataException">
        ///     Бросается, если исторические данные за указанный период недоступны
        /// </exception>
        public async Task GetHistoryDataAsync(
            IHistoryDataConsumer consumer,
            Instrument instrument,
            DateTime begin,
            DateTime end,
            HistoryProviderSpan span,
            CancellationToken cancellationToken = new CancellationToken())
        {
            var symbol = await adapter.ResolveSymbolAsync(instrument);

            if (symbol == null)
            {
                consumer.Error($"Unable to resolve symbol for {instrument}");
                return;
            }

            QLAdapter.Log.Debug().Print($"Candles request: {symbol}, span {span}, from {begin} to {end}");
            var dataRequestMessage = new QLHistoryDataRequest(symbol, span);
            var request            = new HistoryDataRequest(dataRequestMessage.id, instrument, begin, end, span);

            using (requestsLock.Lock())
            {
                requests[request.Id] = request;
            }

            // Поддержка отмены запроса
            cancellationToken.RegisterSafe(() => request.TrySetCanceled());

            adapter.SendMessage(dataRequestMessage);

            var data = await request.Task;

            QLAdapter.Log.Debug().Print("Push candles to consumer. ", LogFields.RequestId(request.Id));
            consumer.Update(data, HistoryDataUpdateType.Batch);
        }
예제 #8
0
        private async Task SendResolutionRequestAsync(ResolutionRequest request)
        {
            var instrument = request.Instrument;
            var data       = await InstrumentConverter.ResolveInstrumentAsync(adapter, instrument);

            // если символ не зарезолвился, выходим
            if (data == null)
            {
                request.Resolve(uint.MaxValue);
                return;
            }

            var message = new InformationRequest
            {
                symbol_resolution_request = new SymbolResolutionRequest {
                    symbol = data.Symbol
                },
                id = request.Id
            };

            request.OnSent();

            using (requestBatchLock.Lock())
            {
                requestBatch.Add(message);
            }

            _Log.Debug().PrintFormat(
                "Sending a symbol resolution request {0} for instrument {1} mapped to symbol {2}",
                request.Id,
                instrument,
                data.Symbol
                );
        }
예제 #9
0
 /// <summary>
 ///     Запомнить транзакцию
 /// </summary>
 private void StoreTransaction(uint requestId, Transaction transaction)
 {
     using (transactionIdsByRequestIdLock.Lock())
     {
         transactionIdsByRequestId[requestId]             = transaction.TransactionId;
         transactionRequestIds[transaction.TransactionId] = requestId;
     }
 }
 public void Store(int tickerId, Instrument instrument)
 {
     using (syncRoot.Lock())
     {
         instrumentByTicker[tickerId]   = instrument;
         tickerByInstrument[instrument] = tickerId;
     }
 }
예제 #11
0
파일: QLFeed.cs 프로젝트: ralex1975/Polygon
        private async Task HandleAsync(QLInstrumentParams message)
        {
            var instrument = await adapter.ResolveInstrumentAsync(message.code);

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

            decimal pricemin = 0, pricemax = 0;

            decimal.TryParse(message.pricemin, out pricemin);
            decimal.TryParse(message.pricemax, out pricemax);

            // цены шага
            var stepPrices = new[]
            { message.stepPriceT, message.stepPrice, message.stepPriceCl, message.stepPricePrCl };

            // первая ненулевая цена шага
            var stepPriceValue = stepPrices.FirstOrDefault(x => x != 0);

            // проверить утверждение: любая цена шага равна либо stepPriceValue, либо 0
            //Debug.Assert(stepPrices.All(x => x == stepPriceValue || x == 0));
            // NOTE выяснилось, что утверждение иногда не выполняется. Замечен случай с BRM6 stepPricePrCl=stepPrice=stepPriceT=6.61737, stepPriceCl=6.63015

            var ip = new InstrumentParams
            {
                Instrument           = instrument,
                BestBidPrice         = message.bid,
                LastPrice            = message.last,
                LotSize              = message.lotsize,
                BestOfferPrice       = message.offer,
                Vola                 = message.volatility,
                BestBidQuantity      = message.bidQuantity,
                BestOfferQuantity    = message.offerQuantity,
                PriceStep            = message.priceStep,
                PriceStepValue       = stepPriceValue,
                Settlement           = message.settlement,
                PreviousSettlement   = message.previousSettlement,
                BottomPriceLimit     = pricemin,
                TopPriceLimit        = pricemax,
                VolaTranslatedByFeed = true,
                SessionEndTime       = message.endTime,
                OpenInterest         = message.openinterest
            };

            OnMessageReceived(ip);

            using (fullCodesLock.Lock())
            {
                fullCodes[ip.Instrument] = message.fullCode;
            }
        }
예제 #12
0
        /// <summary>
        ///     Обработчик события по статусу заявки
        /// </summary>
        private async void OrderStatusReceived(AdapterEventArgs <OrderStatus> args)
        {
            using (LogManager.Scope())
            {
                try
                {
                    Logger.Debug().Print(
                        "Order status received",
                        LogFields.ExchangeOrderId(args.Message.order_id),
                        LogFields.ChainOrderId(args.Message.chain_order_id),
                        LogFields.State(ConvertionHelper.GetOrderState(args.Message)),
                        LogFields.AccountId(args.Message.account_id),
                        LogFields.ExecOrderId(args.Message.exec_order_id)
                        );

                    args.MarkHandled();

                    // Обрабатываем метаданные контрактов
                    if (args.Message.contract_metadata != null)
                    {
                        foreach (var metadata in args.Message.contract_metadata)
                        {
                            await instrumentResolver.HandleMetadataAsync(metadata);
                        }
                    }

                    // Пытаемся выбрать заявку из контейнера
                    Order order;
                    using (ordersLock.Lock())
                        ordersByOrderExchangeId.TryGetValue(args.Message.chain_order_id, out order);

                    Message message;
                    // Обрабатываем изменение статуса заявки
                    if (order != null)
                    {
                        message = HandleOrderStateAsOrderStateChange(order, args.Message);
                    }
                    // Обрабатываем заявку как новую
                    else
                    {
                        message = HandleOrderStateAsNewOrder(args.Message, out order);
                    }

                    // Отправляем сообщение и TransactionReply
                    if (message != null)
                    {
                        OnMessageReceived(message);
                        TryEmitTransactionReplies(args.Message);

                        // Обрабатываем сделки
                        TryEmitFills(args.Message, order);
                    }
                }
                catch (Exception e)
                {
                    Logger.Error().Print(e, $"Failed to process {args.Message}");
                }
            }
        }
예제 #13
0
        /// <summary>
        ///     Запуск транспорта
        /// </summary>
        public void Start()
        {
            using (syncRoot.Lock())
            {
                if (isConnected)
                {
                    return;
                }

                isConnected = Adapter.Connect(settings.Host, settings.Port, settings.ClientId);
            }
        }
예제 #14
0
            public bool Update(ref L1FundamentalMsg msg)
            {
                Confirm();

                using (syncRoot.Lock())
                {
                    InstrumentParams.DecimalPlaces  = msg.DecimalPlaces;
                    InstrumentParams.PriceStep      = msg.PriceStep;
                    InstrumentParams.PriceStepValue = msg.PriceStepValue;

                    return(true);
                }
            }
예제 #15
0
        private void RequestMarketDataSubscription(InstrumentSubscription subscription, MarketDataSubscription.Level level)
        {
            var marketDataSubscription = new MarketDataSubscription
            {
                contract_id = subscription.ContractId,
                level       = (uint)level
            };

            subscription.StartWaitForData(level);
            using (requestBatchLock.Lock())
            {
                requestBatch.Add(marketDataSubscription);
            }
        }
예제 #16
0
        public async Task <string[]> LookupSymbols(string code, int?maxResults)
        {
            var operation = new SymbolLookupRequest(maxResults);
            var requestId = LookupSocketWrapper.RequestIdPrefix + Guid.NewGuid().ToString("N");

            using (symbolLookupRequestsLock.Lock())
            {
                symbolLookupRequests[requestId] = operation;
            }

            lookupSocket.RequestSymbolLookup(code, null, requestId);

            var result = await operation.Task;

            return(result);
        }
예제 #17
0
 public void AddPoint(HistoryDataPoint point)
 {
     using (historyPointsLock.Lock())
     {
         points.Add(point);
     }
 }
예제 #18
0
        /// <summary>
        ///     Подписаться на инструмент.
        /// </summary>
        /// <param name="instrument">
        ///     Инструмент для подписки.
        /// </param>
        public async Task <SubscriptionResult> Subscribe(Instrument instrument)
        {
            using (LogManager.Scope())
            {
                var data = await instrumentConverter.ResolveInstrumentAsync(this, instrument);

                if (data == null)
                {
                    return(SubscriptionResult.Error(instrument, $"Unable to resolve symbol for {instrument}"));
                }

                // Забираем подписку из коллекции или создаем новую
                InstrumentSubscription subscription;
                bool isNewSubscription;
                using (instrumentSubscriptionsLock.Lock())
                {
                    if (instrumentSubscriptionsByInstrument.TryGetValue(instrument, out subscription))
                    {
                        isNewSubscription = false;
                    }
                    else
                    {
                        subscription = new InstrumentSubscription(instrument, data, OnInstrumentSubscriptionTimedOut);
                        instrumentSubscriptionsByInstrument.Add(instrument, subscription);

                        instrumentSubscriptionsByCode[subscription.Code] = subscription;
                        isNewSubscription = true;
                    }
                }

                if (isNewSubscription)
                {
                    // Если подписка уже существовала, то ничего не делаем
                    // В противном случае требуется подписаться

                    // Подписываемся
                    socketL1.Subscribe(subscription.Code);
                    subscription.BeginTimeout();
                }

                return(await subscription.Task);
            }
        }
예제 #19
0
        public OrderBook Update(int position, int operation, int side, double price, int size)
        {
            using (syncRoot.Lock())
            {
                // Выбираем нужную сторону стакана
                List <OrderBookItem> targetList;
                switch (side)
                {
                case 0:
                    targetList = asks;
                    break;

                case 1:
                    targetList = bids;
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(side));
                }

                // Дополняем стакан до нужной глубины
                var op = side == 0 ? OrderOperation.Sell : OrderOperation.Buy;
                while (targetList.Count <= position)
                {
                    targetList.Add(new OrderBookItem {
                        Operation = op
                    });
                }

                var item = targetList[position];
                switch (operation)
                {
                case 0:
                    // Добавляем строку в стакан
                    item.Price    = (decimal)price;
                    item.Quantity = size;
                    break;

                case 1:
                    // Обновляем строку в стакане
                    item.Price    = (decimal)price;
                    item.Quantity = size;
                    break;

                case 2:
                    // Удаляем строку из стакана
                    item.Price    = (decimal)price;
                    item.Quantity = 0;
                    break;
                }

                // Собираем стакан
                return(BuildOrderBook());
            }
        }
예제 #20
0
        /// <summary>
        ///     Получить Contract ID для инструмента
        /// </summary>
        /// <param name="instrument">
        ///     Инструмент
        /// </param>
        /// <returns>
        ///     Contract ID
        /// </returns>
        public async Task <uint> GetContractIdAsync(Instrument instrument)
        {
            using (LogManager.Scope())
            {
                // Ищем ID контракта в кеше
                uint contractId;
                using (cacheLock.Lock())
                {
                    if (cachedContractIds.TryGetValue(instrument, out contractId))
                    {
                        return(contractId);
                    }
                }

                // Ищем или создаем запрос инструмента
                ResolutionRequest request;
                var sendRequest = false;
                using (resolutionRequestsLock.Lock())
                {
                    if (!resolutionRequestsByInstrument.TryGetValue(instrument, out request))
                    {
                        var requestId = adapter.GetNextRequestId();
                        request = new ResolutionRequest(requestId, instrument);

                        resolutionRequestsById.Add(requestId, request);
                        resolutionRequestsByInstrument.Add(instrument, request);

                        sendRequest = true;
                    }
                }

                // Отправляем запрос инструмента, если он был создан
                if (sendRequest)
                {
                    await SendResolutionRequestAsync(request);
                }

                // Дожидаемся отработки запроса
                contractId = await request.Task;
                return(contractId);
            }
        }
예제 #21
0
        public bool Connect()
        {
            try
            {
                using (socketSyncLock.Lock())
                {
                    socket.Connect(endPoint);
                }

                OnConnected();
                WaitForData();
            }
            catch (Exception e)
            {
                log.Error().Print(e, $"Failed to connect to IQConnect ({socketConnectionType})");
                return(false);
            }

            SendCommand(CommandFormatter.GetConnectCommand(socketConnectionType));
            return(true);
        }
예제 #22
0
        public string Add(Transaction transaction)
        {
            using (_transactionIdsLock.Lock())
            {
                if (!_transactionIdToClientOrderIdMap.TryGetValue(transaction.TransactionId, out var clOrderId))
                {
                    clOrderId = Xid.NewXid().ToString();
                    _transactionIdToClientOrderIdMap[transaction.TransactionId] = clOrderId;
                    _clientOrderIdToTransactionIdMap[clOrderId] = transaction.TransactionId;
                }

                return clOrderId;
            }
        }
예제 #23
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);
            });
        }
예제 #24
0
        /// <summary>
        ///     Проверить подписку
        /// </summary>
        async Task <SubscriptionTestResult> ISubscriptionTester <InstrumentData> .TestSubscriptionAsync(InstrumentData data)
        {
            var id      = GetNextRequestId();
            var request = new ResolutionRequest(data.Symbol, id);

            using (resolutionRequestsLock.Lock())
            {
                resolutionRequestsById.Add(id, request);
            }

            var message = new InformationRequest
            {
                symbol_resolution_request = new SymbolResolutionRequest {
                    symbol = data.Symbol
                },
                id = id
            };

            SendMessage(message);

            return(await request.Task);
        }
        /// <summary>
        ///     Получить исторические данные
        /// </summary>
        /// <param name="consumer">
        ///     Потребитель исторических данных
        /// </param>
        /// <param name="instrument">
        ///     Инструмент
        /// </param>
        /// <param name="begin">
        ///     Начало диапазона
        /// </param>
        /// <param name="end">
        ///     Конец диапазона
        /// </param>
        /// <param name="span">
        ///     Интервал свечей для исторических данных
        /// </param>
        /// <param name="cancellationToken">
        ///     Токен отмены
        /// </param>
        /// <returns>
        ///     Исторические данные
        /// </returns>
        /// <remarks>
        ///     Провайдер вправе переопределить параметры исторических графиков - диапазон, интервал,
        ///     если он не в состоянии предоставить запрошенные данные.
        /// </remarks>
        /// <exception cref="NoHistoryDataException">
        ///     Бросается, если исторические данные за указанный период недоступны
        /// </exception>
        public async Task GetHistoryDataAsync(
            IHistoryDataConsumer consumer,
            Instrument instrument,
            DateTime begin,
            DateTime end,
            HistoryProviderSpan span,
            CancellationToken cancellationToken = new CancellationToken())
        {
            var message =
                await PrepareTimeBarRequestAsync(instrument, begin, end, span, TimeBarRequest.RequestType.GET);

            if (message == null)
            {
                throw new ArgumentException($"Unable to resolve instrument {instrument}");
            }

            var request = new HistoryDataRequest(this, consumer, instrument, begin, end, span, message);

            using (requestsLock.Lock())
            {
                requests[message.request_id] = request;
            }

            CQGCAdapter.Log.Debug().Print(
                "Requesting history data block",
                LogFields.RequestId(message.request_id),
                LogFields.ContractId(message.time_bar_parameters.contract_id));
            adapter.SendMessage(message);

            // Поддержка отмены запроса
            cancellationToken.RegisterSafe(() => request.TrySetCanceled());

            var data = await request.Task;

            consumer.Update(data, HistoryDataUpdateType.Batch);
        }
        public InstrumentParams GetInstrumentParams(Instrument instrument)
        {
            using (syncRoot.Lock())
            {
                InstrumentParams instrumentParams;
                if (!cachedInstrumentParams.TryGetValue(instrument, out instrumentParams))
                {
                    instrumentParams = new InstrumentParams {
                        Instrument = instrument
                    };
                    cachedInstrumentParams.Add(instrument, instrumentParams);
                }

                return(instrumentParams);
            }
        }
예제 #27
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;
                    }
                }
            }
        }
예제 #28
0
 public void SaveOrderParams(Guid transactionId, string clOrderId, string symbol, decimal qty, char side)
 {
     using (_syncRoot.Lock())
     {
         if (!_orderByTransactionIdMap.ContainsKey(transactionId))
         {
             var orderParams = new OrderParams
             {
                 Symbol = symbol,
                 Qty    = qty,
                 Side   = side
             };
             _orderByTransactionIdMap.Add(transactionId, orderParams);
             _clOrderIdToTransactionIdMap.Add(clOrderId, transactionId);
             _transactionIdToClOrderIdMap.Add(transactionId, clOrderId);
         }
     }
 }
예제 #29
0
        /// <summary>
        ///     Обработчик события получения позиции
        /// </summary>
        private async void PositionStatusReceived(AdapterEventArgs <PositionStatus> args)
        {
            using (LogManager.Scope())
            {
                try
                {
                    args.MarkHandled();

                    // Ищем счет для позиции
                    string accountCode;
                    using (accountsLock.ReadLock())
                    {
                        if (!accountCodesById.TryGetValue(args.Message.account_id, out accountCode))
                        {
                            Logger.Error().PrintFormat(
                                "Unable to process position on contract #{0}: account #{1} is unknown",
                                args.Message.contract_id,
                                args.Message.account_id);
                            return;
                        }
                    }

                    // Обрабатываем метаданные контрактов
                    if (args.Message.contract_metadata != null)
                    {
                        await
                        instrumentResolver.HandleMetadataAsync(args.Message.contract_metadata,
                                                               $"A position in \"{accountCode}\" account");
                    }

                    // Ищем инструмент для позиции
                    var instrument = instrumentResolver.GetInstrument(args.Message.contract_id);
                    if (instrument == null)
                    {
                        Logger.Warn().PrintFormat(
                            "Received a position on contract #{0} in account {1} but no matching instrument is found",
                            args.Message.contract_id,
                            accountCode);
                        return;
                    }

                    // Рассчитываем позицию
                    var position = new PositionMessage
                    {
                        Account    = accountCode,
                        Instrument = instrument
                    };

                    var message = new StringBuilder();
                    message.AppendFormat("Position received: {0} [ ", instrument.Code);

                    using (openPositionsLock.Lock())
                    {
                        Dictionary <uint, Dictionary <int, OpenPosition> > d1;
                        if (!openPositions.TryGetValue(args.Message.account_id, out d1))
                        {
                            d1 = new Dictionary <uint, Dictionary <int, OpenPosition> >();
                            openPositions.Add(args.Message.account_id, d1);
                        }

                        Dictionary <int, OpenPosition> d2;
                        if (!d1.TryGetValue(args.Message.contract_id, out d2))
                        {
                            d2 = new Dictionary <int, OpenPosition>();
                            d1.Add(args.Message.contract_id, d2);
                        }

                        if (args.Message.is_snapshot)
                        {
                            d2.Clear();
                        }

                        position.Quantity = 0;
                        foreach (var p in args.Message.open_position)
                        {
                            var fmt = ObjectLogFormatter.Create(PrintOption.Nested, "CQGC_POSITION");
                            fmt.AddField(LogFieldNames.Id, p.id);
                            fmt.AddField(LogFieldNames.Price, p.price);
                            fmt.AddField(LogFieldNames.Quantity, p.qty);
                            fmt.AddField(LogFieldNames.TradeDate, p.trade_date);
                            fmt.AddField(LogFieldNames.TradeUtcTime, p.trade_utc_time);
                            fmt.AddField(LogFieldNames.StatementDate, p.statement_date);

                            message.Append(fmt.Print(PrintOption.Nested));
                            message.Append(", ");

                            position.Quantity = (int)p.qty;
                            position.Price    = (decimal)p.price;

                            d2[p.id] = p;
                        }

                        var volume   = 0d;
                        var quantity = 0u;

                        foreach (var pair in d2)
                        {
                            volume   += pair.Value.price * pair.Value.qty;
                            quantity += pair.Value.qty;
                        }

                        position.Quantity = (int)quantity;
                        position.Price    = quantity != 0u ? (decimal)(volume / quantity) : 0;
                    }

                    if (args.Message.is_short_open_position)
                    {
                        position.Quantity *= -1;
                    }

                    message.Append("]: ");
                    message.Append(LogFields.Price(position.Price));
                    message.Append(LogFields.Quantity(position.Quantity));
                    message.Append(LogFields.IsSnapshot(args.Message.is_snapshot));

                    Logger.Debug().Print(message.ToString().Preformatted());

                    // Отправляем сообщение
                    OnMessageReceived(position);
                }
                catch (Exception e)
                {
                    Logger.Error().Print(e, $"Failed to process {args.Message}");
                }
            }
        }
예제 #30
0
        private async Task UpdateLoopAsync(DateTime begin)
        {
            using (LogManager.Scope())
            {
                try
                {
                    while (true)
                    {
                        // Загружаем блок исторических данных
                        var end = DateTime.Now;
                        // TODO handle OperationCanceledException
                        var fetchedPoints = await gateway.FetchHistoryDataAsync(instrumentSymbol, begin, end, span, token);

                        // Обновляем точку старта на последнюю свечу, чтобы не грузить повторно
                        if (fetchedPoints.Any())
                        {
                            begin = fetchedPoints.Select(_ => _.Point).OrderByDescending(_ => _).First();
                        }

                        using (syncRoot.Lock())
                        {
                            // Объединяем с набором данных
                            int added, updated;
                            MergePoints(fetchedPoints, out added, out updated);

                            // Оповещаем потребителя
                            if (added > 0 || updated > 0)
                            {
                                begin = data.End;

                                if (added == 1 && updated == 0)
                                {
                                    consumer.Update(data, HistoryDataUpdateType.OnePointAdded);
                                }
                                else if (added == 0 && updated == 1)
                                {
                                    consumer.Update(data, HistoryDataUpdateType.OnePointUpdated);
                                }
                                else
                                {
                                    consumer.Update(data, HistoryDataUpdateType.Batch);
                                }
                            }
                            else
                            {
                                begin = end;
                            }
                        }

                        // Ждем до следущего обновления
                        await Task.Delay(FetchInterval, token);
                    }
                }
                catch (OperationCanceledException) { }
                catch (NoHistoryDataException)
                {
                    _Log.Debug().Print($"No more historical data is available", LogFields.Symbol(instrumentSymbol));
                }
                catch (Exception e)
                {
                    HandleException(e, e.Message);
                }
            }
        }