public static void WritePrice <T>(this BitArrayWriter writer, decimal price, decimal prevPrice, MetaInfo <T> info, SecurityId securityId, bool useLong = false) where T : MetaInfo <T> { if ((price % info.PriceStep) != 0) { throw new ArgumentException(LocalizedStrings.Str1007Params.Put(info.PriceStep, securityId, price), "info"); } try { var stepCount = (long)((price - prevPrice) / info.PriceStep); // ОЛ может содержать заявки с произвольно большими ценами if (useLong) { writer.WriteLong(stepCount); } else { writer.WriteInt((int)stepCount); } } catch (OverflowException ex) { throw new ArgumentException(LocalizedStrings.Str1008Params.Put(price, prevPrice, info.PriceStep, useLong), ex); } }
public static void WritePrice(this BitArrayWriter writer, decimal price, decimal prevPrice, MetaInfo info, SecurityId securityId, bool useLong = false) { var priceStep = info.PriceStep; if (priceStep == 0) { throw new InvalidOperationException(LocalizedStrings.Str2925); } if ((price % priceStep) != 0) { throw new ArgumentException(LocalizedStrings.Str1007Params.Put(priceStep, securityId, price), nameof(info)); } try { var stepCount = (long)((price - prevPrice) / priceStep); // ОЛ может содержать заявки с произвольно большими ценами if (useLong) { writer.WriteLong(stepCount); } else { writer.WriteInt((int)stepCount); } } catch (OverflowException ex) { throw new ArgumentException(LocalizedStrings.Str1008Params.Put(price, prevPrice, priceStep, useLong), ex); } }
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); } } }
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 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); } }
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 <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); if (metaInfo.Version < MarketDataVersions.Version50) { continue; } writer.Write(news.ExpiryDate != null); if (news.ExpiryDate != null) { writer.WriteLong(news.ExpiryDate.Value.To <long>()); } writer.WriteStringEx(news.SecurityId?.BoardCode); } }
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); } } }
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); } } }
protected override void OnSave(BitArrayWriter writer, IEnumerable <ExecutionMessage> items, OrderLogMetaInfo metaInfo) { if (metaInfo.IsEmpty() && !items.IsEmpty()) { var item = items.First(); metaInfo.FirstOrderId = metaInfo.LastOrderId = item.OrderId; metaInfo.FirstTransactionId = metaInfo.LastTransactionId = item.TransactionId; metaInfo.ServerOffset = item.ServerTime.Offset; } writer.WriteInt(items.Count()); var allowNonOrdered = metaInfo.Version >= MarketDataVersions.Version47; var isUtc = metaInfo.Version >= MarketDataVersions.Version48; foreach (var item in items) { var hasTrade = item.TradeId != 0 || item.TradePrice != 0; if (item.OrderId <= 0) { throw new ArgumentOutOfRangeException("items", item.OrderId, LocalizedStrings.Str925); } // 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("items", item.Price, LocalizedStrings.Str926Params.Put(item.OrderId)); if (item.Volume <= 0) { throw new ArgumentOutOfRangeException("items", item.Volume, LocalizedStrings.Str927Params.Put(item.OrderId)); } if (hasTrade) { if (item.TradeId <= 0) { throw new ArgumentOutOfRangeException("items", item.TradeId, LocalizedStrings.Str1012Params.Put(item.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("items", item.TradePrice, LocalizedStrings.Str929Params.Put(item.TradeId, item.OrderId)); } metaInfo.LastOrderId = writer.SerializeId(item.OrderId, metaInfo.LastOrderId); var orderPrice = item.Price; 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.FirstNonSystemPrice == 0) { metaInfo.FirstNonSystemPrice = metaInfo.LastNonSystemPrice = orderPrice; } metaInfo.LastNonSystemPrice = writer.WriteDecimal(orderPrice, metaInfo.LastNonSystemPrice); } } writer.WriteVolume(item.Volume, metaInfo, SecurityId); writer.Write(item.Side == Sides.Buy); metaInfo.LastTime = writer.WriteTime(item.ServerTime, metaInfo.LastTime, LocalizedStrings.Str1013, allowNonOrdered, isUtc, metaInfo.ServerOffset); if (hasTrade) { writer.Write(true); if (metaInfo.FirstTradeId == 0) { metaInfo.FirstTradeId = metaInfo.LastTradeId = item.TradeId; } metaInfo.LastTradeId = writer.SerializeId(item.TradeId, metaInfo.LastTradeId); writer.WritePriceEx(item.TradePrice, metaInfo, SecurityId); } else { writer.Write(false); writer.Write(item.OrderState == OrderStates.Active); } if (metaInfo.Version < MarketDataVersions.Version31) { continue; } var status = item.OrderStatus; if (status == null) { writer.Write(false); } else { writer.Write(true); writer.WriteInt((int)status); } if (metaInfo.Version < MarketDataVersions.Version33) { continue; } writer.WriteInt((int)item.TimeInForce); writer.Write(item.IsSystem); if (metaInfo.Version < MarketDataVersions.Version34) { continue; } metaInfo.LastTransactionId = writer.SerializeId(item.TransactionId, metaInfo.LastTransactionId); if (metaInfo.Version < MarketDataVersions.Version40) { continue; } if (metaInfo.Version < MarketDataVersions.Version46) { writer.WriteLong(0 /*item.Latency.Ticks*/); } var portfolio = item.PortfolioName; var isEmptyPf = portfolio == null || portfolio == Portfolio.AnonymousPortfolio.Name; writer.Write(!isEmptyPf); if (isEmptyPf) { continue; } metaInfo.Portfolios.TryAdd(item.PortfolioName); writer.WriteInt(metaInfo.Portfolios.IndexOf(item.PortfolioName)); } }
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); } } }
protected override void OnSave(BitArrayWriter writer, IEnumerable <ExecutionMessage> messages, TradeMetaInfo metaInfo) { if (metaInfo.IsEmpty()) { var first = messages.First(); metaInfo.FirstId = metaInfo.PrevId = first.TradeId; metaInfo.ServerOffset = first.ServerTime.Offset; } writer.WriteInt(messages.Count()); var allowNonOrdered = metaInfo.Version >= MarketDataVersions.Version48; var isUtc = metaInfo.Version >= MarketDataVersions.Version50; foreach (var msg in messages) { if (msg.ExecutionType != ExecutionTypes.Tick) { throw new ArgumentOutOfRangeException("messages", msg.ExecutionType, LocalizedStrings.Str1019Params.Put(msg.TradeId)); } // сделки для индексов имеют нулевой номер if (msg.TradeId < 0) { throw new ArgumentOutOfRangeException("messages", msg.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)); // pyhta4og. // http://stocksharp.com/forum/yaf_postsm6450_Oshibka-pri-importie-instrumientov-s-Finama.aspx#post6450 if (msg.Volume < 0) { throw new ArgumentOutOfRangeException("messages", msg.Volume, LocalizedStrings.Str1022Params.Put(msg.TradeId)); } metaInfo.PrevId = writer.SerializeId(msg.TradeId, metaInfo.PrevId); writer.WriteVolume(msg.Volume, metaInfo, SecurityId); writer.WritePriceEx(msg.TradePrice, metaInfo, SecurityId); writer.WriteSide(msg.OriginSide); metaInfo.LastTime = writer.WriteTime(msg.ServerTime, metaInfo.LastTime, LocalizedStrings.Str1023, allowNonOrdered, isUtc, metaInfo.ServerOffset); 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) { metaInfo.LastLocalTime = writer.WriteTime(msg.LocalTime, metaInfo.LastLocalTime, LocalizedStrings.Str1024, allowNonOrdered, isUtc, metaInfo.LocalOffset); } } if (metaInfo.Version < MarketDataVersions.Version42) { continue; } writer.Write(msg.IsSystem); if (!msg.IsSystem) { writer.WriteInt(msg.TradeStatus); } 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); } } }
protected override void OnSave(BitArrayWriter writer, IEnumerable <QuoteChangeMessage> messages, QuoteMetaInfo metaInfo) { if (metaInfo.IsEmpty()) { var firstDepth = messages.First(); //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.ServerTime.Offset; metaInfo.IncrementalOnly = firstDepth.State != null; metaInfo.FirstSeqNum = metaInfo.PrevSeqNum = firstDepth.SeqNum; } 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; var buildFrom = metaInfo.Version >= MarketDataVersions.Version59; var seqNumAndPos = metaInfo.Version >= MarketDataVersions.Version60; foreach (var m in messages) { var quoteMsg = m; if (metaInfo.IncrementalOnly) { if (quoteMsg.State == null) { throw new InvalidOperationException(LocalizedStrings.StorageRequiredIncremental.Put(true)); } } else { if (quoteMsg.State != null) { throw new InvalidOperationException(LocalizedStrings.StorageRequiredIncremental.Put(false)); } } //if (m.IsFullEmpty()) // throw new ArgumentException(LocalizedStrings.Str1309, nameof(messages)); //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; QuoteChangeMessage delta; if (metaInfo.IncrementalOnly) { writer.WriteInt((int)quoteMsg.State.Value); delta = quoteMsg; } else { var isFull = prevQuoteMsg == null; writer.Write(isFull); 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); } if (!buildFrom) { continue; } writer.WriteBuildFrom(quoteMsg.BuildFrom); if (!seqNumAndPos) { continue; } writer.WriteSeqNum(quoteMsg, metaInfo); writer.Write(quoteMsg.HasPositions); } }
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 <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 long SerializeId(this BitArrayWriter writer, long id, long prevId) { writer.WriteLong(id - prevId); return(id); }
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); } }
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 <ExecutionMessage> messages, OrderLogMetaInfo metaInfo) { if (metaInfo.IsEmpty() && !messages.IsEmpty()) { var item = messages.First(); metaInfo.FirstOrderId = metaInfo.LastOrderId = item.OrderId ?? default; metaInfo.FirstTransactionId = metaInfo.LastTransactionId = item.TransactionId; metaInfo.ServerOffset = item.ServerTime.Offset; metaInfo.FirstSeqNum = metaInfo.PrevSeqNum = item.SeqNum; } 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; var useBalance = metaInfo.Version >= MarketDataVersions.Version54; var buildFrom = metaInfo.Version >= MarketDataVersions.Version55; var seqNum = metaInfo.Version >= MarketDataVersions.Version56; var useLong = metaInfo.Version >= MarketDataVersions.Version57; var largeDecimal = metaInfo.Version >= MarketDataVersions.Version57; var stringId = metaInfo.Version >= MarketDataVersions.Version58; foreach (var message in messages) { var hasTrade = message.TradeId != null || message.TradePrice != null || !message.TradeStringId.IsEmpty(); var orderId = message.OrderId; if (orderId is null) { if (!stringId) { throw new ArgumentOutOfRangeException(nameof(messages), message.TransactionId, LocalizedStrings.Str925); } } if (message.DataType != DataType.OrderLog) { throw new ArgumentOutOfRangeException(nameof(messages), message.DataType, LocalizedStrings.Str1695Params.Put(message)); } // 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 && message.OrderState != OrderStates.Done) { throw new ArgumentOutOfRangeException(nameof(messages), volume, LocalizedStrings.Str927Params.Put(message.TransactionId)); } long?tradeId = null; if (hasTrade) { tradeId = message.TradeId; if (tradeId is null or <= 0) { if (!stringId) { throw new ArgumentOutOfRangeException(nameof(messages), tradeId, LocalizedStrings.Str1012Params.Put(message.TransactionId)); } } // 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 ?? 0, metaInfo.LastOrderId); var orderPrice = message.OrderPrice; if (metaInfo.Version < MarketDataVersions.Version45) { writer.WritePriceEx(orderPrice, metaInfo, SecurityId, false, false); } else { var isAligned = (orderPrice % metaInfo.LastPriceStep) == 0; writer.Write(isAligned); if (isAligned) { if (metaInfo.FirstOrderPrice == 0) { metaInfo.FirstOrderPrice = metaInfo.LastOrderPrice = orderPrice; } var prevPrice = metaInfo.LastOrderPrice; writer.WritePrice(orderPrice, ref prevPrice, metaInfo, SecurityId, true); metaInfo.LastOrderPrice = prevPrice; } else { if (metaInfo.FirstFractionalPrice == 0) { metaInfo.FirstFractionalPrice = metaInfo.LastFractionalPrice = orderPrice; } metaInfo.LastFractionalPrice = writer.WriteDecimal(orderPrice, metaInfo.LastFractionalPrice); } } writer.WriteVolume(volume, metaInfo, largeDecimal); 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 ?? default; } metaInfo.LastTradeId = writer.SerializeId(tradeId ?? default, metaInfo.LastTradeId); writer.WritePriceEx(message.GetTradePrice(), metaInfo, SecurityId, useLong, largeDecimal); if (metaInfo.Version >= MarketDataVersions.Version54) { writer.WriteInt((int)message.OrderState); } } else { writer.Write(false); if (metaInfo.Version >= MarketDataVersions.Version54) { writer.WriteInt((int)message.OrderState); } else { writer.Write(message.OrderState == OrderStates.Active); } } if (metaInfo.Version < MarketDataVersions.Version31) { continue; } writer.WriteNullableInt((int?)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; var isAnonymous = !isEmptyPf && portfolio == Portfolio.AnonymousPortfolio.Name; if (isEmptyPf) { writer.Write(false); } else { if (isAnonymous) { if (metaInfo.Version < MarketDataVersions.Version54) { writer.Write(false); } else { writer.Write(true); writer.Write(true); // is anonymous } } else { writer.Write(true); if (metaInfo.Version > MarketDataVersions.Version54) { writer.Write(false); // not anonymous } metaInfo.Portfolios.TryAdd(message.PortfolioName); writer.WriteInt(metaInfo.Portfolios.IndexOf(message.PortfolioName)); } } if (metaInfo.Version < MarketDataVersions.Version51) { continue; } writer.WriteNullableInt((int?)message.Currency); if (!useBalance) { continue; } if (message.Balance == null) { writer.Write(false); } else { writer.Write(true); if (message.Balance.Value == 0) { writer.Write(false); } else { writer.Write(true); writer.WriteDecimal(message.Balance.Value, 0); } } if (!buildFrom) { continue; } writer.WriteBuildFrom(message.BuildFrom); if (!seqNum) { continue; } writer.WriteSeqNum(message, metaInfo); if (!stringId) { continue; } writer.Write(orderId is null); writer.WriteStringEx(message.OrderStringId); writer.Write(tradeId is null); writer.WriteStringEx(message.TradeStringId); if (message.OrderBuyId != null) { writer.Write(true); metaInfo.LastOrderId = writer.SerializeId(message.OrderBuyId.Value, metaInfo.LastOrderId); } else { writer.Write(false); } if (message.OrderSellId != null) { writer.Write(true); metaInfo.LastOrderId = writer.SerializeId(message.OrderSellId.Value, metaInfo.LastOrderId); } else { writer.Write(false); } writer.WriteNullableBool(message.IsUpTick); writer.WriteNullableDecimal(message.Yield); writer.WriteNullableInt(message.TradeStatus); writer.WriteNullableDecimal(message.OpenInterest); writer.WriteNullableInt((int?)message.OriginSide); } }