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