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 <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); } } }
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.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, 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 <TCandleMessage> candles, CandleMetaInfo metaInfo) { if (metaInfo.IsEmpty()) { var firstCandle = candles.First(); metaInfo.FirstPrice = firstCandle.LowPrice; metaInfo.LastPrice = firstCandle.LowPrice; metaInfo.ServerOffset = firstCandle.OpenTime.Offset; } writer.WriteInt(candles.Count()); var allowNonOrdered = metaInfo.Version >= MarketDataVersions.Version49; var isUtc = metaInfo.Version >= MarketDataVersions.Version50; var allowDiffOffsets = metaInfo.Version >= MarketDataVersions.Version53; foreach (var candle in candles) { 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) { writer.WritePrice(candle.LowPrice, metaInfo.LastPrice, metaInfo, SecurityId); metaInfo.LastPrice = candle.LowPrice; writer.WritePrice(candle.OpenPrice, metaInfo.LastPrice, metaInfo, SecurityId); writer.WritePrice(candle.ClosePrice, metaInfo.LastPrice, metaInfo, SecurityId); writer.WritePrice(candle.HighPrice, metaInfo.LastPrice, metaInfo, SecurityId); } else { writer.WritePriceEx(candle.LowPrice, metaInfo, SecurityId); if (candle.OpenPrice <= candle.ClosePrice) { writer.Write(true); writer.WritePriceEx(candle.OpenPrice, metaInfo, SecurityId); writer.WritePriceEx(candle.ClosePrice, metaInfo, SecurityId); } else { writer.Write(false); writer.WritePriceEx(candle.ClosePrice, metaInfo, SecurityId); writer.WritePriceEx(candle.OpenPrice, metaInfo, SecurityId); } writer.WritePriceEx(candle.HighPrice, metaInfo, SecurityId); } var lastOffset = metaInfo.LastServerOffset; metaInfo.LastTime = writer.WriteTime(candle.OpenTime, metaInfo.LastTime, LocalizedStrings.Str998, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, 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()); if (candle.HighTime.IsDefault()) { first = candle.LowTime; second = default(DateTimeOffset); } else { first = candle.HighTime; second = default(DateTimeOffset); } } if (!first.IsDefault()) { if (first.Offset != lastOffset) { throw new ArgumentException(LocalizedStrings.WrongTimeOffset.Put(first, lastOffset)); } metaInfo.LastTime = writer.WriteTime(first, metaInfo.LastTime, LocalizedStrings.Str999, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, ref lastOffset); } if (!second.IsDefault()) { if (second.Offset != lastOffset) { throw new ArgumentException(LocalizedStrings.WrongTimeOffset.Put(second, lastOffset)); } metaInfo.LastTime = writer.WriteTime(second, metaInfo.LastTime, LocalizedStrings.Str1000, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, ref lastOffset); } } if (metaInfo.Version >= MarketDataVersions.Version47) { writer.Write(!candle.CloseTime.IsDefault()); if (!candle.CloseTime.IsDefault()) { if (candle.CloseTime.Offset != lastOffset) { throw new ArgumentException(LocalizedStrings.WrongTimeOffset.Put(candle.CloseTime, lastOffset)); } metaInfo.LastTime = writer.WriteTime(candle.CloseTime, metaInfo.LastTime, LocalizedStrings.Str1001, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, ref lastOffset); } } else { var time = writer.WriteTime(candle.CloseTime, metaInfo.LastTime, LocalizedStrings.Str1001, allowNonOrdered, isUtc, metaInfo.ServerOffset, allowDiffOffsets, 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 (metaInfo.Version < MarketDataVersions.Version54) { continue; } var priceLevels = candle.PriceLevels; writer.Write(priceLevels != null); if (priceLevels == null) { continue; } priceLevels = priceLevels.ToArray(); writer.WriteInt(priceLevels.Count()); foreach (var level in priceLevels) { if (metaInfo.Version < MarketDataVersions.Version56) { writer.WritePrice(level.Price, metaInfo.LastPrice, metaInfo, SecurityId); } 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); } } } } }
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 <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); } }