/// <summary> /// Private constructor used to keep track of how a user defined the insight period. /// </summary> /// <param name="symbol">The symbol this insight is for</param> /// <param name="periodSpec">A specification defining how the insight's period was defined, via time span, via resolution/barcount, via close time</param> /// <param name="type">The type of insight, price/volatility</param> /// <param name="direction">The predicted direction</param> /// <param name="magnitude">The predicted magnitude as a percentage change</param> /// <param name="confidence">The confidence in this insight</param> /// <param name="sourceModel">An identifier defining the model that generated this insight</param> /// <param name="weight">The portfolio weight of this insight</param> private Insight(Symbol symbol, IPeriodSpecification periodSpec, InsightType type, InsightDirection direction, double?magnitude, double?confidence, string sourceModel = null, double?weight = null) { Id = Guid.NewGuid(); Score = new InsightScore(); SourceModel = sourceModel; Symbol = symbol; Type = type; Direction = direction; // Optional Magnitude = magnitude; Confidence = confidence; Weight = weight; _periodSpecification = periodSpec; // keep existing behavior of Insight.Price such that we set the period immediately var period = (periodSpec as TimeSpanPeriodSpecification)?.Period; if (period != null) { Period = period.Value; } }
/// <summary> /// Initializes a new instance of the <see cref="Insight"/> class /// </summary> /// <param name="symbol">The symbol this insight is for</param> /// <param name="period">The period over which the prediction will come true</param> /// <param name="type">The type of insight, price/volatility</param> /// <param name="direction">The predicted direction</param> /// <param name="magnitude">The predicted magnitude as a percentage change</param> /// <param name="confidence">The confidence in this insight</param> /// <param name="sourceModel">An identifier defining the model that generated this insight</param> public Insight(Symbol symbol, TimeSpan period, InsightType type, InsightDirection direction, double? magnitude, double? confidence, string sourceModel = null) { Id = Guid.NewGuid(); Score = new InsightScore(); SourceModel = sourceModel; Symbol = symbol; Type = type; Direction = direction; Period = period; // Optional Magnitude = magnitude; Confidence = confidence; _periodSpecification = new TimeSpanPeriodSpecification(period); }
private PeriodCountConsolidatorBase(IPeriodSpecification periodSpecification) { _periodSpecification = periodSpecification; _period = _periodSpecification.Period; }
/// <summary> /// Updates this consolidator with the specified data. This method is /// responsible for raising the DataConsolidated event /// In time span mode, the bar range is closed on the left and open on the right: [T, T+TimeSpan). /// For example, if time span is 1 minute, we have [10:00, 10:01): so data at 10:01 is not /// included in the bar starting at 10:00. /// </summary> /// <exception cref="InvalidOperationException">Thrown when multiple symbols are being consolidated.</exception> /// <param name="data">The new data for the consolidator</param> public override void Update(T data) { if (!_securityIdentifierIsSet) { _securityIdentifierIsSet = true; _securityIdentifier = data.Symbol.ID; } else if (!data.Symbol.ID.Equals(_securityIdentifier)) { throw new InvalidOperationException($"Consolidators can only be used with a single symbol. The previous consolidated SecurityIdentifier ({_securityIdentifier}) is not the same as in the current data ({data.Symbol.ID})."); } if (!ShouldProcess(data)) { // first allow the base class a chance to filter out data it doesn't want // before we start incrementing counts and what not return; } if (!_validateTimeSpan && _period.HasValue && _periodSpecification is TimeSpanPeriodSpecification) { // only do this check once _validateTimeSpan = true; var dataLength = data.EndTime - data.Time; if (dataLength == _period) { // if the user is consolidating period 'X' with data of length 'X', be gentle, and transform into a bar of count 1 consolidation, we want to avoid issues like #3062 _maxCount = 1; _periodSpecification = new BarCountPeriodSpecification(); _period = _periodSpecification.Period; } else if (dataLength > _period) { throw new ArgumentException($"For Symbol {data.Symbol} can not consolidate bars of period: {_period}, using data of the same or higher period: {data.EndTime - data.Time}"); } } //Decide to fire the event var fireDataConsolidated = false; // decide to aggregate data before or after firing OnDataConsolidated event // always aggregate before firing in counting mode bool aggregateBeforeFire = _maxCount.HasValue; if (_maxCount.HasValue) { // we're in count mode _currentCount++; if (_currentCount >= _maxCount.Value) { _currentCount = 0; fireDataConsolidated = true; } } if (!_lastEmit.HasValue) { // initialize this value for period computations _lastEmit = IsTimeBased ? DateTime.MinValue : data.Time; } if (_period.HasValue) { // we're in time span mode and initialized if (_workingBar != null && data.Time - _workingBar.Time >= _period.Value && GetRoundedBarTime(data.Time) > _lastEmit) { fireDataConsolidated = true; } // special case: always aggregate before event trigger when TimeSpan is zero if (_period.Value == TimeSpan.Zero) { fireDataConsolidated = true; aggregateBeforeFire = true; } } if (aggregateBeforeFire) { if (data.Time >= _lastEmit) { AggregateBar(ref _workingBar, data); } } //Fire the event if (fireDataConsolidated) { var workingTradeBar = _workingBar as TradeBar; if (workingTradeBar != null) { // we kind of are cheating here... if (_period.HasValue) { workingTradeBar.Period = _period.Value; } // since trade bar has period it aggregates this properly else if (!(data is TradeBar)) { workingTradeBar.Period = data.Time - _lastEmit.Value; } } // Set _lastEmit first because OnDataConsolidated will set _workingBar to null _lastEmit = IsTimeBased && _workingBar != null ? _workingBar.EndTime : data.Time; OnDataConsolidated(_workingBar); } if (!aggregateBeforeFire) { if (data.Time >= _lastEmit) { AggregateBar(ref _workingBar, data); } } }