/// <summary> /// Execute the primary thread for retrieving stock data. /// 1. Subscribe to the streams requested. /// 2. Build bars or tick data requested, primary loop increment smallest possible. /// </summary> public void Run() { //Initialize: // Set up separate thread to handle stream and building packets: var streamThread = new Thread(StreamStoreConsumer); streamThread.Start(); Thread.Sleep(5); // Wait a little for the other thread to init. // This thread converts data into bars "on" the second - assuring the bars are close as // possible to a second unit tradebar (starting at 0 milliseconds). var realtime = new RealTimeSynchronizedTimer(TimeSpan.FromSeconds(1), utcTriggerTime => { // determine if we're on even time boundaries for data emit var onMinute = utcTriggerTime.Second == 0; var onHour = onMinute && utcTriggerTime.Minute == 0; // Determine if this subscription needs to be archived: var items = new List <KeyValuePair <Security, List <BaseData> > >(); var changes = SecurityChanges.None; var performedUniverseSelection = new HashSet <string>(); foreach (var kvp in _subscriptions) { var subscription = kvp.Value; if (subscription.Configuration.Resolution == Resolution.Tick) { continue; } var localTime = new DateTime(utcTriggerTime.Ticks - subscription.OffsetProvider.GetOffsetTicks(utcTriggerTime)); var onDay = onHour && localTime.Hour == 0; // perform universe selection if requested on day changes (don't perform multiple times per market) if (onDay && _algorithm.Universe != null && performedUniverseSelection.Add(subscription.Configuration.Market)) { var coarse = UniverseSelection.GetCoarseFundamentals(subscription.Configuration.Market, subscription.TimeZone, localTime.Date, true); OnFundamental(FundamentalType.Coarse, utcTriggerTime, subscription.Configuration, coarse.ToList()); } var triggerArchive = false; switch (subscription.Configuration.Resolution) { case Resolution.Second: triggerArchive = true; break; case Resolution.Minute: triggerArchive = onMinute; break; case Resolution.Hour: triggerArchive = onHour; break; case Resolution.Daily: triggerArchive = onDay; break; } if (triggerArchive) { var data = subscription.StreamStore.TriggerArchive(utcTriggerTime); if (data != null) { items.Add(new KeyValuePair <Security, List <BaseData> >(subscription.Security, new List <BaseData> { data })); } } } // don't try to add if we're already cancelling if (_cancellationTokenSource.IsCancellationRequested) { return; } Bridge.Add(TimeSlice.Create(utcTriggerTime, _algorithm.TimeZone, _algorithm.Portfolio.CashBook, items, changes)); }); //Start the realtime sampler above realtime.Start(); while (!_cancellationTokenSource.IsCancellationRequested && !_endOfBridges) { // main work of this class is done in the realtime and stream store consumer threads Thread.Sleep(1000); } //Dispose of the realtime clock. realtime.Stop(); //Stop thread _isActive = false; //Exit Live DataStream Feed: Log.Trace("LiveTradingDataFeed.Run(): Exiting LiveTradingDataFeed Run Method"); }