/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; namespace QuantConnect.Algorithm.Framework.Alphas.Analysis { /// /// Defines a context for performing analysis on a single insight /// public class InsightAnalysisContext { private readonly Lazy _lazyHashCode; private DateTime _previousEvaluationTimeUtc; private readonly Dictionary _contextStorage; private readonly TimeSpan _analysisPeriod; /// /// Gets the id of this context which is the same as the insight's id /// public Guid Id => Insight.Id; /// /// Gets the symbol the insight is for /// public Symbol Symbol => Insight.Symbol; /// /// Gets the insight being analyzed /// public Insight Insight { get; } /// /// Gets the insight's current score /// public InsightScore Score => Insight.Score; /// /// Gets ending time of the analysis period /// public DateTime AnalysisEndTimeUtc { get; private set; } /// /// Gets the initial values. These are values of price/volatility at the time the insight was generated /// public SecurityValues InitialValues { get; } /// /// Gets whether or not this insight's period has closed /// public bool InsightPeriodClosed { get; private set; } /// /// Gets the current values. These are values of price/volatility as of the current algorithm time. /// NOTE: Once the scoring has been finalized these values will no longer be updated and will be the /// values as of the last scoring which may not be the same as the prediction end time /// public SecurityValues CurrentValues { get; private set; } /// /// Percentage through the analysis period /// public double NormalizedTime => Time.NormalizeInstantWithinRange(Insight.GeneratedTimeUtc, CurrentValues.TimeUtc, _analysisPeriod); /// /// Percentage of the current time step w.r.t analysis period /// public double NormalizedTimeStep => Time.NormalizeTimeStep(_analysisPeriod, CurrentValues.TimeUtc - _previousEvaluationTimeUtc); /// /// Initializes a new instance of the class /// /// The insight to be analyzed /// The initial security values from when the insight was generated /// The period over which to perform analysis of the insight. This should be /// greater than or equal to . Specify null for default, insight.Period public InsightAnalysisContext(Insight insight, SecurityValues initialValues, TimeSpan analysisPeriod) { Insight = insight; _contextStorage = new Dictionary(); CurrentValues = InitialValues = initialValues; _previousEvaluationTimeUtc = CurrentValues.TimeUtc; // this will always be equal when the InsightManager is initialized with extraAnalysisPeriodRatio == 0 // this is the way LEAN run in the cloud and locally, but support for non-zero ratios are left in for posterity // by short-circuiting this here, we guarantee that analysis end time and close time are identical if (analysisPeriod == insight.Period) { AnalysisEndTimeUtc = insight.CloseTimeUtc; } else { var barSize = Time.Max(analysisPeriod.ToHigherResolutionEquivalent(false).ToTimeSpan(), Time.OneMinute); var barCount = (int)(insight.Period.Ticks / barSize.Ticks); AnalysisEndTimeUtc = Time.GetEndTimeForTradeBars(initialValues.ExchangeHours, insight.CloseTimeUtc, analysisPeriod.ToHigherResolutionEquivalent(false).ToTimeSpan(), barCount, false); } _analysisPeriod = AnalysisEndTimeUtc - initialValues.TimeUtc; _lazyHashCode = new Lazy(() => Id.GetHashCode()); } /// /// Sets the /// internal void SetCurrentValues(SecurityValues values) { _previousEvaluationTimeUtc = CurrentValues.TimeUtc; if (values.TimeUtc >= Insight.CloseTimeUtc) { InsightPeriodClosed = true; if (Insight.Period == Time.EndOfTimeTimeSpan) { // Special case, see OrderBasedInsightGenerator AnalysisEndTimeUtc = Insight.CloseTimeUtc; Insight.Period = Insight.CloseTimeUtc - Insight.GeneratedTimeUtc; } } CurrentValues = values; } /// /// Gets a value from the context's generic storage. /// This is here to allow function to access contextual state without needing to track it themselves /// /// The data type /// The key /// The value if in storage, otherwise default(T) public T Get(string key) { object value; if (_contextStorage.TryGetValue(key, out value)) { return (T)value; } return default(T); } /// /// Sets the key/value in the context's generic storage /// /// The value's key /// The value to be stored public void Set(string key, object value) { _contextStorage[key] = value; } /// /// Determines whether or not this context/insight can be analyzed for the specified score type /// /// The type of insight score /// True to proceed with analyzing this insight for the specified score type, false to skip analysis of the score type public bool ShouldAnalyze(InsightScoreType scoreType) { if (Insight.Direction == InsightDirection.Flat) { return false; } else if (scoreType == InsightScoreType.Magnitude) { return Insight.Magnitude.HasValue; } return true; } /// Returns a string that represents the current object. /// A string that represents the current object. /// 2 public override string ToString() { return $"{Insight.Id}: {Insight.GeneratedTimeUtc}/{Insight.CloseTimeUtc} -- {Insight.Score}"; } /// Serves as the default hash function. /// A hash code for the current object. /// 2 public override int GetHashCode() { return _lazyHashCode.Value; } /// Determines whether the specified object is equal to the current object. /// true if the specified object is equal to the current object; otherwise, false. /// The object to compare with the current object. /// 2 public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; if (obj.GetType() != GetType()) return false; return Id.Equals(((InsightAnalysisContext)obj).Id); } } }