public static void WriteNullableSide(this BitArrayWriter writer, Sides?value) { writer.Write(value != null); if (value is null) { return; } writer.Write(value.Value == Sides.Buy); }
public static void WriteNullableBool(this BitArrayWriter writer, bool?value) { writer.Write(value != null); if (value is null) { return; } writer.Write(value.Value); }
public static void WriteSide(this BitArrayWriter writer, Sides?direction) { if (direction == null) { writer.Write(false); } else { writer.Write(true); writer.Write(direction == Sides.Buy); } }
public static void WriteNullableInt(this BitArrayWriter writer, int?value) { if (value == null) { writer.Write(false); } else { writer.Write(true); writer.WriteInt(value.Value); } }
public static void WriteNullableLong(this BitArrayWriter writer, long?value) { if (value == null) { writer.Write(false); } else { writer.Write(true); writer.WriteLong(value.Value); } }
public static void WriteStringEx(this BitArrayWriter writer, string value) { if (value.IsEmpty()) { writer.Write(false); } else { writer.Write(true); writer.WriteString(value); } }
public static void WriteNullableInt <T>(this BitArrayWriter writer, T?value) where T : struct { if (value == null) { writer.Write(false); } else { writer.Write(true); writer.WriteInt(value.To <int>()); } }
public static void WriteBuildFrom(this BitArrayWriter writer, DataType buildFrom) { writer.Write(buildFrom != null); if (buildFrom == null) { return; } if (buildFrom == DataType.Level1) { writer.WriteInt(0); } else if (buildFrom == DataType.MarketDepth) { writer.WriteInt(1); } else if (buildFrom == DataType.OrderLog) { writer.WriteInt(2); } else if (buildFrom == DataType.Ticks) { writer.WriteInt(3); } else if (buildFrom == DataType.Transactions) { writer.WriteInt(4); } else { writer.WriteInt(5); var(messageType, arg1, arg2, arg3) = buildFrom.Extract(); writer.WriteInt(messageType); writer.WriteLong(arg1); if (arg2 == 0) { writer.Write(false); } else { writer.Write(true); writer.WriteDecimal(arg2, 0); } writer.WriteInt(arg3); } }
public static void WriteDto(this BitArrayWriter writer, DateTimeOffset?dto) { if (dto != null) { writer.Write(true); writer.WriteLong(dto.Value.Ticks); writer.WriteInt(dto.Value.Offset.Hours); writer.WriteInt(dto.Value.Offset.Minutes); } else { writer.Write(false); } }
private static void WriteString(BitArrayWriter writer, IList <string> items, string value) { if (value.IsEmpty()) { writer.Write(false); } else { writer.Write(true); items.TryAdd(value); writer.WriteInt(items.IndexOf(value)); } }
private static void WriteCommission(BitArrayWriter writer, TransactionSerializerMetaInfo metaInfo, decimal?value) { if (value == null) { writer.Write(false); } else { writer.Write(true); writer.WriteDecimal((decimal)value, metaInfo.LastCommission); metaInfo.LastCommission = (decimal)value; } }
private static decimal Write(BitArrayWriter writer, decimal?value, decimal last) { if (value == null) { writer.Write(false); return(last); } else { writer.Write(true); writer.WriteDecimal((decimal)value, last); return(value.Value); } }
public static void WritePriceEx <T>(this BitArrayWriter writer, decimal price, BinaryMetaInfo <T> info, SecurityId securityId) where T : BinaryMetaInfo <T> { if (info.Version < MarketDataVersions.Version41) { writer.WritePrice(price, info.LastPrice, info, securityId); info.LastPrice = price; } else { var isAligned = (price % info.PriceStep) == 0; writer.Write(isAligned); if (isAligned) { if (info.FirstPrice == 0) { info.FirstPrice = info.LastPrice = price; } writer.WritePrice(price, info.LastPrice, info, securityId); info.LastPrice = price; } else { if (info.FirstNonSystemPrice == 0) { info.FirstNonSystemPrice = info.LastNonSystemPrice = price; } info.LastNonSystemPrice = writer.WriteDecimal(price, info.LastNonSystemPrice); } } }
public static void WritePriceEx(this BitArrayWriter writer, decimal price, BinaryMetaInfo info, SecurityId securityId, bool useLong = false) { if (info.Version < MarketDataVersions.Version41) { var prevPrice = info.LastPrice; writer.WritePrice(price, ref prevPrice, info, securityId); info.LastPrice = price; } else { var isAligned = (price % info.LastPriceStep) == 0; writer.Write(isAligned); if (isAligned) { if (info.FirstPrice == 0) { info.FirstPrice = info.LastPrice = price; } var prevPrice = info.LastPrice; writer.WritePrice(price, ref prevPrice, info, securityId, useLong); info.LastPrice = price; } else { if (info.FirstFractionalPrice == 0) { info.FirstFractionalPrice = info.LastFractionalPrice = price; } info.LastFractionalPrice = writer.WriteDecimal(price, info.LastFractionalPrice); } } }
public static decimal WriteDecimal(this BitArrayWriter writer, decimal value, decimal prevValue) { var diff = value - prevValue; if (value != prevValue + diff) { throw new ArgumentOutOfRangeException(nameof(value), LocalizedStrings.Str1006Params.Put(value, prevValue)); } writer.Write(diff >= 0); if (diff < 0) { diff = -diff; } var decBits = decimal.GetBits(diff); writer.WriteInt(decBits[0]); writer.WriteInt(decBits[1]); writer.WriteInt(decBits[2]); writer.WriteInt((decBits[3] >> 16) & 0xff); return(value); }
private static bool TryWriteLargeDecimal(this BitArrayWriter writer, bool largeDecimal, decimal value) { if (largeDecimal) { if (value.Abs() > _largeDecLimit) { writer.Write(true); writer.WriteDecimal(value); return(true); } else { writer.Write(false); } } return(false); }
public static void WriteVolume(this BitArrayWriter writer, decimal volume, BinaryMetaInfo info, bool largeDecimal) { if (info.Version < MarketDataVersions.Version44) { var intVolume = volume.Truncate(); if (intVolume == volume) // объем целочисленный { writer.Write(true); writer.WriteLong((long)intVolume); } else { writer.Write(false); throw new NotSupportedException(LocalizedStrings.Str1010Params.Put(volume)); } } else { if (writer.TryWriteLargeDecimal(largeDecimal, volume)) { return; } var isAligned = (volume % info.VolumeStep) == 0; writer.Write(isAligned); if (isAligned) { writer.WriteLong((long)(volume / info.VolumeStep)); } else { if (info.FirstFractionalVolume == 0) { info.FirstFractionalVolume = info.LastFractionalVolume = volume; } info.LastFractionalVolume = writer.WriteDecimal(volume, info.LastFractionalVolume); } } }
protected override void OnSave(BitArrayWriter writer, IEnumerable <NewsMessage> messages, NewsMetaInfo metaInfo) { var isMetaEmpty = metaInfo.IsEmpty(); writer.WriteInt(messages.Count()); var allowDiffOffsets = metaInfo.Version >= MarketDataVersions.Version46; var isTickPrecision = metaInfo.Version >= MarketDataVersions.Version47; foreach (var news in messages) { if (isMetaEmpty) { metaInfo.ServerOffset = news.ServerTime.Offset; isMetaEmpty = false; } writer.WriteStringEx(news.Id); writer.WriteString(news.Headline); writer.WriteStringEx(news.Story); writer.WriteStringEx(news.Source); writer.WriteStringEx(news.BoardCode); writer.WriteStringEx(news.SecurityId?.SecurityCode); writer.WriteStringEx(news.Url); var lastOffset = metaInfo.LastServerOffset; metaInfo.LastTime = writer.WriteTime(news.ServerTime, metaInfo.LastTime, LocalizedStrings.News, true, true, metaInfo.ServerOffset, allowDiffOffsets, isTickPrecision, ref lastOffset); metaInfo.LastServerOffset = lastOffset; if (metaInfo.Version < MarketDataVersions.Version48) { continue; } writer.Write(news.Priority != null); if (news.Priority != null) { writer.WriteInt((int)news.Priority.Value); } if (metaInfo.Version < MarketDataVersions.Version49) { continue; } writer.WriteStringEx(news.Language); } }
public static void WritePrice(this BitArrayWriter writer, decimal price, ref decimal prevPrice, BinaryMetaInfo info, SecurityId securityId, bool useLong = false, bool nonAdjustPrice = false) { var priceStep = info.LastPriceStep; if (priceStep == 0) { throw new InvalidOperationException(LocalizedStrings.Str2925); } if ((price % priceStep) != 0) { if (!nonAdjustPrice) { throw new ArgumentException(LocalizedStrings.Str1007Params.Put(priceStep, securityId, price), nameof(info)); } writer.Write(false); var priceStepChanged = false; if ((price % info.LastPriceStep) != 0) { var newPriceStep = 1m; var found = false; for (var i = 0; i < 10; i++) { if ((price % newPriceStep) == 0) { found = true; break; } newPriceStep /= 10; } if (!found) { throw new ArgumentException(LocalizedStrings.Str1007Params.Put(priceStep, securityId, price), nameof(info)); } info.LastPriceStep = newPriceStep; //if (info.FirstPriceStep == 0) // info.FirstPriceStep = info.LastPriceStep; priceStepChanged = true; } writer.Write(priceStepChanged); if (priceStepChanged) { WriteDecimal(writer, info.LastPriceStep, 0); } if (info.FirstFractionalPrice == 0) { info.FirstFractionalPrice = info.LastFractionalPrice = price; } var stepCount = (long)((price - info.LastFractionalPrice) / info.LastPriceStep); if (useLong) { writer.WriteLong(stepCount); } else { writer.WriteInt((int)stepCount); } info.LastFractionalPrice = price; return; } if (nonAdjustPrice) { writer.Write(true); } try { var stepCount = (long)((price - prevPrice) / priceStep); // ОЛ может содержать заявки с произвольно большими ценами if (useLong) { writer.WriteLong(stepCount); } else { if (stepCount.Abs() > int.MaxValue) { throw new InvalidOperationException("Range is overflow."); } writer.WriteInt((int)stepCount); } prevPrice = price; } catch (OverflowException ex) { throw new ArgumentException(LocalizedStrings.Str1008Params.Put(price, prevPrice, priceStep, useLong), ex); } }
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()); //var price = firstDepth != null ? GetDepthPrice(firstDepth) : 0; //if (price != 0) //{ // if ((price % metaInfo.PriceStep) == 0) // metaInfo.LastPrice = metaInfo.FirstPrice = price; // else // metaInfo.LastFractionalPrice = metaInfo.FirstFractionalPrice = price; //} metaInfo.ServerOffset = (firstDepth ?? messages.First()).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; var isTickPrecision = metaInfo.Version >= MarketDataVersions.Version53; var nonAdjustPrice = metaInfo.Version >= MarketDataVersions.Version54; var useLong = metaInfo.Version >= MarketDataVersions.Version55; foreach (var m in messages) { var quoteMsg = m; //if (m.IsFullEmpty()) // throw new ArgumentException(LocalizedStrings.Str1309, nameof(messages)); 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), nameof(messages)); var lastOffset = metaInfo.LastServerOffset; metaInfo.LastTime = writer.WriteTime(quoteMsg.ServerTime, metaInfo.LastTime, LocalizedStrings.MarketDepth, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, isTickPrecision, 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*/, useLong, nonAdjustPrice); SerializeQuotes(writer, delta.Asks, metaInfo /*, isFull*/, useLong, nonAdjustPrice); //metaInfo.LastPrice = GetDepthPrice(quoteMsg); if (metaInfo.Version < MarketDataVersions.Version40) { continue; } if (metaInfo.Version < MarketDataVersions.Version46) { writer.WriteLong((quoteMsg.LocalTime - quoteMsg.ServerTime).Ticks); } else { var hasLocalTime = true; if (metaInfo.Version >= MarketDataVersions.Version49) { hasLocalTime = quoteMsg.HasLocalTime(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, isTickPrecision, ref lastOffset, true); metaInfo.LastLocalOffset = lastOffset; } } if (metaInfo.Version < MarketDataVersions.Version51) { continue; } writer.Write(quoteMsg.Currency != null); if (quoteMsg.Currency != null) { writer.WriteInt((int)quoteMsg.Currency.Value); } } }
public static DateTime WriteTime(this BitArrayWriter writer, DateTimeOffset dto, DateTime prevTime, string name, bool allowNonOrdered, bool isUtc, TimeSpan offset, bool allowDiffOffsets, ref TimeSpan prevOffset) { if (writer == null) { throw new ArgumentNullException("writer"); } if (allowDiffOffsets) { writer.Write(dto.Offset == prevOffset); if (prevOffset != dto.Offset) { prevOffset = dto.Offset; writer.WriteInt(prevOffset.Hours); writer.Write(prevOffset.Minutes == 0); if (prevOffset.Minutes != 0) { writer.WriteInt(prevOffset.Minutes); } } } else if (isUtc && dto.Offset != offset) { throw new ArgumentException(LocalizedStrings.WrongTimeOffset.Put(dto, offset)); } dto = dto.Truncate(); var time = isUtc ? dto.UtcDateTime : dto.LocalDateTime; var timeDiff = time - prevTime; if (allowNonOrdered) { if (timeDiff < TimeSpan.Zero) { writer.Write(false); timeDiff = new TimeSpan(-timeDiff.Ticks); } else { writer.Write(true); } if (timeDiff >= TimeSpan.FromMinutes(1)) { writer.Write(true); if (timeDiff <= TimeSpan.FromHours(32)) { writer.Write(true); writer.WriteBits(timeDiff.Hours, 5); } else { writer.Write(false); writer.WriteInt(timeDiff.Hours); } writer.WriteBits(timeDiff.Minutes, 6); writer.WriteBits(timeDiff.Seconds, 6); } else { writer.Write(false); writer.WriteInt(timeDiff.Seconds); } } else { if (timeDiff < TimeSpan.Zero) { throw new ArgumentException(LocalizedStrings.Str1009Params.Put(name, prevTime, time), "dto"); } if (timeDiff >= TimeSpan.FromMinutes(1)) { writer.Write(true); timeDiff = time.TimeOfDay; writer.WriteBits(timeDiff.Hours, 5); writer.WriteBits(timeDiff.Minutes, 6); writer.WriteBits(timeDiff.Seconds, 6); } else { writer.Write(false); writer.WriteInt(timeDiff.Seconds); } } writer.WriteInt(timeDiff.Milliseconds); return(time); }
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); } } }
public static DateTime WriteTime(this BitArrayWriter writer, DateTimeOffset dto, DateTime prevTime, string name, bool allowNonOrdered, bool isUtc, TimeSpan offset, bool allowDiffOffsets, bool isTickPrecision, ref TimeSpan prevOffset, bool bigRange = false) { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (allowDiffOffsets) { writer.Write(dto.Offset == prevOffset); if (prevOffset != dto.Offset) { prevOffset = dto.Offset; writer.WriteInt(prevOffset.Hours); writer.Write(prevOffset.Minutes == 0); if (prevOffset.Minutes != 0) { writer.WriteInt(prevOffset.Minutes); } } } else if (isUtc && dto.Offset != offset) { throw new ArgumentException(LocalizedStrings.WrongTimeOffset.Put(dto, offset)); } if (!isTickPrecision) { dto = dto.StorageBinaryOldTruncate(); } var time = isUtc ? dto.UtcDateTime : dto.LocalDateTime; var timeDiff = time - prevTime; if (allowNonOrdered) { if (timeDiff < TimeSpan.Zero) { writer.Write(false); timeDiff = new TimeSpan(-timeDiff.Ticks); } else { writer.Write(true); } if (timeDiff >= TimeSpan.FromMinutes(1)) { writer.Write(true); if (timeDiff <= TimeSpan.FromHours(32)) { writer.Write(true); writer.WriteBits(timeDiff.Hours, 5); } else { writer.Write(false); writer.WriteInt(timeDiff.Hours); if (timeDiff.Days > 0) { if (!bigRange) { throw new ArgumentOutOfRangeException(nameof(dto), LocalizedStrings.BigRangeError.Put(prevTime, dto)); } writer.Write(true); writer.WriteInt(timeDiff.Days); } else { writer.Write(false); } } writer.WriteBits(timeDiff.Minutes, 6); writer.WriteBits(timeDiff.Seconds, 6); } else { writer.Write(false); writer.WriteInt(timeDiff.Seconds); } } else { if (timeDiff < TimeSpan.Zero) { throw new ArgumentException(LocalizedStrings.Str1009Params.Put(name, prevTime, time), nameof(dto)); } if (timeDiff >= TimeSpan.FromMinutes(1)) { writer.Write(true); timeDiff = time.TimeOfDay; writer.WriteBits(timeDiff.Hours, 5); writer.WriteBits(timeDiff.Minutes, 6); writer.WriteBits(timeDiff.Seconds, 6); } else { writer.Write(false); writer.WriteInt(timeDiff.Seconds); } } writer.WriteInt(timeDiff.Milliseconds); if (isTickPrecision) { writer.WriteInt((int)(timeDiff.Ticks % 10000)); } return(time); }
protected override void OnSave(BitArrayWriter writer, IEnumerable <ExecutionMessage> messages, TransactionSerializerMetaInfo metaInfo) { if (metaInfo.IsEmpty()) { var msg = messages.First(); metaInfo.FirstOrderId = metaInfo.LastOrderId = msg.OrderId ?? 0; metaInfo.FirstTradeId = metaInfo.LastTradeId = msg.TradeId ?? 0; metaInfo.FirstTransactionId = metaInfo.LastTransactionId = msg.TransactionId; metaInfo.FirstOriginalTransactionId = metaInfo.LastOriginalTransactionId = msg.OriginalTransactionId; metaInfo.FirstCommission = metaInfo.LastCommission = msg.Commission ?? 0; metaInfo.FirstPnL = metaInfo.LastPnL = msg.PnL ?? 0; metaInfo.FirstPosition = metaInfo.LastPosition = msg.Position ?? 0; metaInfo.FirstSlippage = metaInfo.LastSlippage = msg.Slippage ?? 0; metaInfo.FirstItemLocalTime = metaInfo.LastItemLocalTime = msg.LocalTime.UtcDateTime; metaInfo.FirstItemLocalOffset = metaInfo.LastItemLocalOffset = msg.LocalTime.Offset; metaInfo.ServerOffset = msg.ServerTime.Offset; } writer.WriteInt(messages.Count()); var allowNonOrdered = metaInfo.Version >= MarketDataVersions.Version48; var isUtc = metaInfo.Version >= MarketDataVersions.Version51; var allowDiffOffsets = metaInfo.Version >= MarketDataVersions.Version56; var isTickPrecision = metaInfo.Version >= MarketDataVersions.Version60; var buildFrom = metaInfo.Version >= MarketDataVersions.Version67; var leverage = metaInfo.Version >= MarketDataVersions.Version68; foreach (var msg in messages) { if (msg.ExecutionType != ExecutionTypes.Transaction) { throw new ArgumentOutOfRangeException(nameof(messages), msg.ExecutionType, LocalizedStrings.Str1695Params.Put(msg)); } // нулевой номер заявки возможен при сохранении в момент регистрации if (msg.OrderId < 0) { throw new ArgumentOutOfRangeException(nameof(messages), msg.OrderId, LocalizedStrings.Str925); } // нулевая цена возможна, если идет "рыночная" продажа по инструменту без планок if (msg.OrderPrice < 0) { throw new ArgumentOutOfRangeException(nameof(messages), msg.OrderPrice, LocalizedStrings.Str926Params.Put(msg.OrderId == null ? msg.OrderStringId : msg.OrderId.To <string>())); } //var volume = msg.Volume; //if (volume < 0) // throw new ArgumentOutOfRangeException(nameof(messages), volume, LocalizedStrings.Str927Params.Put(msg.OrderId == null ? msg.OrderStringId : msg.OrderId.To<string>())); if (msg.HasTradeInfo()) { //if ((msg.TradeId == null && msg.TradeStringId.IsEmpty()) || msg.TradeId <= 0) // throw new ArgumentOutOfRangeException(nameof(messages), msg.TradeId, LocalizedStrings.Str928Params.Put(msg.TransactionId)); if (msg.TradePrice == null || msg.TradePrice <= 0) { throw new ArgumentOutOfRangeException(nameof(messages), msg.TradePrice, LocalizedStrings.Str929Params.Put(msg.TradeId, msg.OrderId)); } } metaInfo.LastTransactionId = writer.SerializeId(msg.TransactionId, metaInfo.LastTransactionId); metaInfo.LastOriginalTransactionId = writer.SerializeId(msg.OriginalTransactionId, metaInfo.LastOriginalTransactionId); writer.Write(msg.HasOrderInfo); writer.Write(msg.HasTradeInfo); writer.Write(msg.OrderId != null); if (msg.OrderId != null) { metaInfo.LastOrderId = writer.SerializeId(msg.OrderId.Value, metaInfo.LastOrderId); } else { writer.WriteStringEx(msg.OrderStringId); } writer.WriteStringEx(msg.OrderBoardId); writer.Write(msg.TradeId != null); if (msg.TradeId != null) { metaInfo.LastTradeId = writer.SerializeId(msg.TradeId.Value, metaInfo.LastTradeId); } else { writer.WriteStringEx(msg.TradeStringId); } if (msg.OrderPrice != 0) { writer.Write(true); writer.WritePriceEx(msg.OrderPrice, metaInfo, SecurityId); } else { writer.Write(false); } if (msg.TradePrice != null) { writer.Write(true); writer.WritePriceEx(msg.TradePrice.Value, metaInfo, SecurityId); } else { writer.Write(false); } writer.Write(msg.Side == Sides.Buy); writer.Write(msg.OrderVolume != null); if (msg.OrderVolume != null) { writer.WriteVolume(msg.OrderVolume.Value, metaInfo, SecurityId); } writer.Write(msg.TradeVolume != null); if (msg.TradeVolume != null) { writer.WriteVolume(msg.TradeVolume.Value, metaInfo, SecurityId); } writer.Write(msg.VisibleVolume != null); if (msg.VisibleVolume != null) { writer.WriteVolume(msg.VisibleVolume.Value, metaInfo, SecurityId); } writer.Write(msg.Balance != null); if (msg.Balance != null) { writer.WriteVolume(msg.Balance.Value, metaInfo, SecurityId); } var lastOffset = metaInfo.LastServerOffset; metaInfo.LastTime = writer.WriteTime(msg.ServerTime, metaInfo.LastTime, LocalizedStrings.Str930, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, isTickPrecision, ref lastOffset); metaInfo.LastServerOffset = lastOffset; writer.WriteNullableInt((int?)msg.OrderType); writer.WriteNullableInt((int?)msg.OrderState); writer.WriteNullableLong(msg.OrderStatus); writer.WriteNullableInt(msg.TradeStatus); writer.WriteNullableInt((int?)msg.TimeInForce); writer.Write(msg.IsSystem != null); if (msg.IsSystem != null) { writer.Write(msg.IsSystem.Value); } writer.Write(msg.IsUpTick != null); if (msg.IsUpTick != null) { writer.Write(msg.IsUpTick.Value); } writer.WriteDto(msg.ExpiryDate); metaInfo.LastCommission = Write(writer, msg.Commission, metaInfo.LastCommission); metaInfo.LastPnL = Write(writer, msg.PnL, metaInfo.LastPnL); metaInfo.LastPosition = Write(writer, msg.Position, metaInfo.LastPosition); metaInfo.LastSlippage = Write(writer, msg.Slippage, metaInfo.LastSlippage); WriteString(writer, metaInfo.Portfolios, msg.PortfolioName); WriteString(writer, metaInfo.ClientCodes, msg.ClientCode); WriteString(writer, metaInfo.BrokerCodes, msg.BrokerCode); WriteString(writer, metaInfo.DepoNames, msg.DepoName); WriteString(writer, metaInfo.UserOrderIds, msg.UserOrderId); WriteString(writer, metaInfo.Comments, msg.Comment); WriteString(writer, metaInfo.SystemComments, msg.SystemComment); WriteString(writer, metaInfo.Errors, msg.Error?.Message); writer.WriteNullableInt((int?)msg.Currency); writer.Write(msg.Latency != null); if (msg.Latency != null) { writer.WriteLong(msg.Latency.Value.Ticks); } writer.Write(msg.OriginSide != null); if (msg.OriginSide != null) { writer.Write(msg.OriginSide.Value == Sides.Buy); } if (metaInfo.Version < MarketDataVersions.Version59) { continue; } WriteItemLocalTime(writer, metaInfo, msg, isTickPrecision); if (metaInfo.Version < MarketDataVersions.Version61) { continue; } writer.Write(msg.IsMarketMaker != null); if (msg.IsMarketMaker != null) { writer.Write(msg.IsMarketMaker.Value); } if (metaInfo.Version < MarketDataVersions.Version62) { continue; } writer.Write(msg.IsMargin != null); if (msg.IsMargin != null) { writer.Write(msg.IsMargin.Value); } if (metaInfo.Version < MarketDataVersions.Version63) { continue; } writer.WriteStringEx(msg.CommissionCurrency); if (metaInfo.Version < MarketDataVersions.Version64) { continue; } writer.Write(msg.IsManual != null); if (msg.IsManual != null) { writer.Write(msg.IsManual.Value); } if (metaInfo.Version < MarketDataVersions.Version65) { continue; } writer.Write(msg.PositionEffect != null); if (msg.PositionEffect != null) { writer.WriteInt((int)msg.PositionEffect.Value); } writer.Write(msg.PostOnly != null); if (msg.PostOnly != null) { writer.Write(msg.PostOnly.Value); } writer.Write(msg.Initiator != null); if (msg.Initiator != null) { writer.Write(msg.Initiator.Value); } if (metaInfo.Version < MarketDataVersions.Version66) { continue; } writer.WriteLong(msg.SeqNum); WriteString(writer, metaInfo.StrategyIds, msg.StrategyId); if (!buildFrom) { continue; } writer.WriteBuildFrom(msg.BuildFrom); if (!leverage) { continue; } writer.WriteNullableInt(msg.Leverage); } }
protected override void OnSave(BitArrayWriter writer, IEnumerable <ExecutionMessage> messages, OrderLogMetaInfo metaInfo) { if (metaInfo.IsEmpty() && !messages.IsEmpty()) { var item = messages.First(); metaInfo.FirstOrderId = metaInfo.LastOrderId = item.SafeGetOrderId(); metaInfo.FirstTransactionId = metaInfo.LastTransactionId = item.TransactionId; metaInfo.ServerOffset = item.ServerTime.Offset; } writer.WriteInt(messages.Count()); var allowNonOrdered = metaInfo.Version >= MarketDataVersions.Version47; var isUtc = metaInfo.Version >= MarketDataVersions.Version48; var allowDiffOffsets = metaInfo.Version >= MarketDataVersions.Version52; var isTickPrecision = metaInfo.Version >= MarketDataVersions.Version53; foreach (var message in messages) { var hasTrade = message.TradeId != null || message.TradePrice != null; var orderId = message.SafeGetOrderId(); if (orderId < 0) { throw new ArgumentOutOfRangeException(nameof(messages), orderId, LocalizedStrings.Str925); } if (message.ExecutionType != ExecutionTypes.OrderLog) { throw new ArgumentOutOfRangeException(nameof(messages), message.ExecutionType, LocalizedStrings.Str1695Params.Put(orderId)); } // sell market orders has zero price (if security do not have min allowed price) // execution ticks (like option execution) may be a zero cost // ticks for spreads may be a zero cost or less than zero //if (item.Price < 0) // throw new ArgumentOutOfRangeException(nameof(messages), item.Price, LocalizedStrings.Str926Params.Put(item.OrderId)); var volume = message.SafeGetVolume(); if (volume <= 0) { throw new ArgumentOutOfRangeException(nameof(messages), volume, LocalizedStrings.Str927Params.Put(message.OrderId)); } long?tradeId = null; if (hasTrade) { tradeId = message.GetTradeId(); if (tradeId <= 0) { throw new ArgumentOutOfRangeException(nameof(messages), tradeId, LocalizedStrings.Str1012Params.Put(message.OrderId)); } // execution ticks (like option execution) may be a zero cost // ticks for spreads may be a zero cost or less than zero //if (item.TradePrice <= 0) // throw new ArgumentOutOfRangeException(nameof(messages), item.TradePrice, LocalizedStrings.Str929Params.Put(item.TradeId, item.OrderId)); } metaInfo.LastOrderId = writer.SerializeId(orderId, metaInfo.LastOrderId); var orderPrice = message.OrderPrice; if (metaInfo.Version < MarketDataVersions.Version45) { writer.WritePriceEx(orderPrice, metaInfo, SecurityId); } else { var isAligned = (orderPrice % metaInfo.PriceStep) == 0; writer.Write(isAligned); if (isAligned) { if (metaInfo.FirstOrderPrice == 0) { metaInfo.FirstOrderPrice = metaInfo.LastOrderPrice = orderPrice; } writer.WritePrice(orderPrice, metaInfo.LastOrderPrice, metaInfo, SecurityId, true); metaInfo.LastOrderPrice = orderPrice; } else { if (metaInfo.FirstFractionalPrice == 0) { metaInfo.FirstFractionalPrice = metaInfo.LastFractionalPrice = orderPrice; } metaInfo.LastFractionalPrice = writer.WriteDecimal(orderPrice, metaInfo.LastFractionalPrice); } } writer.WriteVolume(volume, metaInfo, SecurityId); writer.Write(message.Side == Sides.Buy); var lastOffset = metaInfo.LastServerOffset; metaInfo.LastTime = writer.WriteTime(message.ServerTime, metaInfo.LastTime, LocalizedStrings.Str1013, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, isTickPrecision, ref lastOffset); metaInfo.LastServerOffset = lastOffset; if (hasTrade) { writer.Write(true); if (metaInfo.FirstTradeId == 0) { metaInfo.FirstTradeId = metaInfo.LastTradeId = tradeId.Value; } metaInfo.LastTradeId = writer.SerializeId(tradeId.Value, metaInfo.LastTradeId); writer.WritePriceEx(message.GetTradePrice(), metaInfo, SecurityId); } else { writer.Write(false); writer.Write(message.OrderState == OrderStates.Active); } if (metaInfo.Version < MarketDataVersions.Version31) { continue; } writer.WriteNullableInt(message.OrderStatus); if (metaInfo.Version < MarketDataVersions.Version33) { continue; } if (metaInfo.Version < MarketDataVersions.Version50) { writer.WriteInt((int)(message.TimeInForce ?? TimeInForce.PutInQueue)); } else { writer.Write(message.TimeInForce != null); if (message.TimeInForce != null) { writer.WriteInt((int)message.TimeInForce.Value); } } if (metaInfo.Version >= MarketDataVersions.Version49) { writer.Write(message.IsSystem != null); if (message.IsSystem != null) { writer.Write(message.IsSystem.Value); } } else { writer.Write(message.IsSystem ?? true); } if (metaInfo.Version < MarketDataVersions.Version34) { continue; } metaInfo.LastTransactionId = writer.SerializeId(message.TransactionId, metaInfo.LastTransactionId); if (metaInfo.Version < MarketDataVersions.Version40) { continue; } if (metaInfo.Version < MarketDataVersions.Version46) { writer.WriteLong(0 /*item.Latency.Ticks*/); } var portfolio = message.PortfolioName; var isEmptyPf = portfolio == null || portfolio == Portfolio.AnonymousPortfolio.Name; writer.Write(!isEmptyPf); if (!isEmptyPf) { metaInfo.Portfolios.TryAdd(message.PortfolioName); writer.WriteInt(metaInfo.Portfolios.IndexOf(message.PortfolioName)); } if (metaInfo.Version < MarketDataVersions.Version51) { continue; } writer.Write(message.Currency != null); if (message.Currency != null) { writer.WriteInt((int)message.Currency.Value); } } }
protected override void OnSave(BitArrayWriter writer, IEnumerable <ExecutionMessage> messages, TransactionSerializerMetaInfo metaInfo) { if (metaInfo.IsEmpty()) { var msg = messages.First(); metaInfo.FirstOrderId = metaInfo.LastOrderId = msg.OrderId ?? 0; metaInfo.FirstTradeId = metaInfo.LastTradeId = msg.TradeId ?? 0; metaInfo.FirstTransactionId = metaInfo.LastTransactionId = msg.TransactionId; metaInfo.FirstOriginalTransactionId = metaInfo.LastOriginalTransactionId = msg.OriginalTransactionId; metaInfo.FirstCommission = metaInfo.LastCommission = msg.Commission ?? 0; metaInfo.ServerOffset = msg.ServerTime.Offset; } writer.WriteInt(messages.Count()); var allowNonOrdered = metaInfo.Version >= MarketDataVersions.Version48; var isUtc = metaInfo.Version >= MarketDataVersions.Version51; var allowDiffOffsets = metaInfo.Version >= MarketDataVersions.Version56; foreach (var msg in messages) { var isTrade = msg.ExecutionType == ExecutionTypes.Trade; if (msg.ExecutionType != ExecutionTypes.Order && msg.ExecutionType != ExecutionTypes.Trade) { throw new ArgumentOutOfRangeException(nameof(messages), msg.ExecutionType, LocalizedStrings.Str1695Params.Put(msg.OrderId ?? msg.TradeId)); } // нулевой номер заявки возможен при сохранении в момент регистрации if (msg.OrderId < 0) { throw new ArgumentOutOfRangeException(nameof(messages), msg.OrderId, LocalizedStrings.Str925); } // нулевая цена возможна, если идет "рыночная" продажа по инструменту без планок if (msg.OrderPrice < 0) { throw new ArgumentOutOfRangeException(nameof(messages), msg.OrderPrice, LocalizedStrings.Str926Params.Put(msg.OrderId == null ? msg.OrderStringId : msg.OrderId.To <string>())); } var volume = msg.Volume; if (volume < 0) { throw new ArgumentOutOfRangeException(nameof(messages), volume, LocalizedStrings.Str927Params.Put(msg.OrderId == null ? msg.OrderStringId : msg.OrderId.To <string>())); } if (isTrade) { if ((msg.TradeId == null && msg.TradeStringId.IsEmpty()) || msg.TradeId <= 0) { throw new ArgumentOutOfRangeException(nameof(messages), msg.TradeId, LocalizedStrings.Str928Params.Put(msg.TransactionId)); } if (msg.TradePrice == null || msg.TradePrice <= 0) { throw new ArgumentOutOfRangeException(nameof(messages), msg.TradePrice, LocalizedStrings.Str929Params.Put(msg.TradeId, msg.OrderId)); } } writer.WriteInt((int)msg.ExecutionType); metaInfo.LastTransactionId = writer.SerializeId(msg.TransactionId, metaInfo.LastTransactionId); metaInfo.LastOriginalTransactionId = writer.SerializeId(msg.OriginalTransactionId, metaInfo.LastOriginalTransactionId); if (!isTrade) { if (metaInfo.Version < MarketDataVersions.Version50) { metaInfo.LastOrderId = writer.SerializeId(msg.OrderId ?? 0, metaInfo.LastOrderId); } else { writer.Write(msg.OrderId != null); if (msg.OrderId != null) { metaInfo.LastOrderId = writer.SerializeId(msg.OrderId.Value, metaInfo.LastOrderId); } else { writer.Write(!msg.OrderStringId.IsEmpty()); if (!msg.OrderStringId.IsEmpty()) { writer.WriteString(msg.OrderStringId); } } writer.Write(!msg.OrderBoardId.IsEmpty()); if (!msg.OrderBoardId.IsEmpty()) { writer.WriteString(msg.OrderBoardId); } } } else { if (metaInfo.Version < MarketDataVersions.Version50) { metaInfo.LastTradeId = writer.SerializeId(msg.TradeId ?? 0, metaInfo.LastTradeId); } else { writer.Write(msg.TradeId != null); if (msg.TradeId != null) { metaInfo.LastTradeId = writer.SerializeId(msg.TradeId.Value, metaInfo.LastTradeId); } else { writer.Write(!msg.TradeStringId.IsEmpty()); if (!msg.TradeStringId.IsEmpty()) { writer.WriteString(msg.TradeStringId); } } } } writer.Write(msg.Side == Sides.Buy); writer.WritePriceEx(!isTrade ? msg.OrderPrice : msg.GetTradePrice(), metaInfo, SecurityId); if (metaInfo.Version < MarketDataVersions.Version57) { writer.WriteVolume(volume ?? 0, metaInfo, SecurityId); } else { writer.Write(volume != null); if (volume != null) { writer.WriteVolume(volume.Value, metaInfo, SecurityId); } } if (metaInfo.Version < MarketDataVersions.Version54) { writer.WriteVolume(msg.VisibleVolume ?? 0, metaInfo, SecurityId); writer.WriteVolume(msg.Balance ?? 0, metaInfo, SecurityId); } else { writer.Write(msg.VisibleVolume != null); if (msg.VisibleVolume != null) { writer.WriteVolume(msg.VisibleVolume.Value, metaInfo, SecurityId); } writer.Write(msg.Balance != null); if (msg.Balance != null) { writer.WriteVolume(msg.Balance.Value, metaInfo, SecurityId); } } var lastOffset = metaInfo.LastServerOffset; metaInfo.LastTime = writer.WriteTime(msg.ServerTime, metaInfo.LastTime, LocalizedStrings.Str930, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, ref lastOffset); metaInfo.LastServerOffset = lastOffset; writer.WriteInt((int)msg.OrderType); writer.WriteNullableInt(msg.OrderState); writer.WriteNullableInt(msg.OrderStatus); if (metaInfo.Version < MarketDataVersions.Version52) { writer.WriteInt(msg.TradeStatus ?? 0); } else { writer.WriteNullableInt(msg.TradeStatus); } if (metaInfo.Version < MarketDataVersions.Version53) { writer.WriteInt((int)(msg.TimeInForce ?? TimeInForce.PutInQueue)); } else { writer.Write(msg.TimeInForce != null); if (msg.TimeInForce != null) { writer.WriteInt((int)msg.TimeInForce.Value); } } if (metaInfo.Version < MarketDataVersions.Version52) { writer.Write(msg.IsSystem ?? true); } else { writer.Write(msg.IsSystem != null); if (msg.IsSystem != null) { writer.Write(msg.IsSystem.Value); } } writer.WriteLong(msg.ExpiryDate != null ? msg.ExpiryDate.Value.Ticks : 0L); WriteCommission(writer, metaInfo, msg.Commission); WriteString(writer, metaInfo.Portfolios, msg.PortfolioName); WriteString(writer, metaInfo.StrategyIds, msg.UserOrderId); WriteString(writer, metaInfo.Comments, msg.Comment); WriteString(writer, metaInfo.Errors, msg.Error != null ? msg.Error.Message : null); if (metaInfo.Version < MarketDataVersions.Version55) { continue; } writer.Write(msg.Currency != null); if (msg.Currency != null) { writer.WriteInt((int)msg.Currency.Value); } } }
public static DateTime WriteTime(this BitArrayWriter writer, DateTimeOffset dto, DateTime prevTime, string name, bool allowNonOrdered, bool isUtc, TimeSpan offset) { if (writer == null) { throw new ArgumentNullException("writer"); } if (isUtc && dto.Offset != offset) { throw new ArgumentException("Время {0} имеет неправильное смещение. Ожидается {1}.".Put(dto, offset)); } dto = dto.Truncate(); var time = isUtc ? dto.UtcDateTime : dto.LocalDateTime; var timeDiff = time - prevTime; if (allowNonOrdered) { if (timeDiff < TimeSpan.Zero) { writer.Write(false); timeDiff = new TimeSpan(-timeDiff.Ticks); } else { writer.Write(true); } if (timeDiff >= TimeSpan.FromMinutes(1)) { writer.Write(true); if (timeDiff <= TimeSpan.FromHours(32)) { writer.Write(true); writer.WriteBits(timeDiff.Hours, 5); } else { writer.Write(false); writer.WriteInt(timeDiff.Hours); } writer.WriteBits(timeDiff.Minutes, 6); writer.WriteBits(timeDiff.Seconds, 6); } else { writer.Write(false); writer.WriteInt(timeDiff.Seconds); } } else { if (timeDiff < TimeSpan.Zero) { throw new ArgumentException(LocalizedStrings.Str1009Params.Put(name, prevTime, time), "dto"); } if (timeDiff >= TimeSpan.FromMinutes(1)) { writer.Write(true); timeDiff = time.TimeOfDay; writer.WriteBits(timeDiff.Hours, 5); writer.WriteBits(timeDiff.Minutes, 6); writer.WriteBits(timeDiff.Seconds, 6); } else { writer.Write(false); writer.WriteInt(timeDiff.Seconds); } } writer.WriteInt(timeDiff.Milliseconds); return(time); }
protected override void OnSave(BitArrayWriter writer, IEnumerable <TCandleMessage> candles, CandleMetaInfo metaInfo) { if (metaInfo.IsEmpty()) { var firstCandle = candles.First(); var low = firstCandle.LowPrice; if ((low % metaInfo.PriceStep) == 0) { metaInfo.FirstPrice = metaInfo.LastPrice = low; } else { metaInfo.FirstFractionalPrice = metaInfo.LastFractionalPrice = low; } metaInfo.ServerOffset = firstCandle.OpenTime.Offset; metaInfo.FirstSeqNum = metaInfo.PrevSeqNum = firstCandle.SeqNum; } writer.WriteInt(candles.Count()); var allowNonOrdered = metaInfo.Version >= MarketDataVersions.Version49; var isUtc = metaInfo.Version >= MarketDataVersions.Version50; var allowDiffOffsets = metaInfo.Version >= MarketDataVersions.Version53; var useLevels = metaInfo.Version >= MarketDataVersions.Version54; var bigRange = metaInfo.Version >= MarketDataVersions.Version57; var isTickPrecision = bigRange; var useLong = metaInfo.Version >= MarketDataVersions.Version58; var buildFrom = metaInfo.Version >= MarketDataVersions.Version59; var seqNum = metaInfo.Version >= MarketDataVersions.Version60; foreach (var candle in candles) { if (candle.State == CandleStates.Active) { throw new ArgumentException(LocalizedStrings.CandleActiveNotSupport.Put(candle), nameof(candle)); } writer.WriteVolume(candle.TotalVolume, metaInfo, SecurityId); if (metaInfo.Version < MarketDataVersions.Version52) { writer.WriteVolume(candle.RelativeVolume ?? 0, metaInfo, SecurityId); } else { writer.Write(candle.RelativeVolume != null); if (candle.RelativeVolume != null) { writer.WriteVolume(candle.RelativeVolume.Value, metaInfo, SecurityId); } } if (metaInfo.Version < MarketDataVersions.Version56) { var prevPrice = metaInfo.LastPrice; writer.WritePrice(candle.LowPrice, ref prevPrice, metaInfo, SecurityId); metaInfo.LastPrice = prevPrice; prevPrice = metaInfo.LastPrice; writer.WritePrice(candle.OpenPrice, ref prevPrice, metaInfo, SecurityId); prevPrice = metaInfo.LastPrice; writer.WritePrice(candle.ClosePrice, ref prevPrice, metaInfo, SecurityId); prevPrice = metaInfo.LastPrice; writer.WritePrice(candle.HighPrice, ref prevPrice, metaInfo, SecurityId); } else { writer.WritePriceEx(candle.LowPrice, metaInfo, SecurityId, useLong); if (candle.OpenPrice <= candle.ClosePrice) { writer.Write(true); writer.WritePriceEx(candle.OpenPrice, metaInfo, SecurityId, useLong); writer.WritePriceEx(candle.ClosePrice, metaInfo, SecurityId, useLong); } else { writer.Write(false); writer.WritePriceEx(candle.ClosePrice, metaInfo, SecurityId, useLong); writer.WritePriceEx(candle.OpenPrice, metaInfo, SecurityId, useLong); } writer.WritePriceEx(candle.HighPrice, metaInfo, SecurityId, useLong); } if (!candle.CloseTime.IsDefault() && candle.OpenTime > candle.CloseTime) { throw new ArgumentException(LocalizedStrings.MoreThanCloseTime.Put(candle.OpenTime, candle.CloseTime)); } var lastOffset = metaInfo.LastServerOffset; metaInfo.LastTime = writer.WriteTime(candle.OpenTime, metaInfo.LastTime, LocalizedStrings.Str998, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, isTickPrecision, ref lastOffset); metaInfo.LastServerOffset = lastOffset; if (metaInfo.Version >= MarketDataVersions.Version46) { var isAll = !candle.HighTime.IsDefault() && !candle.LowTime.IsDefault(); DateTimeOffset first; DateTimeOffset second; writer.Write(isAll); if (isAll) { var isOrdered = candle.HighTime <= candle.LowTime; writer.Write(isOrdered); first = isOrdered ? candle.HighTime : candle.LowTime; second = isOrdered ? candle.LowTime : candle.HighTime; } else { writer.Write(!candle.HighTime.IsDefault()); writer.Write(!candle.LowTime.IsDefault()); first = candle.HighTime.IsDefault() ? candle.LowTime : candle.HighTime; second = default; } if (!first.IsDefault()) { if (first.Offset != lastOffset && !allowDiffOffsets) { throw new ArgumentException(LocalizedStrings.WrongTimeOffset.Put(first, lastOffset)); } if (!candle.CloseTime.IsDefault() && first > candle.CloseTime) { throw new ArgumentException(LocalizedStrings.MoreThanCloseTime.Put(first, candle.CloseTime)); } metaInfo.LastTime = writer.WriteTime(first, metaInfo.LastTime, LocalizedStrings.Str999, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, isTickPrecision, ref lastOffset, bigRange); } if (!second.IsDefault()) { if (second.Offset != lastOffset && !allowDiffOffsets) { throw new ArgumentException(LocalizedStrings.WrongTimeOffset.Put(second, lastOffset)); } if (!candle.CloseTime.IsDefault() && second > candle.CloseTime) { throw new ArgumentException(LocalizedStrings.MoreThanCloseTime.Put(second, candle.CloseTime)); } metaInfo.LastTime = writer.WriteTime(second, metaInfo.LastTime, LocalizedStrings.Str1000, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, isTickPrecision, ref lastOffset, bigRange); } } if (metaInfo.Version >= MarketDataVersions.Version47) { writer.Write(!candle.CloseTime.IsDefault()); if (!candle.CloseTime.IsDefault()) { if (candle.CloseTime.Offset != lastOffset && !allowDiffOffsets) { throw new ArgumentException(LocalizedStrings.WrongTimeOffset.Put(candle.CloseTime, lastOffset)); } metaInfo.LastTime = writer.WriteTime(candle.CloseTime, metaInfo.LastTime, LocalizedStrings.Str1001, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, isTickPrecision, ref lastOffset, bigRange); } } else { var time = writer.WriteTime(candle.CloseTime, metaInfo.LastTime, LocalizedStrings.Str1001, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, false, ref lastOffset); if (metaInfo.Version >= MarketDataVersions.Version41) { metaInfo.LastTime = time; } } if (metaInfo.Version >= MarketDataVersions.Version46) { if (metaInfo.Version < MarketDataVersions.Version51) { writer.WriteVolume(candle.OpenVolume ?? 0m, metaInfo, SecurityId); writer.WriteVolume(candle.HighVolume ?? 0m, metaInfo, SecurityId); writer.WriteVolume(candle.LowVolume ?? 0m, metaInfo, SecurityId); writer.WriteVolume(candle.CloseVolume ?? 0m, metaInfo, SecurityId); } else { if (candle.OpenVolume == null) { writer.Write(false); } else { writer.Write(true); writer.WriteVolume(candle.OpenVolume.Value, metaInfo, SecurityId); } if (candle.HighVolume == null) { writer.Write(false); } else { writer.Write(true); writer.WriteVolume(candle.HighVolume.Value, metaInfo, SecurityId); } if (candle.LowVolume == null) { writer.Write(false); } else { writer.Write(true); writer.WriteVolume(candle.LowVolume.Value, metaInfo, SecurityId); } if (candle.CloseVolume == null) { writer.Write(false); } else { writer.Write(true); writer.WriteVolume(candle.CloseVolume.Value, metaInfo, SecurityId); } } } writer.WriteInt((int)candle.State); if (metaInfo.Version < MarketDataVersions.Version45) { continue; } var oi = candle.OpenInterest; if (metaInfo.Version < MarketDataVersions.Version48) { writer.WriteVolume(oi ?? 0m, metaInfo, SecurityId); } else { writer.Write(oi != null); if (oi != null) { writer.WriteVolume(oi.Value, metaInfo, SecurityId); } } if (metaInfo.Version < MarketDataVersions.Version52) { continue; } writer.Write(candle.DownTicks != null); if (candle.DownTicks != null) { writer.WriteInt(candle.DownTicks.Value); } writer.Write(candle.UpTicks != null); if (candle.UpTicks != null) { writer.WriteInt(candle.UpTicks.Value); } writer.Write(candle.TotalTicks != null); if (candle.TotalTicks != null) { writer.WriteInt(candle.TotalTicks.Value); } if (!useLevels) { continue; } var priceLevels = candle.PriceLevels; writer.Write(priceLevels != null); if (priceLevels != null) { priceLevels = priceLevels.ToArray(); writer.WriteInt(priceLevels.Count()); foreach (var level in priceLevels) { if (metaInfo.Version < MarketDataVersions.Version56) { var prevPrice = metaInfo.LastPrice; writer.WritePrice(level.Price, ref prevPrice, metaInfo, SecurityId); metaInfo.LastPrice = prevPrice; } else { writer.WritePriceEx(level.Price, metaInfo, SecurityId); } writer.WriteInt(level.BuyCount); writer.WriteInt(level.SellCount); writer.WriteVolume(level.BuyVolume, metaInfo, SecurityId); writer.WriteVolume(level.SellVolume, metaInfo, SecurityId); if (metaInfo.Version >= MarketDataVersions.Version55) { writer.WriteVolume(level.TotalVolume, metaInfo, SecurityId); } var volumes = level.BuyVolumes; if (volumes == null) { writer.Write(false); } else { writer.Write(true); volumes = volumes.ToArray(); writer.WriteInt(volumes.Count()); foreach (var volume in volumes) { writer.WriteVolume(volume, metaInfo, SecurityId); } } volumes = level.SellVolumes; if (volumes == null) { writer.Write(false); } else { writer.Write(true); volumes = volumes.ToArray(); writer.WriteInt(volumes.Count()); foreach (var volume in volumes) { writer.WriteVolume(volume, metaInfo, SecurityId); } } } } if (!buildFrom) { continue; } writer.WriteBuildFrom(candle.BuildFrom); if (!seqNum) { continue; } writer.WriteSeqNum(candle, metaInfo); } }
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 <ExecutionMessage> messages, TickMetaInfo metaInfo) { if (metaInfo.IsEmpty()) { var first = messages.First(); metaInfo.FirstId = metaInfo.PrevId = first.TradeId ?? 0; 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; var isTickPrecision = metaInfo.Version >= MarketDataVersions.Version55; var useLong = metaInfo.Version >= MarketDataVersions.Version56; foreach (var msg in messages) { if (msg.ExecutionType != ExecutionTypes.Tick) { throw new ArgumentOutOfRangeException(nameof(messages), msg.ExecutionType, LocalizedStrings.Str1695Params.Put(msg)); } var tradeId = msg.TradeId ?? 0; // сделки для индексов имеют нулевой номер 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(nameof(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.TradeVolume; 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, useLong); writer.WriteSide(msg.OriginSide); var lastOffset = metaInfo.LastServerOffset; metaInfo.LastTime = writer.WriteTime(msg.ServerTime, metaInfo.LastTime, LocalizedStrings.Str985, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, isTickPrecision, ref lastOffset); metaInfo.LastServerOffset = lastOffset; if (metaInfo.Version < MarketDataVersions.Version40) { continue; } if (metaInfo.Version < MarketDataVersions.Version47) { writer.WriteLong((msg.LocalTime - msg.ServerTime).Ticks); } else { var hasLocalTime = true; if (metaInfo.Version >= MarketDataVersions.Version49) { hasLocalTime = msg.HasLocalTime(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, isTickPrecision, ref lastOffset, true); 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); } } }