/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals, V0.1 * Created by Jared Broad */ /********************************************************** * USING NAMESPACES **********************************************************/ using System; using System.Collections.Generic; using System.Linq; using QuantConnect.AlgorithmFactory; using QuantConnect.Brokerages; using QuantConnect.Configuration; using QuantConnect.Interfaces; using QuantConnect.Lean.Engine.Results; using QuantConnect.Logging; using QuantConnect.Packets; namespace QuantConnect.Lean.Engine.Setup { /// /// Console setup handler to initialize and setup the Lean Engine properties for a local backtest /// public class ConsoleSetupHandler : ISetupHandler { /******************************************************** * PUBLIC PROPERTIES *********************************************************/ /// /// Error which occured during setup may appear here. /// public List Errors { get; set; } /// /// Maximum runtime of the strategy. (Set to 10 years for local backtesting). /// public TimeSpan MaximumRuntime { get; private set; } /// /// Starting capital for the algorithm (Loaded from the algorithm code). /// public decimal StartingCapital { get; private set; } /// /// Start date for the backtest. /// public DateTime StartingDate { get; private set; } /// /// Maximum number of orders for this backtest. /// public int MaxOrders { get; private set; } /******************************************************** * PUBLIC CONSTRUCTOR *********************************************************/ /// /// Setup the algorithm data, cash, job start end date etc: /// public ConsoleSetupHandler() { MaxOrders = int.MaxValue; StartingCapital = 0; StartingDate = new DateTime(1998, 01, 01); MaximumRuntime = TimeSpan.FromDays(10 * 365); Errors = new List(); } /******************************************************** * PUBLIC METHODS *********************************************************/ /// /// Creates a new algorithm instance. Checks configuration for a specific type name, and if present will /// force it to find that one /// /// Physical path of the algorithm dll. /// Algorithm instance public IAlgorithm CreateAlgorithmInstance(string assemblyPath) { string error; IAlgorithm algorithm; var algorithmName = Config.Get("algorithm-type-name"); // don't force load times to be fast here since we're running locally, this allows us to debug // and step through some code that may take us longer than the default 10 seconds var loader = new Loader(TimeSpan.FromHours(1), names => names.Single(name => MatchTypeName(name, algorithmName))); var complete = loader.TryCreateAlgorithmInstanceWithIsolator(assemblyPath, out algorithm, out error); if (!complete) throw new Exception(error + ": try re-building algorithm."); return algorithm; } /// /// Setup the algorithm cash, dates and portfolio as desired. /// /// Existing algorithm instance /// New brokerage instance /// Backtesting job /// Boolean true on successfully setting up the console. public bool Setup(IAlgorithm algorithm, out IBrokerage brokerage, AlgorithmNodePacket baseJob) { var initializeComplete = false; brokerage = new Brokerage(); //Error case. try { //Set common variables for console programs: if (baseJob.Type == PacketType.BacktestNode) { var backtestJob = baseJob as BacktestNodePacket; //Setup Base Algorithm: algorithm.Initialize(); //Construct the backtest job packet: backtestJob.PeriodStart = algorithm.StartDate; backtestJob.PeriodFinish = algorithm.EndDate; backtestJob.BacktestId = "LOCALHOST"; backtestJob.UserId = 1001; backtestJob.Type = PacketType.BacktestNode; //Endpoints: backtestJob.TransactionEndpoint = TransactionHandlerEndpoint.Backtesting; backtestJob.ResultEndpoint = ResultHandlerEndpoint.Console; backtestJob.DataEndpoint = DataFeedEndpoint.FileSystem; backtestJob.RealTimeEndpoint = RealTimeEndpoint.Backtesting; backtestJob.SetupEndpoint = SetupHandlerEndpoint.Console; //Backtest Specific Parameters: StartingDate = backtestJob.PeriodStart; StartingCapital = algorithm.Portfolio.Cash; baseJob = backtestJob; } else { var liveJob = baseJob as LiveNodePacket; //Live Job Parameters: liveJob.UserId = 1001; liveJob.DeployId = "LOCALHOST"; liveJob.IssuedAt = DateTime.Now.Subtract(TimeSpan.FromSeconds(86399 - 60)); //For testing, first access token expires in 60 sec. refresh. liveJob.LifeTime = TimeSpan.FromSeconds(86399); liveJob.AccessToken = "123456"; liveJob.AccountId = 123456; liveJob.RefreshToken = ""; liveJob.Type = PacketType.LiveNode; //Endpoints: liveJob.TransactionEndpoint = TransactionHandlerEndpoint.Tradier; liveJob.ResultEndpoint = ResultHandlerEndpoint.LiveTrading; liveJob.DataEndpoint = DataFeedEndpoint.Tradier; liveJob.RealTimeEndpoint = RealTimeEndpoint.LiveTrading; liveJob.SetupEndpoint = SetupHandlerEndpoint.Console; //Call in the tradier setup: var setup = new TradierSetupHandler(); setup.Setup(algorithm, out brokerage, baseJob); //Live Specific Parameters: StartingDate = DateTime.Now; StartingCapital = algorithm.Portfolio.Cash; baseJob = liveJob; } } catch (Exception err) { Log.Error("ConsoleSetupHandler().Setup(): " + err.Message); } if (Errors.Count == 0) { initializeComplete = true; } return initializeComplete; } /// /// Error handlers in event of a brokerage error. /// /// Result handler for sending results on error. /// Brokerage instance /// Not used for local setup. /// Boolean true on successfully setting up local algorithm public bool SetupErrorHandler(IResultHandler results, IBrokerage brokerage) { return true; } /// /// Matches type names as namespace qualified or just the name /// If expectedTypeName is null or empty, this will always return true /// /// /// /// True on matching the type name private static bool MatchTypeName(string currentTypeFullName, string expectedTypeName) { if (string.IsNullOrEmpty(expectedTypeName)) { return true; } return currentTypeFullName == expectedTypeName || currentTypeFullName.Substring(currentTypeFullName.LastIndexOf('.') + 1) == expectedTypeName; } } // End Result Handler Thread: } // End Namespace