69d2f5ae82
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled
API Tests / build (push) Has been cancelled
Benchmarks / build (push) Has been cancelled
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
* Make FOPs selection universe file-based for backtesting * Make FOPs option chains universe file based * Make Future universe selection file-based like option universe * Make Future universe selection file-based like option universe * Abstraction cleanup * Add FuturesChains API to QC algorithm Also refactor future chain provider to use the new FutureUniverse instead of zip file names * Update regression algorithms stats * Refactor QuantBook option and future history to use new universes * Fix failing tests * Fix failing tests * Fix failing tests * Minor future chains unit test improvement * Add futures chains DataFrame property Also, remove IDerivativeSecurity interface from Future * Add DataFrame property to FuturesChains class * Add regression algorithms * Add regression algorithms * Replace QCAlgorithm.FutureChainProvider usages with new FuturesChain api * Minor fixes * Reduce number of universe files in repo * Minor data fixes * Regression algorithms updates * Add implicit conversion from FuturesContract to Symbol Modified algorithms to use futures contract objects directly instead of accessing their Symbol property. Removed unnecessary import statements and redundant lines in various files. * Improve resolution handling for history requests * Changed _auxiliaryData field to lazily-initialized AuxiliaryData property * Refactor data handling in BaseChain and TimeSliceFactory - Added `AddData` method to `BaseChain` for adding market data - Refactored `TimeSliceFactory` to use `BaseChain.AddData` method * Remove specific constructors and indexers from Chain classes Removed public indexers in `BaseChains` for getting or setting `BaseChain` instances by `ticker` or `Symbol`, which were used for Pythonnet compatibility. * Remove chain cache logic from FuturesChainUniverse * Refactor class and interface names for clarity Renamed `FileBasedUniverse` to `BaseChainUniverseData` and `IFileBasedUniverse` to `IChainUniverseData`. * Add base class for options and futures contracts - Introduced `BaseContract` as an abstract base class for contracts, consolidating common properties and methods. - Removed ISymbolInterface * Add minor fix for future options tickers parsing Added tests * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Clean chain provider classes up * Remove ZipEntryName other classes and unused code Removed ZipEntryName class and references across various files. Removed DataQueueFuturesChainUniverseDataCollectionEnumerator and DataQueueOptionChainUniverseDataCollectionEnumerator classes. Removed OptionChainUniverseSubscriptionEnumeratorFactory class. Removed unused code for handling OptionChainUniverse and FuturesChainUniverse in FileSystemDataFeed.cs and LiveTradingDataFeed.cs. Removed several test files related to enumerator factories and universe data collection. * Minor changes and cleanup * Trigger Build * Trigger Build * Refactor FuturesContract data handling Forward price data from bars and ticks stored in private fields for improved memory usage * Fix: use universe data for market data in FuturesContract * Update regression algorithms stats after rebase Added HSI futures universe files * Sort configs by internal flag Internals go first * Throw from option universe data filters for future options Future options IV, Open interest and greeks are not supported for future options * Minor changes * Improve some regression algorithms * Minor fix for failing unit tests * Update FOPs universe file header Removed greeks and IV columns. Updated FOPs universe files: removed outdated columns. * Minor unit test fix * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Minor fix * Add history provider as constructor argument for chain providers * Update new regression algorithms data points count * Minor fix for FakeDataQueue * Add initialize method to chain providers classes * Minor changes * Trigger Build * Trigger Build * Trigger Build * Minor fix * Minor fix * Trigger Build * Trigger Build * Trigger Build * Trigger Build * Add logs to ProcessedDataProvider * Removed test logs * Minor fix * Support downloading options and futures universe files from api data provider
229 lines
11 KiB
C#
229 lines
11 KiB
C#
/*
|
|
* 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 NodaTime;
|
|
using QuantConnect.Util;
|
|
using QuantConnect.Data;
|
|
using QuantConnect.Logging;
|
|
using QuantConnect.Interfaces;
|
|
using QuantConnect.Securities;
|
|
using QuantConnect.Configuration;
|
|
using QuantConnect.Lean.Engine.DataFeeds;
|
|
using QuantConnect.Data.UniverseSelection;
|
|
using DataFeeds = QuantConnect.Lean.Engine.DataFeeds;
|
|
using QuantConnect.DownloaderDataProvider.Launcher.Models;
|
|
using QuantConnect.DownloaderDataProvider.Launcher.Models.Constants;
|
|
using QuantConnect.Lean.Engine.HistoricalData;
|
|
|
|
namespace QuantConnect.DownloaderDataProvider.Launcher;
|
|
public static class Program
|
|
{
|
|
/// <summary>
|
|
/// Synchronizer in charge of guaranteeing a single operation per file path
|
|
/// </summary>
|
|
private readonly static KeyStringSynchronizer DiskSynchronizer = new();
|
|
|
|
/// <summary>
|
|
/// The provider used to cache history data files
|
|
/// </summary>
|
|
private static readonly IDataCacheProvider _dataCacheProvider = new DiskDataCacheProvider(DiskSynchronizer);
|
|
|
|
/// <summary>
|
|
/// Represents the time interval of 5 seconds.
|
|
/// </summary>
|
|
private static TimeSpan _logDisplayInterval = TimeSpan.FromSeconds(5);
|
|
|
|
/// <summary>
|
|
/// Provides access to exchange hours and raw data times zones in various markets
|
|
/// </summary>
|
|
private static readonly MarketHoursDatabase _marketHoursDatabase = MarketHoursDatabase.FromDataFolder();
|
|
|
|
/// <summary>
|
|
/// The main entry point for the application.
|
|
/// </summary>
|
|
/// <param name="args">Command-line arguments passed to the application.</param>
|
|
public static void Main(string[] args)
|
|
{
|
|
// Parse report arguments and merge with config to use in the optimizer
|
|
if (args.Length > 0)
|
|
{
|
|
Config.MergeCommandLineArgumentsWithConfiguration(DownloaderDataProviderArgumentParser.ParseArguments(args));
|
|
}
|
|
|
|
InitializeConfigurations();
|
|
|
|
var dataDownloader = Composer.Instance.GetExportedValueByTypeName<IDataDownloader>(Config.Get(DownloaderCommandArguments.CommandDownloaderDataDownloader));
|
|
var commandDataType = Config.Get(DownloaderCommandArguments.CommandDataType).ToUpperInvariant();
|
|
|
|
switch (commandDataType)
|
|
{
|
|
case "UNIVERSE":
|
|
RunUniverseDownloader(dataDownloader, new DataUniverseDownloadConfig());
|
|
break;
|
|
case "TRADE":
|
|
case "QUOTE":
|
|
case "OPENINTEREST":
|
|
RunDownload(dataDownloader, new DataDownloadConfig(), Globals.DataFolder, _dataCacheProvider);
|
|
break;
|
|
default:
|
|
Log.Error($"QuantConnect.DownloaderDataProvider.Launcher: Unsupported command data type '{commandDataType}'. Valid options: UNIVERSE, TRADE, QUOTE, OPENINTEREST.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Executes a data download operation using the specified data downloader.
|
|
/// </summary>
|
|
/// <param name="dataDownloader">An instance of an object implementing the <see cref="IDataDownloader"/> interface, responsible for downloading data.</param>
|
|
/// <param name="dataDownloadConfig">Configuration settings for the data download operation.</param>
|
|
/// <param name="dataDirectory">The directory where the downloaded data will be stored.</param>
|
|
/// <param name="dataCacheProvider">The provider used to cache history data files</param>
|
|
/// <param name="mapSymbol">True if the symbol should be mapped while writing the data</param>
|
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="dataDownloader"/> is null.</exception>
|
|
public static void RunDownload(IDataDownloader dataDownloader, DataDownloadConfig dataDownloadConfig, string dataDirectory, IDataCacheProvider dataCacheProvider, bool mapSymbol = true)
|
|
{
|
|
if (dataDownloader == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(dataDownloader), "The data downloader instance cannot be null. Please ensure that a valid instance of data downloader is provided.");
|
|
}
|
|
|
|
var totalDownloadSymbols = dataDownloadConfig.Symbols.Count;
|
|
var completeSymbolCount = 0;
|
|
var startDownloadUtcTime = DateTime.UtcNow;
|
|
|
|
foreach (var symbol in dataDownloadConfig.Symbols)
|
|
{
|
|
var downloadParameters = new DataDownloaderGetParameters(symbol, dataDownloadConfig.Resolution, dataDownloadConfig.StartDate, dataDownloadConfig.EndDate, dataDownloadConfig.TickType);
|
|
|
|
Log.Trace($"DownloaderDataProvider.Main(): Starting download {downloadParameters}");
|
|
var downloadedData = dataDownloader.Get(downloadParameters);
|
|
|
|
if (downloadedData == null)
|
|
{
|
|
completeSymbolCount++;
|
|
Log.Trace($"DownloaderDataProvider.Main(): No data available for the following parameters: {downloadParameters}");
|
|
continue;
|
|
}
|
|
|
|
var (dataTimeZone, exchangeTimeZone) = GetDataAndExchangeTimeZoneBySymbol(symbol);
|
|
|
|
var writer = new LeanDataWriter(dataDownloadConfig.Resolution, symbol, dataDirectory, dataDownloadConfig.TickType, dataCacheProvider, mapSymbol: mapSymbol);
|
|
|
|
var groupedData = DataFeeds.DownloaderDataProvider.FilterAndGroupDownloadDataBySymbol(
|
|
downloadedData,
|
|
symbol,
|
|
dataDownloadConfig.DataType,
|
|
exchangeTimeZone,
|
|
dataTimeZone,
|
|
downloadParameters.StartUtc,
|
|
downloadParameters.EndUtc);
|
|
|
|
var lastLogStatusTime = DateTime.UtcNow;
|
|
|
|
foreach (var data in groupedData)
|
|
{
|
|
writer.Write(data.Select(data =>
|
|
{
|
|
var utcNow = DateTime.UtcNow;
|
|
if (utcNow - lastLogStatusTime >= _logDisplayInterval)
|
|
{
|
|
lastLogStatusTime = utcNow;
|
|
Log.Trace($"Downloading data for {downloadParameters.Symbol}. Please hold on...");
|
|
}
|
|
return data;
|
|
}));
|
|
}
|
|
|
|
completeSymbolCount++;
|
|
var symbolPercentComplete = (double)completeSymbolCount / totalDownloadSymbols * 100;
|
|
Log.Trace($"DownloaderDataProvider.RunDownload(): {symbolPercentComplete:F2}% complete ({completeSymbolCount} out of {totalDownloadSymbols} symbols)");
|
|
|
|
Log.Trace($"DownloaderDataProvider.RunDownload(): Download completed for {downloadParameters.Symbol} at {downloadParameters.Resolution} resolution, " +
|
|
$"covering the period from {dataDownloadConfig.StartDate} to {dataDownloadConfig.EndDate}.");
|
|
}
|
|
Log.Trace($"All downloads completed in {(DateTime.UtcNow - startDownloadUtcTime).TotalSeconds:F2} seconds.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initiates the universe downloader using the provided configuration.
|
|
/// </summary>
|
|
/// <param name="dataDownloader">The data downloader instance.</param>
|
|
/// <param name="dataUniverseDownloadConfig">The universe download configuration.</param>
|
|
private static void RunUniverseDownloader(IDataDownloader dataDownloader, DataUniverseDownloadConfig dataUniverseDownloadConfig)
|
|
{
|
|
foreach (var symbol in dataUniverseDownloadConfig.Symbols)
|
|
{
|
|
var universeDownloadParameters = new DataUniverseDownloaderGetParameters(symbol, dataUniverseDownloadConfig.StartDate, dataUniverseDownloadConfig.EndDate);
|
|
UniverseExtensions.RunUniverseDownloader(dataDownloader, universeDownloadParameters);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the data time zone and exchange time zone associated with the specified symbol.
|
|
/// </summary>
|
|
/// <param name="symbol">The symbol for which to retrieve time zones.</param>
|
|
/// <returns>
|
|
/// A tuple containing the data time zone and exchange time zone.
|
|
/// The data time zone represents the time zone for data related to the symbol.
|
|
/// The exchange time zone represents the time zone for trading activities related to the symbol.
|
|
/// </returns>
|
|
private static (DateTimeZone dataTimeZone, DateTimeZone exchangeTimeZone) GetDataAndExchangeTimeZoneBySymbol(Symbol symbol)
|
|
{
|
|
var entry = _marketHoursDatabase.GetEntry(symbol.ID.Market, symbol, symbol.SecurityType);
|
|
return (entry.DataTimeZone, entry.ExchangeHours.TimeZone);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes various configurations for the application.
|
|
/// This method sets up logging, data providers, map file providers, and factor file providers.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The method reads configuration values to determine whether debugging is enabled,
|
|
/// which log handler to use, and which data, map file, and factor file providers to initialize.
|
|
/// </remarks>
|
|
/// <seealso cref="Log"/>
|
|
/// <seealso cref="Config"/>
|
|
/// <seealso cref="Composer"/>
|
|
/// <seealso cref="ILogHandler"/>
|
|
/// <seealso cref="IDataProvider"/>
|
|
/// <seealso cref="IMapFileProvider"/>
|
|
/// <seealso cref="IFactorFileProvider"/>
|
|
public static void InitializeConfigurations()
|
|
{
|
|
Log.DebuggingEnabled = Config.GetBool("debug-mode", false);
|
|
Log.LogHandler = Composer.Instance.GetExportedValueByTypeName<ILogHandler>(Config.Get("log-handler", "CompositeLogHandler"));
|
|
|
|
var dataProvider = Composer.Instance.GetExportedValueByTypeName<IDataProvider>("DefaultDataProvider");
|
|
var mapFileProvider = Composer.Instance.GetExportedValueByTypeName<IMapFileProvider>(Config.Get("map-file-provider", "LocalDiskMapFileProvider"));
|
|
var factorFileProvider = Composer.Instance.GetExportedValueByTypeName<IFactorFileProvider>(Config.Get("factor-file-provider", "LocalDiskFactorFileProvider"));
|
|
|
|
var optionChainProvider = Composer.Instance.GetPart<IOptionChainProvider>();
|
|
if (optionChainProvider == null)
|
|
{
|
|
var historyManager = Composer.Instance.GetExportedValueByTypeName<HistoryProviderManager>(nameof(HistoryProviderManager));
|
|
historyManager.Initialize(new HistoryProviderInitializeParameters(null, null, dataProvider, _dataCacheProvider,
|
|
mapFileProvider, factorFileProvider, _ => { }, false, new DataPermissionManager(), null, new AlgorithmSettings()));
|
|
var baseOptionChainProvider = new LiveOptionChainProvider();
|
|
baseOptionChainProvider.Initialize(new(mapFileProvider, historyManager));
|
|
optionChainProvider = new CachingOptionChainProvider(baseOptionChainProvider);
|
|
Composer.Instance.AddPart(optionChainProvider);
|
|
}
|
|
|
|
mapFileProvider.Initialize(dataProvider);
|
|
factorFileProvider.Initialize(mapFileProvider, dataProvider);
|
|
}
|
|
}
|