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
269 lines
12 KiB
C#
269 lines
12 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 System;
|
|
using QuantConnect.Util;
|
|
using QuantConnect.Logging;
|
|
using QuantConnect.Packets;
|
|
using QuantConnect.Algorithm;
|
|
using QuantConnect.Interfaces;
|
|
using QuantConnect.Configuration;
|
|
using System.Collections.Generic;
|
|
using QuantConnect.AlgorithmFactory;
|
|
using QuantConnect.Lean.Engine.DataFeeds;
|
|
using QuantConnect.Brokerages.Backtesting;
|
|
|
|
namespace QuantConnect.Lean.Engine.Setup
|
|
{
|
|
/// <summary>
|
|
/// Backtesting setup handler processes the algorithm initialize method and sets up the internal state of the algorithm class.
|
|
/// </summary>
|
|
public class BacktestingSetupHandler : ISetupHandler
|
|
{
|
|
/// <summary>
|
|
/// The worker thread instance the setup handler should use
|
|
/// </summary>
|
|
public WorkerThread WorkerThread { get; set; }
|
|
|
|
/// <summary>
|
|
/// Internal errors list from running the setup procedures.
|
|
/// </summary>
|
|
public List<Exception> Errors { get; set; }
|
|
|
|
/// <summary>
|
|
/// Maximum runtime of the algorithm in seconds.
|
|
/// </summary>
|
|
/// <remarks>Maximum runtime is a formula based on the number and resolution of symbols requested, and the days backtesting</remarks>
|
|
public TimeSpan MaximumRuntime { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Starting capital according to the users initialize routine.
|
|
/// </summary>
|
|
/// <remarks>Set from the user code.</remarks>
|
|
/// <seealso cref="QCAlgorithm.SetCash(decimal)"/>
|
|
public decimal StartingPortfolioValue { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Start date for analysis loops to search for data.
|
|
/// </summary>
|
|
/// <seealso cref="QCAlgorithm.SetStartDate(DateTime)"/>
|
|
public DateTime StartingDate { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Maximum number of orders for this backtest.
|
|
/// </summary>
|
|
/// <remarks>To stop algorithm flooding the backtesting system with hundreds of megabytes of order data we limit it to 100 per day</remarks>
|
|
public int MaxOrders { get; protected set; }
|
|
|
|
/// <summary>
|
|
/// Initialize the backtest setup handler.
|
|
/// </summary>
|
|
public BacktestingSetupHandler()
|
|
{
|
|
MaximumRuntime = TimeSpan.FromSeconds(300);
|
|
Errors = new List<Exception>();
|
|
StartingDate = new DateTime(1998, 01, 01);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create a new instance of an algorithm from a physical dll path.
|
|
/// </summary>
|
|
/// <param name="assemblyPath">The path to the assembly's location</param>
|
|
/// <param name="algorithmNodePacket">Details of the task required</param>
|
|
/// <returns>A new instance of IAlgorithm, or throws an exception if there was an error</returns>
|
|
public virtual IAlgorithm CreateAlgorithmInstance(AlgorithmNodePacket algorithmNodePacket, string assemblyPath)
|
|
{
|
|
string error;
|
|
IAlgorithm algorithm;
|
|
|
|
var debugNode = algorithmNodePacket as BacktestNodePacket;
|
|
var debugging = debugNode != null && debugNode.Debugging || Config.GetBool("debugging", false);
|
|
|
|
if (debugging && !BaseSetupHandler.InitializeDebugging(algorithmNodePacket, WorkerThread))
|
|
{
|
|
throw new AlgorithmSetupException("Failed to initialize debugging");
|
|
}
|
|
|
|
// Limit load times to 90 seconds and force the assembly to have exactly one derived type
|
|
var loader = new Loader(debugging, algorithmNodePacket.Language, BaseSetupHandler.AlgorithmCreationTimeout, names => names.SingleOrAlgorithmTypeName(Config.Get("algorithm-type-name", algorithmNodePacket.AlgorithmId)), WorkerThread);
|
|
var complete = loader.TryCreateAlgorithmInstanceWithIsolator(assemblyPath, algorithmNodePacket.RamAllocation, out algorithm, out error);
|
|
if (!complete) throw new AlgorithmSetupException($"During the algorithm initialization, the following exception has occurred: {error}");
|
|
|
|
return algorithm;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new <see cref="BacktestingBrokerage"/> instance
|
|
/// </summary>
|
|
/// <param name="algorithmNodePacket">Job packet</param>
|
|
/// <param name="uninitializedAlgorithm">The algorithm instance before Initialize has been called</param>
|
|
/// <param name="factory">The brokerage factory</param>
|
|
/// <returns>The brokerage instance, or throws if error creating instance</returns>
|
|
public virtual IBrokerage CreateBrokerage(AlgorithmNodePacket algorithmNodePacket, IAlgorithm uninitializedAlgorithm, out IBrokerageFactory factory)
|
|
{
|
|
factory = new BacktestingBrokerageFactory();
|
|
return new BacktestingBrokerage(uninitializedAlgorithm);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Setup the algorithm cash, dates and data subscriptions as desired.
|
|
/// </summary>
|
|
/// <param name="parameters">The parameters object to use</param>
|
|
/// <returns>Boolean true on successfully initializing the algorithm</returns>
|
|
public bool Setup(SetupHandlerParameters parameters)
|
|
{
|
|
var algorithm = parameters.Algorithm;
|
|
var job = parameters.AlgorithmNodePacket as BacktestNodePacket;
|
|
if (job == null)
|
|
{
|
|
throw new ArgumentException("Expected BacktestNodePacket but received " + parameters.AlgorithmNodePacket.GetType().Name);
|
|
}
|
|
|
|
BaseSetupHandler.Setup(parameters);
|
|
|
|
if (algorithm == null)
|
|
{
|
|
Errors.Add(new AlgorithmSetupException("Could not create instance of algorithm"));
|
|
return false;
|
|
}
|
|
|
|
algorithm.Name = job.Name;
|
|
|
|
//Make sure the algorithm start date ok.
|
|
if (job.PeriodStart == default(DateTime))
|
|
{
|
|
Errors.Add(new AlgorithmSetupException("Algorithm start date was never set"));
|
|
return false;
|
|
}
|
|
|
|
var controls = job.Controls;
|
|
var isolator = new Isolator();
|
|
var initializeComplete = isolator.ExecuteWithTimeLimit(TimeSpan.FromMinutes(5), () =>
|
|
{
|
|
try
|
|
{
|
|
parameters.ResultHandler.SendStatusUpdate(AlgorithmStatus.Initializing, "Initializing algorithm...");
|
|
//Set our parameters
|
|
algorithm.SetParameters(job.Parameters);
|
|
algorithm.SetAvailableDataTypes(BaseSetupHandler.GetConfiguredDataFeeds());
|
|
|
|
//Algorithm is backtesting, not live:
|
|
algorithm.SetAlgorithmMode(job.AlgorithmMode);
|
|
|
|
//Set the source impl for the event scheduling
|
|
algorithm.Schedule.SetEventSchedule(parameters.RealTimeHandler);
|
|
|
|
// set the option chain provider
|
|
var optionChainProvider = new BacktestingOptionChainProvider();
|
|
var initParameters = new ChainProviderInitializeParameters(parameters.MapFileProvider, algorithm.HistoryProvider);
|
|
optionChainProvider.Initialize(initParameters);
|
|
algorithm.SetOptionChainProvider(new CachingOptionChainProvider(optionChainProvider));
|
|
|
|
// set the future chain provider
|
|
var futureChainProvider = new BacktestingFutureChainProvider();
|
|
futureChainProvider.Initialize(initParameters);
|
|
algorithm.SetFutureChainProvider(new CachingFutureChainProvider(futureChainProvider));
|
|
|
|
// before we call initialize
|
|
BaseSetupHandler.LoadBacktestJobAccountCurrency(algorithm, job);
|
|
|
|
//Initialise the algorithm, get the required data:
|
|
algorithm.Initialize();
|
|
|
|
// set start and end date if present in the job
|
|
if (job.PeriodStart.HasValue)
|
|
{
|
|
algorithm.SetStartDate(job.PeriodStart.Value);
|
|
}
|
|
if (job.PeriodFinish.HasValue)
|
|
{
|
|
algorithm.SetEndDate(job.PeriodFinish.Value);
|
|
}
|
|
|
|
if(job.OutOfSampleMaxEndDate.HasValue)
|
|
{
|
|
if(algorithm.EndDate > job.OutOfSampleMaxEndDate.Value)
|
|
{
|
|
Log.Trace($"BacktestingSetupHandler.Setup(): setting end date to {job.OutOfSampleMaxEndDate.Value:yyyyMMdd}");
|
|
algorithm.SetEndDate(job.OutOfSampleMaxEndDate.Value);
|
|
|
|
if (algorithm.StartDate > algorithm.EndDate)
|
|
{
|
|
algorithm.SetStartDate(algorithm.EndDate);
|
|
}
|
|
}
|
|
}
|
|
|
|
// after we call initialize
|
|
BaseSetupHandler.LoadBacktestJobCashAmount(algorithm, job);
|
|
|
|
// after algorithm was initialized, should set trading days per year for our great portfolio statistics
|
|
BaseSetupHandler.SetBrokerageTradingDayPerYear(algorithm);
|
|
|
|
// finalize initialization
|
|
algorithm.PostInitialize();
|
|
}
|
|
catch (Exception err)
|
|
{
|
|
Errors.Add(new AlgorithmSetupException("During the algorithm initialization, the following exception has occurred: ", err));
|
|
}
|
|
}, controls.RamAllocation,
|
|
sleepIntervalMillis: 100, // entire system is waiting on this, so be as fast as possible
|
|
workerThread: WorkerThread);
|
|
|
|
if (Errors.Count > 0)
|
|
{
|
|
// if we already got an error just exit right away
|
|
return false;
|
|
}
|
|
|
|
//Before continuing, detect if this is ready:
|
|
if (!initializeComplete) return false;
|
|
|
|
MaximumRuntime = TimeSpan.FromMinutes(job.Controls.MaximumRuntimeMinutes);
|
|
|
|
BaseSetupHandler.SetupCurrencyConversions(algorithm, parameters.UniverseSelection);
|
|
StartingPortfolioValue = algorithm.Portfolio.Cash;
|
|
|
|
// Get and set maximum orders for this job
|
|
MaxOrders = job.Controls.BacktestingMaxOrders;
|
|
algorithm.SetMaximumOrders(MaxOrders);
|
|
|
|
//Starting date of the algorithm:
|
|
StartingDate = algorithm.StartDate;
|
|
|
|
//Put into log for debugging:
|
|
Log.Trace("SetUp Backtesting: User: " + job.UserId + " ProjectId: " + job.ProjectId + " AlgoId: " + job.AlgorithmId);
|
|
Log.Trace($"Dates: Start: {algorithm.StartDate.ToStringInvariant("d")} " +
|
|
$"End: {algorithm.EndDate.ToStringInvariant("d")} " +
|
|
$"Cash: {StartingPortfolioValue.ToStringInvariant("C")} " +
|
|
$"MaximumRuntime: {MaximumRuntime} " +
|
|
$"MaxOrders: {MaxOrders}");
|
|
|
|
return initializeComplete;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
/// </summary>
|
|
/// <filterpriority>2</filterpriority>
|
|
public void Dispose()
|
|
{
|
|
}
|
|
} // End Result Handler Thread:
|
|
|
|
} // End Namespace
|