/// <summary> /// To convert quotes. /// </summary> /// <param name="message">Quotes.</param> /// <returns>Stream <see cref="ExecutionMessage"/>.</returns> public IEnumerable<ExecutionMessage> ToExecutionLog(QuoteChangeMessage message) { if (message == null) throw new ArgumentNullException(nameof(message)); if (!_priceStepUpdated || !_volumeStepUpdated) { var quote = message.GetBestBid() ?? message.GetBestAsk(); if (quote != null) { _securityDefinition.PriceStep = quote.Price.GetDecimalInfo().EffectiveScale.GetPriceStep(); _securityDefinition.VolumeStep = quote.Volume.GetDecimalInfo().EffectiveScale.GetPriceStep(); _priceStepUpdated = true; _volumeStepUpdated = true; } } _lastDepthDate = message.LocalTime.Date; // чтобы склонировать внутренние котировки //message = (QuoteChangeMessage)message.Clone(); // TODO для ускорения идет shallow copy котировок var newBids = message.IsSorted ? message.Bids : message.Bids.OrderByDescending(q => q.Price); var newAsks = message.IsSorted ? message.Asks : message.Asks.OrderBy(q => q.Price); return ProcessQuoteChange(message.LocalTime, message.ServerTime, newBids.ToArray(), newAsks.ToArray()); }
/// <summary> /// Initializes a new instance of the <see cref="TimeQuoteChange"/>. /// </summary> /// <param name="quote">The quote, from which changes will be copied.</param> /// <param name="message">The message with quotes.</param> public TimeQuoteChange(QuoteChange quote, QuoteChangeMessage message) { if (quote == null) throw new ArgumentNullException("quote"); SecurityId = message.SecurityId; ServerTime = message.ServerTime; LocalTime = message.LocalTime; Price = quote.Price; Volume = quote.Volume; Side = quote.Side; }
/// <summary> /// Создать копию объекта. /// </summary> /// <returns>Копия.</returns> public override Message Clone() { var clone = new QuoteChangeMessage { LocalTime = LocalTime, SecurityId = SecurityId, Bids = Bids.Select(q => q.Clone()).ToArray(), Asks = Asks.Select(q => q.Clone()).ToArray(), ServerTime = ServerTime, IsSorted = IsSorted }; this.CopyExtensionInfo(clone); return(clone); }
private void CreateAssociatedSecurityQuotes(QuoteChangeMessage quoteMsg) { if (!SessionHolder.CreateAssociatedSecurity) { return; } if (quoteMsg.SecurityId.IsDefault()) { return; } var builder = _quoteChangeDepthBuilders .SafeAdd(quoteMsg.SecurityId.SecurityCode, c => new QuoteChangeDepthBuilder(c, SessionHolder.AssociatedBoardCode)); NewOutMessage.SafeInvoke(builder.Process(quoteMsg)); }
public QuoteChangeMessage Process(QuoteChangeMessage message) { _feeds[message.SecurityId] = message; var bids = _feeds.SelectMany(f => f.Value.Bids).ToArray(); var asks = _feeds.SelectMany(f => f.Value.Asks).ToArray(); return(new QuoteChangeMessage { SecurityId = new SecurityId { SecurityCode = _securityCode, BoardCode = _boardCode }, ServerTime = message.ServerTime, LocalTime = message.LocalTime, Bids = bids, Asks = asks }); }
/// <summary> /// Создать <see cref="OrderLogMarketDepthBuilder"/>. /// </summary> /// <param name="depth">Стакан.</param> /// <param name="maxDepth">Максимальная глубина стакана. По-умолчанию равно <see cref="int.MaxValue"/>, что означает бесконечную глубину.</param> public OrderLogMarketDepthBuilder(QuoteChangeMessage depth, int maxDepth = int.MaxValue) { if (depth == null) throw new ArgumentNullException("depth"); if (!depth.IsSorted) throw new ArgumentException(LocalizedStrings.Str942, "depth"); _depth = depth; _maxDepth = maxDepth; foreach (var bid in depth.Bids) _bids.Add(bid.Price, bid); foreach (var ask in depth.Asks) _asks.Add(ask.Price, ask); _exchange = depth.SecurityId.BoardCode.IsEmpty() ? ExchangeBoard.Forts : ExchangeBoard.GetBoard(depth.SecurityId.BoardCode) ?? ExchangeBoard.Forts; }
private void SessionOnStil2Reply(ref Array arrayL2Update) { var asksUpdate = new List<QuoteChange>(); var bidsUpdate = new List<QuoteChange>(); foreach (structSTIL2Update structL2Update in arrayL2Update) { switch (structL2Update.bstrSide.ToSide()) { case Sides.Buy: { bidsUpdate.Add(new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty) { BoardCode = structL2Update.bstrMaker }); break; } case Sides.Sell: { asksUpdate.Add(new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty) { BoardCode = structL2Update.bstrMaker }); break; } } } var quote = (structSTIL2Update)arrayL2Update.GetValue(0); _depths[quote.bstrSymbol] = Tuple.Create(asksUpdate, bidsUpdate); var message = new QuoteChangeMessage { SecurityId = new SecurityId { SecurityCode = quote.bstrSymbol, BoardCode = AssociatedBoardCode, }, Asks = asksUpdate, Bids = bidsUpdate, ServerTime = quote.bstrTime.StrToTime(), }; SendOutMessage(message); }
private void SessionOnStil2Update(ref structSTIL2Update structL2Update) { var depth = _depths[structL2Update.bstrSymbol]; var quote = new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty); var quotes = quote.Side == Sides.Sell ? depth.Item1 : depth.Item2; switch (structL2Update.bstrAction) { case "A": // add { quotes.Add(quote); break; } case "C": // change { quotes.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); quotes.Add(quote); break; } case "D": // delete { quotes.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); break; } } var board = structL2Update.bstrMaker; if (board.IsEmpty()) board = AssociatedBoardCode; var message = new QuoteChangeMessage { SecurityId = new SecurityId { SecurityCode = structL2Update.bstrSymbol, BoardCode = board, }, Asks = depth.Item1.ToArray(), Bids = depth.Item2.ToArray(), ServerTime = structL2Update.bstrTime.StrToTime(), }; SendOutMessage(message); }
/// <summary> /// Process message. /// </summary> /// <param name="message">Message.</param> /// <returns>The result of processing. If <see langword="null" /> is returned, then generator has no sufficient data to generate new message.</returns> protected override Message OnProcess(Message message) { if (_boardDefinition == null) { if (message.Type == MessageTypes.Board) _boardDefinition = (BoardMessage)message.Clone(); return null; } DateTimeOffset time; switch (message.Type) { case MessageTypes.Level1Change: { var l1Msg = (Level1ChangeMessage)message; var value = l1Msg.Changes.TryGetValue(Level1Fields.LastTradePrice); if (value != null) _lastTradePrice = (decimal)value; value = l1Msg.Changes.TryGetValue(Level1Fields.BestBidPrice); if (value != null) _bestBidPrice = (decimal)value; value = l1Msg.Changes.TryGetValue(Level1Fields.BestAskPrice); if (value != null) _bestAskPrice = (decimal)value; time = l1Msg.ServerTime; break; } case MessageTypes.Execution: { var execMsg = (ExecutionMessage)message; switch (execMsg.ExecutionType) { case ExecutionTypes.Tick: { var tradePrice = execMsg.TradePrice; if (null == _prevTradePrice) { _prevTradePrice = tradePrice; _bestAskPrice = tradePrice; _bestBidPrice = tradePrice; } switch (execMsg.OriginSide) { case null: { if (tradePrice > _prevTradePrice) { _bestAskPrice = tradePrice; //BestBid = PrevTrade; _prevTradePrice = tradePrice; } else if (tradePrice < _prevTradePrice) { _bestBidPrice = tradePrice; //BestAsk = PrevTrade; _prevTradePrice = tradePrice; } break; } case Sides.Buy: _bestAskPrice = tradePrice; break; default: _bestBidPrice = tradePrice; break; } _lastTradePrice = tradePrice; _newTrades = true; break; } default: return null; } time = execMsg.ServerTime; break; } case MessageTypes.Time: { var timeMsg = (TimeMessage)message; time = timeMsg.ServerTime; break; } default: return null; } if (_currGenerations == 0 || _bestBidPrice == null || _bestAskPrice == null) return null; var isTradeTime = _boardDefinition.IsTradeTime(time); var canProcess = GenerateDepthOnEachTrade && _newTrades ? isTradeTime : (IsTimeToGenerate(time) && isTradeTime); if (!canProcess) return null; _currGenerations = MaxGenerations; var depth = new QuoteChangeMessage { SecurityId = SecurityId, ServerTime = time, LocalTime = time.LocalDateTime, }; if (_bestBidPrice == null || _bestAskPrice == null) { if (_lastTradePrice == null) throw new InvalidOperationException(LocalizedStrings.Str1142); _bestBidPrice = _bestAskPrice = _lastTradePrice; } if (_currGenerations == 0) throw new InvalidOperationException(LocalizedStrings.Str1143); var bidPrice = _bestBidPrice; var askPrice = _bestAskPrice; var minSpred = MinSpreadStepCount * SecurityDefinition.PriceStep; var maxStread = MaxSpreadStepCount * SecurityDefinition.PriceStep; if ((askPrice - bidPrice) < minSpred) { if (_bestBidPrice == _lastTradePrice) // up trend askPrice = bidPrice + minSpred; else bidPrice = askPrice - minSpred; } else if ((askPrice - bidPrice) > maxStread) { if (_bestBidPrice == _lastTradePrice) // down trend askPrice = bidPrice + maxStread; else bidPrice = askPrice - maxStread; } var bids = new List<QuoteChange> { new QuoteChange(Sides.Buy, bidPrice.Value, Volumes.Next()) }; var count = MaxBidsDepth - bids.Count; for (var i = 0; i < count; i++) { var quote = CreateQuote(bidPrice.Value, Sides.Buy); if (quote.Price <= 0) break; bids.Add(quote); bidPrice = quote.Price; } var asks = new List<QuoteChange> { new QuoteChange(Sides.Sell, askPrice.Value, Volumes.Next()) }; count = MaxAsksDepth - asks.Count; for (var i = 0; i < count; i++) { var quote = CreateQuote(askPrice.Value, Sides.Sell); if (quote.Price <= 0) break; asks.Add(quote); askPrice = quote.Price; } depth.Bids = bids; depth.Asks = asks; _newTrades = false; _currGenerations--; return depth; }
private void ConvertFile(string fileName, IStorageRegistry registry, StorageFormats format, ExchangeBoard board) { if (!_isStarted) return; var fileNameKey = format + "_" + fileName; if (_convertedFiles.Contains(fileNameKey)) return; _logManager.Application.AddInfoLog("Конвертация файла {0}.", fileName); const int maxBufCount = 1000; var data = new Dictionary<Security, Tuple<List<QuoteChangeMessage>, List<ExecutionMessage>, List<Level1ChangeMessage>, List<ExecutionMessage>>>(); using (var qr = QshReader.Open(fileName)) { var currentDate = qr.CurrentDateTime; for (var i = 0; i < qr.StreamCount; i++) { var stream = (ISecurityStream)qr[i]; var security = GetSecurity(stream.Security, board); var priceStep = security.PriceStep ?? 1; var securityId = security.ToSecurityId(); var lastTransactionId = 0L; var secData = data.SafeAdd(security, key => Tuple.Create(new List<QuoteChangeMessage>(), new List<ExecutionMessage>(), new List<Level1ChangeMessage>(), new List<ExecutionMessage>())); switch (stream.Type) { case StreamType.Stock: { ((IStockStream)stream).Handler += (key, quotes, spread) => { var quotes2 = quotes.Select(q => { Sides side; switch (q.Type) { case QuoteType.Unknown: case QuoteType.Free: case QuoteType.Spread: throw new ArgumentException(q.Type.ToString()); case QuoteType.Ask: case QuoteType.BestAsk: side = Sides.Sell; break; case QuoteType.Bid: case QuoteType.BestBid: side = Sides.Buy; break; default: throw new ArgumentOutOfRangeException(); } return new QuoteChange(side, priceStep * q.Price, q.Volume); }).ToArray(); var md = new QuoteChangeMessage { SecurityId = securityId, ServerTime = currentDate.ApplyTimeZone(TimeHelper.Moscow), Bids = quotes2.Where(q => q.Side == Sides.Buy), Asks = quotes2.Where(q => q.Side == Sides.Sell), }; //if (md.Verify()) //{ secData.Item1.Add(md); if (secData.Item1.Count > maxBufCount) { registry.GetQuoteMessageStorage(security).Save(secData.Item1); secData.Item1.Clear(); } //} //else // _logManager.Application.AddErrorLog("Стакан для {0} в момент {1} не прошел валидацию. Лучший бид {2}, Лучший офер {3}.", security, qr.CurrentDateTime, md.BestBid, md.BestAsk); }; break; } case StreamType.Deals: { ((IDealsStream)stream).Handler += deal => { secData.Item2.Add(new ExecutionMessage { ExecutionType = ExecutionTypes.Tick, SecurityId = securityId, OpenInterest = deal.OI == 0 ? (long?)null : deal.OI, ServerTime = deal.DateTime.ApplyTimeZone(TimeHelper.Moscow), Volume = deal.Volume, TradeId = deal.Id == 0 ? (long?)null : deal.Id, TradePrice = (decimal)deal.Price, OriginSide = deal.Type == DealType.Buy ? Sides.Buy : (deal.Type == DealType.Sell ? Sides.Sell : (Sides?)null) }); if (secData.Item2.Count > maxBufCount) { registry.GetTickMessageStorage(security).Save(secData.Item2); secData.Item2.Clear(); } }; break; } case StreamType.OrdLog: { ((IOrdLogStream)stream).Handler += (key, ol) => { var currTransactionId = ol.DateTime.Ticks; if (lastTransactionId < currTransactionId) lastTransactionId = currTransactionId; else if (lastTransactionId >= currTransactionId) lastTransactionId++; var msg = new ExecutionMessage { ExecutionType = ExecutionTypes.OrderLog, SecurityId = securityId, OpenInterest = ol.OI == 0 ? (long?)null : ol.OI, OrderId = ol.OrderId, Price = priceStep * ol.Price, ServerTime = ol.DateTime.ApplyTimeZone(TimeHelper.Moscow), Volume = ol.Amount, Balance = ol.AmountRest, TradeId = ol.DealId == 0 ? (long?)null : ol.DealId, TradePrice = ol.DealPrice == 0 ? (decimal?)null : priceStep * ol.DealPrice, TransactionId = lastTransactionId }; var status = 0; if (ol.Flags.Contains(OrdLogFlags.Add)) { msg.OrderState = OrderStates.Active; } else if (ol.Flags.Contains(OrdLogFlags.Fill)) { msg.OrderState = OrderStates.Done; } else if (ol.Flags.Contains(OrdLogFlags.Canceled)) { msg.OrderState = OrderStates.Done; status |= 0x200000; } else if (ol.Flags.Contains(OrdLogFlags.CanceledGroup)) { msg.OrderState = OrderStates.Done; status |= 0x400000; } else if (ol.Flags.Contains(OrdLogFlags.Moved)) { status |= 0x100000; } if (ol.Flags.Contains(OrdLogFlags.Buy)) { msg.Side = Sides.Buy; } else if (ol.Flags.Contains(OrdLogFlags.Sell)) { msg.Side = Sides.Sell; } if (ol.Flags.Contains(OrdLogFlags.FillOrKill)) { msg.TimeInForce = TimeInForce.MatchOrCancel; status |= 0x00080000; } if (ol.Flags.Contains(OrdLogFlags.Quote)) { msg.TimeInForce = TimeInForce.PutInQueue; status |= 0x01; } if (ol.Flags.Contains(OrdLogFlags.Counter)) { status |= 0x02; } if (ol.Flags.Contains(OrdLogFlags.CrossTrade)) { status |= 0x20000000; } if (ol.Flags.Contains(OrdLogFlags.NonSystem)) { msg.IsSystem = false; status |= 0x04; } if (ol.Flags.Contains(OrdLogFlags.EndOfTransaction)) { status |= 0x1000; } msg.OrderStatus = (OrderStatus)status; secData.Item4.Add(msg); if (secData.Item4.Count > maxBufCount) { registry.GetOrderLogMessageStorage(security).Save(secData.Item4); secData.Item4.Clear(); } }; break; } case StreamType.AuxInfo: { ((IAuxInfoStream)stream).Handler += (key, info) => { secData.Item3.Add(new Level1ChangeMessage { SecurityId = securityId, ServerTime = info.DateTime.ApplyTimeZone(TimeHelper.Moscow), } .TryAdd(Level1Fields.LastTradePrice, priceStep * info.Price) .TryAdd(Level1Fields.BidsVolume, (decimal)info.BidTotal) .TryAdd(Level1Fields.AsksVolume, (decimal)info.AskTotal) .TryAdd(Level1Fields.HighPrice, priceStep * info.HiLimit) .TryAdd(Level1Fields.LowPrice, priceStep * info.LoLimit) .TryAdd(Level1Fields.OpenInterest, (decimal)info.OI)); if (secData.Item3.Count > maxBufCount) { registry.GetLevel1MessageStorage(security).Save(secData.Item3); secData.Item3.Clear(); } }; break; } case StreamType.Orders: case StreamType.Trades: case StreamType.Messages: case StreamType.None: { continue; } default: throw new ArgumentOutOfRangeException("Неподдерживаемый тип потока {0}.".Put(stream.Type)); } } while (qr.CurrentDateTime != DateTime.MaxValue && _isStarted) qr.Read(true); } if (!_isStarted) return; foreach (var pair in data) { if (pair.Value.Item1.Any()) { registry.GetQuoteMessageStorage(pair.Key, format: format).Save(pair.Value.Item1); } if (pair.Value.Item2.Any()) { registry.GetTickMessageStorage(pair.Key, format: format).Save(pair.Value.Item2); } if (pair.Value.Item3.Any()) { registry.GetLevel1MessageStorage(pair.Key, format: format).Save(pair.Value.Item3); } if (pair.Value.Item4.Any()) { registry.GetOrderLogMessageStorage(pair.Key, format: format).Save(pair.Value.Item4); } } File.AppendAllLines(_convertedFilesFile, new[] { fileNameKey }); _convertedFiles.Add(fileNameKey); }
/// <summary> /// To upfate the order book. /// </summary> /// <param name="message">Market depth.</param> public void UpdateDepth(QuoteChangeMessage message) { if (message == null) throw new ArgumentNullException(nameof(message)); var clone = new QuoteChangeMessage { Bids = message.Bids, Asks = message.Asks, IsSorted = message.IsSorted, }; lock (_lastDepthSync) _lastQuoteMsg = clone; }
/// <summary> /// To process the message, containing data on order book. /// </summary> /// <param name="quoteMsg">The message, containing data on order book.</param> public void ProcessQuotes(QuoteChangeMessage quoteMsg) { var ask = quoteMsg.GetBestAsk(); AskPrice = ask != null ? ask.Price : 0; var bid = quoteMsg.GetBestBid(); BidPrice = bid != null ? bid.Price : 0; _unrealizedPnL = null; }
/// <summary> /// Create a copy of <see cref="QuoteChangeMessage"/>. /// </summary> /// <returns>Copy.</returns> public override Message Clone() { var clone = new QuoteChangeMessage { LocalTime = LocalTime, SecurityId = SecurityId, Bids = Bids.Select(q => q.Clone()).ToArray(), Asks = Asks.Select(q => q.Clone()).ToArray(), ServerTime = ServerTime, IsSorted = IsSorted, Currency = Currency, }; this.CopyExtensionInfo(clone); return clone; }
private void SessionOnStil2Update(ref structSTIL2Update structL2Update) { var asksUpdate = _depths[structL2Update.bstrSymbol].Item1; var bidsUpdate = _depths[structL2Update.bstrSymbol].Item2; var quote = new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal) structL2Update.fPrice, structL2Update.nQty) {BoardCode = structL2Update.bstrMaker}; switch (structL2Update.bstrSide.ToSide()) { case Sides.Buy: { switch (structL2Update.bstrAction) { case "A": // add { bidsUpdate.Add(quote); break; } case "C": // change { bidsUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); bidsUpdate.Add(quote); break; } case "D": // delete { bidsUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); break; } } break; } case Sides.Sell: { switch (structL2Update.bstrAction) { case "A": // add { asksUpdate.Add(quote); break; } case "C": // change { asksUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); asksUpdate.Add(quote); break; } case "D": // delete { asksUpdate.RemoveWhere(q => q.Price == quote.Price && q.BoardCode == quote.BoardCode); break; } } break; } } var message = new QuoteChangeMessage { SecurityId = new SecurityId { SecurityCode = structL2Update.bstrSymbol, BoardCode = "All", }, Asks = asksUpdate, Bids = bidsUpdate, ServerTime = structL2Update.bstrTime.StrToTime(), }; SendOutMessage(message); }
QuoteChangeMessage IOrderLogMarketDepthBuilder.Update(ExecutionMessage item) { if (item == null) { throw new ArgumentNullException(nameof(item)); } if (item.ExecutionType != ExecutionTypes.OrderLog) { throw new ArgumentException(nameof(item)); } if (item.OrderPrice == 0) { return(null); } _depth.ServerTime = item.ServerTime; _depth.LocalTime = item.LocalTime; QuoteChange?changedQuote = null; var quotes = item.Side == Sides.Buy ? _bids : _asks; if (item.IsOrderLogRegistered()) { if (item.OrderVolume != null) { QuoteChange ProcessRegister <T>(T id, Dictionary <T, decimal> orders) { var quote = quotes.SafeAdd(item.OrderPrice, key => new QuoteChange(key, 0)); var volume = item.OrderVolume.Value; if (orders.TryGetValue(id, out var prevVolume)) { quote.Volume += (volume - prevVolume); orders[id] = volume; } else { quote.Volume += volume; orders.Add(id, volume); } quotes[item.OrderPrice] = quote; return(quote); } if (item.OrderId != null) { changedQuote = ProcessRegister(item.OrderId.Value, _ordersByNum); } else if (!item.OrderStringId.IsEmpty()) { changedQuote = ProcessRegister(item.OrderStringId, _ordersByString); } } } else if (item.IsOrderLogMatched()) { var volume = item.TradeVolume ?? item.OrderVolume; if (volume != null) { QuoteChange?ProcessMatched <T>(T id, Dictionary <T, decimal> orders) { if (orders.TryGetValue(id, out var prevVolume)) { orders[id] = prevVolume - volume.Value; if (quotes.TryGetValue(item.OrderPrice, out var quote)) { quote.Volume -= volume.Value; if (quote.Volume <= 0) { quotes.Remove(item.OrderPrice); } quotes[item.OrderPrice] = quote; return(quote); } } return(null); } if (item.OrderId != null) { changedQuote = ProcessMatched(item.OrderId.Value, _ordersByNum); } else if (!item.OrderStringId.IsEmpty()) { changedQuote = ProcessMatched(item.OrderStringId, _ordersByString); } } } else if (item.IsOrderLogCanceled()) { QuoteChange?ProcessCanceled <T>(T id, Dictionary <T, decimal> orders) { if (orders.TryGetAndRemove(id, out var prevVolume)) { if (quotes.TryGetValue(item.OrderPrice, out var quote)) { quote.Volume -= prevVolume; if (quote.Volume <= 0) { quotes.Remove(item.OrderPrice); } quotes[item.OrderPrice] = quote; return(quote); } } return(null); } if (item.OrderId != null) { changedQuote = ProcessCanceled(item.OrderId.Value, _ordersByNum); } else if (!item.OrderStringId.IsEmpty()) { changedQuote = ProcessCanceled(item.OrderStringId, _ordersByString); } } if (changedQuote == null) { return(null); } var increment = new QuoteChangeMessage { ServerTime = item.ServerTime, LocalTime = item.LocalTime, SecurityId = _depth.SecurityId, State = QuoteChangeStates.Increment, }; var q = changedQuote.Value; if (item.Side == Sides.Buy) { increment.Bids = new[] { q } } ; else { increment.Asks = new[] { q } }; return(increment); } }
private void SessionOnStil2Reply(ref Array arrayL2Update) { var asksUpdate = new List<QuoteChange>(); var bidsUpdate = new List<QuoteChange>(); foreach (structSTIL2Update structL2Update in arrayL2Update) { switch (structL2Update.bstrSide.ToSide()) { case Sides.Buy: { bidsUpdate.Add(new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal) structL2Update.fPrice, structL2Update.nQty) {BoardCode = structL2Update.bstrMaker}); break; } case Sides.Sell: { asksUpdate.Add(new QuoteChange(structL2Update.bstrSide.ToSide(), (decimal)structL2Update.fPrice, structL2Update.nQty) { BoardCode = structL2Update.bstrMaker}); break; } } } var quote = (structSTIL2Update)arrayL2Update.GetValue(0); if (_depths.ContainsKey(quote.bstrSymbol)) { _depths.Remove(quote.bstrSymbol); } _depths.Add(quote.bstrSymbol, new Tuple<List<QuoteChange>, List<QuoteChange>>(asksUpdate, bidsUpdate)); var message = new QuoteChangeMessage { SecurityId = new SecurityId { SecurityCode = quote.bstrSymbol, BoardCode = "All", }, Asks = asksUpdate, Bids = bidsUpdate, ServerTime = quote.bstrTime.StrToTime(), }; SendOutMessage(message); }