/// <summary> /// Returns an enumerable which provides the data to stream to the algorithm /// </summary> public virtual IEnumerable <TimeSlice> StreamData(CancellationToken cancellationToken) { PostInitialize(); // GetTimeProvider() will call GetInitialFrontierTime() which // will consume added subscriptions so we need to do this after initialization TimeProvider = GetTimeProvider(); SubscriptionSynchronizer.SetTimeProvider(TimeProvider); var previousEmitTime = DateTime.MaxValue; var enumerator = SubscriptionSynchronizer .Sync(SubscriptionManager.DataFeedSubscriptions, cancellationToken) .GetEnumerator(); var previousWasTimePulse = false; while (!cancellationToken.IsCancellationRequested) { TimeSlice timeSlice; try { if (!enumerator.MoveNext()) { // the enumerator ended break; } timeSlice = enumerator.Current; } catch (Exception err) { Log.Error(err); // notify the algorithm about the error, so it can be reported to the user Algorithm.RunTimeError = err; Algorithm.Status = AlgorithmStatus.RuntimeError; break; } // check for cancellation if (timeSlice == null || cancellationToken.IsCancellationRequested) { break; } // SubscriptionFrontierTimeProvider will return twice the same time if there are no more subscriptions or if Subscription.Current is null if (timeSlice.Time != previousEmitTime || previousWasTimePulse) { previousEmitTime = timeSlice.Time; previousWasTimePulse = timeSlice.IsTimePulse; yield return(timeSlice); } else if (timeSlice.SecurityChanges == SecurityChanges.None) { // there's no more data to pull off, we're done (frontier is max value and no security changes) break; } } enumerator.DisposeSafely(); Log.Trace("Synchronizer.GetEnumerator(): Exited thread."); }
/// <summary> /// Initializes the instance of the Synchronizer class /// </summary> public override void Initialize( IAlgorithm algorithm, IDataFeedSubscriptionManager dataFeedSubscriptionManager) { base.Initialize(algorithm, dataFeedSubscriptionManager); // the time provider, is the real time provider _timeProvider = GetTimeProvider(); _frontierTimeProvider = new LiveTimeProvider(realTime: TimeProvider); // the synchronizer will use our '_frontierTimeProvider' which initially during warmup will be using // the base time provider which is the subscription based time provider (like backtesting) // once wawrmup finishes it will start using the realtime provider SubscriptionSynchronizer.SetTimeProvider(_frontierTimeProvider); // attach event handlers to subscriptions dataFeedSubscriptionManager.SubscriptionAdded += (sender, subscription) => { subscription.NewDataAvailable += OnSubscriptionNewDataAvailable; }; dataFeedSubscriptionManager.SubscriptionRemoved += (sender, subscription) => { subscription.NewDataAvailable -= OnSubscriptionNewDataAvailable; }; _realTimeScheduleEventService = new RealTimeScheduleEventService(new RealTimeProvider()); // this schedule event will be our time pulse _realTimeScheduleEventService.NewEvent += (sender, args) => _newLiveDataEmitted.Set(); }
/// <summary> /// Initializes the instance of the Synchronizer class /// </summary> public void Initialize( IAlgorithm algorithm, IDataFeedSubscriptionManager dataFeedSubscriptionManager, bool liveMode) { _subscriptionManager = dataFeedSubscriptionManager; _algorithm = algorithm; _liveMode = liveMode; _subscriptionSynchronizer = new SubscriptionSynchronizer( _subscriptionManager.UniverseSelection); if (_liveMode) { TimeProvider = GetTimeProvider(); _subscriptionSynchronizer.SetTimeProvider(TimeProvider); } }
/// <summary> /// Initializes the instance of the Synchronizer class /// </summary> public override void Initialize( IAlgorithm algorithm, IDataFeedSubscriptionManager dataFeedSubscriptionManager) { base.Initialize(algorithm, dataFeedSubscriptionManager); TimeProvider = GetTimeProvider(); SubscriptionSynchronizer.SetTimeProvider(TimeProvider); // attach event handlers to subscriptions dataFeedSubscriptionManager.SubscriptionAdded += (sender, subscription) => { subscription.NewDataAvailable += OnSubscriptionNewDataAvailable; }; dataFeedSubscriptionManager.SubscriptionRemoved += (sender, subscription) => { subscription.NewDataAvailable -= OnSubscriptionNewDataAvailable; }; }
/// <summary> /// Initializes the instance of the Synchronizer class /// </summary> public void Initialize( IAlgorithm algorithm, IDataFeedSubscriptionManager subscriptionManager, IDataFeed dataFeed, // To be removed, when subscriptionManager is completely in front of the DF bool liveMode, CashBook cashBook) { _subscriptionManager = subscriptionManager; _algorithm = algorithm; _cashBook = cashBook; _liveMode = liveMode; _dataFeed = dataFeed; _subscriptionSynchronizer = new SubscriptionSynchronizer(_subscriptionManager.UniverseSelection, _cashBook); if (_liveMode) { TimeProvider = GetTimeProvider(); _subscriptionSynchronizer.SetTimeProvider(TimeProvider); } }
private void PostInitialize() { _subscriptionSynchronizer.SubscriptionFinished += (sender, subscription) => { _dataFeed.RemoveSubscription(subscription.Configuration); Log.Debug("Synchronizer.SubscriptionFinished(): Finished subscription:" + $"{subscription.Configuration} at {FrontierTimeProvider.GetUtcNow()} UTC"); }; // this is set after the algorithm initializes _dateTimeZone = _algorithm.TimeZone; _subscriptionSynchronizer.SetSliceTimeZone(_dateTimeZone); if (!_liveMode) { // GetTimeProvider() will call GetInitialFrontierTime() which // will consume added subscriptions so we need to do this after initialization TimeProvider = GetTimeProvider(); _subscriptionSynchronizer.SetTimeProvider(TimeProvider); } }
/// <summary> /// Initializes the instance of the Synchronizer class /// </summary> public override void Initialize( IAlgorithm algorithm, IDataFeedSubscriptionManager dataFeedSubscriptionManager) { base.Initialize(algorithm, dataFeedSubscriptionManager); _timeProvider = GetTimeProvider(); SubscriptionSynchronizer.SetTimeProvider(TimeProvider); // attach event handlers to subscriptions dataFeedSubscriptionManager.SubscriptionAdded += (sender, subscription) => { subscription.NewDataAvailable += OnSubscriptionNewDataAvailable; }; dataFeedSubscriptionManager.SubscriptionRemoved += (sender, subscription) => { subscription.NewDataAvailable -= OnSubscriptionNewDataAvailable; }; _realTimeScheduleEventService = new RealTimeScheduleEventService(new RealTimeProvider()); // this schedule event will be our time pulse _realTimeScheduleEventService.NewEvent += (sender, args) => _newLiveDataEmitted.Set(); }
/// <summary> /// Returns an enumerable which provides the data to stream to the algorithm /// </summary> public virtual IEnumerable <TimeSlice> StreamData(CancellationToken cancellationToken) { PostInitialize(); // GetTimeProvider() will call GetInitialFrontierTime() which // will consume added subscriptions so we need to do this after initialization TimeProvider = GetTimeProvider(); SubscriptionSynchronizer.SetTimeProvider(TimeProvider); var previousEmitTime = DateTime.MaxValue; var enumerator = SubscriptionSynchronizer .Sync(SubscriptionManager.DataFeedSubscriptions, cancellationToken) .GetEnumerator(); var previousWasTimePulse = false; // this is a just in case flag to stop looping if time does not advance var retried = false; while (!cancellationToken.IsCancellationRequested) { TimeSlice timeSlice; try { if (!enumerator.MoveNext()) { // the enumerator ended break; } timeSlice = enumerator.Current; } catch (Exception err) { Log.Error(err); // notify the algorithm about the error, so it can be reported to the user Algorithm.RunTimeError = err; Algorithm.Status = AlgorithmStatus.RuntimeError; break; } // check for cancellation if (timeSlice == null || cancellationToken.IsCancellationRequested) { break; } // SubscriptionFrontierTimeProvider will return twice the same time if there are no more subscriptions or if Subscription.Current is null if (timeSlice.Time != previousEmitTime || previousWasTimePulse) { previousEmitTime = timeSlice.Time; previousWasTimePulse = timeSlice.IsTimePulse; // if we emitted, clear retry flag retried = false; yield return(timeSlice); } else if (timeSlice.SecurityChanges == SecurityChanges.None) { // if the slice has data lets retry just once more... this could happen // with subscriptions added after initialize using algorithm.AddSecurity() API, // where the subscription start time is the current time loop (but should just happen once) if (!timeSlice.Slice.HasData || retried) { // there's no more data to pull off, we're done (frontier is max value and no security changes) break; } retried = true; } } enumerator.DisposeSafely(); Log.Trace("Synchronizer.GetEnumerator(): Exited thread."); }