/// <summary> /// Get middle of spread. /// </summary> /// <param name="message">Market depth.</param> /// <returns>The middle of spread. Is <see langword="null" />, if quotes are empty.</returns> public static decimal?GetSpreadMiddle(this QuoteChangeMessage message) { var bestBid = message.GetBestBid(); var bestAsk = message.GetBestAsk(); return((bestBid?.Price).GetSpreadMiddle(bestAsk?.Price)); }
/// <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> /// 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; }