/// <summary> /// Initializes the calculation stream. /// </summary> /// <param name="startTime">The start time.</param> /// <param name="endTime">The end time.</param> /// <param name="processingInterval">The processing interval.</param> /// <param name="configuration">The aggregate configuration.</param> public void Initialize( DateTime startTime, DateTime endTime, double processingInterval, AggregateConfiguration configuration) { m_startTime = startTime; m_endTime = endTime; m_configuration = configuration; m_processingInterval = processingInterval; m_timeFlowsBackward = (endTime < startTime); m_values = new LinkedList<DataValue>(); m_lastRawTimestamp = (m_timeFlowsBackward) ? DateTime.MaxValue : DateTime.MinValue; TimeSlice slice = new TimeSlice(); slice.StartTime = startTime; slice.EndTime = slice.StartTime.AddMilliseconds((m_timeFlowsBackward) ? -m_processingInterval : m_processingInterval); slice.EarlyBound = null; slice.LateBound = null; slice.Complete = false; m_nextSlice = slice; }
private IEnumerable <TimeSlice> Stream(AlgorithmNodePacket job, IAlgorithm algorithm, IDataFeed feed, IResultHandler results, CancellationToken cancellationToken) { bool setStartTime = false; var timeZone = algorithm.TimeZone; var history = algorithm.HistoryProvider; // get the required history job from the algorithm DateTime?lastHistoryTimeUtc = null; var historyRequests = algorithm.GetWarmupHistoryRequests().ToList(); // initialize variables for progress computation var start = DateTime.UtcNow.Ticks; var nextStatusTime = DateTime.UtcNow.AddSeconds(1); var minimumIncrement = algorithm.UniverseManager .Select(x => x.Value.Configuration.Resolution.ToTimeSpan()) .DefaultIfEmpty(Time.OneSecond) .Min(); minimumIncrement = minimumIncrement == TimeSpan.Zero ? Time.OneSecond : minimumIncrement; if (historyRequests.Count != 0) { // rewrite internal feed requests var subscriptions = algorithm.SubscriptionManager.Subscriptions.Where(x => !x.IsInternalFeed).ToList(); var minResolution = subscriptions.Count > 0 ? subscriptions.Min(x => x.Resolution) : Resolution.Second; foreach (var request in historyRequests) { Security security; if (algorithm.Securities.TryGetValue(request.Symbol, out security) && security.SubscriptionDataConfig.IsInternalFeed) { if (request.Resolution < minResolution) { request.Resolution = minResolution; request.FillForwardResolution = request.FillForwardResolution.HasValue ? minResolution : (Resolution?)null; } } } // rewrite all to share the same fill forward resolution if (historyRequests.Any(x => x.FillForwardResolution.HasValue)) { minResolution = historyRequests.Where(x => x.FillForwardResolution.HasValue).Min(x => x.FillForwardResolution.Value); foreach (var request in historyRequests.Where(x => x.FillForwardResolution.HasValue)) { request.FillForwardResolution = minResolution; } } foreach (var request in historyRequests) { start = Math.Min(request.StartTimeUtc.Ticks, start); Log.Trace(string.Format("AlgorithmManager.Stream(): WarmupHistoryRequest: {0}: Start: {1} End: {2} Resolution: {3}", request.Symbol, request.StartTimeUtc, request.EndTimeUtc, request.Resolution)); } // make the history request and build time slices foreach (var slice in history.GetHistory(historyRequests, timeZone)) { TimeSlice timeSlice; try { // we need to recombine this slice into a time slice var paired = new List <KeyValuePair <Security, List <BaseData> > >(); foreach (var symbol in slice.Keys) { var security = algorithm.Securities[symbol]; var data = slice[symbol]; var list = new List <BaseData>(); var ticks = data as List <Tick>; if (ticks != null) { list.AddRange(ticks); } else { list.Add(data); } paired.Add(new KeyValuePair <Security, List <BaseData> >(security, list)); } timeSlice = TimeSlice.Create(slice.Time.ConvertToUtc(timeZone), timeZone, algorithm.Portfolio.CashBook, paired, SecurityChanges.None); } catch (Exception err) { Log.Error(err); algorithm.RunTimeError = err; yield break; } if (timeSlice != null) { if (!setStartTime) { setStartTime = true; _previousTime = timeSlice.Time; algorithm.Debug("Algorithm warming up..."); } if (DateTime.UtcNow > nextStatusTime) { // send some status to the user letting them know we're done history, but still warming up, // catching up to real time data nextStatusTime = DateTime.UtcNow.AddSeconds(1); var percent = (int)(100 * (timeSlice.Time.Ticks - start) / (double)(DateTime.UtcNow.Ticks - start)); results.SendStatusUpdate(AlgorithmStatus.History, string.Format("Catching up to realtime {0}%...", percent)); } yield return(timeSlice); lastHistoryTimeUtc = timeSlice.Time; } } } // if we're not live or didn't event request warmup, then set us as not warming up if (!algorithm.LiveMode || historyRequests.Count == 0) { algorithm.SetFinishedWarmingUp(); results.SendStatusUpdate(AlgorithmStatus.Running); if (historyRequests.Count != 0) { algorithm.Debug("Algorithm finished warming up."); Log.Trace("AlgorithmManager.Stream(): Finished warmup"); } } foreach (var timeSlice in feed) { if (!setStartTime) { setStartTime = true; _previousTime = timeSlice.Time; } if (algorithm.LiveMode && algorithm.IsWarmingUp) { // this is hand-over logic, we spin up the data feed first and then request // the history for warmup, so there will be some overlap between the data if (lastHistoryTimeUtc.HasValue) { // make sure there's no historical data, this only matters for the handover var hasHistoricalData = false; foreach (var data in timeSlice.Slice.Ticks.Values.SelectMany(x => x).Concat <BaseData>(timeSlice.Slice.Bars.Values)) { // check if any ticks in the list are on or after our last warmup point, if so, skip this data if (data.EndTime.ConvertToUtc(algorithm.Securities[data.Symbol].Exchange.TimeZone) >= lastHistoryTimeUtc) { hasHistoricalData = true; break; } } if (hasHistoricalData) { continue; } // prevent us from doing these checks every loop lastHistoryTimeUtc = null; } // in live mode wait to mark us as finished warming up when // the data feed has caught up to now within the min increment if (timeSlice.Time > DateTime.UtcNow.Subtract(minimumIncrement)) { algorithm.SetFinishedWarmingUp(); results.SendStatusUpdate(AlgorithmStatus.Running); algorithm.Debug("Algorithm finished warming up."); Log.Trace("AlgorithmManager.Stream(): Finished warmup"); } else if (DateTime.UtcNow > nextStatusTime) { // send some status to the user letting them know we're done history, but still warming up, // catching up to real time data nextStatusTime = DateTime.UtcNow.AddSeconds(1); var percent = (int)(100 * (timeSlice.Time.Ticks - start) / (double)(DateTime.UtcNow.Ticks - start)); results.SendStatusUpdate(AlgorithmStatus.History, string.Format("Catching up to realtime {0}%...", percent)); } } yield return(timeSlice); } }
/// <summary> /// 添加或修改或移去的时间片 /// </summary> /// <param name="tTimer"></param> /// <param name="newIndex"></param> /// <param name="isAdd"></param> private static void Change( TimeSlice tTimer, long newIndex, bool isAdd ) { s_LockTimerChangeEntryChangeQueue.Enter(); { // 在ProcessChangeQueue(...)中释放入不使用的列表中 s_TimerChangeEntryChangeQueue.Enqueue( new TimerChangeEntry( tTimer, newIndex, isAdd ) ); } s_LockTimerChangeEntryChangeQueue.Exit(); // 发生事件 s_Signal.Set(); }
/// <summary> /// 地图点激活 /// </summary> public virtual void OnSpaceNodeActivate() { m_SpaceNodeActivateTimeSlice = TimeSlice.StartTimeSlice(TimeSpan.FromMilliseconds(1000), SpaceNodeActivateCallback); }
/// <summary> /// Computes the value for the timeslice. /// </summary> /// <param name="slice">The time slice to use for the computation.</param> /// <returns>The value for the time slice.</returns> protected DataValue ComputeValue(TimeSlice slice) { return Interpolate(slice.StartTime, slice.EarlyBound); }
/// <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).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(); } }
public void SliceTest() { TimeSlice.Slice(); Assert.Inconclusive("无法验证不返回值的方法。"); }
public TimeSliceEx(TimeSlice slice, int dayTradeBegin, int dayTradeEnd) { _slice = slice; UpdateTradeType(dayTradeBegin, dayTradeEnd); }
public TimeSliceEx(TimeSlice slice) { _slice = slice; }
public virtual void OnUpdate(TimeSlice time) { }
public TimeSlice GetLivingTime(DateTime tradingday, string instrumentid) { Instrument instr = this[instrumentid]; if (instr != null && _tfMgr != null) { string productid = GetProduct(instrumentid); return(_tfMgr.GetLivingTime(tradingday, instr.Market, instr.ExchangeID, productid)); } if (instr == null) { //期货没有后缀 var prodct = GetProduct(instrumentid); if (prodct == "" || prodct[0] == '.') { return(null); } FutureProduct product = GetFutureProduct(prodct); if (product == null) { return(null); } if (product.AllSlice != null && product.AllSlice.Count > 0) { TimeSlice tslice = new TimeSlice { BeginTime = product.AllSlice[0].BeginTime, EndTime = product.AllSlice[product.AllSlice.Count - 1].EndTime }; return(tslice); } Exchange exchange = GetExchange(product.ExchangeID); if (exchange == null) { return(null); } if (exchange.AllSlice != null && exchange.AllSlice.Count > 0) { TimeSlice tslice = new TimeSlice { BeginTime = exchange.AllSlice[0].BeginTime, EndTime = exchange.AllSlice[exchange.AllSlice.Count - 1].EndTime }; return(tslice); } } else { if (instr.Market == EnumMarket.期货) { Future future = instr as Future; if (future == null) { return(null); } FutureProduct product = GetFutureProduct(future.ProductID); if (product == null) { return(null); } if (product.AllSlice != null && product.AllSlice.Count > 0) { TimeSlice tslice = new TimeSlice(); tslice.BeginTime = product.AllSlice[0].BeginTime; tslice.EndTime = product.AllSlice[product.AllSlice.Count - 1].EndTime; return(tslice); } } Exchange exchange = GetExchange(instr.ExchangeID); if (exchange == null) { return(null); } if (exchange.AllSlice != null && exchange.AllSlice.Count > 0) { TimeSlice tslice = new TimeSlice(); tslice.BeginTime = exchange.AllSlice[0].BeginTime; tslice.EndTime = exchange.AllSlice[exchange.AllSlice.Count - 1].EndTime; return(tslice); } } return(null); }
/// <summary> /// /// </summary> /// <param name="tTimer"></param> /// <param name="newIndex"></param> /// <param name="isAdd"></param> public TimerChangeEntry(TimeSlice tTimer, long newIndex, bool isAdd) { m_TimerSlice = tTimer; m_NewPriority = newIndex; m_IsAddTimerSlice = isAdd; }
/// <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> /// 添加或修改或移去时间片 /// </summary> /// <param name="tTimer"></param> public static void AddTimer( TimeSlice tTimer ) { Change( tTimer, (long)tTimer.Frequency, true ); }
/// <summary> /// Returns the next processed value. /// </summary> /// <param name="returnPartial">If true a partial interval should be processed.</param> /// <returns>The processed value. Null if nothing available and returnPartial is false.</returns> public DataValue GetProcessedValue(bool returnPartial) { // do nothing if slice not complete and partial values not requested. if (!m_nextSlice.Complete) { if (CompareTimestamps(m_endTime, m_nextSlice.EndTime) > 0) { if (!returnPartial) { return null; } } } // check for end. if (CompareTimestamps(m_endTime, m_nextSlice.StartTime) <= 0) { return null; } // compute the value. DataValue value = ComputeValue(m_nextSlice); TimeSlice slice = new TimeSlice(); slice.StartTime = m_nextSlice.EndTime; slice.EndTime = slice.StartTime.AddMilliseconds((m_timeFlowsBackward) ? -m_processingInterval : m_processingInterval); slice.EarlyBound = FindEarlyBound(slice.StartTime); slice.LateBound = FindLateBound(slice.EarlyBound, slice.EndTime); slice.Complete = slice.LateBound != null; m_nextSlice = slice; // remove all data prior to the early bound. if (slice.EarlyBound != null) { LinkedListNode<DataValue> ii = slice.EarlyBound.Previous; while (ii != null) { LinkedListNode<DataValue> next = ii.Previous; m_values.Remove(ii); ii = next; } } return value; }
/// <summary> /// 修改时间片优先级 /// </summary> /// <param name="tTimer"></param> /// <param name="newPrio"></param> public static void PriorityChange( TimeSlice tTimer, TimerFrequency newPriority ) { Change( tTimer, (long)newPriority, false ); }
/// <summary> /// 移去时间片 /// </summary> /// <param name="tTimer"></param> public static void RemoveTimer( TimeSlice tTimer ) { Change( tTimer, -1, false ); }
/// <summary> /// /// </summary> /// <param name="tTimer"></param> /// <param name="newIndex"></param> /// <param name="isAdd"></param> public TimerChangeEntry( TimeSlice tTimer, long newIndex, bool isAdd ) { m_TimerSlice = tTimer; m_NewPriority = newIndex; m_IsAddTimerSlice = isAdd; }