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 <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); } } } } }