protected override void OnSave(BitArrayWriter writer, IEnumerable <ExecutionMessage> messages, TickMetaInfo metaInfo) { if (metaInfo.IsEmpty()) { var first = messages.First(); metaInfo.FirstId = metaInfo.PrevId = first.GetTradeId(); metaInfo.ServerOffset = first.ServerTime.Offset; } writer.WriteInt(messages.Count()); var allowNonOrdered = metaInfo.Version >= MarketDataVersions.Version48; var isUtc = metaInfo.Version >= MarketDataVersions.Version50; var allowDiffOffsets = metaInfo.Version >= MarketDataVersions.Version54; foreach (var msg in messages) { if (msg.ExecutionType != ExecutionTypes.Tick) { throw new ArgumentOutOfRangeException(nameof(messages), msg.ExecutionType, LocalizedStrings.Str1695Params.Put(msg.TradeId)); } var tradeId = msg.GetTradeId(); // сделки для индексов имеют нулевой номер if (tradeId < 0) { throw new ArgumentOutOfRangeException(nameof(messages), tradeId, LocalizedStrings.Str1020); } // execution ticks (like option execution) may be a zero cost // ticks for spreads may be a zero cost or less than zero //if (msg.TradePrice < 0) // throw new ArgumentOutOfRangeException("messages", msg.TradePrice, LocalizedStrings.Str1021Params.Put(msg.TradeId)); metaInfo.PrevId = writer.SerializeId(tradeId, metaInfo.PrevId); // pyhta4og. // http://stocksharp.com/forum/yaf_postsm6450_Oshibka-pri-importie-instrumientov-s-Finama.aspx#post6450 var volume = msg.Volume; if (metaInfo.Version < MarketDataVersions.Version53) { if (volume == null) { throw new ArgumentException(LocalizedStrings.Str1022Params.Put((object)msg.TradeId ?? msg.TradeStringId), nameof(messages)); } if (volume < 0) { throw new ArgumentOutOfRangeException(nameof(messages), volume, LocalizedStrings.Str1022Params.Put(msg.TradeId)); } writer.WriteVolume(volume.Value, metaInfo, SecurityId); } else { writer.Write(volume != null); if (volume != null) { if (volume < 0) { throw new ArgumentOutOfRangeException(nameof(messages), volume, LocalizedStrings.Str1022Params.Put(msg.TradeId)); } writer.WriteVolume(volume.Value, metaInfo, SecurityId); } } writer.WritePriceEx(msg.GetTradePrice(), metaInfo, SecurityId); writer.WriteSide(msg.OriginSide); var lastOffset = metaInfo.LastServerOffset; metaInfo.LastTime = writer.WriteTime(msg.ServerTime, metaInfo.LastTime, LocalizedStrings.Str985, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, ref lastOffset); metaInfo.LastServerOffset = lastOffset; if (metaInfo.Version < MarketDataVersions.Version40) { continue; } if (metaInfo.Version < MarketDataVersions.Version47) { writer.WriteLong(SecurityId.GetLatency(msg.ServerTime, msg.LocalTime).Ticks); } else { var hasLocalTime = true; if (metaInfo.Version >= MarketDataVersions.Version49) { hasLocalTime = !msg.LocalTime.IsDefault() && msg.LocalTime != msg.ServerTime; writer.Write(hasLocalTime); } if (hasLocalTime) { lastOffset = metaInfo.LastLocalOffset; metaInfo.LastLocalTime = writer.WriteTime(msg.LocalTime, metaInfo.LastLocalTime, LocalizedStrings.Str1024, allowNonOrdered, isUtc, metaInfo.LocalOffset, allowDiffOffsets, ref lastOffset); metaInfo.LastLocalOffset = lastOffset; } } if (metaInfo.Version < MarketDataVersions.Version42) { continue; } if (metaInfo.Version >= MarketDataVersions.Version51) { writer.Write(msg.IsSystem != null); if (msg.IsSystem != null) { writer.Write(msg.IsSystem.Value); } } else { writer.Write(msg.IsSystem ?? true); } if (msg.IsSystem == false) { if (metaInfo.Version >= MarketDataVersions.Version51) { writer.WriteNullableInt(msg.TradeStatus); } else { writer.WriteInt(msg.TradeStatus ?? 0); } } var oi = msg.OpenInterest; if (metaInfo.Version < MarketDataVersions.Version46) { writer.WriteVolume(oi ?? 0m, metaInfo, SecurityId); } else { writer.Write(oi != null); if (oi != null) { writer.WriteVolume(oi.Value, metaInfo, SecurityId); } } if (metaInfo.Version < MarketDataVersions.Version45) { continue; } writer.Write(msg.IsUpTick != null); if (msg.IsUpTick != null) { writer.Write(msg.IsUpTick.Value); } if (metaInfo.Version < MarketDataVersions.Version52) { continue; } writer.Write(msg.Currency != null); if (msg.Currency != null) { writer.WriteInt((int)msg.Currency.Value); } } }
protected override void OnSave(BitArrayWriter writer, IEnumerable <QuoteChangeMessage> messages, QuoteMetaInfo metaInfo) { if (metaInfo.IsEmpty()) { var firstDepth = messages.FirstOrDefault(d => !d.Bids.IsEmpty() || !d.Asks.IsEmpty()); if (firstDepth == null) { throw new ArgumentException(LocalizedStrings.Str931, "messages"); } metaInfo.LastPrice = metaInfo.FirstPrice = GetDepthPrice(firstDepth); //pyh: будет баг если первый стакан пустой и с другим временем. //metaInfo.FirstTime = firstDepth.LastChangeTime; metaInfo.ServerOffset = firstDepth.ServerTime.Offset; } writer.WriteInt(messages.Count()); QuoteChangeMessage prevQuoteMsg = null; var allowNonOrdered = metaInfo.Version >= MarketDataVersions.Version47; var isUtc = metaInfo.Version >= MarketDataVersions.Version50; foreach (var quoteMsg in messages) { //if (depth.IsFullEmpty()) // throw new ArgumentException("Переданный стакан является пустым.", "depths"); var bid = quoteMsg.GetBestBid(); var ask = quoteMsg.GetBestAsk(); // у LMAX бид и оффер могут быть равны if (bid != null && ask != null && bid.Price > ask.Price) { throw new ArgumentException(LocalizedStrings.Str932Params.Put(bid.Price, ask.Price, quoteMsg.ServerTime), "messages"); } metaInfo.LastTime = writer.WriteTime(quoteMsg.ServerTime, metaInfo.LastTime, LocalizedStrings.MarketDepth, allowNonOrdered, isUtc, metaInfo.ServerOffset); var isFull = prevQuoteMsg == null; writer.Write(isFull); // пишем, полный ли стакан или это дельта var delta = isFull ? quoteMsg : prevQuoteMsg.GetDelta(quoteMsg); prevQuoteMsg = quoteMsg; SerializeQuotes(writer, delta.Bids, metaInfo /*, isFull*/); SerializeQuotes(writer, delta.Asks, metaInfo /*, isFull*/); metaInfo.LastPrice = GetDepthPrice(quoteMsg); if (metaInfo.Version < MarketDataVersions.Version40) { continue; } if (metaInfo.Version < MarketDataVersions.Version46) { writer.WriteLong(SecurityId.GetLatency(quoteMsg.ServerTime, quoteMsg.LocalTime).Ticks); } else { var hasLocalTime = true; if (metaInfo.Version >= MarketDataVersions.Version49) { hasLocalTime = !quoteMsg.LocalTime.IsDefault() && quoteMsg.LocalTime != quoteMsg.ServerTime; writer.Write(hasLocalTime); } if (hasLocalTime) { metaInfo.LastLocalTime = writer.WriteTime(quoteMsg.LocalTime, metaInfo.LastLocalTime, LocalizedStrings.Str934, allowNonOrdered, isUtc, metaInfo.LocalOffset); } } } }
protected override void OnSave(BitArrayWriter writer, IEnumerable <QuoteChangeMessage> messages, QuoteMetaInfo metaInfo) { if (metaInfo.IsEmpty()) { var firstDepth = messages.FirstOrDefault(d => !d.Bids.IsEmpty() || !d.Asks.IsEmpty()); if (firstDepth == null) { throw new ArgumentException(LocalizedStrings.Str931, "messages"); } metaInfo.LastPrice = metaInfo.FirstPrice = GetDepthPrice(firstDepth); //pyh: будет баг если первый стакан пустой и с другим временем. //metaInfo.FirstTime = firstDepth.LastChangeTime; metaInfo.ServerOffset = firstDepth.ServerTime.Offset; } writer.WriteInt(messages.Count()); QuoteChangeMessage prevQuoteMsg = null; var allowNonOrdered = metaInfo.Version >= MarketDataVersions.Version47; var isUtc = metaInfo.Version >= MarketDataVersions.Version50; var allowDiffOffsets = metaInfo.Version >= MarketDataVersions.Version52; foreach (var m in messages) { var quoteMsg = m; //if (depth.IsFullEmpty()) // throw new ArgumentException("Переданный стакан является пустым.", "depths"); if (!quoteMsg.IsSorted) { quoteMsg = (QuoteChangeMessage)quoteMsg.Clone(); quoteMsg.Bids = quoteMsg.Bids.OrderByDescending(q => q.Price).ToArray(); quoteMsg.Asks = quoteMsg.Asks.OrderBy(q => q.Price).ToArray(); } var bid = quoteMsg.GetBestBid(); var ask = quoteMsg.GetBestAsk(); // LMAX has equals best bid and ask if (bid != null && ask != null && bid.Price > ask.Price) { throw new ArgumentException(LocalizedStrings.Str932Params.Put(bid.Price, ask.Price, quoteMsg.ServerTime), "messages"); } var lastOffset = metaInfo.LastServerOffset; metaInfo.LastTime = writer.WriteTime(quoteMsg.ServerTime, metaInfo.LastTime, LocalizedStrings.MarketDepth, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, ref lastOffset); metaInfo.LastServerOffset = lastOffset; var isFull = prevQuoteMsg == null; writer.Write(isFull); var delta = isFull ? quoteMsg : prevQuoteMsg.GetDelta(quoteMsg); prevQuoteMsg = quoteMsg; SerializeQuotes(writer, delta.Bids, metaInfo /*, isFull*/); SerializeQuotes(writer, delta.Asks, metaInfo /*, isFull*/); metaInfo.LastPrice = GetDepthPrice(quoteMsg); if (metaInfo.Version < MarketDataVersions.Version40) { continue; } if (metaInfo.Version < MarketDataVersions.Version46) { writer.WriteLong(SecurityId.GetLatency(quoteMsg.ServerTime, quoteMsg.LocalTime).Ticks); } else { var hasLocalTime = true; if (metaInfo.Version >= MarketDataVersions.Version49) { hasLocalTime = !quoteMsg.LocalTime.IsDefault() && quoteMsg.LocalTime != quoteMsg.ServerTime; writer.Write(hasLocalTime); } if (hasLocalTime) { lastOffset = metaInfo.LastLocalOffset; metaInfo.LastLocalTime = writer.WriteTime(quoteMsg.LocalTime, metaInfo.LastLocalTime, LocalizedStrings.Str934, allowNonOrdered, isUtc, metaInfo.LocalOffset, allowDiffOffsets, ref lastOffset); metaInfo.LastLocalOffset = lastOffset; } } if (metaInfo.Version < MarketDataVersions.Version51) { continue; } writer.Write(quoteMsg.Currency != null); if (quoteMsg.Currency != null) { writer.WriteInt((int)quoteMsg.Currency.Value); } } }