/// <summary> /// Enumerates the subscriptions into slices /// </summary> private IEnumerable <Slice> CreateSliceEnumerableFromSubscriptions(List <Subscription> subscriptions, DateTimeZone sliceTimeZone) { // required by TimeSlice.Create, but we don't need it's behavior var cashBook = new CashBook(); cashBook.Clear(); var frontier = DateTime.MinValue; while (true) { var earlyBirdTicks = long.MaxValue; var data = new List <DataFeedPacket>(); foreach (var subscription in subscriptions) { if (subscription.EndOfStream) { continue; } var packet = new DataFeedPacket(subscription.Security, subscription.Configuration); var offsetProvider = subscription.OffsetProvider; var currentOffsetTicks = offsetProvider.GetOffsetTicks(frontier); while (subscription.Current.EndTime.Ticks - currentOffsetTicks <= frontier.Ticks) { // we want bars rounded using their subscription times, we make a clone // so we don't interfere with the enumerator's internal logic var clone = subscription.Current.Clone(subscription.Current.IsFillForward); clone.Time = clone.Time.RoundDown(subscription.Configuration.Increment); packet.Add(clone); Interlocked.Increment(ref _dataPointCount); if (!subscription.MoveNext()) { break; } } // only add if we have data if (packet.Count != 0) { data.Add(packet); } // udate our early bird ticks (next frontier time) if (subscription.Current != null) { // take the earliest between the next piece of data or the next tz discontinuity var nextDataOrDiscontinuity = Math.Min(subscription.Current.EndTime.Ticks - currentOffsetTicks, offsetProvider.GetNextDiscontinuity()); earlyBirdTicks = Math.Min(earlyBirdTicks, nextDataOrDiscontinuity); } } // end of subscriptions if (earlyBirdTicks == long.MaxValue) { break; } if (data.Count != 0) { // reuse the slice construction code from TimeSlice.Create yield return(TimeSlice.Create(frontier, sliceTimeZone, cashBook, data, SecurityChanges.None).Slice); } frontier = new DateTime(Math.Max(earlyBirdTicks, frontier.Ticks), DateTimeKind.Utc); } // make sure we clean up after ourselves foreach (var subscription in subscriptions) { subscription.Dispose(); } }
/// <summary> /// Enumerates the subscriptions into slices /// </summary> protected IEnumerable <Slice> CreateSliceEnumerableFromSubscriptions(List <Subscription> subscriptions, DateTimeZone sliceTimeZone) { // required by TimeSlice.Create, but we don't need it's behavior var frontier = DateTime.MinValue; var timeSliceFactory = new TimeSliceFactory(sliceTimeZone); while (true) { var earlyBirdTicks = long.MaxValue; var data = new List <DataFeedPacket>(); foreach (var subscription in subscriptions.Where(subscription => !subscription.EndOfStream)) { if (subscription.Current == null && !subscription.MoveNext()) { // initial pump. We do it here and not when creating the subscriptions so // that parallel workers can all start as fast as possible continue; } var packet = new DataFeedPacket(subscription.Security, subscription.Configuration); while (subscription.Current.EmitTimeUtc <= frontier) { packet.Add(subscription.Current.Data); Interlocked.Increment(ref _dataPointCount); if (!subscription.MoveNext()) { break; } } // only add if we have data if (packet.Count != 0) { data.Add(packet); } // update our early bird ticks (next frontier time) if (subscription.Current != null) { // take the earliest between the next piece of data or the next tz discontinuity earlyBirdTicks = Math.Min(earlyBirdTicks, subscription.Current.EmitTimeUtc.Ticks); } } if (data.Count != 0) { // reuse the slice construction code from TimeSlice.Create yield return(timeSliceFactory.Create(frontier, data, SecurityChanges.None, new Dictionary <Universe, BaseDataCollection>()).Slice); } // end of subscriptions, after we emit, else we might drop a data point if (earlyBirdTicks == long.MaxValue) { break; } frontier = new DateTime(Math.Max(earlyBirdTicks, frontier.Ticks), DateTimeKind.Utc); } // make sure we clean up after ourselves foreach (var subscription in subscriptions) { subscription.Dispose(); } }
/// <summary> /// Enumerates the subscriptions into slices /// </summary> protected IEnumerable <Slice> CreateSliceEnumerableFromSubscriptions(List <Subscription> subscriptions, DateTimeZone sliceTimeZone) { // required by TimeSlice.Create, but we don't need it's behavior var cashBook = new CashBook(); cashBook.Clear(); var frontier = DateTime.MinValue; while (true) { var earlyBirdTicks = long.MaxValue; var data = new List <DataFeedPacket>(); foreach (var subscription in subscriptions) { if (subscription.EndOfStream) { continue; } var packet = new DataFeedPacket(subscription.Security, subscription.Configuration); while (subscription.Current.EmitTimeUtc <= frontier) { packet.Add(subscription.Current.Data); Interlocked.Increment(ref _dataPointCount); if (!subscription.MoveNext()) { break; } } // only add if we have data if (packet.Count != 0) { data.Add(packet); } // udate our early bird ticks (next frontier time) if (subscription.Current != null) { // take the earliest between the next piece of data or the next tz discontinuity earlyBirdTicks = Math.Min(earlyBirdTicks, subscription.Current.EmitTimeUtc.Ticks); } } // end of subscriptions if (earlyBirdTicks == long.MaxValue) { break; } if (data.Count != 0) { // reuse the slice construction code from TimeSlice.Create yield return(TimeSlice.Create(frontier, sliceTimeZone, cashBook, data, SecurityChanges.None, new Dictionary <Universe, BaseDataCollection>()).Slice); } frontier = new DateTime(Math.Max(earlyBirdTicks, frontier.Ticks), DateTimeKind.Utc); } // make sure we clean up after ourselves foreach (var subscription in subscriptions) { subscription.Dispose(); } }