/* * 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 NodaTime; using System.Linq; using QuantConnect.Data; using QuantConnect.Util; using QuantConnect.Interfaces; using QuantConnect.Securities; using QuantConnect.Data.Market; using System.Collections.Generic; using QuantConnect.Python; using Python.Runtime; namespace QuantConnect.Algorithm { public partial class QCAlgorithm { /// /// Gets or sets the history provider for the algorithm /// public IHistoryProvider HistoryProvider { get; set; } /// /// Gets whether or not this algorithm is still warming up /// [DocumentationAttribute(HistoricalData)] public bool IsWarmingUp { get; private set; } /// /// Sets the warm up period to the specified value /// /// The amount of time to warm up, this does not take into account market hours/weekends [DocumentationAttribute(HistoricalData)] public void SetWarmup(TimeSpan timeSpan) { SetWarmUp(timeSpan, null); } /// /// Sets the warm up period to the specified value /// /// The amount of time to warm up, this does not take into account market hours/weekends [DocumentationAttribute(HistoricalData)] public void SetWarmUp(TimeSpan timeSpan) { SetWarmup(timeSpan); } /// /// Sets the warm up period to the specified value /// /// The amount of time to warm up, this does not take into account market hours/weekends /// The resolution to request [DocumentationAttribute(HistoricalData)] public void SetWarmup(TimeSpan timeSpan, Resolution? resolution) { SetWarmup(null, timeSpan, resolution); } /// /// Sets the warm up period to the specified value /// /// The amount of time to warm up, this does not take into account market hours/weekends /// The resolution to request [DocumentationAttribute(HistoricalData)] public void SetWarmUp(TimeSpan timeSpan, Resolution? resolution) { SetWarmup(timeSpan, resolution); } /// /// Sets the warm up period by resolving a start date that would send that amount of data into /// the algorithm. The highest (smallest) resolution in the securities collection will be used. /// For example, if an algorithm has minute and daily data and 200 bars are requested, that would /// use 200 minute bars. /// /// The number of data points requested for warm up [DocumentationAttribute(HistoricalData)] public void SetWarmup(int barCount) { SetWarmUp(barCount, null); } /// /// Sets the warm up period by resolving a start date that would send that amount of data into /// the algorithm. The highest (smallest) resolution in the securities collection will be used. /// For example, if an algorithm has minute and daily data and 200 bars are requested, that would /// use 200 minute bars. /// /// The number of data points requested for warm up [DocumentationAttribute(HistoricalData)] public void SetWarmUp(int barCount) { SetWarmup(barCount); } /// /// Sets the warm up period by resolving a start date that would send that amount of data into /// the algorithm. /// /// The number of data points requested for warm up /// The resolution to request [DocumentationAttribute(HistoricalData)] public void SetWarmup(int barCount, Resolution? resolution) { SetWarmup(barCount, null, resolution); } /// /// Sets the warm up period by resolving a start date that would send that amount of data into /// the algorithm. /// /// The number of data points requested for warm up /// The resolution to request [DocumentationAttribute(HistoricalData)] public void SetWarmUp(int barCount, Resolution? resolution) { SetWarmup(barCount, resolution); } /// /// Sets to false to indicate this algorithm has finished its warm up /// [DocumentationAttribute(HistoricalData)] public void SetFinishedWarmingUp() { IsWarmingUp = false; } /// /// Message for exception that is thrown when the implicit conversion between symbol and string fails /// private readonly string _symbolEmptyErrorMessage = "Cannot create history for the given ticker. " + "Either explicitly use a symbol object to make the history request " + "or ensure the symbol has been added using the AddSecurity() method before making the history request."; /// /// Gets the history requests required for provide warm up data for the algorithm /// /// [DocumentationAttribute(HistoricalData)] private bool TryGetWarmupHistoryStartTime(out DateTime result) { result = Time; if (_warmupBarCount.HasValue) { var symbols = Securities.Keys; if (symbols.Count != 0) { var startTimeUtc = CreateBarCountHistoryRequests(symbols, _warmupBarCount.Value, Settings.WarmupResolution) .DefaultIfEmpty() .Min(request => request == null ? default : request.StartTimeUtc); if(startTimeUtc != default) { result = startTimeUtc.ConvertFromUtc(TimeZone); return true; } } var defaultResolutionToUse = UniverseSettings.Resolution; if (Settings.WarmupResolution.HasValue) { defaultResolutionToUse = Settings.WarmupResolution.Value; } // if the algorithm has no added security, let's take a look at the universes to determine // what the start date should be used. Defaulting to always open result = Time - _warmupBarCount.Value * defaultResolutionToUse.ToTimeSpan(); foreach (var universe in _pendingUniverseAdditions.Concat(UniverseManager.Values)) { var config = universe.Configuration; var resolution = universe.Configuration.Resolution; if (Settings.WarmupResolution.HasValue) { resolution = Settings.WarmupResolution.Value; } var exchange = MarketHoursDatabase.GetExchangeHours(config); var start = _historyRequestFactory.GetStartTimeAlgoTz(config.Symbol, _warmupBarCount.Value, resolution, exchange, config.DataTimeZone); // we choose the min start result = result < start ? result : start; } return true; } if (_warmupTimeSpan.HasValue) { result = Time - _warmupTimeSpan.Value; return true; } return false; } /// /// Get the history for all configured securities over the requested span. /// This will use the resolution and other subscription settings for each security. /// The symbols must exist in the Securities collection. /// /// The span over which to request data. This is a calendar span, so take into consideration weekends and such /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing data over the most recent span for all configured securities [DocumentationAttribute(HistoricalData)] public IEnumerable History(TimeSpan span, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { return History(Securities.Keys, Time - span, Time, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset).Memoize(); } /// /// Get the history for all configured securities over the requested span. /// This will use the resolution and other subscription settings for each security. /// The symbols must exist in the Securities collection. /// /// The number of bars to request /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing data over the most recent span for all configured securities [DocumentationAttribute(HistoricalData)] public IEnumerable History(int periods, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { return History(Securities.Keys, periods, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset).Memoize(); } /// /// Gets the historical data for all symbols of the requested type over the requested span. /// The symbol's configured values for resolution and fill forward behavior will be used /// The symbols must exist in the Securities collection. /// /// The span over which to retrieve recent historical data /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable> History(TimeSpan span, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode ? dataNormalizationMode = null, int? contractDepthOffset = null) where T : IBaseData { return History(Securities.Keys, span, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset).Memoize(); } /// /// Gets the historical data for the specified symbols over the requested span. /// The symbols must exist in the Securities collection. /// /// The data type of the symbols /// The symbols to retrieve historical data for /// The span over which to retrieve recent historical data /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable> History(IEnumerable symbols, TimeSpan span, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) where T : IBaseData { return History(symbols, Time - span, Time, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset).Memoize(); } /// /// Gets the historical data for the specified symbols. The exact number of bars will be returned for /// each symbol. This may result in some data start earlier/later than others due to when various /// exchanges are open. The symbols must exist in the Securities collection. /// /// The data type of the symbols /// The symbols to retrieve historical data for /// The number of bars to request /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable> History(IEnumerable symbols, int periods, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) where T : IBaseData { CheckPeriodBasedHistoryRequestResolution(symbols, resolution); var requests = CreateBarCountHistoryRequests(symbols, typeof(T), periods, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset); return GetDataTypedHistory(requests); } /// /// Gets the historical data for the specified symbols between the specified dates. The symbols must exist in the Securities collection. /// /// The data type of the symbols /// The symbols to retrieve historical data for /// The start time in the algorithm's time zone /// The end time in the algorithm's time zone /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable> History(IEnumerable symbols, DateTime start, DateTime end, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) where T : IBaseData { var requests = CreateDateRangeHistoryRequests(symbols, typeof(T), start, end, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset); return GetDataTypedHistory(requests); } /// /// Gets the historical data for the specified symbol over the request span. The symbol must exist in the Securities collection. /// /// The data type of the symbol /// The symbol to retrieve historical data for /// The span over which to retrieve recent historical data /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable History(Symbol symbol, TimeSpan span, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) where T : IBaseData { return History(symbol, Time - span, Time, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset).Memoize(); } /// /// Gets the historical data for the specified symbol. The exact number of bars will be returned. /// The symbol must exist in the Securities collection. /// /// The symbol to retrieve historical data for /// The number of bars to request /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable History(Symbol symbol, int periods, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { if (symbol == null) throw new ArgumentException(_symbolEmptyErrorMessage); resolution = GetResolution(symbol, resolution); CheckPeriodBasedHistoryRequestResolution(new[] { symbol }, resolution); var marketHours = GetMarketHours(symbol); var start = _historyRequestFactory.GetStartTimeAlgoTz(symbol, periods, resolution.Value, marketHours.ExchangeHours, marketHours.DataTimeZone, extendedMarketHours); return History(symbol, start, Time, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset); } /// /// Gets the historical data for the specified symbol. The exact number of bars will be returned. /// The symbol must exist in the Securities collection. /// /// The data type of the symbol /// The symbol to retrieve historical data for /// The number of bars to request /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable History(Symbol symbol, int periods, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) where T : IBaseData { resolution = GetResolution(symbol, resolution); CheckPeriodBasedHistoryRequestResolution(new[] { symbol }, resolution); var requests = CreateBarCountHistoryRequests(new [] { symbol }, typeof(T), periods, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset); return GetDataTypedHistory(requests, symbol); } /// /// Gets the historical data for the specified symbol between the specified dates. The symbol must exist in the Securities collection. /// /// The symbol to retrieve historical data for /// The start time in the algorithm's time zone /// The end time in the algorithm's time zone /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable History(Symbol symbol, DateTime start, DateTime end, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) where T : IBaseData { var requests = CreateDateRangeHistoryRequests(new[] { symbol }, typeof(T), start, end, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset); return GetDataTypedHistory(requests, symbol); } /// /// Gets the historical data for the specified symbol over the request span. The symbol must exist in the Securities collection. /// /// The symbol to retrieve historical data for /// The span over which to retrieve recent historical data /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable History(Symbol symbol, TimeSpan span, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { return History(symbol, Time - span, Time, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset); } /// /// Gets the historical data for the specified symbol over the request span. The symbol must exist in the Securities collection. /// /// The symbol to retrieve historical data for /// The start time in the algorithm's time zone /// The end time in the algorithm's time zone /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable History(Symbol symbol, DateTime start, DateTime end, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { var securityType = symbol.ID.SecurityType; if (securityType == SecurityType.Forex || securityType == SecurityType.Cfd) { Error("Calling History method on a Forex or CFD security will return an empty result. Please use the generic version with QuoteBar type parameter."); } var resolutionToUse = resolution ?? GetResolution(symbol, resolution); if (resolutionToUse == Resolution.Tick) { throw new InvalidOperationException("Calling History method with Resolution.Tick will return an empty result." + " Please use the generic version with Tick type parameter or provide a list of Symbols to use the Slice history request API."); } return History(new[] { symbol }, start, end, resolutionToUse, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset).Get(symbol).Memoize(); } /// /// Gets the historical data for the specified symbols over the requested span. /// The symbol's configured values for resolution and fill forward behavior will be used /// The symbols must exist in the Securities collection. /// /// The symbols to retrieve historical data for /// The span over which to retrieve recent historical data /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable History(IEnumerable symbols, TimeSpan span, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { return History(symbols, Time - span, Time, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset).Memoize(); } /// /// Gets the historical data for the specified symbols. The exact number of bars will be returned for /// each symbol. This may result in some data start earlier/later than others due to when various /// exchanges are open. The symbols must exist in the Securities collection. /// /// The symbols to retrieve historical data for /// The number of bars to request /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable History(IEnumerable symbols, int periods, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { CheckPeriodBasedHistoryRequestResolution(symbols, resolution); return History(CreateBarCountHistoryRequests(symbols, periods, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset)).Memoize(); } /// /// Gets the historical data for the specified symbols between the specified dates. The symbols must exist in the Securities collection. /// /// The symbols to retrieve historical data for /// The start time in the algorithm's time zone /// The end time in the algorithm's time zone /// The resolution to request /// True to fill forward missing data, false otherwise /// True to include extended market hours data, false otherwise /// The contract mapping mode to use for the security history request /// The price scaling mode to use for the securities history /// The continuous contract desired offset from the current front month. /// For example, 0 will use the front month, 1 will use the back month contract /// An enumerable of slice containing the requested historical data [DocumentationAttribute(HistoricalData)] public IEnumerable History(IEnumerable symbols, DateTime start, DateTime end, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { return History(CreateDateRangeHistoryRequests(symbols, start, end, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset)).Memoize(); } /// /// Executes the specified history request /// /// the history request to execute /// An enumerable of slice satisfying the specified history request [DocumentationAttribute(HistoricalData)] public IEnumerable History(HistoryRequest request) { return History(new[] { request }).Memoize(); } /// /// Executes the specified history requests /// /// the history requests to execute /// An enumerable of slice satisfying the specified history request [DocumentationAttribute(HistoricalData)] public IEnumerable History(IEnumerable requests) { return History(requests, TimeZone).Memoize(); } /// /// Yields data to warmup a security for all it's subscribed data types /// /// object for which to retrieve historical data /// Securities historical data [DocumentationAttribute(AddingData)] [DocumentationAttribute(HistoricalData)] public IEnumerable GetLastKnownPrices(Security security) { return GetLastKnownPrices(security.Symbol); } /// /// Yields data to warmup a security for all it's subscribed data types /// /// The symbol we want to get seed data for /// Securities historical data [DocumentationAttribute(AddingData)] [DocumentationAttribute(HistoricalData)] public IEnumerable GetLastKnownPrices(Symbol symbol) { if (!HistoryRequestValid(symbol) || HistoryProvider == null) { return Enumerable.Empty(); } var result = new Dictionary(); Resolution? resolution = null; Func requestData = period => { var historyRequests = CreateBarCountHistoryRequests(new[] { symbol }, period) .Select(request => { // For speed and memory usage, use Resolution.Minute as the minimum resolution request.Resolution = (Resolution)Math.Max((int)Resolution.Minute, (int)request.Resolution); // force no fill forward behavior request.FillForwardResolution = null; resolution = request.Resolution; return request; }) // request only those tick types we didn't get the data we wanted .Where(request => !result.ContainsKey(request.TickType)) .ToList(); foreach (var slice in History(historyRequests)) { for (var i = 0; i < historyRequests.Count; i++) { var historyRequest = historyRequests[i]; var data = slice.Get(historyRequest.DataType); if (data.ContainsKey(symbol)) { // keep the last data point per tick type result[historyRequest.TickType] = (BaseData)data[symbol]; } } } // true when all history requests tick types have a data point return historyRequests.All(request => result.ContainsKey(request.TickType)); }; if (!requestData(5)) { if (resolution.HasValue) { // If the first attempt to get the last know price returns null, it maybe the case of an illiquid security. // We increase the look-back period for this case accordingly to the resolution to cover 3 trading days var periods = resolution.Value == Resolution.Daily ? 3 : resolution.Value == Resolution.Hour ? 24 : 1440; requestData(periods); } else { // this shouldn't happen but just in case QuantConnect.Logging.Log.Error( $"QCAlgorithm.GetLastKnownPrices(): no history request was created for symbol {symbol} at {Time}"); } } // return the data ordered by time ascending return result.Values.OrderBy(data => data.Time); } /// /// Get the last known price using the history provider. /// Useful for seeding securities with the correct price /// /// object for which to retrieve historical data /// A single object with the last known price [Obsolete("This method is obsolete please use 'GetLastKnownPrices' which will return the last data point" + " for each type associated with the requested security")] [DocumentationAttribute(AddingData)] [DocumentationAttribute(HistoricalData)] public BaseData GetLastKnownPrice(Security security) { return GetLastKnownPrices(security.Symbol) // since we are returning a single data point let's respect order .OrderByDescending(data => GetTickTypeOrder(data.Symbol.SecurityType, LeanData.GetCommonTickTypeForCommonDataTypes(data.GetType(), data.Symbol.SecurityType))) .LastOrDefault(); } /// /// Centralized logic to get data typed history given a list of requests for the specified symbol. /// This method is used to keep backwards compatibility for those History methods that expect an ArgumentException to be thrown /// when the security and the requested data type do not match /// /// /// This method will check for Python custom data types in order to call the right Slice.Get dynamic method /// private IEnumerable GetDataTypedHistory(IEnumerable requests, Symbol symbol) where T : IBaseData { var type = typeof(T); var historyRequests = requests.Where(x => x != null).ToList(); if (historyRequests.Count == 0) { throw new ArgumentException($"No history data could be fetched. " + $"This could be due to the specified security not being of the requested type. Symbol: {symbol} Requested Type: {type.Name}"); } var slices = History(historyRequests, TimeZone); IEnumerable result = null; // If T is a custom data coming from Python (a class derived from PythonData), T will get here as PythonData // and not the actual custom type. We take care of this especial case by using a dynamic version of GetDataTypedHistory that // receives the Python type, and we get it from the history requests. if (type == typeof(PythonData)) { result = GetPythonCustomDataTypeHistory(slices, historyRequests, symbol).OfType(); } // TODO: This is a patch to fix the issue with the Slice.GetImpl method returning only the last tick // for each symbol instead of the whole list of ticks. // The actual issue is Slice.GetImpl, so patch this can be removed right after it is properly addressed. // A proposed solution making the Tick class a BaseDataCollection and make the Ticks class a dictionary Symbol->Tick instead of // Symbol->List so we can use the Slice.Get methods to collect all ticks in every slice instead of only the last one. else if (type == typeof(Tick)) { result = (IEnumerable)slices.Select(x => x.Ticks).Where(x => x.ContainsKey(symbol)).SelectMany(x => x[symbol]); } else { result = slices.Get(symbol); } return result.Memoize(); } /// /// Centralized logic to get data typed history for a given list of requests. /// /// /// This method will check for Python custom data types in order to call the right Slice.Get dynamic method /// private IEnumerable> GetDataTypedHistory(IEnumerable requests) where T : IBaseData { var historyRequests = requests.Where(x => x != null).ToList(); var slices = History(historyRequests, TimeZone); IEnumerable> result = null; if (typeof(T) == typeof(PythonData)) { result = GetPythonCustomDataTypeHistory(slices, historyRequests).OfType>(); } else { result = slices.Get(); } return result.Memoize(); } [DocumentationAttribute(HistoricalData)] private IEnumerable History(IEnumerable requests, DateTimeZone timeZone) { var sentMessage = false; var hasPythonDataRequest = false; // filter out any universe securities that may have made it this far var filteredRequests = requests.Where(hr => HistoryRequestValid(hr.Symbol)).ToList(); for (var i = 0; i < filteredRequests.Count; i++) { var request = filteredRequests[i]; // prevent future requests if (request.EndTimeUtc > UtcTime) { var endTimeUtc = UtcTime; var startTimeUtc = request.StartTimeUtc; if (request.StartTimeUtc > request.EndTimeUtc) { startTimeUtc = request.EndTimeUtc; } filteredRequests[i] = new HistoryRequest(startTimeUtc, endTimeUtc, request.DataType, request.Symbol, request.Resolution, request.ExchangeHours, request.DataTimeZone, request.FillForwardResolution, request.IncludeExtendedMarketHours, request.IsCustomData, request.DataNormalizationMode, request.TickType, request.DataMappingMode, request.ContractDepthOffset); if (!sentMessage) { sentMessage = true; Debug("Request for future history modified to end now."); } } if (!hasPythonDataRequest) { hasPythonDataRequest = request.IsCustomData && typeof(PythonData).IsAssignableFrom(request.DataType); } } // filter out future data to prevent look ahead bias var history = HistoryProvider.GetHistory(filteredRequests, timeZone); if (hasPythonDataRequest && PythonEngine.IsInitialized) { // add protection against potential python deadlocks return WrapPythonDataHistory(history); } return history; } /// /// Helper method to create history requests from a date range /// private IEnumerable CreateDateRangeHistoryRequests(IEnumerable symbols, DateTime startAlgoTz, DateTime endAlgoTz, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { return CreateDateRangeHistoryRequests(symbols, typeof(BaseData), startAlgoTz, endAlgoTz, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset); } /// /// Helper method to create history requests from a date range with custom data type /// private IEnumerable CreateDateRangeHistoryRequests(IEnumerable symbols, Type requestedType, DateTime startAlgoTz, DateTime endAlgoTz, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { return symbols.Where(HistoryRequestValid).SelectMany(x => { var requests = new List(); foreach (var config in GetMatchingSubscriptions(x, requestedType, resolution)) { var request = _historyRequestFactory.CreateHistoryRequest(config, startAlgoTz, endAlgoTz, GetExchangeHours(x), resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset); requests.Add(request); } return requests; }); } /// /// Helper methods to create a history request for the specified symbols and bar count /// private IEnumerable CreateBarCountHistoryRequests(IEnumerable symbols, int periods, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { return CreateBarCountHistoryRequests(symbols, typeof(BaseData), periods, resolution, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset); } /// /// Helper methods to create a history request for the specified symbols and bar count with custom data type /// private IEnumerable CreateBarCountHistoryRequests(IEnumerable symbols, Type requestedType, int periods, Resolution? resolution = null, bool? fillForward = null, bool? extendedMarketHours = null, DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int? contractDepthOffset = null) { return symbols.Where(HistoryRequestValid).SelectMany(symbol => { var res = GetResolution(symbol, resolution); var exchange = GetExchangeHours(symbol); var configs = GetMatchingSubscriptions(symbol, requestedType, resolution).ToList(); if (configs.Count == 0) { return Enumerable.Empty(); } var start = _historyRequestFactory.GetStartTimeAlgoTz(symbol, periods, res, exchange, configs.First().DataTimeZone, extendedMarketHours); var end = Time; return configs.Select(config => _historyRequestFactory.CreateHistoryRequest(config, start, end, exchange, res, fillForward, extendedMarketHours, dataMappingMode, dataNormalizationMode, contractDepthOffset)); }); } private int GetTickTypeOrder(SecurityType securityType, TickType tickType) { return SubscriptionManager.AvailableDataTypes[securityType].IndexOf(tickType); } private IEnumerable GetMatchingSubscriptions(Symbol symbol, Type type, Resolution? resolution = null) { var matchingSubscriptions = SubscriptionManager.SubscriptionDataConfigService // we add internal subscription so that history requests are covered, this allows us to warm them up too .GetSubscriptionDataConfigs(symbol, includeInternalConfigs:true) // find all subscriptions matching the requested type with a higher resolution than requested .OrderByDescending(s => s.Resolution) // lets make sure to respect the order of the data types .ThenByDescending(config => GetTickTypeOrder(config.SecurityType, config.TickType)) .Where(s => SubscriptionDataConfigTypeFilter(type, s.Type)); var internalConfig = new List(); var userConfig = new List(); foreach (var config in matchingSubscriptions) { if (config.IsInternalFeed) { internalConfig.Add(config); } else { userConfig.Add(config); } } // if we have any user defined subscription configuration we use it, else we use internal ones if any List configs = null; if(userConfig.Count != 0) { configs = userConfig; } else if (internalConfig.Count != 0) { configs = internalConfig; } // we use the subscription manager registered configurations here, we can not rely on the Securities collection // since this might be called when creating a security and warming it up if (configs != null && configs.Count != 0) { if (resolution.HasValue && (resolution == Resolution.Daily || resolution == Resolution.Hour) && symbol.SecurityType == SecurityType.Equity) { // for Daily and Hour resolution, for equities, we have to // filter out any existing subscriptions that could be of Quote type // This could happen if they were Resolution.Minute/Second/Tick return configs.Where(s => s.TickType != TickType.Quote); } return configs; } else { var entry = MarketHoursDatabase.GetEntry(symbol, new []{ type }); resolution = GetResolution(symbol, resolution); return SubscriptionManager .LookupSubscriptionConfigDataTypes(symbol.SecurityType, resolution.Value, symbol.IsCanonical()) .Where(tuple => SubscriptionDataConfigTypeFilter(type, tuple.Item1)) .Select(x => new SubscriptionDataConfig( x.Item1, symbol, resolution.Value, entry.DataTimeZone, entry.ExchangeHours.TimeZone, UniverseSettings.FillForward, UniverseSettings.ExtendedMarketHours, true, false, x.Item2, true, UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType))); } } /// /// Helper method to determine if the provided config type passes the filter of the target type /// /// If the target type is , config types will return false. /// This is useful to filter OpenInterest by default from history requests unless it's explicitly requested private bool SubscriptionDataConfigTypeFilter(Type targetType, Type configType) { var targetIsGenericType = targetType == typeof(BaseData); return targetType.IsAssignableFrom(configType) && (!targetIsGenericType || configType != typeof(OpenInterest)); } private SecurityExchangeHours GetExchangeHours(Symbol symbol) { return GetMarketHours(symbol).ExchangeHours; } private MarketHoursDatabase.Entry GetMarketHours(Symbol symbol) { var hoursEntry = MarketHoursDatabase.GetEntry(symbol.ID.Market, symbol, symbol.ID.SecurityType); // user can override the exchange hours in algorithm, i.e. HistoryAlgorithm Security security; if (Securities.TryGetValue(symbol, out security)) { return new MarketHoursDatabase.Entry(hoursEntry.DataTimeZone, security.Exchange.Hours); } return hoursEntry; } private Resolution GetResolution(Symbol symbol, Resolution? resolution) { Security security; if (Securities.TryGetValue(symbol, out security)) { if (resolution != null) { return resolution.Value; } Resolution? result = null; var hasNonInternal = false; foreach (var config in SubscriptionManager.SubscriptionDataConfigService .GetSubscriptionDataConfigs(symbol, includeInternalConfigs: true) // we process non internal configs first .OrderBy(config => config.IsInternalFeed ? 1 : 0)) { if (!config.IsInternalFeed || !hasNonInternal) { // once we find a non internal config we ignore internals hasNonInternal |= !config.IsInternalFeed; if (!result.HasValue || config.Resolution < result) { result = config.Resolution; } } } return result ?? UniverseSettings.Resolution; } else { return resolution ?? UniverseSettings.Resolution; } } /// /// Validate a symbol for a history request. /// Universe and canonical symbols are only valid for future security types /// private bool HistoryRequestValid(Symbol symbol) { return symbol.SecurityType == SecurityType.Future || !UniverseManager.ContainsKey(symbol) && !symbol.IsCanonical(); } /// /// Will set warmup settings validating the algorithm has not finished initialization yet /// private void SetWarmup(int? barCount, TimeSpan? timeSpan, Resolution? resolution) { if (_locked) { throw new InvalidOperationException("QCAlgorithm.SetWarmup(): This method cannot be used after algorithm initialized"); } _warmupTimeSpan = timeSpan; _warmupBarCount = barCount; Settings.WarmupResolution = resolution; } /// /// Throws if a period bases history request is made for tick resolution, which is not allowed. /// private void CheckPeriodBasedHistoryRequestResolution(IEnumerable symbols, Resolution? resolution) { if (symbols.Any(symbol => GetResolution(symbol, resolution) == Resolution.Tick)) { throw new InvalidOperationException("History functions that accept a 'periods' parameter can not be used with Resolution.Tick"); } } /// /// Centralized logic to get data typed history given a list of requests for the specified symbol. /// This method is used to keep backwards compatibility for those History methods that expect an ArgumentException to be thrown /// when the security and the requested data type do not match /// /// /// This method is only used for Python algorithms, specially for those requesting custom data type history. /// The reason for using this method is that custom data type Python history calls to /// will always use (the custom data base class) /// as the T argument, because the custom data class is a Python type, which will cause the history data in the slices to not be matched /// to the actual requested type, resulting in an empty list of slices. /// private static IEnumerable GetPythonCustomDataTypeHistory(IEnumerable slices, List requests, Symbol symbol = null) { if (requests.Count == 0 || requests.Any(x => x.DataType != requests[0].DataType)) { throw new ArgumentException("QCAlgorithm.GetPythonCustomDataTypeHistory(): All history requests must be for the same data type"); } var pythonType = requests[0].DataType; if (symbol == null) { return slices.Get(pythonType); } return slices.Get(pythonType, symbol); } /// /// Wraps the resulting history enumerable in case of a Python custom data history request. /// We need to get and release the Python GIL when parallel history requests are enabled to avoid deadlocks /// in the custom data readers. /// private static IEnumerable WrapPythonDataHistory(IEnumerable history) { using var enumerator = history.GetEnumerator(); var hasData = true; while (hasData) { // TODO: we don't really need the GIL. We should find a way to check whether we have the lock and only call this wrapper method if we do. using (Py.GIL()) { var state = PythonEngine.BeginAllowThreads(); hasData = enumerator.MoveNext(); PythonEngine.EndAllowThreads(state); } if (hasData) { yield return enumerator.Current; } } } } }