/* * 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.IO; using System.Linq; using QuantConnect.Util; using QuantConnect.Data; using QuantConnect.Logging; using QuantConnect.Securities; using QuantConnect.Interfaces; using QuantConnect.Configuration; namespace QuantConnect.Lean.Engine.DataFeeds { /// /// Data provider which downloads data using an or implementation /// public class DownloaderDataProvider : BaseDownloaderDataProvider { private readonly IDataDownloader _dataDownloader; /// /// Creates a new instance /// public DownloaderDataProvider() { var dataDownloaderConfig = Config.Get("data-downloader"); if (!string.IsNullOrEmpty(dataDownloaderConfig)) { _dataDownloader = Composer.Instance.GetExportedValueByTypeName(dataDownloaderConfig); } else { throw new ArgumentException("DownloaderDataProvider(): requires 'data-downloader' to be set with a valid type name"); } } /// /// Determines if it should downloads new data and retrieves data from disc /// /// A string representing where the data is stored /// A of the data requested public override Stream Fetch(string key) { return DownloadOnce(key, s => { if (LeanData.TryParsePath(key, out var symbol, out var date, out var resolution, out var tickType, out var dataType)) { var dataTimeZone = MarketHoursDatabase.FromDataFolder().GetDataTimeZone(symbol.ID.Market, symbol, symbol.SecurityType); DateTime startTimeUtc; DateTime endTimeUtc; if (resolution < Resolution.Hour) { // we can get the date from the path startTimeUtc = date.ConvertToUtc(dataTimeZone); endTimeUtc = date.Add(resolution.ToTimeSpan()).ConvertToUtc(dataTimeZone); } else { try { startTimeUtc = symbol.ID.Date; } catch (InvalidOperationException) { startTimeUtc = Time.BeginningOfTime; } endTimeUtc = DateTime.UtcNow; } // Save the data var writer = new LeanDataWriter(resolution, symbol, Globals.DataFolder, tickType); try { var data = _dataDownloader.Get(symbol, resolution, startTimeUtc, endTimeUtc) .Where(baseData => symbol.SecurityType == SecurityType.Base || baseData.GetType() == dataType) // for canonical symbols, downloader will return data for all of the chain .GroupBy(baseData => baseData.Symbol); foreach (var dataPerSymbol in data) { writer.Write(dataPerSymbol); } } catch (Exception e) { Log.Error(e); } } }); } /// /// Main filter to determine if this file needs to be downloaded /// /// File we are looking at /// True if should download protected override bool NeedToDownload(string filePath) { // Ignore null and invalid data requests if (filePath == null || filePath.Contains("fine", StringComparison.InvariantCultureIgnoreCase) && filePath.Contains("fundamental", StringComparison.InvariantCultureIgnoreCase) || filePath.Contains("map_files", StringComparison.InvariantCultureIgnoreCase) || filePath.Contains("factor_files", StringComparison.InvariantCultureIgnoreCase) || filePath.Contains("margins", StringComparison.InvariantCultureIgnoreCase) && filePath.Contains("future", StringComparison.InvariantCultureIgnoreCase)) { return false; } // Only download if it doesn't exist or is out of date. // Files are only "out of date" for non date based files (hour, daily, margins, etc.) because this data is stored all in one file return !File.Exists(filePath) || filePath.IsOutOfDate(); } } }