/// <summary>
 /// Sets the <see cref="TimeSliceFactory"/> instance to use
 /// </summary>
 /// <param name="timeSliceFactory">Used to create the new <see cref="TimeSlice"/></param>
 public void SetTimeSliceFactory(TimeSliceFactory timeSliceFactory)
 {
     if (_timeSliceFactory != null)
     {
         throw new Exception("SubscriptionSynchronizer.SetTimeSliceFactory(): can only be called once");
     }
     _timeSliceFactory = timeSliceFactory;
 }
Exemplo n.º 2
0
        /// <summary>
        /// Performs additional initialization steps after algorithm initialization
        /// </summary>
        protected virtual void PostInitialize()
        {
            SubscriptionSynchronizer.SubscriptionFinished += (sender, subscription) =>
            {
                SubscriptionManager.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;
            TimeSliceFactory = new TimeSliceFactory(_dateTimeZone);
            SubscriptionSynchronizer.SetTimeSliceFactory(TimeSliceFactory);
        }
Exemplo n.º 3
0
        private void PostInitialize()
        {
            _subscriptionSynchronizer.SubscriptionFinished += (sender, subscription) =>
            {
                _subscriptionManager.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;
            _timeSliceFactory = new TimeSliceFactory(_dateTimeZone);
            _subscriptionSynchronizer.SetTimeSliceFactory(_timeSliceFactory);

            if (!_liveMode)
            {
                // GetTimeProvider() will call GetInitialFrontierTime() which
                // will consume added subscriptions so we need to do this after initialization
                TimeProvider = GetTimeProvider();
                _subscriptionSynchronizer.SetTimeProvider(TimeProvider);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Returns an enumerable which provides the data to stream to the algorithm
        /// </summary>
        public override IEnumerable <TimeSlice> StreamData(CancellationToken cancellationToken)
        {
            PostInitialize();

            var shouldSendExtraEmptyPacket = false;
            var nextEmit      = DateTime.MinValue;
            var lastLoopStart = DateTime.UtcNow;

            var enumerator = SubscriptionSynchronizer
                             .Sync(SubscriptionManager.DataFeedSubscriptions, cancellationToken)
                             .GetEnumerator();

            var previousWasTimePulse = false;

            while (!cancellationToken.IsCancellationRequested)
            {
                var now = DateTime.UtcNow;
                if (!previousWasTimePulse)
                {
                    if (!_newLiveDataEmitted.IsSet)
                    {
                        // if we just crossed into the next second let's loop again, we will flush any consolidator bar
                        // else we will wait to be notified by the subscriptions or our scheduled event service every second
                        if (lastLoopStart.Second == now.Second)
                        {
                            _realTimeScheduleEventService.ScheduleEvent(TimeSpan.FromMilliseconds(GetPulseDueTime(now)), now);
                            _newLiveDataEmitted.Wait();
                        }
                    }
                    _newLiveDataEmitted.Reset();
                }

                lastLoopStart = now;

                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;
                    shouldSendExtraEmptyPacket = true;
                    break;
                }

                // check for cancellation
                if (timeSlice == null || cancellationToken.IsCancellationRequested)
                {
                    break;
                }

                var frontierUtc = FrontierTimeProvider.GetUtcNow();
                // emit on data or if we've elapsed a full second since last emit or there are security changes
                if (timeSlice.SecurityChanges != SecurityChanges.None ||
                    timeSlice.IsTimePulse ||
                    timeSlice.Data.Count != 0 ||
                    frontierUtc >= nextEmit)
                {
                    previousWasTimePulse = timeSlice.IsTimePulse;
                    yield return(timeSlice);

                    // force emitting every second since the data feed is
                    // the heartbeat of the application
                    nextEmit = frontierUtc.RoundDown(Time.OneSecond).Add(Time.OneSecond);
                }
            }

            if (shouldSendExtraEmptyPacket)
            {
                // send last empty packet list before terminating,
                // so the algorithm manager has a chance to detect the runtime error
                // and exit showing the correct error instead of a timeout
                nextEmit = FrontierTimeProvider.GetUtcNow().RoundDown(Time.OneSecond);
                if (!cancellationToken.IsCancellationRequested)
                {
                    var timeSlice = TimeSliceFactory.Create(
                        nextEmit,
                        new List <DataFeedPacket>(),
                        SecurityChanges.None,
                        new Dictionary <Universe, BaseDataCollection>());
                    yield return(timeSlice);
                }
            }

            enumerator.DisposeSafely();
            Log.Trace("LiveSynchronizer.GetEnumerator(): Exited thread.");
        }
Exemplo n.º 5
0
        /// <summary>
        /// Returns an enumerable which provides the data to stream to the algorithm
        /// </summary>
        public override IEnumerable <TimeSlice> StreamData(CancellationToken cancellationToken)
        {
            PostInitialize();

            var shouldSendExtraEmptyPacket = false;
            var nextEmit = DateTime.MinValue;

            while (!cancellationToken.IsCancellationRequested)
            {
                _newLiveDataEmitted.WaitOne(TimeSpan.FromMilliseconds(500));

                TimeSlice timeSlice;
                try
                {
                    timeSlice = SubscriptionSynchronizer.Sync(SubscriptionManager.DataFeedSubscriptions);
                }
                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;
                    shouldSendExtraEmptyPacket = true;
                    break;
                }

                // check for cancellation
                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }

                var frontierUtc = FrontierTimeProvider.GetUtcNow();
                // emit on data or if we've elapsed a full second since last emit or there are security changes
                if (timeSlice.SecurityChanges != SecurityChanges.None ||
                    timeSlice.Data.Count != 0 ||
                    frontierUtc >= nextEmit)
                {
                    yield return(timeSlice);

                    // force emitting every second since the data feed is
                    // the heartbeat of the application
                    nextEmit = frontierUtc.RoundDown(Time.OneSecond).Add(Time.OneSecond);
                }
            }

            if (shouldSendExtraEmptyPacket)
            {
                // send last empty packet list before terminating,
                // so the algorithm manager has a chance to detect the runtime error
                // and exit showing the correct error instead of a timeout
                nextEmit = FrontierTimeProvider.GetUtcNow().RoundDown(Time.OneSecond);
                if (!cancellationToken.IsCancellationRequested)
                {
                    var timeSlice = TimeSliceFactory.Create(
                        nextEmit,
                        new List <DataFeedPacket>(),
                        SecurityChanges.None,
                        new Dictionary <Universe, BaseDataCollection>());
                    yield return(timeSlice);
                }
            }

            Log.Trace("LiveSynchronizer.GetEnumerator(): Exited thread.");
        }