public void Notify(string symbol, List <Order> orders) { using (locker.CreateLock()) { foreach (var subscriptor in subscriptors) { if (subscriptor.Value.Contains(symbol)) { var notification = new OrderBookNotification() { Symbol = symbol, Orders = OrderConverter.GetOrders(orders) }; Send(subscriptor.Key, new NotificationMessage(notification)); } } } }
private void Client_UpdateMarketDepth(OrderBookNotification orderBook) { var needDepth = _depths.Find(d => d.SecurityNameCode == orderBook.CurrencyPair); if (needDepth == null) { return; } foreach (var level in orderBook.Datas) { var price = ParseDecimal(level.Price); var volume = ParseDecimal(level.Quantity); if (level.order_type == OrderBookEvent.OrderType.Ask) { var needLevel = needDepth.Asks.Find(l => l.Price == price); if (needLevel != null) { if (level.Quantity == "0") { needDepth.Asks.Remove(needLevel); } else { needLevel.Ask = volume; } } else { needDepth.Asks.Add(new MarketDepthLevel { Ask = volume, Price = price }); _needSortAsks = true; } } else if (level.order_type == OrderBookEvent.OrderType.Bid) { var needLevel = needDepth.Bids.Find(l => l.Price == price); if (needLevel != null) { if (level.Quantity == "0") { needDepth.Bids.Remove(needLevel); } else { needLevel.Bid = volume; } } else { needDepth.Bids.Add(new MarketDepthLevel { Bid = volume, Price = price }); _needSortBids = true; } } needDepth.Time = DateTime.UtcNow; } if (_needSortAsks) { needDepth.Asks.Sort((a, b) => { if (a.Price > b.Price) { return(1); } else if (a.Price < b.Price) { return(-1); } else { return(0); } }); _needSortAsks = false; } if (_needSortBids) { needDepth.Bids.Sort((a, b) => { if (a.Price > b.Price) { return(-1); } else if (a.Price < b.Price) { return(1); } else { return(0); } }); _needSortBids = false; } if (MarketDepthEvent != null) { MarketDepthEvent(needDepth.GetCopy()); } }
private void HandleUpdate(OrderBookNotification data) { _lastSequence++; UpdateOrderBook(_lastSequence, data.Data.Where(d => d.OrderType == OrderBidAskType.Bid), data.Data.Where(d => d.OrderType == OrderBidAskType.Ask)); }
/// <summary> /// takes messages from the common queue, converts them to C # classes and sends them to up /// берет сообщения из общей очереди, конвертирует их в классы C# и отправляет на верх /// </summary> public void Converter() { while (true) { try { if (_isDisposed) { return; } if (!_newMessage.IsEmpty) { WsResponse response; if (_newMessage.TryDequeue(out response)) { if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.TradeChannelSubscribed) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { TradeChannelSubscribedResponse message = ProtoBuf.Serializer.Deserialize <TradeChannelSubscribedResponse>(messageStream); SendLogMessage("Успешная подписка на все сделки", LogMessageType.System); } } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.TradeNotify) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { TradeNotification message = ProtoBuf.Serializer.Deserialize <TradeNotification>(messageStream); NewTradesEvent?.Invoke(message); } } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.Error) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { ErrorResponse message = ProtoBuf.Serializer.Deserialize <ErrorResponse>(messageStream); var token = response.Meta.Token; if (message.Message.StartsWith("Channel already subscribed")) { continue; } if (token.StartsWith("NewOrder")) { var order = new PrivateOrderRawEvent(); order.Id = -1; MyOrderEvent?.Invoke(Convert.ToInt32(token.Split('_')[1]), GetPortfolioName(), order); } if (message.Message.StartsWith("insufficient funds")) { continue; } SendLogMessage("WsClient error : " + message.Message, LogMessageType.Error); } } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.ChannelUnsubscribed) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { ChannelUnsubscribedResponse message = ProtoBuf.Serializer.Deserialize <ChannelUnsubscribedResponse>(messageStream); } } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.LoginResponse) { IsConnected = true; if (Connected != null) { Connected(); } // SendLogMessage("Соединение через вебсокет успешно установлено", LogMessageType.System); } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.BalanceChangeChannelSubscribed) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { PrivateSubscribeBalanceChangeChannelRequest message = ProtoBuf.Serializer.Deserialize <PrivateSubscribeBalanceChangeChannelRequest>(messageStream); } } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.BalanceChangeNotify) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { PrivateChangeBalanceNotification message = ProtoBuf.Serializer.Deserialize <PrivateChangeBalanceNotification>(messageStream); if (UpdatePortfolio != null) { UpdatePortfolio(GetPortfolioName(), message); } } } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.OrderBookNotify) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { OrderBookNotification message = ProtoBuf.Serializer.Deserialize <OrderBookNotification>(messageStream); if (UpdateMarketDepth != null) { UpdateMarketDepth(message); } } } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.OrderBookChannelSubscribed) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { OrderBookChannelSubscribedResponse message = ProtoBuf.Serializer.Deserialize <OrderBookChannelSubscribedResponse>(messageStream); // SendLogMessage("Успешная подписка на стакан котировок", LogMessageType.System); if (NewMarketDepth != null) { NewMarketDepth(message); } } } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.PrivateOrderRawChannelSubscribed) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { //SendLogMessage("Успешная подписка на мои ордера", LogMessageType.System); } } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.PrivateOrderRawNotify) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { PrivateOrderRawNotification message = ProtoBuf.Serializer.Deserialize <PrivateOrderRawNotification>(messageStream); foreach (var ev in message.Datas) { if (!_myOrders.ContainsValue(ev.Id)) { _orderEvents.Add(ev); } else { var needNumberUser = _myOrders.First(o => o.Value == ev.Id); MyOrderEvent?.Invoke(needNumberUser.Key, GetPortfolioName(), ev); } } //SendLogMessage("Пришла информацияпо ордеру", LogMessageType.System); } } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.PrivateTradeChannelSubscribed) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { //SendLogMessage("Успешная подписка на мои сделки", LogMessageType.System); } } else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.PrivateTradeNotify) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { PrivateTradeNotification message = ProtoBuf.Serializer.Deserialize <PrivateTradeNotification>(messageStream); //SendLogMessage("Пришла моя сделка", LogMessageType.System); foreach (var t in message.Datas) { if (!_myOrders.ContainsValue(t.OrderBuyId)) { _queueMyTradeEvents.Add(t); } else { MyTradeEvent?.Invoke(t.OrderBuyId.ToString(), t); } if (!_myOrders.ContainsValue(t.OrderSellId)) { _queueMyTradeEvents.Add(t); } else { MyTradeEvent?.Invoke(t.OrderSellId.ToString(), t); } } } }//PUT_LIMIT_ORDER_RESPONSE else if (response.Meta.ResponseType == WsResponseMetaData.WsResponseMsgType.PutLimitOrderResponse) { using (MemoryStream messageStream = new MemoryStream(response.Msg)) { PutLimitOrderResponse message = ProtoBuf.Serializer.Deserialize <PutLimitOrderResponse>(messageStream); var orderData = response.Meta.Token.Split('_'); int id = Convert.ToInt32(orderData[1]); _myOrders.Add(id, message.OrderId); HandleAllNeedEvents(message.OrderId); } } } } else { Thread.Sleep(1); } } catch (Exception exception) { SendLogMessage(exception.Message, LogMessageType.Error); } } }