/* * 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.Collections.Generic; using System.Linq; using System.Linq.Expressions; using NodaTime; using NodaTime.TimeZones; using QuantConnect.Benchmarks; using QuantConnect.Brokerages; using QuantConnect.Data; using QuantConnect.Data.Auxiliary; using QuantConnect.Data.UniverseSelection; using QuantConnect.Indicators; using QuantConnect.Interfaces; using QuantConnect.Notifications; using QuantConnect.Orders; using QuantConnect.Parameters; using QuantConnect.Scheduling; using QuantConnect.Securities; using QuantConnect.Securities.Cfd; using QuantConnect.Securities.Equity; using QuantConnect.Securities.Forex; using QuantConnect.Securities.Option; using QuantConnect.Statistics; using QuantConnect.Util; using SecurityTypeMarket = System.Tuple; namespace QuantConnect.Algorithm { /// /// QC Algorithm Base Class - Handle the basic requirements of a trading algorithm, /// allowing user to focus on event methods. The QCAlgorithm class implements Portfolio, /// Securities, Transactions and Data Subscription Management. /// public partial class QCAlgorithm : MarshalByRefObject, IAlgorithm { private readonly TimeKeeper _timeKeeper; private LocalTimeKeeper _localTimeKeeper; private DateTime _startDate; //Default start and end dates. private DateTime _endDate; //Default end to yesterday private RunMode _runMode = RunMode.Series; private bool _locked; private bool _liveMode; private string _algorithmId = ""; private List _debugMessages = new List(); private List _logMessages = new List(); private List _errorMessages = new List(); //Error tracking to avoid message flooding: private string _previousDebugMessage = ""; private string _previousErrorMessage = ""; private bool _sentNoDataError = false; private readonly MarketHoursDatabase _marketHoursDatabase; private readonly SymbolPropertiesDatabase _symbolPropertiesDatabase; // used for calling through to void OnData(Slice) if no override specified private bool _checkedForOnDataSlice; private Action _onDataSlice; // set by SetBenchmark helper API functions private Symbol _benchmarkSymbol = QuantConnect.Symbol.Empty; // flips to true when the user private bool _userSetSecurityInitializer = false; // warmup resolution variables private TimeSpan? _warmupTimeSpan; private int? _warmupBarCount; private Dictionary _parameters = new Dictionary(); /// /// QCAlgorithm Base Class Constructor - Initialize the underlying QCAlgorithm components. /// QCAlgorithm manages the transactions, portfolio, charting and security subscriptions for the users algorithms. /// public QCAlgorithm() { Status = AlgorithmStatus.Running; // AlgorithmManager will flip this when we're caught up with realtime IsWarmingUp = true; //Initialise the Algorithm Helper Classes: //- Note - ideally these wouldn't be here, but because of the DLL we need to make the classes shared across // the Worker & Algorithm, limiting ability to do anything else. //Initialise Start and End Dates: _startDate = new DateTime(1998, 01, 01); _endDate = DateTime.Now.AddDays(-1); // intialize our time keeper with only new york _timeKeeper = new TimeKeeper(_startDate, new[] { TimeZones.NewYork }); // set our local time zone _localTimeKeeper = _timeKeeper.GetLocalTimeKeeper(TimeZones.NewYork); //Initialise Data Manager SubscriptionManager = new SubscriptionManager(_timeKeeper); Securities = new SecurityManager(_timeKeeper); Transactions = new SecurityTransactionManager(Securities); Portfolio = new SecurityPortfolioManager(Securities, Transactions); BrokerageModel = new DefaultBrokerageModel(); Notify = new NotificationManager(false); // Notification manager defaults to disabled. //Initialise Algorithm RunMode to Series - Parallel Mode deprecated: _runMode = RunMode.Series; //Initialise to unlocked: _locked = false; // get exchange hours loaded from the market-hours-database.csv in /Data/market-hours _marketHoursDatabase = MarketHoursDatabase.FromDataFolder(); // get symbol properties loaded from the symbol-properties-database.csv in /Data/symbol-properties _symbolPropertiesDatabase = SymbolPropertiesDatabase.FromDataFolder(); // universe selection UniverseManager = new UniverseManager(); Universe = new UniverseDefinitions(this); UniverseSettings = new UniverseSettings(Resolution.Minute, 2m, true, false, TimeSpan.FromDays(1)); // initialize our scheduler, this acts as a liason to the real time handler Schedule = new ScheduleManager(Securities, TimeZone); // initialize the trade builder TradeBuilder = new TradeBuilder(FillGroupingMethod.FillToFill, FillMatchingMethod.FIFO); SecurityInitializer = new BrokerageModelSecurityInitializer(new DefaultBrokerageModel(AccountType.Margin)); CandlestickPatterns = new CandlestickPatterns(this); } /// /// Security collection is an array of the security objects such as Equities and FOREX. Securities data /// manages the properties of tradeable assets such as price, open and close time and holdings information. /// public SecurityManager Securities { get; set; } /// /// Portfolio object provieds easy access to the underlying security-holding properties; summed together in a way to make them useful. /// This saves the user time by providing common portfolio requests in a single /// public SecurityPortfolioManager Portfolio { get; set; } /// /// Generic Data Manager - Required for compiling all data feeds in order, and passing them into algorithm event methods. /// The subscription manager contains a list of the data feed's we're subscribed to and properties of each data feed. /// public SubscriptionManager SubscriptionManager { get; set; } /// /// Gets the brokerage model - used to model interactions with specific brokerages. /// public IBrokerageModel BrokerageModel { get; private set; } /// /// Gets the brokerage message handler used to decide what to do /// with each message sent from the brokerage /// public IBrokerageMessageHandler BrokerageMessageHandler { get; set; } /// /// Notification Manager for Sending Live Runtime Notifications to users about important events. /// public NotificationManager Notify { get; set; } /// /// Gets schedule manager for adding/removing scheduled events /// public ScheduleManager Schedule { get; private set; } /// /// Gets or sets the current status of the algorithm /// public AlgorithmStatus Status { get; set; } /// /// Gets an instance that is to be used to initialize newly created securities. /// public ISecurityInitializer SecurityInitializer { get; private set; } /// /// Gets the Trade Builder to generate trades from executions /// public TradeBuilder TradeBuilder { get; private set; } /// /// Gets an instance to access the candlestick pattern helper methods /// public CandlestickPatterns CandlestickPatterns { get; private set; } /// /// Gets the date rules helper object to make specifying dates for events easier /// public DateRules DateRules { get { return Schedule.DateRules; } } /// /// Gets the time rules helper object to make specifying times for events easier /// public TimeRules TimeRules { get { return Schedule.TimeRules; } } /// /// Public name for the algorithm as automatically generated by the IDE. Intended for helping distinguish logs by noting /// the algorithm-id. /// /// public string Name { get; set; } /// /// Read-only value for current time frontier of the algorithm in terms of the /// /// During backtesting this is primarily sourced from the data feed. During live trading the time is updated from the system clock. public DateTime Time { get { return _localTimeKeeper.LocalTime; } } /// /// Current date/time in UTC. /// public DateTime UtcTime { get { return _timeKeeper.UtcTime; } } /// /// Gets the time zone used for the property. The default value /// is /// public DateTimeZone TimeZone { get { return _localTimeKeeper.TimeZone; } } /// /// Value of the user set start-date from the backtest. /// /// This property is set with SetStartDate() and defaults to the earliest QuantConnect data available - Jan 1st 1998. It is ignored during live trading /// public DateTime StartDate { get { return _startDate; } } /// /// Value of the user set start-date from the backtest. Controls the period of the backtest. /// /// This property is set with SetEndDate() and defaults to today. It is ignored during live trading. /// public DateTime EndDate { get { return _endDate; } } /// /// Algorithm Id for this backtest or live algorithm. /// /// A unique identifier for public string AlgorithmId { get { return _algorithmId; } } /// /// Control the server setup run style for the backtest: Automatic, Parallel or Series. /// /// /// Series mode runs all days through one computer, allowing memory of the previous days. /// Parallel mode runs all days separately which maximises speed but gives no memory of a previous day trading. /// /// The RunMode enum propert is now obsolete. All algorithms will default to RunMode.Series for series backtests. [Obsolete("The RunMode enum propert is now obsolete. All algorithms will default to RunMode.Series for series backtests.")] public RunMode RunMode { get { return _runMode; } } /// /// Boolean property indicating the algorithm is currently running in live mode. /// /// Intended for use where certain behaviors will be enabled while the algorithm is trading live: such as notification emails, or displaying runtime statistics. public bool LiveMode { get { return _liveMode; } } /// /// Storage for debugging messages before the event handler has passed control back to the Lean Engine. /// /// public List DebugMessages { get { return _debugMessages; } set { _debugMessages = value; } } /// /// Storage for log messages before the event handlers have passed control back to the Lean Engine. /// /// public List LogMessages { get { return _logMessages; } set { _logMessages = value; } } /// /// Gets the run time error from the algorithm, or null if none was encountered. /// public Exception RunTimeError { get; set; } /// /// List of error messages generated by the user's code calling the "Error" function. /// /// This method is best used within a try-catch bracket to handle any runtime errors from a user algorithm. /// public List ErrorMessages { get { return _errorMessages; } set { _errorMessages = value; } } /// /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized. /// /// /// /// public virtual void Initialize() { //Setup Required Data throw new NotImplementedException("Please override the Initialize() method"); } /// /// Called by setup handlers after Initialize and allows the algorithm a chance to organize /// the data gather in the Initialize method /// public void PostInitialize() { // if the benchmark hasn't been set yet, set it if (Benchmark == null) { // apply the default benchmark if it hasn't been set if (_benchmarkSymbol == null || _benchmarkSymbol == QuantConnect.Symbol.Empty) { _benchmarkSymbol = QuantConnect.Symbol.Create("SPY", SecurityType.Equity, Market.USA); } // if the requested benchmark symbol wasn't already added, then add it now // we do a simple compare here for simplicity, also it avoids confusion over // the desired market. Security security; if (!Securities.TryGetValue(_benchmarkSymbol, out security)) { // add the security as an internal feed so the algorithm doesn't receive the data Resolution resolution; if (_liveMode) { resolution = Resolution.Second; } else { // check to see if any universes arn't the ones added via AddSecurity var hasNonAddSecurityUniverses = ( from kvp in UniverseManager let config = kvp.Value.Configuration let symbol = UserDefinedUniverse.CreateSymbol(config.SecurityType, config.Market) where config.Symbol != symbol select kvp).Any(); resolution = hasNonAddSecurityUniverses ? UniverseSettings.Resolution : Resolution.Daily; } security = SecurityManager.CreateSecurity(Portfolio, SubscriptionManager, _marketHoursDatabase, _symbolPropertiesDatabase, SecurityInitializer, _benchmarkSymbol, resolution, true, 1m, false, true, false); AddToUserDefinedUniverse(security); } // just return the current price Benchmark = new SecurityBenchmark(security); } // add option underlying securities if not present foreach (var option in Securities.Select(x => x.Value).OfType