Lean  $LEAN_TAG$
QCAlgorithm.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using System.Collections.Generic;
18 using System.Linq;
19 using System.Linq.Expressions;
20 using System.Globalization;
21 using NodaTime;
22 using NodaTime.TimeZones;
25 using QuantConnect.Data;
29 using QuantConnect.Orders;
39 using QuantConnect.Util;
42 using System.Collections.Concurrent;
51 using QuantConnect.Storage;
52 using Index = QuantConnect.Securities.Index.Index;
56 using Python.Runtime;
58 using Newtonsoft.Json;
59 
60 namespace QuantConnect.Algorithm
61 {
62  /// <summary>
63  /// QC Algorithm Base Class - Handle the basic requirements of a trading algorithm,
64  /// allowing user to focus on event methods. The QCAlgorithm class implements Portfolio,
65  /// Securities, Transactions and Data Subscription Management.
66  /// </summary>
67  public partial class QCAlgorithm : MarshalByRefObject, IAlgorithm
68  {
69  #region Documentation Attribute Categories
70  const string AddingData = "Adding Data";
71  const string AlgorithmFramework = "Algorithm Framework";
72  const string Charting = "Charting";
73  const string ConsolidatingData = "Consolidating Data";
74  const string HandlingData = "Handling Data";
75  const string HistoricalData = "Historical Data";
76  const string Indicators = "Indicators";
77  const string LiveTrading = "Live Trading";
78  const string Logging = "Logging";
79  const string MachineLearning = "Machine Learning";
80  const string Modeling = "Modeling";
81  const string ParameterAndOptimization = "Parameter and Optimization";
82  const string ScheduledEvents = "Scheduled Events";
83  const string SecuritiesAndPortfolio = "Securities and Portfolio";
84  const string TradingAndOrders = "Trading and Orders";
85  const string Universes = "Universes";
86  const string StatisticsTag = "Statistics";
87  #endregion
88 
89  /// <summary>
90  /// Maximum length of the name or tags of a backtest
91  /// </summary>
92  protected const int MaxNameAndTagsLength = 200;
93 
94  /// <summary>
95  /// Maximum number of tags allowed for a backtest
96  /// </summary>
97  protected const int MaxTagsCount = 100;
98 
99  private readonly TimeKeeper _timeKeeper;
100  private LocalTimeKeeper _localTimeKeeper;
101 
102  private string _name;
103  private HashSet<string> _tags;
104  private bool _tagsLimitReachedLogSent;
105  private bool _tagsCollectionTruncatedLogSent;
106  private DateTime _start;
107  private DateTime _startDate; //Default start and end dates.
108  private DateTime _endDate; //Default end to yesterday
109  private bool _locked;
110  private bool _liveMode;
111  private AlgorithmMode _algorithmMode;
112  private DeploymentTarget _deploymentTarget;
113  private string _algorithmId = "";
114  private ConcurrentQueue<string> _debugMessages = new ConcurrentQueue<string>();
115  private ConcurrentQueue<string> _logMessages = new ConcurrentQueue<string>();
116  private ConcurrentQueue<string> _errorMessages = new ConcurrentQueue<string>();
117  private IStatisticsService _statisticsService;
118  private IBrokerageModel _brokerageModel;
119 
120  private readonly HashSet<string> _oneTimeCommandErrors = new();
121  private readonly Dictionary<string, Func<CallbackCommand, bool?>> _registeredCommands = new(StringComparer.InvariantCultureIgnoreCase);
122 
123  //Error tracking to avoid message flooding:
124  private string _previousDebugMessage = "";
125  private string _previousErrorMessage = "";
126 
127  /// <summary>
128  /// Gets the market hours database in use by this algorithm
129  /// </summary>
131 
132  /// <summary>
133  /// Gets the symbol properties database in use by this algorithm
134  /// </summary>
136 
137  // used for calling through to void OnData(Slice) if no override specified
138  private bool _checkedForOnDataSlice;
139  private Action<Slice> _onDataSlice;
140 
141  // flips to true when the user
142  private bool _userSetSecurityInitializer;
143 
144  // warmup resolution variables
145  private TimeSpan? _warmupTimeSpan;
146  private int? _warmupBarCount;
147  private Dictionary<string, string> _parameters = new Dictionary<string, string>();
148  private SecurityDefinitionSymbolResolver _securityDefinitionSymbolResolver;
149 
150  private readonly HistoryRequestFactory _historyRequestFactory;
151 
152  private IApi _api;
153 
154  /// <summary>
155  /// QCAlgorithm Base Class Constructor - Initialize the underlying QCAlgorithm components.
156  /// QCAlgorithm manages the transactions, portfolio, charting and security subscriptions for the users algorithms.
157  /// </summary>
158  public QCAlgorithm()
159  {
160  Name = GetType().Name;
161  Tags = new();
162  Status = AlgorithmStatus.Running;
163 
164  // AlgorithmManager will flip this when we're caught up with realtime
165  IsWarmingUp = true;
166 
167  //Initialise the Algorithm Helper Classes:
168  //- Note - ideally these wouldn't be here, but because of the DLL we need to make the classes shared across
169  // the Worker & Algorithm, limiting ability to do anything else.
170 
171  //Initialise Start Date:
172  _startDate = new DateTime(1998, 01, 01);
173  // intialize our time keeper with only new york
174  _timeKeeper = new TimeKeeper(_startDate, new[] { TimeZones.NewYork });
175  // set our local time zone
176  _localTimeKeeper = _timeKeeper.GetLocalTimeKeeper(TimeZones.NewYork);
177  //Initialise End Date:
178  SetEndDate(DateTime.UtcNow.ConvertFromUtc(TimeZone));
179 
180  // Set default algorithm mode as backtesting
181  _algorithmMode = AlgorithmMode.Backtesting;
182 
183  // Set default deployment target as local
184  _deploymentTarget = DeploymentTarget.LocalPlatform;
185 
186  _securityDefinitionSymbolResolver = SecurityDefinitionSymbolResolver.GetInstance();
187 
188  Settings = new AlgorithmSettings();
190 
191  //Initialise Data Manager
192  SubscriptionManager = new SubscriptionManager(_timeKeeper);
193 
194  Securities = new SecurityManager(_timeKeeper);
197  SignalExport = new SignalExportManager(this);
198 
201  Notify = new NotificationManager(false); // Notification manager defaults to disabled.
202 
203  //Initialise to unlocked:
204  _locked = false;
205 
206  // get exchange hours loaded from the market-hours-database.csv in /Data/market-hours
209 
210  // universe selection
212  Universe = new UniverseDefinitions(this);
213  UniverseSettings = new UniverseSettings(Resolution.Minute, Security.NullLeverage, true, false, TimeSpan.FromDays(1));
214 
215  // initialize our scheduler, this acts as a liason to the real time handler
217 
218  // initialize the trade builder
220 
222 
224 
225  // initialize trading calendar
227 
230  _historyRequestFactory = new HistoryRequestFactory(this);
231 
232  // set model defaults, universe selection set via PostInitialize
233  SetAlpha(new NullAlphaModel());
238 
239  Insights = new InsightManager(this);
240  }
241 
242  /// <summary>
243  /// Event fired when the algorithm generates insights
244  /// </summary>
245  [DocumentationAttribute(AlgorithmFramework)]
246  public event AlgorithmEvent<GeneratedInsightsCollection> InsightsGenerated;
247 
248  /// <summary>
249  /// Security collection is an array of the security objects such as Equities and FOREX. Securities data
250  /// manages the properties of tradeable assets such as price, open and close time and holdings information.
251  /// </summary>
252  [DocumentationAttribute(SecuritiesAndPortfolio)]
254  {
255  get;
256  set;
257  }
258 
259  /// <summary>
260  /// Read-only dictionary containing all active securities. An active security is
261  /// a security that is currently selected by the universe or has holdings or open orders.
262  /// </summary>
263  [DocumentationAttribute(SecuritiesAndPortfolio)]
264  public IReadOnlyDictionary<Symbol, Security> ActiveSecurities => UniverseManager.ActiveSecurities;
265 
266  /// <summary>
267  /// Portfolio object provieds easy access to the underlying security-holding properties; summed together in a way to make them useful.
268  /// This saves the user time by providing common portfolio requests in a single
269  /// </summary>
270  [DocumentationAttribute(SecuritiesAndPortfolio)]
272  {
273  get;
274  set;
275  }
276 
277  /// <summary>
278  /// Gets the account currency
279  /// </summary>
280  [DocumentationAttribute(SecuritiesAndPortfolio)]
282 
283  /// <summary>
284  /// Gets the time keeper instance
285  /// </summary>
286  public ITimeKeeper TimeKeeper => _timeKeeper;
287 
288  /// <summary>
289  /// Generic Data Manager - Required for compiling all data feeds in order, and passing them into algorithm event methods.
290  /// The subscription manager contains a list of the data feed's we're subscribed to and properties of each data feed.
291  /// </summary>
292  [DocumentationAttribute(HandlingData)]
294  {
295  get;
296  set;
297  }
298 
299  /// <summary>
300  /// SignalExport - Allows sending export signals to different 3rd party API's. For example, it allows to send signals
301  /// to Collective2, CrunchDAO and Numerai API's
302  /// </summary>
303  [DocumentationAttribute(SecuritiesAndPortfolio)]
305  {
306  get;
307  }
308 
309  /// <summary>
310  /// The project id associated with this algorithm if any
311  /// </summary>
312  public int ProjectId
313  {
314  get;
315  set;
316  }
317 
318  /// <summary>
319  /// Gets the brokerage model - used to model interactions with specific brokerages.
320  /// </summary>
321  [DocumentationAttribute(Modeling)]
323  {
324  get
325  {
326  return _brokerageModel;
327  }
328  private set
329  {
330  _brokerageModel = value;
331  try
332  {
333  BrokerageName = Brokerages.BrokerageModel.GetBrokerageName(_brokerageModel);
334  }
335  catch (ArgumentOutOfRangeException)
336  {
337  // The brokerage model might be a custom one which has not a corresponding BrokerageName
338  BrokerageName = BrokerageName.Default;
339  }
340  }
341  }
342 
343  /// <summary>
344  /// Gets the brokerage name.
345  /// </summary>
346  [DocumentationAttribute(Modeling)]
348  {
349  get;
350  private set;
351  }
352 
353  /// <summary>
354  /// Gets the brokerage message handler used to decide what to do
355  /// with each message sent from the brokerage
356  /// </summary>
357  [DocumentationAttribute(Modeling)]
359  {
360  get;
361  set;
362  }
363 
364  /// <summary>
365  /// Gets the risk free interest rate model used to get the interest rates
366  /// </summary>
367  [DocumentationAttribute(Modeling)]
369  {
370  get;
371  private set;
372  }
373 
374  /// <summary>
375  /// Notification Manager for Sending Live Runtime Notifications to users about important events.
376  /// </summary>
377  [DocumentationAttribute(LiveTrading)]
379  {
380  get;
381  set;
382  }
383 
384  /// <summary>
385  /// Gets schedule manager for adding/removing scheduled events
386  /// </summary>
387  [DocumentationAttribute(ScheduledEvents)]
389  {
390  get;
391  private set;
392  }
393 
394  /// <summary>
395  /// Gets or sets the current status of the algorithm
396  /// </summary>
397  [DocumentationAttribute(HandlingData)]
398  public AlgorithmStatus Status
399  {
400  get;
401  set;
402  }
403 
404  /// <summary>
405  /// Gets an instance that is to be used to initialize newly created securities.
406  /// </summary>
407  [DocumentationAttribute(AddingData)]
409  {
410  get;
411  private set;
412  }
413 
414  /// <summary>
415  /// Gets the Trade Builder to generate trades from executions
416  /// </summary>
417  [DocumentationAttribute(TradingAndOrders)]
419  {
420  get;
421  private set;
422  }
423 
424  /// <summary>
425  /// Gets an instance to access the candlestick pattern helper methods
426  /// </summary>
427  [DocumentationAttribute(Indicators)]
429  {
430  get;
431  private set;
432  }
433 
434  /// <summary>
435  /// Gets the date rules helper object to make specifying dates for events easier
436  /// </summary>
437  [DocumentationAttribute(ScheduledEvents)]
438  public DateRules DateRules
439  {
440  get { return Schedule.DateRules; }
441  }
442 
443  /// <summary>
444  /// Gets the time rules helper object to make specifying times for events easier
445  /// </summary>
446  [DocumentationAttribute(ScheduledEvents)]
447  public TimeRules TimeRules
448  {
449  get { return Schedule.TimeRules; }
450  }
451 
452  /// <summary>
453  /// Gets trading calendar populated with trading events
454  /// </summary>
455  [DocumentationAttribute(ScheduledEvents)]
457  {
458  get;
459  private set;
460  }
461 
462  /// <summary>
463  /// Gets the user settings for the algorithm
464  /// </summary>
465  [DocumentationAttribute(HandlingData)]
467  {
468  get;
469  private set;
470  }
471 
472  /// <summary>
473  /// Gets the option chain provider, used to get the list of option contracts for an underlying symbol
474  /// </summary>
475  [DocumentationAttribute(AddingData)]
476  [Obsolete("OptionChainProvider property is will soon be deprecated. " +
477  "The new OptionChain() method should be used to fetch equity and index option chains, " +
478  "which will contain additional data per contract, like daily price data, implied volatility and greeks.")]
479  public IOptionChainProvider OptionChainProvider { get; private set; }
480 
481  /// <summary>
482  /// Gets the future chain provider, used to get the list of future contracts for an underlying symbol
483  /// </summary>
484  [DocumentationAttribute(AddingData)]
485  public IFutureChainProvider FutureChainProvider { get; private set; }
486 
487  /// <summary>
488  /// Gets the default order properties
489  /// </summary>
490  [DocumentationAttribute(TradingAndOrders)]
492 
493  /// <summary>
494  /// Public name for the algorithm as automatically generated by the IDE. Intended for helping distinguish logs by noting
495  /// the algorithm-id.
496  /// </summary>
497  /// <seealso cref="AlgorithmId"/>
498  [DocumentationAttribute(HandlingData)]
499  public string Name
500  {
501  get
502  {
503  return _name;
504  }
505  set
506  {
507  if (_locked)
508  {
509  throw new InvalidOperationException("Cannot set algorithm name after it is initialized.");
510  }
511 
512  if (!string.IsNullOrEmpty(value))
513  {
514  _name = value.Truncate(MaxNameAndTagsLength);
515  }
516  }
517  }
518 
519  /// <summary>
520  /// A list of tags associated with the algorithm or the backtest, useful for categorization
521  /// </summary>
522  [DocumentationAttribute(HandlingData)]
523  public HashSet<string> Tags
524  {
525  get
526  {
527  return _tags;
528  }
529  set
530  {
531  if (value == null)
532  {
533  return;
534  }
535 
536  var tags = value.Where(x => !string.IsNullOrEmpty(x?.Trim())).ToList();
537 
538  if (tags.Count > MaxTagsCount && !_tagsCollectionTruncatedLogSent)
539  {
540  Log($"Warning: The tags collection cannot contain more than {MaxTagsCount} items. It will be truncated.");
541  _tagsCollectionTruncatedLogSent = true;
542  }
543 
544  _tags = tags.Take(MaxTagsCount).ToHashSet(tag => tag.Truncate(MaxNameAndTagsLength));
545  if (_locked)
546  {
547  TagsUpdated?.Invoke(this, Tags);
548  }
549  }
550  }
551 
552  /// <summary>
553  /// Event fired algorithm's name is changed
554  /// </summary>
555  [DocumentationAttribute(HandlingData)]
556  public event AlgorithmEvent<string> NameUpdated;
557 
558  /// <summary>
559  /// Event fired when the tag collection is updated
560  /// </summary>
561  [DocumentationAttribute(HandlingData)]
562  public event AlgorithmEvent<HashSet<string>> TagsUpdated;
563 
564  /// <summary>
565  /// Read-only value for current time frontier of the algorithm in terms of the <see cref="TimeZone"/>
566  /// </summary>
567  /// <remarks>During backtesting this is primarily sourced from the data feed. During live trading the time is updated from the system clock.</remarks>
568  [DocumentationAttribute(HandlingData)]
569  public DateTime Time
570  {
571  get { return _localTimeKeeper.LocalTime; }
572  }
573 
574  /// <summary>
575  /// Current date/time in UTC.
576  /// </summary>
577  [DocumentationAttribute(HandlingData)]
578  public DateTime UtcTime
579  {
580  get { return _timeKeeper.UtcTime; }
581  }
582 
583  /// <summary>
584  /// Gets the time zone used for the <see cref="Time"/> property. The default value
585  /// is <see cref="TimeZones.NewYork"/>
586  /// </summary>
587  [DocumentationAttribute(HandlingData)]
588  public DateTimeZone TimeZone
589  {
590  get { return _localTimeKeeper.TimeZone; }
591  }
592 
593  /// <summary>
594  /// Value of the user set start-date from the backtest.
595  /// </summary>
596  /// <remarks>This property is set with SetStartDate() and defaults to the earliest QuantConnect data available - Jan 1st 1998. It is ignored during live trading </remarks>
597  /// <seealso cref="SetStartDate(DateTime)"/>
598  [DocumentationAttribute(HandlingData)]
599  public DateTime StartDate => _startDate;
600 
601  /// <summary>
602  /// Value of the user set start-date from the backtest. Controls the period of the backtest.
603  /// </summary>
604  /// <remarks> This property is set with SetEndDate() and defaults to today. It is ignored during live trading.</remarks>
605  /// <seealso cref="SetEndDate(DateTime)"/>
606  [DocumentationAttribute(HandlingData)]
607  public DateTime EndDate
608  {
609  get
610  {
611  return _endDate;
612  }
613  }
614 
615  /// <summary>
616  /// Algorithm Id for this backtest or live algorithm.
617  /// </summary>
618  /// <remarks>A unique identifier for </remarks>
619  [DocumentationAttribute(HandlingData)]
620  public string AlgorithmId
621  {
622  get
623  {
624  return _algorithmId;
625  }
626  }
627 
628  /// <summary>
629  /// Boolean property indicating the algorithm is currently running in live mode.
630  /// </summary>
631  /// <remarks>Intended for use where certain behaviors will be enabled while the algorithm is trading live: such as notification emails, or displaying runtime statistics.</remarks>
632  [DocumentationAttribute(LiveTrading)]
633  public bool LiveMode
634  {
635  get
636  {
637  return _liveMode;
638  }
639  }
640 
641  /// <summary>
642  /// Algorithm running mode.
643  /// </summary>
645  {
646  get
647  {
648  return _algorithmMode;
649  }
650  }
651 
652  /// <summary>
653  /// Deployment target, either local or cloud.
654  /// </summary>
656  {
657  get
658  {
659  return _deploymentTarget;
660  }
661  }
662 
663  /// <summary>
664  /// Storage for debugging messages before the event handler has passed control back to the Lean Engine.
665  /// </summary>
666  /// <seealso cref="Debug(string)"/>
667  [DocumentationAttribute(Logging)]
668  public ConcurrentQueue<string> DebugMessages
669  {
670  get
671  {
672  return _debugMessages;
673  }
674  set
675  {
676  _debugMessages = value;
677  }
678  }
679 
680  /// <summary>
681  /// Storage for log messages before the event handlers have passed control back to the Lean Engine.
682  /// </summary>
683  /// <seealso cref="Log(string)"/>
684  [DocumentationAttribute(Logging)]
685  public ConcurrentQueue<string> LogMessages
686  {
687  get
688  {
689  return _logMessages;
690  }
691  set
692  {
693  _logMessages = value;
694  }
695  }
696 
697  /// <summary>
698  /// Gets the run time error from the algorithm, or null if none was encountered.
699  /// </summary>
700  [DocumentationAttribute(Logging)]
701  public Exception RunTimeError { get; set; }
702 
703  /// <summary>
704  /// List of error messages generated by the user's code calling the "Error" function.
705  /// </summary>
706  /// <remarks>This method is best used within a try-catch bracket to handle any runtime errors from a user algorithm.</remarks>
707  /// <see cref="Error(string)"/>
708  [DocumentationAttribute(Logging)]
709  public ConcurrentQueue<string> ErrorMessages
710  {
711  get
712  {
713  return _errorMessages;
714  }
715  set
716  {
717  _errorMessages = value;
718  }
719  }
720 
721  /// <summary>
722  /// Returns the current Slice object
723  /// </summary>
724  [DocumentationAttribute(HandlingData)]
725  public Slice CurrentSlice { get; private set; }
726 
727  /// <summary>
728  /// Gets the object store, used for persistence
729  /// </summary>
730  [DocumentationAttribute(HandlingData)]
731  [DocumentationAttribute(MachineLearning)]
732  public ObjectStore ObjectStore { get; private set; }
733 
734  /// <summary>
735  /// The current statistics for the running algorithm.
736  /// </summary>
737  [DocumentationAttribute(StatisticsTag)]
739  {
740  get
741  {
742  return _statisticsService?.StatisticsResults() ?? new StatisticsResults();
743  }
744  }
745 
746  /// <summary>
747  /// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
748  /// </summary>
749  /// <seealso cref="SetStartDate(DateTime)"/>
750  /// <seealso cref="SetEndDate(DateTime)"/>
751  /// <seealso cref="SetCash(decimal)"/>
752  [DocumentationAttribute(AlgorithmFramework)]
753  [DocumentationAttribute(HandlingData)]
754  public virtual void Initialize()
755  {
756  //Setup Required Data
757  throw new NotImplementedException("Please override the Initialize() method");
758  }
759 
760  /// <summary>
761  /// Called by setup handlers after Initialize and allows the algorithm a chance to organize
762  /// the data gather in the Initialize method
763  /// </summary>
764  [DocumentationAttribute(AlgorithmFramework)]
765  [DocumentationAttribute(HandlingData)]
766  public virtual void PostInitialize()
767  {
768  if (_endDate < _startDate)
769  {
770  throw new ArgumentException("Please select an algorithm end date greater than start date.");
771  }
772 
773  var portfolioConstructionModel = PortfolioConstruction as PortfolioConstructionModel;
774  if (portfolioConstructionModel != null)
775  {
776  // only override default values if user set the algorithm setting
778  {
779  portfolioConstructionModel.RebalanceOnSecurityChanges
781  }
783  {
784  portfolioConstructionModel.RebalanceOnInsightChanges
786  }
787  }
788  else
789  {
792  {
793  Debug("Warning: rebalance portfolio settings are set but not supported by the current IPortfolioConstructionModel type: " +
794  $"{PortfolioConstruction.GetType()}");
795  }
796  }
797 
799 
800  // if the benchmark hasn't been set yet, load in the default from the brokerage model
801  if (Benchmark == null)
802  {
803  Benchmark = BrokerageModel.GetBenchmark(Securities);
804  }
805 
806  // Check benchmark timezone against algorithm timezone to warn for misaligned statistics
807  if (Benchmark is SecurityBenchmark securityBenchmark)
808  {
809  // Only warn on algorithms subscribed to daily resolution as its statistics will suffer the most
810  var subscription = SubscriptionManager.Subscriptions.OrderByDescending(x => x.Resolution).FirstOrDefault();
811  var benchmarkTimeZone = MarketHoursDatabase.GetDataTimeZone(securityBenchmark.Security.Symbol.ID.Market,
812  securityBenchmark.Security.Symbol, securityBenchmark.Security.Type);
813  if ((subscription?.Resolution == Resolution.Daily || UniverseSettings.Resolution == Resolution.Daily) && benchmarkTimeZone != TimeZone)
814  {
815  Log($"QCAlgorithm.PostInitialize(): Warning: Using a security benchmark of a different timezone ({benchmarkTimeZone})" +
816  $" than the algorithm TimeZone ({TimeZone}) may lead to skewed and incorrect statistics. Use a higher resolution than daily to minimize.");
817  }
818  }
819 
820  if (TryGetWarmupHistoryStartTime(out var result))
821  {
822  SetDateTime(result.ConvertToUtc(TimeZone));
823  }
824  else
825  {
827  }
828 
830  {
831  Debug("Accurate daily end-times now enabled by default. See more at https://qnt.co/3YHaWHL. To disable it and use legacy daily bars set self.settings.daily_precise_end_time = False.");
832  }
833 
834  // perform end of time step checks, such as enforcing underlying securities are in raw data mode
835  OnEndOfTimeStep();
836  }
837 
838  /// <summary>
839  /// Called when the algorithm has completed initialization and warm up.
840  /// </summary>
841  [DocumentationAttribute(HandlingData)]
842  public virtual void OnWarmupFinished()
843  {
844  }
845 
846  /// <summary>
847  /// Gets the parameter with the specified name. If a parameter with the specified name does not exist,
848  /// the given default value is returned if any, else null
849  /// </summary>
850  /// <param name="name">The name of the parameter to get</param>
851  /// <param name="defaultValue">The default value to return</param>
852  /// <returns>The value of the specified parameter, or defaultValue if not found or null if there's no default value</returns>
853  [DocumentationAttribute(ParameterAndOptimization)]
854  public string GetParameter(string name, string defaultValue = null)
855  {
856  return _parameters.TryGetValue(name, out var value) ? value : defaultValue;
857  }
858 
859  /// <summary>
860  /// Gets the parameter with the specified name parsed as an integer. If a parameter with the specified name does not exist,
861  /// or the conversion is not possible, the given default value is returned
862  /// </summary>
863  /// <param name="name">The name of the parameter to get</param>
864  /// <param name="defaultValue">The default value to return</param>
865  /// <returns>The value of the specified parameter, or defaultValue if not found or null if there's no default value</returns>
866  [DocumentationAttribute(ParameterAndOptimization)]
867  public int GetParameter(string name, int defaultValue)
868  {
869  return _parameters.TryGetValue(name, out var strValue) && int.TryParse(strValue, out var value) ? value : defaultValue;
870  }
871 
872  /// <summary>
873  /// Gets the parameter with the specified name parsed as a double. If a parameter with the specified name does not exist,
874  /// or the conversion is not possible, the given default value is returned
875  /// </summary>
876  /// <param name="name">The name of the parameter to get</param>
877  /// <param name="defaultValue">The default value to return</param>
878  /// <returns>The value of the specified parameter, or defaultValue if not found or null if there's no default value</returns>
879  [DocumentationAttribute(ParameterAndOptimization)]
880  public double GetParameter(string name, double defaultValue)
881  {
882  return _parameters.TryGetValue(name, out var strValue) &&
883  double.TryParse(strValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) ? value : defaultValue;
884  }
885 
886  /// <summary>
887  /// Gets the parameter with the specified name parsed as a decimal. If a parameter with the specified name does not exist,
888  /// or the conversion is not possible, the given default value is returned
889  /// </summary>
890  /// <param name="name">The name of the parameter to get</param>
891  /// <param name="defaultValue">The default value to return</param>
892  /// <returns>The value of the specified parameter, or defaultValue if not found or null if there's no default value</returns>
893  [DocumentationAttribute(ParameterAndOptimization)]
894  public decimal GetParameter(string name, decimal defaultValue)
895  {
896  return _parameters.TryGetValue(name, out var strValue) &&
897  decimal.TryParse(strValue, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) ? value : defaultValue;
898  }
899 
900  /// <summary>
901  /// Gets a read-only dictionary with all current parameters
902  /// </summary>
903  [DocumentationAttribute(ParameterAndOptimization)]
904  public IReadOnlyDictionary<string, string> GetParameters()
905  {
906  return _parameters.ToReadOnlyDictionary();
907  }
908 
909  /// <summary>
910  /// Sets the parameters from the dictionary
911  /// </summary>
912  /// <param name="parameters">Dictionary containing the parameter names to values</param>
913  [DocumentationAttribute(ParameterAndOptimization)]
914  public void SetParameters(Dictionary<string, string> parameters)
915  {
916  // save off a copy and try to apply the parameters
917  _parameters = parameters.ToDictionary();
918  try
919  {
920  ParameterAttribute.ApplyAttributes(parameters, this);
921  }
922  catch (Exception err)
923  {
924  Error("Error applying parameter values: " + err.Message);
925  }
926  }
927 
928  /// <summary>
929  /// Set the available data feeds in the <see cref="SecurityManager"/>
930  /// </summary>
931  /// <param name="availableDataTypes">The different <see cref="TickType"/> each <see cref="Security"/> supports</param>
932  [DocumentationAttribute(HandlingData)]
933  public void SetAvailableDataTypes(Dictionary<SecurityType, List<TickType>> availableDataTypes)
934  {
935  if (availableDataTypes == null)
936  {
937  return;
938  }
939 
940  foreach (var dataFeed in availableDataTypes)
941  {
942  SubscriptionManager.AvailableDataTypes[dataFeed.Key] = dataFeed.Value;
943  }
944  }
945 
946  /// <summary>
947  /// Sets the security initializer, used to initialize/configure securities after creation.
948  /// The initializer will be applied to all universes and manually added securities.
949  /// </summary>
950  /// <param name="securityInitializer">The security initializer</param>
951  [DocumentationAttribute(AddingData)]
952  [DocumentationAttribute(Modeling)]
953  public void SetSecurityInitializer(ISecurityInitializer securityInitializer)
954  {
955  if (_locked)
956  {
957  throw new Exception("SetSecurityInitializer() cannot be called after algorithm initialization. " +
958  "When you use the SetSecurityInitializer() method it will apply to all universes and manually added securities.");
959  }
960 
961  if (_userSetSecurityInitializer)
962  {
963  Debug("Warning: SetSecurityInitializer() has already been called, existing security initializers in all universes will be overwritten.");
964  }
965 
966  // this flag will prevent calls to SetBrokerageModel from overwriting this initializer
967  _userSetSecurityInitializer = true;
968  SecurityInitializer = securityInitializer;
969  }
970 
971  /// <summary>
972  /// Sets the security initializer function, used to initialize/configure securities after creation.
973  /// The initializer will be applied to all universes and manually added securities.
974  /// </summary>
975  /// <param name="securityInitializer">The security initializer function</param>
976  [Obsolete("This method is deprecated. Please use this overload: SetSecurityInitializer(Action<Security> securityInitializer)")]
977  [DocumentationAttribute(AddingData)]
978  [DocumentationAttribute(Modeling)]
979  public void SetSecurityInitializer(Action<Security, bool> securityInitializer)
980  {
981  SetSecurityInitializer(new FuncSecurityInitializer(security => securityInitializer(security, false)));
982  }
983 
984  /// <summary>
985  /// Sets the security initializer function, used to initialize/configure securities after creation.
986  /// The initializer will be applied to all universes and manually added securities.
987  /// </summary>
988  /// <param name="securityInitializer">The security initializer function</param>
989  [DocumentationAttribute(AddingData)]
990  [DocumentationAttribute(Modeling)]
991  public void SetSecurityInitializer(Action<Security> securityInitializer)
992  {
993  SetSecurityInitializer(new FuncSecurityInitializer(securityInitializer));
994  }
995 
996  /// <summary>
997  /// Sets the option chain provider, used to get the list of option contracts for an underlying symbol
998  /// </summary>
999  /// <param name="optionChainProvider">The option chain provider</param>
1000  [DocumentationAttribute(AddingData)]
1001  public void SetOptionChainProvider(IOptionChainProvider optionChainProvider)
1002  {
1003  OptionChainProvider = optionChainProvider;
1004  }
1005 
1006  /// <summary>
1007  /// Sets the future chain provider, used to get the list of future contracts for an underlying symbol
1008  /// </summary>
1009  /// <param name="futureChainProvider">The future chain provider</param>
1010  [DocumentationAttribute(AddingData)]
1011  public void SetFutureChainProvider(IFutureChainProvider futureChainProvider)
1012  {
1013  FutureChainProvider = futureChainProvider;
1014  }
1015 
1016  /// <summary>
1017  /// Event - v3.0 DATA EVENT HANDLER: (Pattern) Basic template for user to override for receiving all subscription data in a single event
1018  /// </summary>
1019  /// <code>
1020  /// TradeBars bars = slice.Bars;
1021  /// Ticks ticks = slice.Ticks;
1022  /// TradeBar spy = slice["SPY"];
1023  /// List{Tick} aaplTicks = slice["AAPL"]
1024  /// Quandl oil = slice["OIL"]
1025  /// dynamic anySymbol = slice[symbol];
1026  /// DataDictionary{Quandl} allQuandlData = slice.Get{Quand}
1027  /// Quandl oil = slice.Get{Quandl}("OIL")
1028  /// </code>
1029  /// <param name="slice">The current slice of data keyed by symbol string</param>
1030  [DocumentationAttribute(HandlingData)]
1031  public virtual void OnData(Slice slice)
1032  {
1033  // as a default implementation, let's look for and call OnData(Slice) just in case a user forgot to use the override keyword
1034  if (!_checkedForOnDataSlice)
1035  {
1036  _checkedForOnDataSlice = true;
1037 
1038  var method = GetType().GetMethods()
1039  .Where(x => x.Name == "OnData")
1040  .Where(x => x.DeclaringType != typeof(QCAlgorithm))
1041  .Where(x => x.GetParameters().Length == 1)
1042  .FirstOrDefault(x => x.GetParameters()[0].ParameterType == typeof(Slice));
1043 
1044  if (method == null)
1045  {
1046  return;
1047  }
1048 
1049  var self = Expression.Constant(this);
1050  var parameter = Expression.Parameter(typeof(Slice), "data");
1051  var call = Expression.Call(self, method, parameter);
1052  var lambda = Expression.Lambda<Action<Slice>>(call, parameter);
1053  _onDataSlice = lambda.Compile();
1054  }
1055  // if we have it, then invoke it
1056  if (_onDataSlice != null)
1057  {
1058  _onDataSlice(slice);
1059  }
1060  }
1061 
1062  /// <summary>
1063  /// Event handler to be called when there's been a split event
1064  /// </summary>
1065  /// <param name="splits">The current time slice splits</param>
1066  [DocumentationAttribute(HandlingData)]
1067  public virtual void OnSplits(Splits splits)
1068  {
1069  }
1070 
1071  /// <summary>
1072  /// Event handler to be called when there's been a dividend event
1073  /// </summary>
1074  /// <param name="dividends">The current time slice dividends</param>
1075  [DocumentationAttribute(HandlingData)]
1076  public virtual void OnDividends(Dividends dividends)
1077  {
1078  }
1079 
1080  /// <summary>
1081  /// Event handler to be called when there's been a delistings event
1082  /// </summary>
1083  /// <param name="delistings">The current time slice delistings</param>
1084  [DocumentationAttribute(HandlingData)]
1085  public virtual void OnDelistings(Delistings delistings)
1086  {
1087  }
1088 
1089  /// <summary>
1090  /// Event handler to be called when there's been a symbol changed event
1091  /// </summary>
1092  /// <param name="symbolsChanged">The current time slice symbol changed events</param>
1093  [DocumentationAttribute(HandlingData)]
1094  public virtual void OnSymbolChangedEvents(SymbolChangedEvents symbolsChanged)
1095  {
1096  }
1097 
1098  /// <summary>
1099  /// Event fired each time the we add/remove securities from the data feed
1100  /// </summary>
1101  /// <param name="changes">Security additions/removals for this time step</param>
1102  [DocumentationAttribute(AddingData)]
1103  [DocumentationAttribute(Universes)]
1104  public virtual void OnSecuritiesChanged(SecurityChanges changes)
1105  {
1106  }
1107 
1108  /// <summary>
1109  /// Margin call event handler. This method is called right before the margin call orders are placed in the market.
1110  /// </summary>
1111  /// <param name="requests">The orders to be executed to bring this algorithm within margin limits</param>
1112  [DocumentationAttribute(Modeling)]
1113  [DocumentationAttribute(TradingAndOrders)]
1114  public virtual void OnMarginCall(List<SubmitOrderRequest> requests)
1115  {
1116  }
1117 
1118  /// <summary>
1119  /// Margin call warning event handler. This method is called when Portfolio.MarginRemaining is under 5% of your Portfolio.TotalPortfolioValue
1120  /// </summary>
1121  [DocumentationAttribute(Modeling)]
1122  [DocumentationAttribute(TradingAndOrders)]
1123  public virtual void OnMarginCallWarning()
1124  {
1125  }
1126 
1127  /// <summary>
1128  /// End of a trading day event handler. This method is called at the end of the algorithm day (or multiple times if trading multiple assets).
1129  /// </summary>
1130  /// <remarks>Method is called 10 minutes before closing to allow user to close out position.</remarks>
1131  /// <remarks>Deprecated because different assets have different market close times,
1132  /// and because Python does not support two methods with the same name</remarks>
1133  [Obsolete("This method is deprecated and will be removed after August 2021. Please use this overload: OnEndOfDay(Symbol symbol)")]
1134  [DocumentationAttribute(HandlingData)]
1135  public virtual void OnEndOfDay()
1136  {
1137 
1138  }
1139 
1140  /// <summary>
1141  /// End of a trading day event handler. This method is called at the end of the algorithm day (or multiple times if trading multiple assets).
1142  /// </summary>
1143  /// <remarks>
1144  /// This method is left for backwards compatibility and is invoked via <see cref="OnEndOfDay(Symbol)"/>, if that method is
1145  /// override then this method will not be called without a called to base.OnEndOfDay(string)
1146  /// </remarks>
1147  /// <param name="symbol">Asset symbol for this end of day event. Forex and equities have different closing hours.</param>
1148  [DocumentationAttribute(HandlingData)]
1149  public virtual void OnEndOfDay(string symbol)
1150  {
1151  }
1152 
1153  /// <summary>
1154  /// End of a trading day event handler. This method is called at the end of the algorithm day (or multiple times if trading multiple assets).
1155  /// </summary>
1156  /// <param name="symbol">Asset symbol for this end of day event. Forex and equities have different closing hours.</param>
1157  [DocumentationAttribute(HandlingData)]
1158  public virtual void OnEndOfDay(Symbol symbol)
1159  {
1160  OnEndOfDay(symbol.ToString());
1161  }
1162 
1163  /// <summary>
1164  /// End of algorithm run event handler. This method is called at the end of a backtest or live trading operation. Intended for closing out logs.
1165  /// </summary>
1166  [DocumentationAttribute(HandlingData)]
1167  public virtual void OnEndOfAlgorithm()
1168  {
1169 
1170  }
1171 
1172  /// <summary>
1173  /// Order fill event handler. On an order fill update the resulting information is passed to this method.
1174  /// </summary>
1175  /// <param name="orderEvent">Order event details containing details of the events</param>
1176  /// <remarks>This method can be called asynchronously and so should only be used by seasoned C# experts. Ensure you use proper locks on thread-unsafe objects</remarks>
1177  [DocumentationAttribute(TradingAndOrders)]
1178  public virtual void OnOrderEvent(OrderEvent orderEvent)
1179  {
1180 
1181  }
1182 
1183  /// <summary>
1184  /// Option assignment event handler. On an option assignment event for short legs the resulting information is passed to this method.
1185  /// </summary>
1186  /// <param name="assignmentEvent">Option exercise event details containing details of the assignment</param>
1187  /// <remarks>This method can be called asynchronously and so should only be used by seasoned C# experts. Ensure you use proper locks on thread-unsafe objects</remarks>
1188  [DocumentationAttribute(TradingAndOrders)]
1189  public virtual void OnAssignmentOrderEvent(OrderEvent assignmentEvent)
1190  {
1191 
1192  }
1193 
1194  /// <summary>
1195  /// Brokerage message event handler. This method is called for all types of brokerage messages.
1196  /// </summary>
1197  [DocumentationAttribute(LiveTrading)]
1198  [DocumentationAttribute(Modeling)]
1199  [DocumentationAttribute(TradingAndOrders)]
1200  public virtual void OnBrokerageMessage(BrokerageMessageEvent messageEvent)
1201  {
1202 
1203  }
1204 
1205  /// <summary>
1206  /// Brokerage disconnected event handler. This method is called when the brokerage connection is lost.
1207  /// </summary>
1208  [DocumentationAttribute(LiveTrading)]
1209  public virtual void OnBrokerageDisconnect()
1210  {
1211 
1212  }
1213 
1214  /// <summary>
1215  /// Brokerage reconnected event handler. This method is called when the brokerage connection is restored after a disconnection.
1216  /// </summary>
1217  [DocumentationAttribute(LiveTrading)]
1218  public virtual void OnBrokerageReconnect()
1219  {
1220 
1221  }
1222 
1223  /// <summary>
1224  /// Update the internal algorithm time frontier.
1225  /// </summary>
1226  /// <remarks>For internal use only to advance time.</remarks>
1227  /// <param name="frontier">Current utc datetime.</param>
1228  [DocumentationAttribute(HandlingData)]
1229  public void SetDateTime(DateTime frontier)
1230  {
1231  _timeKeeper.SetUtcDateTime(frontier);
1232  if (_locked && IsWarmingUp && Time >= _start)
1233  {
1235  }
1236  }
1237 
1238  /// <summary>
1239  /// Sets the time zone of the <see cref="Time"/> property in the algorithm
1240  /// </summary>
1241  /// <param name="timeZone">The desired time zone</param>
1242  [DocumentationAttribute(HandlingData)]
1243  public void SetTimeZone(string timeZone)
1244  {
1245  DateTimeZone tz;
1246  try
1247  {
1248  tz = DateTimeZoneProviders.Tzdb[timeZone];
1249  }
1250  catch (DateTimeZoneNotFoundException)
1251  {
1252  throw new ArgumentException($"TimeZone with id '{timeZone}' was not found. For a complete list of time zones please visit: http://en.wikipedia.org/wiki/List_of_tz_database_time_zones");
1253  }
1254 
1255  SetTimeZone(tz);
1256  }
1257 
1258  /// <summary>
1259  /// Sets the time zone of the <see cref="Time"/> property in the algorithm
1260  /// </summary>
1261  /// <param name="timeZone">The desired time zone</param>
1262  [DocumentationAttribute(HandlingData)]
1263  public void SetTimeZone(DateTimeZone timeZone)
1264  {
1265  if (_locked)
1266  {
1267  throw new InvalidOperationException("Algorithm.SetTimeZone(): Cannot change time zone after algorithm running.");
1268  }
1269 
1270  if (timeZone == null) throw new ArgumentNullException(nameof(timeZone));
1271  _timeKeeper.AddTimeZone(timeZone);
1272  _localTimeKeeper = _timeKeeper.GetLocalTimeKeeper(timeZone);
1273 
1274  // the time rules need to know the default time zone as well
1275  TimeRules.SetDefaultTimeZone(timeZone);
1276  DateRules.SetDefaultTimeZone(timeZone);
1277 
1278  // In BackTest mode we reset the Algorithm time to reflect the new timezone
1279  // startDate is set by the user so we expect it to be for their timezone already
1280  // so there is no need to update it.
1281  if (!LiveMode)
1282  {
1283  _start = _startDate;
1284  SetDateTime(_startDate.ConvertToUtc(TimeZone));
1285  }
1286  // In live mode we need to adjust startDate to reflect the new timezone
1287  // startDate is set by Lean to the default timezone (New York), so we must update it here
1288  else
1289  {
1290  SetLiveModeStartDate();
1291  }
1292  }
1293 
1294  /// <summary>
1295  /// Sets the brokerage to emulate in backtesting or paper trading.
1296  /// This can be used for brokerages that have been implemented in LEAN
1297  /// </summary>
1298  /// <param name="brokerage">The brokerage to emulate</param>
1299  /// <param name="accountType">The account type (Cash or Margin)</param>
1300  [DocumentationAttribute(Modeling)]
1301  public void SetBrokerageModel(BrokerageName brokerage, AccountType accountType = AccountType.Margin)
1302  {
1303  SetBrokerageModel(Brokerages.BrokerageModel.Create(Transactions, brokerage, accountType));
1304  }
1305 
1306  /// <summary>
1307  /// Sets the brokerage to emulate in backtesting or paper trading.
1308  /// This can be used to set a custom brokerage model.
1309  /// </summary>
1310  /// <param name="model">The brokerage model to use</param>
1311  [DocumentationAttribute(Modeling)]
1313  {
1314  BrokerageModel = model;
1315  if (!_userSetSecurityInitializer)
1316  {
1317  // purposefully use the direct setter vs Set method so we don't flip the switch :/
1319 
1320  // update models on securities added earlier (before SetBrokerageModel is called)
1321  foreach (var kvp in Securities)
1322  {
1323  var security = kvp.Value;
1324 
1325  // save the existing leverage specified in AddSecurity,
1326  // if Leverage needs to be set in a SecurityInitializer,
1327  // SetSecurityInitializer must be called before SetBrokerageModel
1328  var leverage = security.Leverage;
1329 
1330  SecurityInitializer.Initialize(security);
1331 
1332  // restore the saved leverage
1333  security.SetLeverage(leverage);
1334  }
1335  }
1336  }
1337 
1338  /// <summary>
1339  /// Sets the implementation used to handle messages from the brokerage.
1340  /// The default implementation will forward messages to debug or error
1341  /// and when a <see cref="BrokerageMessageType.Error"/> occurs, the algorithm
1342  /// is stopped.
1343  /// </summary>
1344  /// <param name="handler">The message handler to use</param>
1345  [DocumentationAttribute(Modeling)]
1346  [DocumentationAttribute(Logging)]
1348  {
1349  BrokerageMessageHandler = handler ?? throw new ArgumentNullException(nameof(handler));
1350  }
1351 
1352  /// <summary>
1353  /// Sets the risk free interest rate model to be used in the algorithm
1354  /// </summary>
1355  /// <param name="model">The risk free interest rate model to use</param>
1356  [DocumentationAttribute(Modeling)]
1358  {
1359  RiskFreeInterestRateModel = model ?? throw new ArgumentNullException(nameof(model));
1360  }
1361 
1362  /// <summary>
1363  /// Sets the benchmark used for computing statistics of the algorithm to the specified symbol
1364  /// </summary>
1365  /// <param name="symbol">symbol to use as the benchmark</param>
1366  /// <param name="securityType">Is the symbol an equity, forex, base, etc. Default SecurityType.Equity</param>
1367  /// <remarks>
1368  /// Must use symbol that is available to the trade engine in your data store(not strictly enforced)
1369  /// </remarks>
1370  [Obsolete("Symbol implicit operator to string is provided for algorithm use only.")]
1371  [DocumentationAttribute(TradingAndOrders)]
1372  [DocumentationAttribute(SecuritiesAndPortfolio)]
1373  [DocumentationAttribute(Indicators)]
1374  public void SetBenchmark(SecurityType securityType, string symbol)
1375  {
1376  if (_locked)
1377  {
1378  throw new InvalidOperationException("Algorithm.SetBenchmark(): Cannot change Benchmark after algorithm initialized.");
1379  }
1380 
1381  string market;
1382  if (!BrokerageModel.DefaultMarkets.TryGetValue(securityType, out market))
1383  {
1384  market = Market.USA;
1385  }
1386 
1387  var benchmarkSymbol = QuantConnect.Symbol.Create(symbol, securityType, market);
1388  SetBenchmark(benchmarkSymbol);
1389  }
1390 
1391  /// <summary>
1392  /// Sets the benchmark used for computing statistics of the algorithm to the specified ticker, defaulting to SecurityType.Equity
1393  /// if the ticker doesn't exist in the algorithm
1394  /// </summary>
1395  /// <param name="ticker">Ticker to use as the benchmark</param>
1396  /// <remarks>
1397  /// Overload to accept ticker without passing SecurityType. If ticker is in portfolio it will use that SecurityType, otherwise will default to SecurityType.Equity
1398  /// </remarks>
1399  [DocumentationAttribute(TradingAndOrders)]
1400  [DocumentationAttribute(SecuritiesAndPortfolio)]
1401  [DocumentationAttribute(Indicators)]
1402  public void SetBenchmark(string ticker)
1403  {
1404  Symbol symbol;
1405 
1406  // Check the cache for the symbol
1407  if (!SymbolCache.TryGetSymbol(ticker, out symbol))
1408  {
1409  // Check our securities for a symbol matched with this ticker
1410  symbol = Securities.FirstOrDefault(x => x.Key.Value == ticker).Key;
1411 
1412  // If we didn't find a symbol matching our ticker, create one.
1413  if (symbol == null)
1414  {
1415  Debug($"Warning: SetBenchmark({ticker}): no existing symbol found, benchmark security will be added with {SecurityType.Equity} type.");
1416  symbol = QuantConnect.Symbol.Create(ticker, SecurityType.Equity, Market.USA);
1417  }
1418  }
1419 
1420  // Send our symbol through
1421  SetBenchmark(symbol);
1422  }
1423 
1424  /// <summary>
1425  /// Sets the benchmark used for computing statistics of the algorithm to the specified symbol
1426  /// </summary>
1427  /// <param name="symbol">symbol to use as the benchmark</param>
1428  [DocumentationAttribute(TradingAndOrders)]
1429  [DocumentationAttribute(SecuritiesAndPortfolio)]
1430  [DocumentationAttribute(Indicators)]
1431  public void SetBenchmark(Symbol symbol)
1432  {
1433  if (_locked)
1434  {
1435  throw new InvalidOperationException("Algorithm.SetBenchmark(): Cannot change Benchmark after algorithm initialized.");
1436  }
1437 
1438  // Create our security benchmark
1440  }
1441 
1442  /// <summary>
1443  /// Sets the specified function as the benchmark, this function provides the value of
1444  /// the benchmark at each date/time requested
1445  /// </summary>
1446  /// <param name="benchmark">The benchmark producing function</param>
1447  [DocumentationAttribute(TradingAndOrders)]
1448  [DocumentationAttribute(SecuritiesAndPortfolio)]
1449  [DocumentationAttribute(Indicators)]
1450  public void SetBenchmark(Func<DateTime, decimal> benchmark)
1451  {
1452  if (_locked)
1453  {
1454  throw new InvalidOperationException("Algorithm.SetBenchmark(): Cannot change Benchmark after algorithm initialized.");
1455  }
1456 
1457  Benchmark = new FuncBenchmark(benchmark);
1458  }
1459 
1460  /// <summary>
1461  /// Benchmark
1462  /// </summary>
1463  /// <remarks>Use Benchmark to override default symbol based benchmark, and create your own benchmark. For example a custom moving average benchmark </remarks>
1464  ///
1465  [DocumentationAttribute(TradingAndOrders)]
1466  [DocumentationAttribute(SecuritiesAndPortfolio)]
1467  [DocumentationAttribute(Indicators)]
1468  public IBenchmark Benchmark
1469  {
1470  get;
1471  private set;
1472  }
1473 
1474  /// <summary>
1475  /// Sets name to the currently running backtest
1476  /// </summary>
1477  /// <param name="name">The name for the backtest</param>
1478  public void SetName(string name)
1479  {
1480  Name = name;
1481  }
1482 
1483  /// <summary>
1484  /// Adds a tag to the algorithm
1485  /// </summary>
1486  /// <param name="tag">The tag to add</param>
1487  public void AddTag(string tag)
1488  {
1489  if (!string.IsNullOrEmpty(tag?.Trim()))
1490  {
1491  if (Tags.Count >= MaxTagsCount)
1492  {
1493  if (!_tagsLimitReachedLogSent)
1494  {
1495  Log($"Warning: AddTag({tag}): Unable to add tag. Tags are limited to a maximum of {MaxTagsCount}.");
1496  _tagsLimitReachedLogSent = true;
1497  }
1498  return;
1499  }
1500 
1501  // We'll only notify the tad update after the algorithm has been initialized
1502  if (Tags.Add(tag.Truncate(MaxNameAndTagsLength)) && _locked)
1503  {
1504  TagsUpdated?.Invoke(this, Tags);
1505  }
1506  }
1507  }
1508 
1509  /// <summary>
1510  /// Sets the tags for the algorithm
1511  /// </summary>
1512  /// <param name="tags">The tags</param>
1513  public void SetTags(HashSet<string> tags)
1514  {
1515  Tags = tags;
1516  }
1517 
1518  /// <summary>
1519  /// Sets the account currency cash symbol this algorithm is to manage, as well as
1520  /// the starting cash in this currency if given
1521  /// </summary>
1522  /// <remarks>Has to be called during <see cref="Initialize"/> before
1523  /// calling <see cref="SetCash(decimal)"/> or adding any <see cref="Security"/></remarks>
1524  /// <param name="accountCurrency">The account currency cash symbol to set</param>
1525  /// <param name="startingCash">The account currency starting cash to set</param>
1526  [DocumentationAttribute(SecuritiesAndPortfolio)]
1527  public void SetAccountCurrency(string accountCurrency, decimal? startingCash = null)
1528  {
1529  if (_locked)
1530  {
1531  throw new InvalidOperationException("Algorithm.SetAccountCurrency(): " +
1532  "Cannot change AccountCurrency after algorithm initialized.");
1533  }
1534 
1535  if (startingCash == null)
1536  {
1537  Debug($"Changing account currency from {AccountCurrency} to {accountCurrency}...");
1538  }
1539  else
1540  {
1541  Debug($"Changing account currency from {AccountCurrency} to {accountCurrency}, with a starting cash of {startingCash}...");
1542  }
1543 
1544  Portfolio.SetAccountCurrency(accountCurrency, startingCash);
1545  }
1546 
1547  /// <summary>
1548  /// Set initial cash for the strategy while backtesting. During live mode this value is ignored
1549  /// and replaced with the actual cash of your brokerage account.
1550  /// </summary>
1551  /// <param name="startingCash">Starting cash for the strategy backtest</param>
1552  /// <remarks>Alias of SetCash(decimal)</remarks>
1553  [DocumentationAttribute(SecuritiesAndPortfolio)]
1554  public void SetCash(double startingCash)
1555  {
1556  SetCash((decimal)startingCash);
1557  }
1558 
1559  /// <summary>
1560  /// Set initial cash for the strategy while backtesting. During live mode this value is ignored
1561  /// and replaced with the actual cash of your brokerage account.
1562  /// </summary>
1563  /// <param name="startingCash">Starting cash for the strategy backtest</param>
1564  /// <remarks>Alias of SetCash(decimal)</remarks>
1565  [DocumentationAttribute(SecuritiesAndPortfolio)]
1566  public void SetCash(int startingCash)
1567  {
1568  SetCash((decimal)startingCash);
1569  }
1570 
1571  /// <summary>
1572  /// Set initial cash for the strategy while backtesting. During live mode this value is ignored
1573  /// and replaced with the actual cash of your brokerage account.
1574  /// </summary>
1575  /// <param name="startingCash">Starting cash for the strategy backtest</param>
1576  [DocumentationAttribute(SecuritiesAndPortfolio)]
1577  public void SetCash(decimal startingCash)
1578  {
1579  if (!_locked)
1580  {
1581  Portfolio.SetCash(startingCash);
1582  }
1583  else
1584  {
1585  throw new InvalidOperationException("Algorithm.SetCash(): Cannot change cash available after algorithm initialized.");
1586  }
1587  }
1588 
1589  /// <summary>
1590  /// Set the cash for the specified symbol
1591  /// </summary>
1592  /// <param name="symbol">The cash symbol to set</param>
1593  /// <param name="startingCash">Decimal cash value of portfolio</param>
1594  /// <param name="conversionRate">The current conversion rate for the</param>
1595  [DocumentationAttribute(SecuritiesAndPortfolio)]
1596  public void SetCash(string symbol, decimal startingCash, decimal conversionRate = 0)
1597  {
1598  if (!_locked)
1599  {
1600  Portfolio.SetCash(symbol, startingCash, conversionRate);
1601  }
1602  else
1603  {
1604  throw new InvalidOperationException("Algorithm.SetCash(): Cannot change cash available after algorithm initialized.");
1605  }
1606  }
1607 
1608  /// <summary>
1609  /// Set the start date for backtest.
1610  /// </summary>
1611  /// <param name="day">Int starting date 1-30</param>
1612  /// <param name="month">Int month starting date</param>
1613  /// <param name="year">Int year starting date</param>
1614  /// <remarks>Wrapper for SetStartDate(DateTime).
1615  /// Must be less than end date.
1616  /// Ignored in live trading mode.</remarks>
1617  /// <seealso cref="SetStartDate(DateTime)"/>
1618  [DocumentationAttribute(HandlingData)]
1619  public void SetStartDate(int year, int month, int day)
1620  {
1621  try
1622  {
1623  var start = new DateTime(year, month, day);
1624 
1625  // We really just want the date of the start, so it's 12am of the requested day (first moment of the day)
1626  start = start.Date;
1627 
1628  SetStartDate(start);
1629  }
1630  catch (Exception err)
1631  {
1632  throw new ArgumentException($"Date Invalid: {err.Message}");
1633  }
1634  }
1635 
1636  /// <summary>
1637  /// Set the end date for a backtest run
1638  /// </summary>
1639  /// <param name="day">Int end date 1-30</param>
1640  /// <param name="month">Int month end date</param>
1641  /// <param name="year">Int year end date</param>
1642  /// <remarks>Wrapper for SetEndDate(datetime).</remarks>
1643  /// <seealso cref="SetEndDate(DateTime)"/>
1644  [DocumentationAttribute(HandlingData)]
1645  public void SetEndDate(int year, int month, int day)
1646  {
1647  try
1648  {
1649  var end = new DateTime(year, month, day);
1650 
1651  // we want the end date to be just before the next day (last moment of the day)
1652  end = end.Date.AddDays(1).Subtract(TimeSpan.FromTicks(1));
1653 
1654  SetEndDate(end);
1655  }
1656  catch (Exception err)
1657  {
1658  throw new ArgumentException($"Date Invalid: {err.Message}");
1659  }
1660  }
1661 
1662  /// <summary>
1663  /// Set the algorithm id (backtestId or live deployId for the algorithm).
1664  /// </summary>
1665  /// <param name="algorithmId">String Algorithm Id</param>
1666  /// <remarks>Intended for internal QC Lean Engine use only as a setter for AlgorithmId</remarks>
1667  [DocumentationAttribute(HandlingData)]
1668  public void SetAlgorithmId(string algorithmId)
1669  {
1670  _algorithmId = algorithmId;
1671  }
1672 
1673  /// <summary>
1674  /// Set the start date for the backtest
1675  /// </summary>
1676  /// <param name="start">Datetime Start date for backtest</param>
1677  /// <remarks>Must be less than end date and within data available</remarks>
1678  /// <seealso cref="SetStartDate(int, int, int)"/>
1679  [DocumentationAttribute(HandlingData)]
1680  public void SetStartDate(DateTime start)
1681  {
1682  // no need to set this value in live mode, will be set using the current time.
1683  if (_liveMode) return;
1684 
1685  //Round down
1686  start = start.RoundDown(TimeSpan.FromDays(1));
1687 
1688  //Validate the start date:
1689  //1. Check range;
1690  if (start < (new DateTime(1900, 01, 01)))
1691  {
1692  throw new ArgumentOutOfRangeException(nameof(start), "Please select a start date after January 1st, 1900.");
1693  }
1694 
1695  //2. Check future date
1696  var todayInAlgorithmTimeZone = DateTime.UtcNow.ConvertFromUtc(TimeZone).Date;
1697  if (start > todayInAlgorithmTimeZone)
1698  {
1699  throw new ArgumentOutOfRangeException(nameof(start), "Please select start date less than today");
1700  }
1701 
1702  //3. Check not locked already:
1703  if (!_locked)
1704  {
1705  _start = _startDate = start;
1706  SetDateTime(_startDate.ConvertToUtc(TimeZone));
1707  }
1708  else
1709  {
1710  throw new InvalidOperationException("Algorithm.SetStartDate(): Cannot change start date after algorithm initialized.");
1711  }
1712  }
1713 
1714  /// <summary>
1715  /// Set the end date for a backtest.
1716  /// </summary>
1717  /// <param name="end">Datetime value for end date</param>
1718  /// <remarks>Must be greater than the start date</remarks>
1719  /// <seealso cref="SetEndDate(int, int, int)"/>
1720  [DocumentationAttribute(HandlingData)]
1721  public void SetEndDate(DateTime end)
1722  {
1723  // no need to set this value in live mode, will be set using the current time.
1724  if (_liveMode) return;
1725 
1726  //1. Check not locked already:
1727  if (_locked)
1728  {
1729  throw new InvalidOperationException("Algorithm.SetEndDate(): Cannot change end date after algorithm initialized.");
1730  }
1731 
1732  //Validate:
1733  //2. Check Range:
1734  var yesterdayInAlgorithmTimeZone = DateTime.UtcNow.ConvertFromUtc(TimeZone).Date.AddDays(-1);
1735  if (end > yesterdayInAlgorithmTimeZone)
1736  {
1737  end = yesterdayInAlgorithmTimeZone;
1738  }
1739 
1740  //3. Make this at the very end of the requested date
1741  _endDate = end.RoundDown(TimeSpan.FromDays(1)).AddDays(1).AddTicks(-1);
1742  }
1743 
1744  /// <summary>
1745  /// Lock the algorithm initialization to avoid user modifiying cash and data stream subscriptions
1746  /// </summary>
1747  /// <remarks>Intended for Internal QC Lean Engine use only to prevent accidental manipulation of important properties</remarks>
1748  [DocumentationAttribute(AlgorithmFramework)]
1749  public void SetLocked()
1750  {
1751  _locked = true;
1752 
1753  // The algorithm is initialized, we can now send the initial name and tags updates
1754  NameUpdated?.Invoke(this, Name);
1755  TagsUpdated?.Invoke(this, Tags);
1756  }
1757 
1758  /// <summary>
1759  /// Gets whether or not this algorithm has been locked and fully initialized
1760  /// </summary>
1761  [DocumentationAttribute(AlgorithmFramework)]
1762  public bool GetLocked()
1763  {
1764  return _locked;
1765  }
1766 
1767  /// <summary>
1768  /// Set live mode state of the algorithm run: Public setter for the algorithm property LiveMode.
1769  /// </summary>
1770  [DocumentationAttribute(LiveTrading)]
1771  public void SetLiveMode(bool live)
1772  {
1773  if (!_locked)
1774  {
1775  _liveMode = live;
1776  Notify = new NotificationManager(live);
1777  TradeBuilder.SetLiveMode(live);
1778  Securities.SetLiveMode(live);
1779  Transactions.SetLiveMode(live);
1780  if (live)
1781  {
1782  SetLiveModeStartDate();
1783  _algorithmMode = AlgorithmMode.Live;
1784  }
1785  }
1786  }
1787 
1788  /// <summary>
1789  /// Sets the algorithm running mode
1790  /// </summary>
1791  /// <param name="algorithmMode">Algorithm mode</param>
1792  public void SetAlgorithmMode(AlgorithmMode algorithmMode)
1793  {
1794  if (!_locked)
1795  {
1796  _algorithmMode = algorithmMode;
1797  SetLiveMode(_algorithmMode == AlgorithmMode.Live);
1798  }
1799  }
1800 
1801  /// <summary>
1802  /// Sets the algorithm deployment target
1803  /// </summary>
1804  /// <param name="deploymentTarget">Deployment target</param>
1805  public void SetDeploymentTarget(DeploymentTarget deploymentTarget)
1806  {
1807  if (!_locked)
1808  {
1809  _deploymentTarget = deploymentTarget;
1810  }
1811  }
1812 
1813  /// <summary>
1814  /// Set the <see cref="ITradeBuilder"/> implementation to generate trades from executions and market price updates
1815  /// </summary>
1816  [DocumentationAttribute(TradingAndOrders)]
1817  public void SetTradeBuilder(ITradeBuilder tradeBuilder)
1818  {
1819  TradeBuilder = tradeBuilder;
1822  }
1823 
1824  /// <summary>
1825  /// Add specified data to our data subscriptions. QuantConnect will funnel this data to the handle data routine.
1826  /// </summary>
1827  /// <param name="securityType">MarketType Type: Equity, Commodity, Future, FOREX or Crypto</param>
1828  /// <param name="ticker">The security ticker</param>
1829  /// <param name="resolution">Resolution of the Data Required</param>
1830  /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param>
1831  /// <param name="extendedMarketHours">Use extended market hours data</param>
1832  /// <param name="dataMappingMode">The contract mapping mode to use for the security</param>
1833  /// <param name="dataNormalizationMode">The price scaling mode to use for the security</param>
1834  [DocumentationAttribute(AddingData)]
1835  public Security AddSecurity(SecurityType securityType, string ticker, Resolution? resolution = null, bool fillForward = true, bool extendedMarketHours = false,
1836  DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null)
1837  {
1838  return AddSecurity(securityType, ticker, resolution, fillForward, Security.NullLeverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1839  }
1840 
1841  /// <summary>
1842  /// Add specified data to required list. QC will funnel this data to the handle data routine.
1843  /// </summary>
1844  /// <param name="securityType">MarketType Type: Equity, Commodity, Future, FOREX or Crypto</param>
1845  /// <param name="ticker">The security ticker</param>
1846  /// <param name="resolution">Resolution of the Data Required</param>
1847  /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param>
1848  /// <param name="leverage">Custom leverage per security</param>
1849  /// <param name="extendedMarketHours">Use extended market hours data</param>
1850  /// <param name="dataMappingMode">The contract mapping mode to use for the security</param>
1851  /// <param name="dataNormalizationMode">The price scaling mode to use for the security</param>
1852  /// <remarks> AddSecurity(SecurityType securityType, Symbol symbol, Resolution resolution, bool fillForward, decimal leverage, bool extendedMarketHours)</remarks>
1853  [DocumentationAttribute(AddingData)]
1854  public Security AddSecurity(SecurityType securityType, string ticker, Resolution? resolution, bool fillForward, decimal leverage, bool extendedMarketHours,
1855  DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null)
1856  {
1857  return AddSecurity(securityType, ticker, resolution, null, fillForward, leverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1858  }
1859 
1860  /// <summary>
1861  /// Set a required SecurityType-symbol and resolution for algorithm
1862  /// </summary>
1863  /// <param name="securityType">MarketType Type: Equity, Commodity, Future, FOREX or Crypto</param>
1864  /// <param name="ticker">The security ticker, e.g. AAPL</param>
1865  /// <param name="resolution">Resolution of the MarketType required: MarketData, Second or Minute</param>
1866  /// <param name="market">The market the requested security belongs to, such as 'usa' or 'fxcm'</param>
1867  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice.</param>
1868  /// <param name="leverage">leverage for this security</param>
1869  /// <param name="extendedMarketHours">Use extended market hours data</param>
1870  /// <param name="dataMappingMode">The contract mapping mode to use for the security</param>
1871  /// <param name="dataNormalizationMode">The price scaling mode to use for the security</param>
1872  [DocumentationAttribute(AddingData)]
1873  public Security AddSecurity(SecurityType securityType, string ticker, Resolution? resolution, string market, bool fillForward, decimal leverage, bool extendedMarketHours,
1874  DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null)
1875  {
1876  // if AddSecurity method is called to add an option or a future, we delegate a call to respective methods
1877  if (securityType == SecurityType.Option)
1878  {
1879  return AddOption(ticker, resolution, market, fillForward, leverage);
1880  }
1881 
1882  if (securityType == SecurityType.Future)
1883  {
1884  return AddFuture(ticker, resolution, market, fillForward, leverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1885  }
1886 
1887  try
1888  {
1889  if (market == null)
1890  {
1891  if (!BrokerageModel.DefaultMarkets.TryGetValue(securityType, out market))
1892  {
1893  throw new KeyNotFoundException($"No default market set for security type: {securityType}");
1894  }
1895  }
1896 
1897  Symbol symbol;
1898  if (!SymbolCache.TryGetSymbol(ticker, out symbol) ||
1899  symbol.ID.Market != market ||
1900  symbol.SecurityType != securityType)
1901  {
1902  symbol = QuantConnect.Symbol.Create(ticker, securityType, market);
1903  }
1904 
1905  return AddSecurity(symbol, resolution, fillForward, leverage, extendedMarketHours, dataMappingMode, dataNormalizationMode);
1906  }
1907  catch (Exception err)
1908  {
1909  Error("Algorithm.AddSecurity(): " + err);
1910  return null;
1911  }
1912  }
1913 
1914  /// <summary>
1915  /// Set a required SecurityType-symbol and resolution for algorithm
1916  /// </summary>
1917  /// <param name="symbol">The security Symbol</param>
1918  /// <param name="resolution">Resolution of the MarketType required: MarketData, Second or Minute</param>
1919  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice.</param>
1920  /// <param name="leverage">leverage for this security</param>
1921  /// <param name="extendedMarketHours">Use extended market hours data</param>
1922  /// <param name="dataMappingMode">The contract mapping mode to use for the security</param>
1923  /// <param name="dataNormalizationMode">The price scaling mode to use for the security</param>
1924  /// <param name="contractDepthOffset">The continuous contract desired offset from the current front month.
1925  /// For example, 0 (default) will use the front month, 1 will use the back month contract</param>
1926  /// <returns>The new Security that was added to the algorithm</returns>
1927  [DocumentationAttribute(AddingData)]
1928  public Security AddSecurity(Symbol symbol, Resolution? resolution = null, bool fillForward = true, decimal leverage = Security.NullLeverage, bool extendedMarketHours = false,
1929  DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int contractDepthOffset = 0)
1930  {
1931  // allow users to specify negative numbers, we get the abs of it
1932  var contractOffset = (uint)Math.Abs(contractDepthOffset);
1933  if (contractOffset > Futures.MaximumContractDepthOffset)
1934  {
1935  throw new ArgumentOutOfRangeException(nameof(contractDepthOffset), $"'contractDepthOffset' current maximum value is {Futures.MaximumContractDepthOffset}." +
1936  $" Front month (0) and only {Futures.MaximumContractDepthOffset} back month contracts are currently supported.");
1937  }
1938 
1939  var isCanonical = symbol.IsCanonical();
1940 
1941  // Short-circuit to AddOptionContract because it will add the underlying if required
1942  if (!isCanonical && symbol.SecurityType.IsOption())
1943  {
1944  return AddOptionContract(symbol, resolution, fillForward, leverage, extendedMarketHours);
1945  }
1946 
1947  var securityResolution = resolution;
1948  var securityFillForward = fillForward;
1949  if (isCanonical && symbol.SecurityType.IsOption() && symbol.SecurityType != SecurityType.FutureOption)
1950  {
1951  // option is daily only, for now exclude FOPs
1952  securityResolution = Resolution.Daily;
1953  securityFillForward = false;
1954  }
1955 
1956  var isFilteredSubscription = !isCanonical;
1957  List<SubscriptionDataConfig> configs;
1958  // we pass dataNormalizationMode to SubscriptionManager.SubscriptionDataConfigService.Add conditionally,
1959  // so the default value for its argument is used when the it is null here.
1960  if (dataNormalizationMode.HasValue)
1961  {
1963  securityResolution,
1964  securityFillForward,
1965  extendedMarketHours,
1966  isFilteredSubscription,
1967  dataNormalizationMode: dataNormalizationMode.Value,
1968  contractDepthOffset: (uint)contractDepthOffset);
1969  }
1970  else
1971  {
1973  securityResolution,
1974  securityFillForward,
1975  extendedMarketHours,
1976  isFilteredSubscription,
1977  contractDepthOffset: (uint)contractDepthOffset);
1978  }
1979 
1980  var security = Securities.CreateSecurity(symbol, configs, leverage);
1981 
1982  if (isCanonical)
1983  {
1984  security.IsTradable = false;
1985  Securities.Add(security);
1986 
1987  // add this security to the user defined universe
1988  Universe universe;
1989  if (!UniverseManager.ContainsKey(symbol))
1990  {
1991  var canonicalConfig = configs.First();
1992  var universeSettingsResolution = canonicalConfig.Resolution;
1993  if (symbol.SecurityType.IsOption())
1994  {
1995  universeSettingsResolution = resolution ?? UniverseSettings.Resolution;
1996  }
1997  var settings = new UniverseSettings(universeSettingsResolution, leverage, fillForward, extendedMarketHours, UniverseSettings.MinimumTimeInUniverse)
1998  {
1999  Asynchronous = UniverseSettings.Asynchronous
2000  };
2001 
2002  if (symbol.SecurityType.IsOption())
2003  {
2004  universe = new OptionChainUniverse((Option)security, settings);
2005  }
2006  else
2007  {
2008  // add the expected configurations of the canonical symbol right away, will allow it to warmup and indicators register to them
2010  GetResolution(symbol, resolution, null), isCanonical: false);
2011  var continuousUniverseSettings = new UniverseSettings(settings)
2012  {
2013  ExtendedMarketHours = extendedMarketHours,
2014  DataMappingMode = dataMappingMode ?? UniverseSettings.DataMappingMode,
2015  DataNormalizationMode = dataNormalizationMode ?? UniverseSettings.GetUniverseNormalizationModeOrDefault(symbol.SecurityType),
2016  ContractDepthOffset = (int)contractOffset,
2017  SubscriptionDataTypes = dataTypes,
2018  Asynchronous = UniverseSettings.Asynchronous
2019  };
2021 
2022  // let's add a MHDB entry for the continuous symbol using the associated security
2023  var continuousContractSymbol = ContinuousContractUniverse.CreateSymbol(security.Symbol);
2024  MarketHoursDatabase.SetEntry(continuousContractSymbol.ID.Market,
2025  continuousContractSymbol.ID.Symbol,
2026  continuousContractSymbol.ID.SecurityType,
2027  security.Exchange.Hours);
2028  AddUniverse(new ContinuousContractUniverse(security, continuousUniverseSettings, LiveMode, new SubscriptionDataConfig(canonicalConfig, symbol: continuousContractSymbol)));
2029 
2030  universe = new FuturesChainUniverse((Future)security, settings);
2031  }
2032 
2033  AddUniverse(universe);
2034  }
2035  return security;
2036  }
2037 
2038  return AddToUserDefinedUniverse(security, configs);
2039  }
2040 
2041  /// <summary>
2042  /// Creates and adds a new <see cref="Equity"/> security to the algorithm
2043  /// </summary>
2044  /// <param name="ticker">The equity ticker symbol</param>
2045  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2046  /// <param name="market">The equity's market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2047  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
2048  /// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
2049  /// <param name="extendedMarketHours">True to send data during pre and post market sessions. Default is <value>false</value></param>
2050  /// <param name="dataNormalizationMode">The price scaling mode to use for the equity</param>
2051  /// <returns>The new <see cref="Equity"/> security</returns>
2052  [DocumentationAttribute(AddingData)]
2053  public Equity AddEquity(string ticker, Resolution? resolution = null, string market = null, bool fillForward = true,
2054  decimal leverage = Security.NullLeverage, bool extendedMarketHours = false, DataNormalizationMode? dataNormalizationMode = null)
2055  {
2056  return AddSecurity<Equity>(SecurityType.Equity, ticker, resolution, market, fillForward, leverage, extendedMarketHours, normalizationMode: dataNormalizationMode);
2057  }
2058 
2059  /// <summary>
2060  /// Creates and adds a new equity <see cref="Option"/> security to the algorithm
2061  /// </summary>
2062  /// <param name="underlying">The underlying equity ticker</param>
2063  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2064  /// <param name="market">The equity's market, <seealso cref="Market"/>. Default is value null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2065  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
2066  /// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
2067  /// <returns>The new <see cref="Option"/> security</returns>
2068  [DocumentationAttribute(AddingData)]
2069  public Option AddOption(string underlying, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
2070  {
2071  if (market == null)
2072  {
2073  if (!BrokerageModel.DefaultMarkets.TryGetValue(SecurityType.Option, out market))
2074  {
2075  throw new KeyNotFoundException($"No default market set for security type: {SecurityType.Option}");
2076  }
2077  }
2078 
2079  var underlyingSymbol = QuantConnect.Symbol.Create(underlying, SecurityType.Equity, market);
2080  return AddOption(underlyingSymbol, resolution, market, fillForward, leverage);
2081  }
2082 
2083  /// <summary>
2084  /// Creates and adds a new <see cref="Option"/> security to the algorithm.
2085  /// This method can be used to add options with non-equity asset classes
2086  /// to the algorithm (e.g. Future Options).
2087  /// </summary>
2088  /// <param name="underlying">Underlying asset Symbol to use as the option's underlying</param>
2089  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2090  /// <param name="market">The option's market, <seealso cref="Market"/>. Default value is null, but will be resolved using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2091  /// <param name="fillForward">If true, data will be provided to the algorithm every Second, Minute, Hour, or Day, while the asset is open and depending on the Resolution this option was configured to use.</param>
2092  /// <param name="leverage">The requested leverage for the </param>
2093  /// <returns>The new option security instance</returns>
2094  /// <exception cref="KeyNotFoundException"></exception>
2095  [DocumentationAttribute(AddingData)]
2096  public Option AddOption(Symbol underlying, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
2097  {
2098  return AddOption(underlying, null, resolution, market, fillForward, leverage);
2099  }
2100 
2101  /// <summary>
2102  /// Creates and adds a new <see cref="Option"/> security to the algorithm.
2103  /// This method can be used to add options with non-equity asset classes
2104  /// to the algorithm (e.g. Future Options).
2105  /// </summary>
2106  /// <param name="underlying">Underlying asset Symbol to use as the option's underlying</param>
2107  /// <param name="targetOption">The target option ticker. This is useful when the option ticker does not match the underlying, e.g. SPX index and the SPXW weekly option. If null is provided will use underlying</param>
2108  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2109  /// <param name="market">The option's market, <seealso cref="Market"/>. Default value is null, but will be resolved using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2110  /// <param name="fillForward">If true, data will be provided to the algorithm every Second, Minute, Hour, or Day, while the asset is open and depending on the Resolution this option was configured to use.</param>
2111  /// <param name="leverage">The requested leverage for the </param>
2112  /// <returns>The new option security instance</returns>
2113  /// <exception cref="KeyNotFoundException"></exception>
2114  [DocumentationAttribute(AddingData)]
2115  public Option AddOption(Symbol underlying, string targetOption, Resolution? resolution = null,
2116  string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
2117  {
2118  var optionType = QuantConnect.Symbol.GetOptionTypeFromUnderlying(underlying);
2119 
2120  if (market == null)
2121  {
2122  if (!BrokerageModel.DefaultMarkets.TryGetValue(optionType, out market))
2123  {
2124  throw new KeyNotFoundException($"No default market set for security type: {optionType}");
2125  }
2126  }
2127 
2128  Symbol canonicalSymbol;
2129 
2130  string alias;
2131  if (!string.IsNullOrEmpty(targetOption))
2132  {
2133  alias = $"?{targetOption}";
2134  }
2135  else
2136  {
2137  alias = $"?{underlying.Value}";
2138  }
2139  if (!SymbolCache.TryGetSymbol(alias, out canonicalSymbol) ||
2140  canonicalSymbol.ID.Market != market ||
2141  !canonicalSymbol.SecurityType.IsOption())
2142  {
2143  canonicalSymbol = QuantConnect.Symbol.CreateCanonicalOption(underlying, targetOption, market, alias);
2144  }
2145 
2146  return (Option)AddSecurity(canonicalSymbol, resolution, fillForward, leverage);
2147  }
2148 
2149  /// <summary>
2150  /// Creates and adds a new <see cref="Future"/> security to the algorithm
2151  /// </summary>
2152  /// <param name="ticker">The future ticker</param>
2153  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2154  /// <param name="market">The futures market, <seealso cref="Market"/>. Default is value null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2155  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
2156  /// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
2157  /// <param name="extendedMarketHours">Use extended market hours data</param>
2158  /// <param name="dataMappingMode">The contract mapping mode to use for the continuous future contract</param>
2159  /// <param name="dataNormalizationMode">The price scaling mode to use for the continuous future contract</param>
2160  /// <param name="contractDepthOffset">The continuous future contract desired offset from the current front month.
2161  /// For example, 0 (default) will use the front month, 1 will use the back month contract</param>
2162  /// <returns>The new <see cref="Future"/> security</returns>
2163  [DocumentationAttribute(AddingData)]
2164  public Future AddFuture(string ticker, Resolution? resolution = null, string market = null,
2165  bool fillForward = true, decimal leverage = Security.NullLeverage, bool extendedMarketHours = false,
2166  DataMappingMode? dataMappingMode = null, DataNormalizationMode? dataNormalizationMode = null, int contractDepthOffset = 0)
2167  {
2168  if (market == null)
2169  {
2170  if (!SymbolPropertiesDatabase.TryGetMarket(ticker, SecurityType.Future, out market)
2171  && !BrokerageModel.DefaultMarkets.TryGetValue(SecurityType.Future, out market))
2172  {
2173  throw new KeyNotFoundException($"No default market set for security type: {SecurityType.Future}");
2174  }
2175  }
2176 
2177  Symbol canonicalSymbol;
2178  var alias = "/" + ticker;
2179  if (!SymbolCache.TryGetSymbol(alias, out canonicalSymbol) ||
2180  canonicalSymbol.ID.Market != market ||
2181  canonicalSymbol.SecurityType != SecurityType.Future)
2182  {
2183  canonicalSymbol = QuantConnect.Symbol.Create(ticker, SecurityType.Future, market, alias);
2184  }
2185 
2186  return (Future)AddSecurity(canonicalSymbol, resolution, fillForward, leverage, extendedMarketHours, dataMappingMode: dataMappingMode,
2187  dataNormalizationMode: dataNormalizationMode, contractDepthOffset: contractDepthOffset);
2188  }
2189 
2190  /// <summary>
2191  /// Creates and adds a new single <see cref="Future"/> contract to the algorithm
2192  /// </summary>
2193  /// <param name="symbol">The futures contract symbol</param>
2194  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2195  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
2196  /// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
2197  /// <param name="extendedMarketHours">Use extended market hours data</param>
2198  /// <returns>The new <see cref="Future"/> security</returns>
2199  [DocumentationAttribute(AddingData)]
2200  public Future AddFutureContract(Symbol symbol, Resolution? resolution = null, bool fillForward = true,
2201  decimal leverage = Security.NullLeverage, bool extendedMarketHours = false)
2202  {
2203  return (Future)AddSecurity(symbol, resolution, fillForward, leverage, extendedMarketHours);
2204  }
2205 
2206  /// <summary>
2207  /// Creates and adds a new Future Option contract to the algorithm.
2208  /// </summary>
2209  /// <param name="symbol">The <see cref="Future"/> canonical symbol (i.e. Symbol returned from <see cref="AddFuture"/>)</param>
2210  /// <param name="optionFilter">Filter to apply to option contracts loaded as part of the universe</param>
2211  /// <returns>The new <see cref="Option"/> security, containing a <see cref="Future"/> as its underlying.</returns>
2212  /// <exception cref="ArgumentException">The symbol provided is not canonical.</exception>
2213  [DocumentationAttribute(AddingData)]
2214  public void AddFutureOption(Symbol symbol, Func<OptionFilterUniverse, OptionFilterUniverse> optionFilter = null)
2215  {
2216  if (!symbol.IsCanonical())
2217  {
2218  throw new ArgumentException("Symbol provided must be canonical (i.e. the Symbol returned from AddFuture(), not AddFutureContract().");
2219  }
2220 
2221  AddUniverseOptions(symbol, optionFilter);
2222  }
2223 
2224  /// <summary>
2225  /// Adds a future option contract to the algorithm.
2226  /// </summary>
2227  /// <param name="symbol">Option contract Symbol</param>
2228  /// <param name="resolution">Resolution of the option contract, i.e. the granularity of the data</param>
2229  /// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
2230  /// <param name="leverage">The leverage to apply to the option contract</param>
2231  /// <param name="extendedMarketHours">Use extended market hours data</param>
2232  /// <returns>Option security</returns>
2233  /// <exception cref="ArgumentException">Symbol is canonical (i.e. a generic Symbol returned from <see cref="AddFuture"/> or <see cref="AddOption(string, Resolution?, string, bool, decimal)"/>)</exception>
2234  [DocumentationAttribute(AddingData)]
2235  public Option AddFutureOptionContract(Symbol symbol, Resolution? resolution = null, bool fillForward = true,
2236  decimal leverage = Security.NullLeverage, bool extendedMarketHours = false)
2237  {
2238  if (symbol.IsCanonical())
2239  {
2240  throw new ArgumentException("Expected non-canonical Symbol (i.e. a Symbol representing a specific Future contract");
2241  }
2242 
2243  return AddOptionContract(symbol, resolution, fillForward, leverage, extendedMarketHours);
2244  }
2245 
2246  /// <summary>
2247  /// Creates and adds index options to the algorithm.
2248  /// </summary>
2249  /// <param name="underlying">The underlying ticker of the Index Option</param>
2250  /// <param name="resolution">Resolution of the index option contracts, i.e. the granularity of the data</param>
2251  /// <param name="market">The foreign exchange trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2252  /// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
2253  /// <returns>Canonical Option security</returns>
2254  [DocumentationAttribute(AddingData)]
2255  public IndexOption AddIndexOption(string underlying, Resolution? resolution = null, string market = null, bool fillForward = true)
2256  {
2257  return AddIndexOption(underlying, null, resolution, market, fillForward);
2258  }
2259 
2260  /// <summary>
2261  /// Creates and adds index options to the algorithm.
2262  /// </summary>
2263  /// <param name="symbol">The Symbol of the <see cref="Security"/> returned from <see cref="AddIndex"/></param>
2264  /// <param name="resolution">Resolution of the index option contracts, i.e. the granularity of the data</param>
2265  /// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
2266  /// <returns>Canonical Option security</returns>
2267  [DocumentationAttribute(AddingData)]
2268  public IndexOption AddIndexOption(Symbol symbol, Resolution? resolution = null, bool fillForward = true)
2269  {
2270  return AddIndexOption(symbol, null, resolution, fillForward);
2271  }
2272 
2273  /// <summary>
2274  /// Creates and adds index options to the algorithm.
2275  /// </summary>
2276  /// <param name="symbol">The Symbol of the <see cref="Security"/> returned from <see cref="AddIndex"/></param>
2277  /// <param name="targetOption">The target option ticker. This is useful when the option ticker does not match the underlying, e.g. SPX index and the SPXW weekly option. If null is provided will use underlying</param>
2278  /// <param name="resolution">Resolution of the index option contracts, i.e. the granularity of the data</param>
2279  /// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
2280  /// <returns>Canonical Option security</returns>
2281  [DocumentationAttribute(AddingData)]
2282  public IndexOption AddIndexOption(Symbol symbol, string targetOption, Resolution? resolution = null, bool fillForward = true)
2283  {
2284  if (symbol.SecurityType != SecurityType.Index)
2285  {
2286  throw new ArgumentException("Symbol provided must be of type SecurityType.Index");
2287  }
2288 
2289  return (IndexOption)AddOption(symbol, targetOption, resolution, symbol.ID.Market, fillForward);
2290  }
2291 
2292  /// <summary>
2293  /// Creates and adds index options to the algorithm.
2294  /// </summary>
2295  /// <param name="underlying">The underlying ticker of the Index Option</param>
2296  /// <param name="targetOption">The target option ticker. This is useful when the option ticker does not match the underlying, e.g. SPX index and the SPXW weekly option. If null is provided will use underlying</param>
2297  /// <param name="resolution">Resolution of the index option contracts, i.e. the granularity of the data</param>
2298  /// <param name="market">The foreign exchange trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2299  /// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
2300  /// <returns>Canonical Option security</returns>
2301  [DocumentationAttribute(AddingData)]
2302  public IndexOption AddIndexOption(string underlying, string targetOption, Resolution? resolution = null, string market = null, bool fillForward = true)
2303  {
2304  if (market == null && !BrokerageModel.DefaultMarkets.TryGetValue(SecurityType.Index, out market))
2305  {
2306  throw new KeyNotFoundException($"No default market set for underlying security type: {SecurityType.Index}");
2307  }
2308 
2309  return AddIndexOption(
2310  QuantConnect.Symbol.Create(underlying, SecurityType.Index, market),
2311  targetOption, resolution, fillForward);
2312  }
2313 
2314  /// <summary>
2315  /// Adds an index option contract to the algorithm.
2316  /// </summary>
2317  /// <param name="symbol">Symbol of the index option contract</param>
2318  /// <param name="resolution">Resolution of the index option contract, i.e. the granularity of the data</param>
2319  /// <param name="fillForward">If true, this will fill in missing data points with the previous data point</param>
2320  /// <returns>Index Option Contract</returns>
2321  /// <exception cref="ArgumentException">The provided Symbol is not an Index Option</exception>
2322  [DocumentationAttribute(AddingData)]
2323  public IndexOption AddIndexOptionContract(Symbol symbol, Resolution? resolution = null, bool fillForward = true)
2324  {
2325  if (symbol.SecurityType != SecurityType.IndexOption || symbol.IsCanonical())
2326  {
2327  throw new ArgumentException("Symbol provided must be non-canonical and of type SecurityType.IndexOption");
2328  }
2329 
2330  return (IndexOption)AddOptionContract(symbol, resolution, fillForward);
2331  }
2332 
2333  /// <summary>
2334  /// Creates and adds a new single <see cref="Option"/> contract to the algorithm
2335  /// </summary>
2336  /// <param name="symbol">The option contract symbol</param>
2337  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2338  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
2339  /// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
2340  /// <param name="extendedMarketHours">Use extended market hours data</param>
2341  /// <returns>The new <see cref="Option"/> security</returns>
2342  [DocumentationAttribute(AddingData)]
2343  public Option AddOptionContract(Symbol symbol, Resolution? resolution = null, bool fillForward = true,
2344  decimal leverage = Security.NullLeverage, bool extendedMarketHours = false)
2345  {
2346  if (symbol == null || !symbol.SecurityType.IsOption() || symbol.Underlying == null)
2347  {
2348  throw new ArgumentException($"Unexpected option symbol {symbol}. " +
2349  $"Please provide a valid option contract with it's underlying symbol set.");
2350  }
2351 
2352  // add underlying if not present
2353  var underlying = symbol.Underlying;
2354  Security underlyingSecurity;
2355  List<SubscriptionDataConfig> underlyingConfigs;
2356  if (!Securities.TryGetValue(underlying, out underlyingSecurity) ||
2357  // The underlying might have been removed, let's see if there's already a subscription for it
2358  (!underlyingSecurity.IsTradable && SubscriptionManager.SubscriptionDataConfigService.GetSubscriptionDataConfigs(underlying).Count == 0))
2359  {
2360  underlyingSecurity = AddSecurity(underlying, resolution, fillForward, leverage, extendedMarketHours);
2362  .GetSubscriptionDataConfigs(underlying);
2363  }
2364  else if (underlyingSecurity != null && underlyingSecurity.IsDelisted)
2365  {
2366  throw new ArgumentException($"The underlying {underlying.SecurityType} asset ({underlying.Value}) is delisted " +
2367  $"(current time is {Time})");
2368  }
2369  else
2370  {
2372  .GetSubscriptionDataConfigs(underlying);
2373 
2374  var dataNormalizationMode = underlyingConfigs.DataNormalizationMode();
2375  if (dataNormalizationMode != DataNormalizationMode.Raw && _locked)
2376  {
2377  // We check the "locked" flag here because during initialization we need to load existing open orders and holdings from brokerages.
2378  // There is no data streaming yet, so it is safe to change the data normalization mode to Raw.
2379  throw new ArgumentException($"The underlying {underlying.SecurityType} asset ({underlying.Value}) is set to " +
2380  $"{dataNormalizationMode}, please change this to DataNormalizationMode.Raw with the " +
2381  "SetDataNormalization() method"
2382  );
2383  }
2384  }
2385 
2386  var configs = SubscriptionManager.SubscriptionDataConfigService.Add(symbol, resolution, fillForward, extendedMarketHours,
2387  dataNormalizationMode: DataNormalizationMode.Raw);
2388  var option = (Option)Securities.CreateSecurity(symbol, configs, leverage, underlying: underlyingSecurity);
2389 
2390  underlyingConfigs.SetDataNormalizationMode(DataNormalizationMode.Raw);
2391  // For backward compatibility we need to refresh the security DataNormalizationMode Property
2392  underlyingSecurity.RefreshDataNormalizationModeProperty();
2393 
2394  Securities.Add(option);
2395 
2396  // get or create the universe
2397  var universeSymbol = OptionContractUniverse.CreateSymbol(symbol.ID.Market, symbol.Underlying.SecurityType);
2398  Universe universe;
2399  if (!UniverseManager.TryGetValue(universeSymbol, out universe))
2400  {
2401  var settings = new UniverseSettings(UniverseSettings)
2402  {
2404  Resolution = underlyingConfigs.GetHighestResolution(),
2405  ExtendedMarketHours = extendedMarketHours
2406  };
2407  universe = AddUniverse(new OptionContractUniverse(new SubscriptionDataConfig(configs.First(), symbol: universeSymbol), settings));
2408  }
2409 
2410  // update the universe
2411  var optionUniverse = universe as OptionContractUniverse;
2412  if (optionUniverse != null)
2413  {
2414  foreach (var subscriptionDataConfig in configs.Concat(underlyingConfigs))
2415  {
2416  optionUniverse.Add(subscriptionDataConfig);
2417  }
2418  }
2419 
2420  return option;
2421  }
2422 
2423  /// <summary>
2424  /// Creates and adds a new <see cref="Forex"/> security to the algorithm
2425  /// </summary>
2426  /// <param name="ticker">The currency pair</param>
2427  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2428  /// <param name="market">The foreign exchange trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2429  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
2430  /// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
2431  /// <returns>The new <see cref="Forex"/> security</returns>
2432  [DocumentationAttribute(AddingData)]
2433  public Forex AddForex(string ticker, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
2434  {
2435  return AddSecurity<Forex>(SecurityType.Forex, ticker, resolution, market, fillForward, leverage, false);
2436  }
2437 
2438  /// <summary>
2439  /// Creates and adds a new <see cref="Cfd"/> security to the algorithm
2440  /// </summary>
2441  /// <param name="ticker">The currency pair</param>
2442  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2443  /// <param name="market">The cfd trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2444  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
2445  /// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
2446  /// <returns>The new <see cref="Cfd"/> security</returns>
2447  [DocumentationAttribute(AddingData)]
2448  public Cfd AddCfd(string ticker, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
2449  {
2450  return AddSecurity<Cfd>(SecurityType.Cfd, ticker, resolution, market, fillForward, leverage, false);
2451  }
2452 
2453 
2454  /// <summary>
2455  /// Creates and adds a new <see cref="Index"/> security to the algorithm
2456  /// </summary>
2457  /// <param name="ticker">The currency pair</param>
2458  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2459  /// <param name="market">The index trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2460  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
2461  /// <returns>The new <see cref="Index"/> security</returns>
2462  [DocumentationAttribute(AddingData)]
2463  public Index AddIndex(string ticker, Resolution? resolution = null, string market = null, bool fillForward = true)
2464  {
2465  var index = AddSecurity<Index>(SecurityType.Index, ticker, resolution, market, fillForward, 1, false);
2466  return index;
2467  }
2468 
2469  /// <summary>
2470  /// Creates and adds a new <see cref="Crypto"/> security to the algorithm
2471  /// </summary>
2472  /// <param name="ticker">The currency pair</param>
2473  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2474  /// <param name="market">The cfd trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2475  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
2476  /// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
2477  /// <returns>The new <see cref="Crypto"/> security</returns>
2478  [DocumentationAttribute(AddingData)]
2479  public Crypto AddCrypto(string ticker, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
2480  {
2481  return AddSecurity<Crypto>(SecurityType.Crypto, ticker, resolution, market, fillForward, leverage, false);
2482  }
2483 
2484  /// <summary>
2485  /// Creates and adds a new <see cref="CryptoFuture"/> security to the algorithm
2486  /// </summary>
2487  /// <param name="ticker">The currency pair</param>
2488  /// <param name="resolution">The <see cref="Resolution"/> of market data, Tick, Second, Minute, Hour, or Daily. Default is <see cref="Resolution.Minute"/></param>
2489  /// <param name="market">The cfd trading market, <seealso cref="Market"/>. Default value is null and looked up using BrokerageModel.DefaultMarkets in <see cref="AddSecurity{T}"/></param>
2490  /// <param name="fillForward">If true, returns the last available data even if none in that timeslice. Default is <value>true</value></param>
2491  /// <param name="leverage">The requested leverage for this equity. Default is set by <see cref="SecurityInitializer"/></param>
2492  /// <returns>The new <see cref="CryptoFuture"/> security</returns>
2493  [DocumentationAttribute(AddingData)]
2494  public CryptoFuture AddCryptoFuture(string ticker, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage)
2495  {
2496  return AddSecurity<CryptoFuture>(SecurityType.CryptoFuture, ticker, resolution, market, fillForward, leverage, false);
2497  }
2498 
2499  /// <summary>
2500  /// Removes the security with the specified symbol. This will cancel all
2501  /// open orders and then liquidate any existing holdings
2502  /// </summary>
2503  /// <param name="symbol">The symbol of the security to be removed</param>
2504  /// <remarks>Sugar syntax for <see cref="AddOptionContract"/></remarks>
2505  [DocumentationAttribute(AddingData)]
2506  public bool RemoveOptionContract(Symbol symbol)
2507  {
2508  return RemoveSecurity(symbol);
2509  }
2510 
2511  /// <summary>
2512  /// Removes the security with the specified symbol. This will cancel all
2513  /// open orders and then liquidate any existing holdings
2514  /// </summary>
2515  /// <param name="symbol">The symbol of the security to be removed</param>
2516  [DocumentationAttribute(AddingData)]
2517  public bool RemoveSecurity(Symbol symbol)
2518  {
2519  Security security;
2520  if (!Securities.TryGetValue(symbol, out security))
2521  {
2522  return false;
2523  }
2524 
2525  if (!IsWarmingUp)
2526  {
2527  // cancel open orders
2528  Transactions.CancelOpenOrders(security.Symbol);
2529  }
2530 
2531  // liquidate if invested
2532  if (security.Invested)
2533  {
2534  Liquidate(security.Symbol);
2535  }
2536 
2537  // Clear cache
2538  security.Cache.Reset();
2539 
2540  // Mark security as not tradable
2541  security.IsTradable = false;
2542  if (symbol.IsCanonical())
2543  {
2544  // remove underlying equity data if it's marked as internal
2545  foreach (var kvp in UniverseManager.Where(x => x.Value.Configuration.Symbol == symbol
2546  || x.Value.Configuration.Symbol == ContinuousContractUniverse.CreateSymbol(symbol)))
2547  {
2548  var universe = kvp.Value;
2549  // remove underlying if not used by other universes
2550  var otherUniverses = UniverseManager.Select(ukvp => ukvp.Value).Where(u => !ReferenceEquals(u, universe)).ToList();
2551  if (symbol.HasUnderlying)
2552  {
2553  var underlying = Securities[symbol.Underlying];
2554  if (!otherUniverses.Any(u => u.Members.ContainsKey(underlying.Symbol)))
2555  {
2556  RemoveSecurity(underlying.Symbol);
2557  }
2558  }
2559 
2560  // remove child securities (option contracts for option chain universes) if not used in other universes
2561  // we order the securities so that the removal is deterministic, it will liquidate any holdings
2562  foreach (var child in universe.Members.Values.OrderBy(security1 => security1.Symbol))
2563  {
2564  if (!otherUniverses.Any(u => u.Members.ContainsKey(child.Symbol)) && !child.Symbol.IsCanonical())
2565  {
2566  RemoveSecurity(child.Symbol);
2567  }
2568  }
2569 
2570  // finally, dispose and remove the canonical security from the universe manager
2571  UniverseManager.Remove(kvp.Key);
2572  _universeSelectionUniverses.Remove(security.Symbol);
2573  }
2574  }
2575  else
2576  {
2577  lock (_pendingUniverseAdditionsLock)
2578  {
2579  // we need to handle existing universes and pending to be added universes, that will be pushed
2580  // at the end of this time step see OnEndOfTimeStep()
2581  foreach (var universe in UniverseManager.Select(x => x.Value).OfType<UserDefinedUniverse>())
2582  {
2583  universe.Remove(symbol);
2584  }
2585  // for existing universes we need to purge pending additions too, also handled at OnEndOfTimeStep()
2586  _pendingUserDefinedUniverseSecurityAdditions.RemoveAll(addition => addition.Security.Symbol == symbol);
2587  }
2588  }
2589 
2590  return true;
2591  }
2592 
2593  /// <summary>
2594  /// AddData<typeparam name="T"/> a new user defined data source, requiring only the minimum config options.
2595  /// The data is added with a default time zone of NewYork (Eastern Daylight Savings Time)
2596  /// </summary>
2597  /// <param name="ticker">Key/Ticker for data</param>
2598  /// <param name="resolution">Resolution of the data</param>
2599  /// <returns>The new <see cref="Security"/></returns>
2600  /// <remarks>Generic type T must implement base data</remarks>
2601  [DocumentationAttribute(AddingData)]
2602  public Security AddData<T>(string ticker, Resolution? resolution = null)
2603  where T : IBaseData, new()
2604  {
2605  //Add this new generic data as a tradeable security:
2606  // Defaults:extended market hours" = true because we want events 24 hours,
2607  // fillforward = false because only want to trigger when there's new custom data.
2608  // leverage = 1 because no leverage on nonmarket data?
2609  return AddData<T>(ticker, resolution, fillForward: false, leverage: 1m);
2610  }
2611 
2612  /// <summary>
2613  /// AddData<typeparam name="T"/> a new user defined data source, requiring only the minimum config options.
2614  /// The data is added with a default time zone of NewYork (Eastern Daylight Savings Time)
2615  /// </summary>
2616  /// <param name="underlying">The underlying symbol for the custom data</param>
2617  /// <param name="resolution">Resolution of the data</param>
2618  /// <returns>The new <see cref="Security"/></returns>
2619  /// <remarks>Generic type T must implement base data</remarks>
2620  [DocumentationAttribute(AddingData)]
2621  public Security AddData<T>(Symbol underlying, Resolution? resolution = null)
2622  where T : IBaseData, new()
2623  {
2624  //Add this new generic data as a tradeable security:
2625  // Defaults:extended market hours" = true because we want events 24 hours,
2626  // fillforward = false because only want to trigger when there's new custom data.
2627  // leverage = 1 because no leverage on nonmarket data?
2628  return AddData<T>(underlying, resolution, fillForward: false, leverage: 1m);
2629  }
2630 
2631 
2632  /// <summary>
2633  /// AddData<typeparam name="T"/> a new user defined data source, requiring only the minimum config options.
2634  /// The data is added with a default time zone of NewYork (Eastern Daylight Savings Time)
2635  /// </summary>
2636  /// <param name="ticker">Key/Ticker for data</param>
2637  /// <param name="resolution">Resolution of the Data Required</param>
2638  /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param>
2639  /// <param name="leverage">Custom leverage per security</param>
2640  /// <returns>The new <see cref="Security"/></returns>
2641  /// <remarks>Generic type T must implement base data</remarks>
2642  [DocumentationAttribute(AddingData)]
2643  public Security AddData<T>(string ticker, Resolution? resolution, bool fillForward, decimal leverage = 1.0m)
2644  where T : IBaseData, new()
2645  {
2646  return AddData<T>(ticker, resolution, null, fillForward, leverage);
2647  }
2648 
2649  /// <summary>
2650  /// AddData<typeparam name="T"/> a new user defined data source, requiring only the minimum config options.
2651  /// The data is added with a default time zone of NewYork (Eastern Daylight Savings Time)
2652  /// </summary>
2653  /// <param name="underlying">The underlying symbol for the custom data</param>
2654  /// <param name="resolution">Resolution of the Data Required</param>
2655  /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param>
2656  /// <param name="leverage">Custom leverage per security</param>
2657  /// <returns>The new <see cref="Security"/></returns>
2658  /// <remarks>Generic type T must implement base data</remarks>
2659  [DocumentationAttribute(AddingData)]
2660  public Security AddData<T>(Symbol underlying, Resolution? resolution, bool fillForward, decimal leverage = 1.0m)
2661  where T : IBaseData, new()
2662  {
2663  return AddData<T>(underlying, resolution, null, fillForward, leverage);
2664  }
2665 
2666  /// <summary>
2667  /// AddData<typeparam name="T"/> a new user defined data source, requiring only the minimum config options.
2668  /// </summary>
2669  /// <param name="ticker">Key/Ticker for data</param>
2670  /// <param name="resolution">Resolution of the Data Required</param>
2671  /// <param name="timeZone">Specifies the time zone of the raw data</param>
2672  /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param>
2673  /// <param name="leverage">Custom leverage per security</param>
2674  /// <returns>The new <see cref="Security"/></returns>
2675  /// <remarks>Generic type T must implement base data</remarks>
2676  [DocumentationAttribute(AddingData)]
2677  public Security AddData<T>(string ticker, Resolution? resolution, DateTimeZone timeZone, bool fillForward = false, decimal leverage = 1.0m)
2678  where T : IBaseData, new()
2679  {
2680  return AddData(typeof(T), ticker, resolution, timeZone, fillForward, leverage);
2681  }
2682 
2683  /// <summary>
2684  /// AddData<typeparam name="T"/> a new user defined data source, requiring only the minimum config options.
2685  /// </summary>
2686  /// <param name="underlying">The underlying symbol for the custom data</param>
2687  /// <param name="resolution">Resolution of the Data Required</param>
2688  /// <param name="timeZone">Specifies the time zone of the raw data</param>
2689  /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param>
2690  /// <param name="leverage">Custom leverage per security</param>
2691  /// <returns>The new <see cref="Security"/></returns>
2692  /// <remarks>Generic type T must implement base data</remarks>
2693  [DocumentationAttribute(AddingData)]
2694  public Security AddData<T>(Symbol underlying, Resolution? resolution, DateTimeZone timeZone, bool fillForward = false, decimal leverage = 1.0m)
2695  where T : IBaseData, new()
2696  {
2697  return AddData(typeof(T), underlying, resolution, timeZone, fillForward, leverage);
2698  }
2699 
2700  /// <summary>
2701  /// AddData<typeparam name="T"/> a new user defined data source including symbol properties and exchange hours,
2702  /// all other vars are not required and will use defaults.
2703  /// </summary>
2704  /// <param name="ticker">Key/Ticker for data</param>
2705  /// <param name="properties">The properties of this new custom data</param>
2706  /// <param name="exchangeHours">The Exchange hours of this symbol</param>
2707  /// <param name="resolution">Resolution of the Data Required</param>
2708  /// <param name="fillForward">When no data available on a tradebar, return the last data that was generated</param>
2709  /// <param name="leverage">Custom leverage per security</param>
2710  /// <returns>The new <see cref="Security"/></returns>
2711  [DocumentationAttribute(AddingData)]
2712  public Security AddData<T>(string ticker, SymbolProperties properties, SecurityExchangeHours exchangeHours, Resolution? resolution = null, bool fillForward = false, decimal leverage = 1.0m)
2713  where T : IBaseData, new()
2714  {
2715  // Get the right key for storage of base type symbols
2716  var key = SecurityIdentifier.GenerateBaseSymbol(typeof(T), ticker);
2717 
2718  // Set our database entries for this data type
2719  SetDatabaseEntries(key, properties, exchangeHours);
2720 
2721  // Then add the data
2722  return AddData(typeof(T), ticker, resolution, null, fillForward, leverage);
2723  }
2724 
2725  /// <summary>
2726  /// Send a debug message to the web console:
2727  /// </summary>
2728  /// <param name="message">Message to send to debug console</param>
2729  /// <seealso cref="Log(string)"/>
2730  /// <seealso cref="Error(string)"/>
2731  [DocumentationAttribute(Logging)]
2732  public void Debug(string message)
2733  {
2734  if (!_liveMode && (string.IsNullOrEmpty(message) || _previousDebugMessage == message)) return;
2735  _debugMessages.Enqueue(message);
2736  _previousDebugMessage = message;
2737  }
2738 
2739  /// <summary>
2740  /// Send a debug message to the web console:
2741  /// </summary>
2742  /// <param name="message">Message to send to debug console</param>
2743  /// <seealso cref="Log(int)"/>
2744  /// <seealso cref="Error(int)"/>
2745  [DocumentationAttribute(Logging)]
2746  public void Debug(int message)
2747  {
2748  Debug(message.ToStringInvariant());
2749  }
2750 
2751  /// <summary>
2752  /// Send a debug message to the web console:
2753  /// </summary>
2754  /// <param name="message">Message to send to debug console</param>
2755  /// <seealso cref="Log(double)"/>
2756  /// <seealso cref="Error(double)"/>
2757  [DocumentationAttribute(Logging)]
2758  public void Debug(double message)
2759  {
2760  Debug(message.ToStringInvariant());
2761  }
2762 
2763  /// <summary>
2764  /// Send a debug message to the web console:
2765  /// </summary>
2766  /// <param name="message">Message to send to debug console</param>
2767  /// <seealso cref="Log(decimal)"/>
2768  /// <seealso cref="Error(decimal)"/>
2769  [DocumentationAttribute(Logging)]
2770  public void Debug(decimal message)
2771  {
2772  Debug(message.ToStringInvariant());
2773  }
2774 
2775  /// <summary>
2776  /// Added another method for logging if user guessed.
2777  /// </summary>
2778  /// <param name="message">String message to log.</param>
2779  /// <seealso cref="Debug(string)"/>
2780  /// <seealso cref="Error(string)"/>
2781  [DocumentationAttribute(Logging)]
2782  public void Log(string message)
2783  {
2784  if (!_liveMode && string.IsNullOrEmpty(message)) return;
2785  _logMessages.Enqueue(message);
2786  }
2787 
2788  /// <summary>
2789  /// Added another method for logging if user guessed.
2790  /// </summary>
2791  /// <param name="message">Int message to log.</param>
2792  /// <seealso cref="Debug(int)"/>
2793  /// <seealso cref="Error(int)"/>
2794  [DocumentationAttribute(Logging)]
2795  public void Log(int message)
2796  {
2797  Log(message.ToStringInvariant());
2798  }
2799 
2800  /// <summary>
2801  /// Added another method for logging if user guessed.
2802  /// </summary>
2803  /// <param name="message">Double message to log.</param>
2804  /// <seealso cref="Debug(double)"/>
2805  /// <seealso cref="Error(double)"/>
2806  [DocumentationAttribute(Logging)]
2807  public void Log(double message)
2808  {
2809  Log(message.ToStringInvariant());
2810  }
2811 
2812  /// <summary>
2813  /// Added another method for logging if user guessed.
2814  /// </summary>
2815  /// <param name="message">Decimal message to log.</param>
2816  /// <seealso cref="Debug(decimal)"/>
2817  /// <seealso cref="Error(decimal)"/>
2818  [DocumentationAttribute(Logging)]
2819  public void Log(decimal message)
2820  {
2821  Log(message.ToStringInvariant());
2822  }
2823 
2824  /// <summary>
2825  /// Send a string error message to the Console.
2826  /// </summary>
2827  /// <param name="message">Message to display in errors grid</param>
2828  /// <seealso cref="Debug(string)"/>
2829  /// <seealso cref="Log(string)"/>
2830  [DocumentationAttribute(Logging)]
2831  public void Error(string message)
2832  {
2833  if (!_liveMode && (string.IsNullOrEmpty(message) || _previousErrorMessage == message)) return;
2834  _errorMessages.Enqueue(message);
2835  _previousErrorMessage = message;
2836  }
2837 
2838  /// <summary>
2839  /// Send a int error message to the Console.
2840  /// </summary>
2841  /// <param name="message">Message to display in errors grid</param>
2842  /// <seealso cref="Debug(int)"/>
2843  /// <seealso cref="Log(int)"/>
2844  [DocumentationAttribute(Logging)]
2845  public void Error(int message)
2846  {
2847  Error(message.ToStringInvariant());
2848  }
2849 
2850  /// <summary>
2851  /// Send a double error message to the Console.
2852  /// </summary>
2853  /// <param name="message">Message to display in errors grid</param>
2854  /// <seealso cref="Debug(double)"/>
2855  /// <seealso cref="Log(double)"/>
2856  [DocumentationAttribute(Logging)]
2857  public void Error(double message)
2858  {
2859  Error(message.ToStringInvariant());
2860  }
2861 
2862  /// <summary>
2863  /// Send a decimal error message to the Console.
2864  /// </summary>
2865  /// <param name="message">Message to display in errors grid</param>
2866  /// <seealso cref="Debug(decimal)"/>
2867  /// <seealso cref="Log(decimal)"/>
2868  [DocumentationAttribute(Logging)]
2869  public void Error(decimal message)
2870  {
2871  Error(message.ToStringInvariant());
2872  }
2873 
2874  /// <summary>
2875  /// Send a string error message to the Console.
2876  /// </summary>
2877  /// <param name="error">Exception object captured from a try catch loop</param>
2878  /// <seealso cref="Debug(string)"/>
2879  /// <seealso cref="Log(string)"/>
2880  [DocumentationAttribute(Logging)]
2881  public void Error(Exception error)
2882  {
2883  var message = error.Message;
2884  if (!_liveMode && (string.IsNullOrEmpty(message) || _previousErrorMessage == message)) return;
2885  _errorMessages.Enqueue(message);
2886  _previousErrorMessage = message;
2887  }
2888 
2889  /// <summary>
2890  /// Terminate the algorithm after processing the current event handler.
2891  /// </summary>
2892  /// <param name="message">Exit message to display on quitting</param>
2893  [DocumentationAttribute(Logging)]
2894  public void Quit(string message = "")
2895  {
2896  Debug("Quit(): " + message);
2897  Status = AlgorithmStatus.Stopped;
2898  }
2899 
2900  /// <summary>
2901  /// Set the Quit flag property of the algorithm.
2902  /// </summary>
2903  /// <remarks>Intended for internal use by the QuantConnect Lean Engine only.</remarks>
2904  /// <param name="quit">Boolean quit state</param>
2905  /// <seealso cref="Quit(String)"/>
2906  [DocumentationAttribute(Logging)]
2907  public void SetQuit(bool quit)
2908  {
2909  if (quit)
2910  {
2911  Status = AlgorithmStatus.Stopped;
2912  }
2913  }
2914 
2915  /// <summary>
2916  /// Converts the string 'ticker' symbol into a full <see cref="Symbol"/> object
2917  /// This requires that the string 'ticker' has been added to the algorithm
2918  /// </summary>
2919  /// <param name="ticker">The ticker symbol. This should be the ticker symbol
2920  /// as it was added to the algorithm</param>
2921  /// <returns>The symbol object mapped to the specified ticker</returns>
2922  [DocumentationAttribute(AddingData)]
2923  [DocumentationAttribute(HandlingData)]
2924  public Symbol Symbol(string ticker)
2925  {
2926  return SymbolCache.GetSymbol(ticker);
2927  }
2928 
2929  /// <summary>
2930  /// For the given symbol will resolve the ticker it used at the current algorithm date
2931  /// </summary>
2932  /// <param name="symbol">The symbol to get the ticker for</param>
2933  /// <returns>The mapped ticker for a symbol</returns>
2934  [DocumentationAttribute(AddingData)]
2935  [DocumentationAttribute(HandlingData)]
2936  public string Ticker(Symbol symbol)
2937  {
2938  return SecurityIdentifier.Ticker(symbol, Time);
2939  }
2940 
2941  /// <summary>
2942  /// Creates and adds a new <see cref="Security"/> to the algorithm
2943  /// </summary>
2944  [DocumentationAttribute(AddingData)]
2945  private T AddSecurity<T>(SecurityType securityType, string ticker, Resolution? resolution, string market, bool fillForward, decimal leverage, bool extendedMarketHours,
2946  DataMappingMode? mappingMode = null, DataNormalizationMode? normalizationMode = null)
2947  where T : Security
2948  {
2949  if (market == null)
2950  {
2951  if (!BrokerageModel.DefaultMarkets.TryGetValue(securityType, out market))
2952  {
2953  throw new Exception("No default market set for security type: " + securityType);
2954  }
2955  }
2956 
2957  Symbol symbol;
2958  if (!SymbolCache.TryGetSymbol(ticker, out symbol) ||
2959  symbol.ID.Market != market ||
2960  symbol.SecurityType != securityType)
2961  {
2962  symbol = QuantConnect.Symbol.Create(ticker, securityType, market);
2963  }
2964 
2965  var configs = SubscriptionManager.SubscriptionDataConfigService.Add(symbol, resolution, fillForward, extendedMarketHours,
2966  dataNormalizationMode: normalizationMode ?? UniverseSettings.DataNormalizationMode,
2967  dataMappingMode: mappingMode ?? UniverseSettings.DataMappingMode);
2968  var security = Securities.CreateSecurity(symbol, configs, leverage);
2969 
2970  return (T)AddToUserDefinedUniverse(security, configs);
2971  }
2972 
2973  /// <summary>
2974  /// Set the historical data provider
2975  /// </summary>
2976  /// <param name="historyProvider">Historical data provider</param>
2977  [DocumentationAttribute(HistoricalData)]
2978  public void SetHistoryProvider(IHistoryProvider historyProvider)
2979  {
2980  if (historyProvider == null)
2981  {
2982  throw new ArgumentNullException(nameof(historyProvider), "Algorithm.SetHistoryProvider(): Historical data provider cannot be null.");
2983  }
2984  HistoryProvider = historyProvider;
2985  }
2986 
2987  /// <summary>
2988  /// Set the runtime error
2989  /// </summary>
2990  /// <param name="exception">Represents error that occur during execution</param>
2991  [DocumentationAttribute(HandlingData)]
2992  [DocumentationAttribute(LiveTrading)]
2993  public void SetRunTimeError(Exception exception)
2994  {
2995  if (exception == null)
2996  {
2997  throw new ArgumentNullException(nameof(exception), "Algorithm.SetRunTimeError(): Algorithm.RunTimeError cannot be set to null.");
2998  }
2999 
3000  RunTimeError = exception;
3001  }
3002 
3003  /// <summary>
3004  /// Set the state of a live deployment
3005  /// </summary>
3006  /// <param name="status">Live deployment status</param>
3007  [DocumentationAttribute(LiveTrading)]
3008  public void SetStatus(AlgorithmStatus status)
3009  {
3010  Status = status;
3011  }
3012 
3013  /// <summary>
3014  /// Downloads the requested resource as a <see cref="string"/>.
3015  /// The resource to download is specified as a <see cref="string"/> containing the URI.
3016  /// </summary>
3017  /// <param name="address">A string containing the URI to download</param>
3018  /// <returns>The requested resource as a <see cref="string"/></returns>
3019  [DocumentationAttribute(AddingData)]
3020  [DocumentationAttribute(MachineLearning)]
3021  public string Download(string address) => Download(address, Enumerable.Empty<KeyValuePair<string, string>>());
3022 
3023  /// <summary>
3024  /// Downloads the requested resource as a <see cref="string"/>.
3025  /// The resource to download is specified as a <see cref="string"/> containing the URI.
3026  /// </summary>
3027  /// <param name="address">A string containing the URI to download</param>
3028  /// <param name="headers">Defines header values to add to the request</param>
3029  /// <returns>The requested resource as a <see cref="string"/></returns>
3030  [DocumentationAttribute(AddingData)]
3031  [DocumentationAttribute(MachineLearning)]
3032  public string Download(string address, IEnumerable<KeyValuePair<string, string>> headers) => Download(address, headers, null, null);
3033 
3034  /// <summary>
3035  /// Downloads the requested resource as a <see cref="string"/>.
3036  /// The resource to download is specified as a <see cref="string"/> containing the URI.
3037  /// </summary>
3038  /// <param name="address">A string containing the URI to download</param>
3039  /// <param name="headers">Defines header values to add to the request</param>
3040  /// <param name="userName">The user name associated with the credentials</param>
3041  /// <param name="password">The password for the user name associated with the credentials</param>
3042  /// <returns>The requested resource as a <see cref="string"/></returns>
3043  [DocumentationAttribute(AddingData)]
3044  [DocumentationAttribute(MachineLearning)]
3045  public string Download(string address, IEnumerable<KeyValuePair<string, string>> headers, string userName, string password)
3046  {
3047  return _api.Download(address, headers, userName, password);
3048  }
3049 
3050  /// <summary>
3051  /// Schedules the provided training code to execute immediately
3052  /// </summary>
3053  /// <param name="trainingCode">The training code to be invoked</param>
3054  [DocumentationAttribute(MachineLearning)]
3055  [DocumentationAttribute(ScheduledEvents)]
3056  public ScheduledEvent Train(Action trainingCode)
3057  {
3058  return Schedule.TrainingNow(trainingCode);
3059  }
3060 
3061  /// <summary>
3062  /// Schedules the training code to run using the specified date and time rules
3063  /// </summary>
3064  /// <param name="dateRule">Specifies what dates the event should run</param>
3065  /// <param name="timeRule">Specifies the times on those dates the event should run</param>
3066  /// <param name="trainingCode">The training code to be invoked</param>
3067  [DocumentationAttribute(MachineLearning)]
3068  [DocumentationAttribute(ScheduledEvents)]
3069  public ScheduledEvent Train(IDateRule dateRule, ITimeRule timeRule, Action trainingCode)
3070  {
3071  return Schedule.Training(dateRule, timeRule, trainingCode);
3072  }
3073 
3074  /// <summary>
3075  /// Event invocator for the <see cref="InsightsGenerated"/> event
3076  /// </summary>
3077  /// <param name="insights">The collection of insights generaed at the current time step</param>
3078  [DocumentationAttribute(AlgorithmFramework)]
3079  private void OnInsightsGenerated(Insight[] insights)
3080  {
3081  // debug printing of generated insights
3082  if (DebugMode)
3083  {
3084  Log($"{Time}: ALPHA: {string.Join(" | ", insights.Select(i => i.ToString()).OrderBy(i => i))}");
3085  }
3086 
3087  Insights.AddRange(insights);
3088 
3089  InsightsGenerated?.Invoke(this, new GeneratedInsightsCollection(UtcTime, insights));
3090  }
3091 
3092  /// <summary>
3093  /// Sets the current slice
3094  /// </summary>
3095  /// <param name="slice">The Slice object</param>
3096  [DocumentationAttribute(HandlingData)]
3097  public void SetCurrentSlice(Slice slice)
3098  {
3099  CurrentSlice = slice;
3100  }
3101 
3102 
3103  /// <summary>
3104  /// Provide the API for the algorithm.
3105  /// </summary>
3106  /// <param name="api">Initiated API</param>
3107  [DocumentationAttribute(HandlingData)]
3108  public void SetApi(IApi api)
3109  {
3110  _api = api;
3111  }
3112 
3113  /// <summary>
3114  /// Sets the object store
3115  /// </summary>
3116  /// <param name="objectStore">The object store</param>
3117  [DocumentationAttribute(HandlingData)]
3118  [DocumentationAttribute(MachineLearning)]
3119  public void SetObjectStore(IObjectStore objectStore)
3120  {
3121  ObjectStore = new ObjectStore(objectStore);
3122  }
3123 
3124  /// <summary>
3125  /// Determines if the Symbol is shortable at the brokerage
3126  /// </summary>
3127  /// <param name="symbol">Symbol to check if shortable</param>
3128  /// <returns>True if shortable</returns>
3129  [DocumentationAttribute(TradingAndOrders)]
3130  public bool Shortable(Symbol symbol)
3131  {
3132  return Shortable(symbol, 0);
3133  }
3134 
3135  /// <summary>
3136  /// Determines if the Symbol is shortable at the brokerage
3137  /// </summary>
3138  /// <param name="symbol">Symbol to check if shortable</param>
3139  /// <param name="shortQuantity">Order's quantity to check if it is currently shortable, taking into account current holdings and open orders</param>
3140  /// <param name="updateOrderId">Optionally the id of the order being updated. When updating an order
3141  /// we want to ignore it's submitted short quantity and use the new provided quantity to determine if we
3142  /// can perform the update</param>
3143  /// <returns>True if the symbol can be shorted by the requested quantity</returns>
3144  [DocumentationAttribute(TradingAndOrders)]
3145  public bool Shortable(Symbol symbol, decimal shortQuantity, int? updateOrderId = null)
3146  {
3147  var security = Securities[symbol];
3148  var shortableQuantity = security.ShortableProvider.ShortableQuantity(symbol, security.LocalTime);
3149  if (shortableQuantity == null)
3150  {
3151  return true;
3152  }
3153 
3154  var openOrderQuantity = Transactions.GetOpenOrdersRemainingQuantity(
3155  // if 'updateOrderId' was given, ignore that orders quantity
3156  order => order.Symbol == symbol && (!updateOrderId.HasValue || order.OrderId != updateOrderId.Value));
3157 
3158  var portfolioQuantity = security.Holdings.Quantity;
3159  // We check portfolio and open orders beforehand to ensure that orderQuantity == 0 case does not return
3160  // a true result whenever we have no more shares left to short.
3161  if (portfolioQuantity + openOrderQuantity <= -shortableQuantity)
3162  {
3163  return false;
3164  }
3165 
3166  shortQuantity = -Math.Abs(shortQuantity);
3167  return portfolioQuantity + shortQuantity + openOrderQuantity >= -shortableQuantity;
3168  }
3169 
3170  /// <summary>
3171  /// Gets the quantity shortable for the given asset
3172  /// </summary>
3173  /// <returns>
3174  /// Quantity shortable for the given asset. Zero if not
3175  /// shortable, or a number greater than zero if shortable.
3176  /// </returns>
3177  [DocumentationAttribute(TradingAndOrders)]
3178  public long ShortableQuantity(Symbol symbol)
3179  {
3180  var security = Securities[symbol];
3181  return security.ShortableProvider.ShortableQuantity(symbol, security.LocalTime) ?? 0;
3182  }
3183 
3184  /// <summary>
3185  /// Converts an ISIN identifier into a <see cref="Symbol"/>
3186  /// </summary>
3187  /// <param name="isin">The International Securities Identification Number (ISIN) of an asset</param>
3188  /// <param name="tradingDate">
3189  /// The date that the stock being looked up is/was traded at.
3190  /// The date is used to create a Symbol with the ticker set to the ticker the asset traded under on the trading date.
3191  /// </param>
3192  /// <returns>Symbol corresponding to the ISIN. If no Symbol with a matching ISIN was found, returns null.</returns>
3193  [DocumentationAttribute(HandlingData)]
3194  [DocumentationAttribute(SecuritiesAndPortfolio)]
3195  public Symbol ISIN(string isin, DateTime? tradingDate = null)
3196  {
3197  return _securityDefinitionSymbolResolver.ISIN(isin, GetVerifiedTradingDate(tradingDate));
3198  }
3199 
3200  /// <summary>
3201  /// Converts a <see cref="Symbol"/> into an ISIN identifier
3202  /// </summary>
3203  /// <param name="symbol">The <see cref="Symbol"/></param>
3204  /// <returns>ISIN corresponding to the Symbol. If no matching ISIN is found, returns null.</returns>
3205  [DocumentationAttribute(HandlingData)]
3206  [DocumentationAttribute(SecuritiesAndPortfolio)]
3207  public string ISIN(Symbol symbol)
3208  {
3209  return _securityDefinitionSymbolResolver.ISIN(symbol);
3210  }
3211 
3212  /// <summary>
3213  /// Converts a composite FIGI identifier into a <see cref="Symbol"/>
3214  /// </summary>
3215  /// <param name="compositeFigi">The composite Financial Instrument Global Identifier (FIGI) of an asset</param>
3216  /// <param name="tradingDate">
3217  /// The date that the stock being looked up is/was traded at.
3218  /// The date is used to create a Symbol with the ticker set to the ticker the asset traded under on the trading date.
3219  /// </param>
3220  /// <returns>Symbol corresponding to the composite FIGI. If no Symbol with a matching composite FIGI was found, returns null.</returns>
3221  /// <remarks>
3222  /// The composite FIGI differs from an exchange-level FIGI, in that it identifies
3223  /// an asset across all exchanges in a single country that the asset trades in.
3224  /// </remarks>
3225  [DocumentationAttribute(HandlingData)]
3226  [DocumentationAttribute(SecuritiesAndPortfolio)]
3227  public Symbol CompositeFIGI(string compositeFigi, DateTime? tradingDate = null)
3228  {
3229  return _securityDefinitionSymbolResolver.CompositeFIGI(compositeFigi, GetVerifiedTradingDate(tradingDate));
3230  }
3231 
3232  /// <summary>
3233  /// Converts a <see cref="Symbol"/> into a composite FIGI identifier
3234  /// </summary>
3235  /// <param name="symbol">The <see cref="Symbol"/></param>
3236  /// <returns>Composite FIGI corresponding to the Symbol. If no matching composite FIGI is found, returns null.</returns>
3237  [DocumentationAttribute(HandlingData)]
3238  [DocumentationAttribute(SecuritiesAndPortfolio)]
3239  public string CompositeFIGI(Symbol symbol)
3240  {
3241  return _securityDefinitionSymbolResolver.CompositeFIGI(symbol);
3242  }
3243 
3244  /// <summary>
3245  /// Converts a CUSIP identifier into a <see cref="Symbol"/>
3246  /// </summary>
3247  /// <param name="cusip">The CUSIP number of an asset</param>
3248  /// <param name="tradingDate">
3249  /// The date that the stock being looked up is/was traded at.
3250  /// The date is used to create a Symbol with the ticker set to the ticker the asset traded under on the trading date.
3251  /// </param>
3252  /// <returns>Symbol corresponding to the CUSIP. If no Symbol with a matching CUSIP was found, returns null.</returns>
3253  [DocumentationAttribute(HandlingData)]
3254  [DocumentationAttribute(SecuritiesAndPortfolio)]
3255  public Symbol CUSIP(string cusip, DateTime? tradingDate = null)
3256  {
3257  return _securityDefinitionSymbolResolver.CUSIP(cusip, GetVerifiedTradingDate(tradingDate));
3258  }
3259 
3260  /// <summary>
3261  /// Converts a <see cref="Symbol"/> into a CUSIP identifier
3262  /// </summary>
3263  /// <param name="symbol">The <see cref="Symbol"/></param>
3264  /// <returns>CUSIP corresponding to the Symbol. If no matching CUSIP is found, returns null.</returns>
3265  [DocumentationAttribute(HandlingData)]
3266  [DocumentationAttribute(SecuritiesAndPortfolio)]
3267  public string CUSIP(Symbol symbol)
3268  {
3269  return _securityDefinitionSymbolResolver.CUSIP(symbol);
3270  }
3271 
3272  /// <summary>
3273  /// Converts a SEDOL identifier into a <see cref="Symbol"/>
3274  /// </summary>
3275  /// <param name="sedol">The SEDOL identifier of an asset</param>
3276  /// <param name="tradingDate">
3277  /// The date that the stock being looked up is/was traded at.
3278  /// The date is used to create a Symbol with the ticker set to the ticker the asset traded under on the trading date.
3279  /// </param>
3280  /// <returns>Symbol corresponding to the SEDOL. If no Symbol with a matching SEDOL was found, returns null.</returns>
3281  [DocumentationAttribute(HandlingData)]
3282  [DocumentationAttribute(SecuritiesAndPortfolio)]
3283  public Symbol SEDOL(string sedol, DateTime? tradingDate = null)
3284  {
3285  return _securityDefinitionSymbolResolver.SEDOL(sedol, GetVerifiedTradingDate(tradingDate));
3286  }
3287 
3288  /// <summary>
3289  /// Converts a <see cref="Symbol"/> into a SEDOL identifier
3290  /// </summary>
3291  /// <param name="symbol">The <see cref="Symbol"/></param>
3292  /// <returns>SEDOL corresponding to the Symbol. If no matching SEDOL is found, returns null.</returns>
3293  [DocumentationAttribute(HandlingData)]
3294  [DocumentationAttribute(SecuritiesAndPortfolio)]
3295  public string SEDOL(Symbol symbol)
3296  {
3297  return _securityDefinitionSymbolResolver.SEDOL(symbol);
3298  }
3299 
3300  /// <summary>
3301  /// Converts a CIK identifier into <see cref="Symbol"/> array
3302  /// </summary>
3303  /// <param name="cik">The CIK identifier of an asset</param>
3304  /// <param name="tradingDate">
3305  /// The date that the stock being looked up is/was traded at.
3306  /// The date is used to create a Symbol with the ticker set to the ticker the asset traded under on the trading date.
3307  /// </param>
3308  /// <returns>Symbols corresponding to the CIK. If no Symbol with a matching CIK was found, returns empty array.</returns>
3309  [DocumentationAttribute(HandlingData)]
3310  [DocumentationAttribute(SecuritiesAndPortfolio)]
3311  public Symbol[] CIK(int cik, DateTime? tradingDate = null)
3312  {
3313  return _securityDefinitionSymbolResolver.CIK(cik, GetVerifiedTradingDate(tradingDate));
3314  }
3315 
3316  /// <summary>
3317  /// Converts a <see cref="Symbol"/> into a CIK identifier
3318  /// </summary>
3319  /// <param name="symbol">The <see cref="Symbol"/></param>
3320  /// <returns>CIK corresponding to the Symbol. If no matching CIK is found, returns null.</returns>
3321  [DocumentationAttribute(HandlingData)]
3322  [DocumentationAttribute(SecuritiesAndPortfolio)]
3323  public int? CIK(Symbol symbol)
3324  {
3325  return _securityDefinitionSymbolResolver.CIK(symbol);
3326  }
3327 
3328  /// <summary>
3329  /// Get the fundamental data for the requested symbol at the current time
3330  /// </summary>
3331  /// <param name="symbol">The <see cref="Symbol"/></param>
3332  /// <returns>The fundamental data for the Symbol</returns>
3333  [DocumentationAttribute(HandlingData)]
3334  [DocumentationAttribute(SecuritiesAndPortfolio)]
3336  {
3337  return new Fundamental(Time, symbol) { EndTime = Time };
3338  }
3339 
3340  /// <summary>
3341  /// Get the fundamental data for the requested symbols at the current time
3342  /// </summary>
3343  /// <param name="symbols">The <see cref="Symbol"/></param>
3344  /// <returns>The fundamental data for the symbols</returns>
3345  [DocumentationAttribute(HandlingData)]
3346  [DocumentationAttribute(SecuritiesAndPortfolio)]
3347  public List<Fundamental> Fundamentals(List<Symbol> symbols)
3348  {
3349  return symbols.Select(symbol => Fundamentals(symbol)).ToList();
3350  }
3351 
3352  /// <summary>
3353  /// Get the option chain for the specified symbol at the current time (<see cref="Time"/>)
3354  /// </summary>
3355  /// <param name="symbol">
3356  /// The symbol for which the option chain is asked for.
3357  /// It can be either the canonical option or the underlying symbol.
3358  /// </param>
3359  /// <param name="flatten">
3360  /// Whether to flatten the resulting data frame. Used from Python when accessing <see cref="OptionChain.DataFrame"/>.
3361  /// See <see cref="History(PyObject, int, Resolution?, bool?, bool?, DataMappingMode?, DataNormalizationMode?, int?, bool)"/>
3362  /// </param>
3363  /// <returns>The option chain</returns>
3364  /// <remarks>
3365  /// As of 2024/09/11, future options chain will not contain any additional data (e.g. daily price data, implied volatility and greeks),
3366  /// it will be populated with the contract symbol only. This is expected to change in the future.
3367  /// </remarks>
3368  [DocumentationAttribute(AddingData)]
3369  public OptionChain OptionChain(Symbol symbol, bool flatten = false)
3370  {
3371  return OptionChains(new[] { symbol }, flatten).Values.SingleOrDefault() ??
3372  new OptionChain(GetCanonicalOptionSymbol(symbol), Time.Date, flatten);
3373  }
3374 
3375  /// <summary>
3376  /// Get the option chains for the specified symbols at the current time (<see cref="Time"/>)
3377  /// </summary>
3378  /// <param name="symbols">
3379  /// The symbols for which the option chain is asked for.
3380  /// It can be either the canonical options or the underlying symbols.
3381  /// </param>
3382  /// <param name="flatten">
3383  /// Whether to flatten the resulting data frame. Used from Python when accessing <see cref="OptionChain.DataFrame"/>.
3384  /// See <see cref="History(PyObject, int, Resolution?, bool?, bool?, DataMappingMode?, DataNormalizationMode?, int?, bool)"/>
3385  /// </param>
3386  /// <returns>The option chains</returns>
3387  [DocumentationAttribute(AddingData)]
3388  public OptionChains OptionChains(IEnumerable<Symbol> symbols, bool flatten = false)
3389  {
3390  var canonicalSymbols = symbols.Select(GetCanonicalOptionSymbol).ToList();
3391  var optionCanonicalSymbols = canonicalSymbols.Where(x => x.SecurityType != SecurityType.FutureOption);
3392  var futureOptionCanonicalSymbols = canonicalSymbols.Where(x => x.SecurityType == SecurityType.FutureOption);
3393 
3394  var optionChainsData = History(optionCanonicalSymbols, 1).GetUniverseData()
3395  .Select(x => (x.Keys.Single(), x.Values.Single().Cast<OptionUniverse>()));
3396 
3397  // TODO: For FOPs, we fall back to the option chain provider until OptionUniverse supports them
3398  var futureOptionChainsData = futureOptionCanonicalSymbols.Select(symbol =>
3399  {
3400  var optionChainData = OptionChainProvider.GetOptionContractList(symbol, Time)
3401  .Select(contractSymbol => new OptionUniverse()
3402  {
3403  Symbol = contractSymbol,
3404  EndTime = Time.Date,
3405  });
3406  return (symbol, optionChainData);
3407  });
3408 
3409  var time = Time.Date;
3410  var chains = new OptionChains(time, flatten);
3411  foreach (var (symbol, contracts) in optionChainsData.Concat(futureOptionChainsData))
3412  {
3413  var symbolProperties = SymbolPropertiesDatabase.GetSymbolProperties(symbol.ID.Market, symbol, symbol.SecurityType, AccountCurrency);
3414  var optionChain = new OptionChain(symbol, time, contracts, symbolProperties, flatten);
3415  chains.Add(symbol, optionChain);
3416  }
3417 
3418  return chains;
3419  }
3420 
3421  /// <summary>
3422  /// Get an authenticated link to execute the given command instance
3423  /// </summary>
3424  /// <param name="command">The target command</param>
3425  /// <returns>The authenticated link</returns>
3426  public string Link(object command)
3427  {
3428  var typeName = command.GetType().Name;
3429  if (command is Command || typeName.Contains("AnonymousType", StringComparison.InvariantCultureIgnoreCase))
3430  {
3431  return CommandLink(typeName, command);
3432  }
3433  return string.Empty;
3434  }
3435 
3436  /// <summary>
3437  /// Register a command type to be used
3438  /// </summary>
3439  /// <typeparam name="T">The command type</typeparam>
3440  public void AddCommand<T>() where T : Command
3441  {
3442  _registeredCommands[typeof(T).Name] = (CallbackCommand command) =>
3443  {
3444  var commandInstance = JsonConvert.DeserializeObject<T>(command.Payload);
3445  return commandInstance.Run(this);
3446  };
3447  }
3448 
3449  /// <summary>
3450  /// Run a callback command instance
3451  /// </summary>
3452  /// <param name="command">The callback command instance</param>
3453  /// <returns>The command result</returns>
3455  {
3456  bool? result = null;
3457  if (_registeredCommands.TryGetValue(command.Type, out var target))
3458  {
3459  try
3460  {
3461  result = target.Invoke(command);
3462  }
3463  catch (Exception ex)
3464  {
3466  if (_oneTimeCommandErrors.Add(command.Type))
3467  {
3468  Log($"Unexpected error running command '{command.Type}' error: '{ex.Message}'");
3469  }
3470  }
3471  }
3472  else
3473  {
3474  if (_oneTimeCommandErrors.Add(command.Type))
3475  {
3476  Log($"Detected unregistered command type '{command.Type}', will be ignored");
3477  }
3478  }
3479  return new CommandResultPacket(command, result) { CommandName = command.Type };
3480  }
3481 
3482  /// <summary>
3483  /// Generic untyped command call handler
3484  /// </summary>
3485  /// <param name="data">The associated data</param>
3486  /// <returns>True if success, false otherwise. Returning null will disable command feedback</returns>
3487  public virtual bool? OnCommand(dynamic data)
3488  {
3489  return true;
3490  }
3491 
3492  private string CommandLink(string typeName, object command)
3493  {
3494  var payload = new Dictionary<string, dynamic> { { "projectId", ProjectId }, { "command", command } };
3495  if (_registeredCommands.ContainsKey(typeName))
3496  {
3497  payload["command[$type]"] = typeName;
3498  }
3499  return Api.Authentication.Link("live/commands/create", payload);
3500  }
3501 
3502  private static Symbol GetCanonicalOptionSymbol(Symbol symbol)
3503  {
3504  // We got the underlying
3505  if (symbol.SecurityType.HasOptions())
3506  {
3507  return QuantConnect.Symbol.CreateCanonicalOption(symbol);
3508  }
3509 
3510  if (symbol.SecurityType.IsOption())
3511  {
3512  return symbol.Canonical;
3513  }
3514 
3515  throw new ArgumentException($"The symbol {symbol} is not an option or an underlying symbol.");
3516  }
3517 
3518  /// <summary>
3519  /// Set the properties and exchange hours for a given key into our databases
3520  /// </summary>
3521  /// <param name="key">Key for database storage</param>
3522  /// <param name="properties">Properties to store</param>
3523  /// <param name="exchangeHours">Exchange hours to store</param>
3524  private void SetDatabaseEntries(string key, SymbolProperties properties, SecurityExchangeHours exchangeHours)
3525  {
3526  // Add entries to our Symbol Properties DB and MarketHours DB
3527  SymbolPropertiesDatabase.SetEntry(Market.USA, key, SecurityType.Base, properties);
3528  MarketHoursDatabase.SetEntry(Market.USA, key, SecurityType.Base, exchangeHours);
3529  }
3530 
3531  /// <summary>
3532  /// Takes a date, and verifies that it is point-in-time. If null
3533  /// time is provided, algorithm time is returned instead.
3534  /// </summary>
3535  /// <param name="tradingDate">
3536  /// The trading date to verify that it is a point-in-time
3537  /// date, or before, relative to the algorithm's current trading date.
3538  /// </param>
3539  /// <returns>The date provided if not null, otherwise the algorithm's current trading date</returns>
3540  /// <exception cref="ArgumentException">
3541  /// The trading date provided is not null and it is after the algorithm's current trading date
3542  /// </exception>
3543  private DateTime GetVerifiedTradingDate(DateTime? tradingDate)
3544  {
3545  tradingDate ??= Time.Date;
3546  if (tradingDate > Time.Date)
3547  {
3548  throw new ArgumentException($"The trading date provided: \"{tradingDate:yyyy-MM-dd}\" is after the current algorithm's trading date: \"{Time:yyyy-MM-dd}\"");
3549  }
3550 
3551  return tradingDate.Value;
3552  }
3553 
3554  /// <summary>
3555  /// Helper method to set the start date during live trading
3556  /// </summary>
3557  private void SetLiveModeStartDate()
3558  {
3559  if (!LiveMode)
3560  {
3561  throw new InvalidOperationException("SetLiveModeStartDate should only be called during live trading!");
3562  }
3563  _start = DateTime.UtcNow.ConvertFromUtc(TimeZone);
3564  // startDate is set relative to the algorithm's timezone.
3565  _startDate = _start.Date;
3566  _endDate = QuantConnect.Time.EndOfTime;
3567  }
3568 
3569  /// <summary>
3570  /// Sets the statistics service instance to be used by the algorithm
3571  /// </summary>
3572  /// <param name="statisticsService">The statistics service instance</param>
3573  public void SetStatisticsService(IStatisticsService statisticsService)
3574  {
3575  if (_statisticsService == null)
3576  {
3577  _statisticsService = statisticsService;
3578  }
3579  }
3580  }
3581 }