Lean  $LEAN_TAG$
QCAlgorithm.Universe.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 NodaTime;
21 using QuantConnect.Data;
26 using QuantConnect.Util;
27 
28 namespace QuantConnect.Algorithm
29 {
30  public partial class QCAlgorithm
31  {
32  // save universe additions and apply at end of time step
33  // this removes temporal dependencies from w/in initialize method
34  // original motivation: adding equity/options to enforce equity raw data mode
35  private readonly object _pendingUniverseAdditionsLock = new object();
36  private readonly List<UserDefinedUniverseAddition> _pendingUserDefinedUniverseSecurityAdditions = new List<UserDefinedUniverseAddition>();
37  private bool _pendingUniverseAdditions;
38  private ConcurrentSet<Symbol> _rawNormalizationWarningSymbols = new ConcurrentSet<Symbol>();
39  private readonly int _rawNormalizationWarningSymbolsMaxCount = 10;
40 
41  /// <summary>
42  /// Gets universe manager which holds universes keyed by their symbol
43  /// </summary>
44  [DocumentationAttribute(Universes)]
46  {
47  get;
48  private set;
49  }
50 
51  /// <summary>
52  /// Gets the universe settings to be used when adding securities via universe selection
53  /// </summary>
54  [DocumentationAttribute(Universes)]
56  {
57  get;
58  private set;
59  }
60 
61  /// <summary>
62  /// Invoked at the end of every time step. This allows the algorithm
63  /// to process events before advancing to the next time step.
64  /// </summary>
65  [DocumentationAttribute(HandlingData)]
66  public void OnEndOfTimeStep()
67  {
68  // rewrite securities w/ derivatives to be in raw mode
69  lock (_pendingUniverseAdditionsLock)
70  {
71  if (!_pendingUniverseAdditions && _pendingUserDefinedUniverseSecurityAdditions.Count == 0)
72  {
73  // no point in looping through everything if there's no pending changes
74  return;
75  }
76 
77  var requiredHistoryRequests = new Dictionary<Security, Resolution>();
78 
79  foreach (var security in Securities.Select(kvp => kvp.Value).Union(
80  _pendingUserDefinedUniverseSecurityAdditions.Select(x => x.Security)))
81  {
82  // check for any derivative securities and mark the underlying as raw
83  if (Securities.Any(skvp => skvp.Key.SecurityType != SecurityType.Base && skvp.Key.HasUnderlyingSymbol(security.Symbol)))
84  {
85  // set data mode raw and default volatility model
86  ConfigureUnderlyingSecurity(security);
87  }
88 
90  .GetSubscriptionDataConfigs(security.Symbol);
91  if (security.Symbol.HasUnderlying && security.Symbol.SecurityType != SecurityType.Base)
92  {
93  Security underlyingSecurity;
94  var underlyingSymbol = security.Symbol.Underlying;
95 
96  var resolution = configs.GetHighestResolution();
97  var isFillForward = configs.IsFillForward();
98  if (UniverseManager.TryGetValue(security.Symbol, out var universe))
99  {
100  // as if the universe had selected this asset, the configuration of the canonical can be different
101  resolution = universe.UniverseSettings.Resolution;
102  isFillForward = universe.UniverseSettings.FillForward;
103  }
104 
105  // create the underlying security object if it doesn't already exist
106  if (!Securities.TryGetValue(underlyingSymbol, out underlyingSecurity))
107  {
108  underlyingSecurity = AddSecurity(underlyingSymbol.SecurityType,
109  underlyingSymbol.Value,
110  resolution,
111  underlyingSymbol.ID.Market,
112  isFillForward,
114  configs.IsExtendedMarketHours(),
115  dataNormalizationMode: DataNormalizationMode.Raw);
116  }
117 
118  // set data mode raw and default volatility model
119  ConfigureUnderlyingSecurity(underlyingSecurity);
120 
121  if (LiveMode && underlyingSecurity.GetLastData() == null)
122  {
123  if (requiredHistoryRequests.ContainsKey(underlyingSecurity))
124  {
125  // lets request the higher resolution
126  var currentResolutionRequest = requiredHistoryRequests[underlyingSecurity];
127  if (currentResolutionRequest != Resolution.Minute // Can not be less than Minute
128  && resolution < currentResolutionRequest)
129  {
130  requiredHistoryRequests[underlyingSecurity] = (Resolution)Math.Max((int)resolution, (int)Resolution.Minute);
131  }
132  }
133  else
134  {
135  requiredHistoryRequests.Add(underlyingSecurity, (Resolution)Math.Max((int)resolution, (int)Resolution.Minute));
136  }
137  }
138  // set the underlying security on the derivative -- we do this in two places since it's possible
139  // to do AddOptionContract w/out the underlying already added and normalized properly
140  var derivative = security as IDerivativeSecurity;
141  if (derivative != null)
142  {
143  derivative.Underlying = underlyingSecurity;
144  }
145  }
146  }
147 
148  if (!requiredHistoryRequests.IsNullOrEmpty())
149  {
150  // Create requests
151  var historyRequests = Enumerable.Empty<HistoryRequest>();
152  foreach (var byResolution in requiredHistoryRequests.GroupBy(x => x.Value))
153  {
154  historyRequests = historyRequests.Concat(
155  CreateBarCountHistoryRequests(byResolution.Select(x => x.Key.Symbol), 3, byResolution.Key));
156  }
157  // Request data
158  var historicLastData = History(historyRequests);
159  historicLastData.PushThrough(x =>
160  {
161  var security = requiredHistoryRequests.Keys.FirstOrDefault(y => y.Symbol == x.Symbol);
162  security?.Cache.AddData(x);
163  });
164  }
165 
166  // add subscriptionDataConfig to their respective user defined universes
167  foreach (var userDefinedUniverseAddition in _pendingUserDefinedUniverseSecurityAdditions)
168  {
169  foreach (var subscriptionDataConfig in userDefinedUniverseAddition.SubscriptionDataConfigs)
170  {
171  userDefinedUniverseAddition.Universe.Add(subscriptionDataConfig);
172  }
173  }
174 
175  // finally add any pending universes, this will make them available to the data feed
176  // The universe will be added at the end of time step, same as the AddData user defined universes.
177  // This is required to be independent of the start and end date set during initialize
179 
180  _pendingUniverseAdditions = false;
181  _pendingUserDefinedUniverseSecurityAdditions.Clear();
182  }
183 
184  if (!_rawNormalizationWarningSymbols.IsNullOrEmpty())
185  {
186  // Log our securities being set to raw price mode
187  Debug($"Warning: The following securities were set to raw price normalization mode to work with options: " +
188  $"{string.Join(", ", _rawNormalizationWarningSymbols.Take(_rawNormalizationWarningSymbolsMaxCount).Select(x => x.Value))}...");
189 
190  // Set our warning list to null to stop emitting these warnings after its done once
191  _rawNormalizationWarningSymbols = null;
192  }
193  }
194 
195  /// <summary>
196  /// Gets a helper that provides pre-defined universe definitions, such as top dollar volume
197  /// </summary>
198  [DocumentationAttribute(Universes)]
200  {
201  get;
202  private set;
203  }
204 
205  /// <summary>
206  /// Adds the universe to the algorithm
207  /// </summary>
208  /// <param name="universe">The universe to be added</param>
209  [DocumentationAttribute(Universes)]
210  public Universe AddUniverse(Universe universe)
211  {
212  if (universe.UniverseSettings == null)
213  {
214  // set default value so that users don't need to pass it
216  }
217  _pendingUniverseAdditions = true;
218  // note: UniverseManager.Add uses TryAdd, so don't need to worry about duplicates here
219  UniverseManager.Add(universe.Configuration.Symbol, universe);
220  return universe;
221  }
222 
223  /// <summary>
224  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
225  /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults
226  /// of SecurityType.Equity, Resolution.Daily, Market.USA, and UniverseSettings
227  /// </summary>
228  /// <typeparam name="T">The data type</typeparam>
229  /// <param name="selector">Function delegate that performs selection on the universe data</param>
230  [DocumentationAttribute(Universes)]
231  public Universe AddUniverse<T>(Func<IEnumerable<BaseData>, IEnumerable<Symbol>> selector)
232  {
233  return AddUniverse<T>(null, selector);
234  }
235 
236  /// <summary>
237  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
238  /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults
239  /// of SecurityType.Equity, Resolution.Daily, Market.USA, and UniverseSettings
240  /// </summary>
241  /// <typeparam name="T">The data type</typeparam>
242  /// <param name="selector">Function delegate that performs selection on the universe data</param>
243  [DocumentationAttribute(Universes)]
244  public Universe AddUniverse<T>(Func<IEnumerable<BaseData>, IEnumerable<string>> selector)
245  {
246  return AddUniverse<T>(null, selector);
247  }
248 
249  /// <summary>
250  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
251  /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults
252  /// of SecurityType.Equity, Resolution.Daily, Market.USA, and UniverseSettings
253  /// </summary>
254  /// <typeparam name="T">The data type</typeparam>
255  /// <param name="name">A unique name for this universe</param>
256  /// <param name="selector">Function delegate that performs selection on the universe data</param>
257  [DocumentationAttribute(Universes)]
258  public Universe AddUniverse<T>(string name, Func<IEnumerable<BaseData>, IEnumerable<Symbol>> selector)
259  {
260  return AddUniverse<T>(name, null, null, null, selector);
261  }
262 
263  /// <summary>
264  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
265  /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults
266  /// of SecurityType.Equity, Resolution.Daily, Market.USA, and UniverseSettings
267  /// </summary>
268  /// <typeparam name="T">The data type</typeparam>
269  /// <param name="name">A unique name for this universe</param>
270  /// <param name="selector">Function delegate that performs selection on the universe data</param>
271  [DocumentationAttribute(Universes)]
272  public Universe AddUniverse<T>(string name, Func<IEnumerable<BaseData>, IEnumerable<string>> selector)
273  {
274  return AddUniverseStringSelector<T>(selector, null, name);
275  }
276 
277  /// <summary>
278  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
279  /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults
280  /// of SecurityType.Equity, Resolution.Daily, and Market.USA
281  /// </summary>
282  /// <typeparam name="T">The data type</typeparam>
283  /// <param name="name">A unique name for this universe</param>
284  /// <param name="universeSettings">The settings used for securities added by this universe</param>
285  /// <param name="selector">Function delegate that performs selection on the universe data</param>
286  [DocumentationAttribute(Universes)]
287  public Universe AddUniverse<T>(string name, UniverseSettings universeSettings, Func<IEnumerable<BaseData>, IEnumerable<Symbol>> selector)
288  {
289  return AddUniverse<T>(name, null, null, universeSettings, selector);
290  }
291 
292  /// <summary>
293  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
294  /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults
295  /// of SecurityType.Equity, Resolution.Daily, and Market.USA
296  /// </summary>
297  /// <typeparam name="T">The data type</typeparam>
298  /// <param name="name">A unique name for this universe</param>
299  /// <param name="universeSettings">The settings used for securities added by this universe</param>
300  /// <param name="selector">Function delegate that performs selection on the universe data</param>
301  [DocumentationAttribute(Universes)]
302  public Universe AddUniverse<T>(string name, UniverseSettings universeSettings, Func<IEnumerable<BaseData>, IEnumerable<string>> selector)
303  {
304  return AddUniverseStringSelector<T>(selector, null, name, null, null, universeSettings);
305  }
306 
307  /// <summary>
308  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
309  /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults
310  /// of SecurityType.Equity, Market.USA and UniverseSettings
311  /// </summary>
312  /// <typeparam name="T">The data type</typeparam>
313  /// <param name="name">A unique name for this universe</param>
314  /// <param name="resolution">The expected resolution of the universe data</param>
315  /// <param name="selector">Function delegate that performs selection on the universe data</param>
316  [DocumentationAttribute(Universes)]
317  public Universe AddUniverse<T>(string name, Resolution resolution, Func<IEnumerable<BaseData>, IEnumerable<Symbol>> selector)
318  {
319  return AddUniverse<T>(name, resolution, null, null, selector);
320  }
321 
322  /// <summary>
323  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
324  /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults
325  /// of SecurityType.Equity, Market.USA and UniverseSettings
326  /// </summary>
327  /// <typeparam name="T">The data type</typeparam>
328  /// <param name="name">A unique name for this universe</param>
329  /// <param name="resolution">The expected resolution of the universe data</param>
330  /// <param name="selector">Function delegate that performs selection on the universe data</param>
331  [DocumentationAttribute(Universes)]
332  public Universe AddUniverse<T>(string name, Resolution resolution, Func<IEnumerable<BaseData>, IEnumerable<string>> selector)
333  {
334  return AddUniverseStringSelector<T>(selector, null, name, resolution);
335  }
336 
337  /// <summary>
338  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
339  /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults
340  /// of SecurityType.Equity, and Market.USA
341  /// </summary>
342  /// <typeparam name="T">The data type</typeparam>
343  /// <param name="name">A unique name for this universe</param>
344  /// <param name="resolution">The expected resolution of the universe data</param>
345  /// <param name="universeSettings">The settings used for securities added by this universe</param>
346  /// <param name="selector">Function delegate that performs selection on the universe data</param>
347  [DocumentationAttribute(Universes)]
348  public Universe AddUniverse<T>(string name, Resolution resolution, UniverseSettings universeSettings, Func<IEnumerable<BaseData>, IEnumerable<Symbol>> selector)
349  {
350  return AddUniverse<T>(name, resolution, market: null, universeSettings, selector);
351  }
352 
353  /// <summary>
354  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
355  /// specified via the <see cref="UniverseSettings"/> property. This universe will use the defaults
356  /// of SecurityType.Equity, and Market.USA
357  /// </summary>
358  /// <typeparam name="T">The data type</typeparam>
359  /// <param name="name">A unique name for this universe</param>
360  /// <param name="resolution">The expected resolution of the universe data</param>
361  /// <param name="universeSettings">The settings used for securities added by this universe</param>
362  /// <param name="selector">Function delegate that performs selection on the universe data</param>
363  [DocumentationAttribute(Universes)]
364  public Universe AddUniverse<T>(string name, Resolution resolution, UniverseSettings universeSettings, Func<IEnumerable<BaseData>, IEnumerable<string>> selector)
365  {
366  return AddUniverseStringSelector<T>(selector, null, name, resolution, universeSettings: universeSettings);
367  }
368 
369  /// <summary>
370  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
371  /// specified via the <see cref="UniverseSettings"/> property.
372  /// </summary>
373  /// <typeparam name="T">The data type</typeparam>
374  /// <param name="name">A unique name for this universe</param>
375  /// <param name="resolution">The expected resolution of the universe data</param>
376  /// <param name="market">The market for selected symbols</param>
377  /// <param name="selector">Function delegate that performs selection on the universe data</param>
378  [DocumentationAttribute(Universes)]
379  public Universe AddUniverse<T>(string name, Resolution resolution, string market, Func<IEnumerable<BaseData>, IEnumerable<Symbol>> selector)
380  {
381  return AddUniverse<T>(name, resolution, market, null, selector);
382  }
383 
384  /// <summary>
385  /// Creates a new universe and adds it to the algorithm. This will use the default universe settings
386  /// specified via the <see cref="UniverseSettings"/> property.
387  /// </summary>
388  /// <typeparam name="T">The data type</typeparam>
389  /// <param name="securityType">The security type the universe produces</param>
390  /// <param name="name">A unique name for this universe</param>
391  /// <param name="resolution">The expected resolution of the universe data</param>
392  /// <param name="market">The market for selected symbols</param>
393  /// <param name="selector">Function delegate that performs selection on the universe data</param>
394  [DocumentationAttribute(Universes)]
395  public Universe AddUniverse<T>(SecurityType securityType, string name, Resolution resolution, string market, Func<IEnumerable<BaseData>, IEnumerable<string>> selector)
396  {
397  return AddUniverseStringSelector<T>(selector, securityType, name, resolution, market);
398  }
399 
400  /// <summary>
401  /// Creates a new universe and adds it to the algorithm
402  /// </summary>
403  /// <typeparam name="T">The data type</typeparam>
404  /// <param name="securityType">The security type the universe produces</param>
405  /// <param name="name">A unique name for this universe</param>
406  /// <param name="resolution">The expected resolution of the universe data</param>
407  /// <param name="market">The market for selected symbols</param>
408  /// <param name="universeSettings">The subscription settings to use for newly created subscriptions</param>
409  /// <param name="selector">Function delegate that performs selection on the universe data</param>
410  [DocumentationAttribute(Universes)]
411  public Universe AddUniverse<T>(SecurityType securityType, string name, Resolution resolution, string market, UniverseSettings universeSettings, Func<IEnumerable<BaseData>, IEnumerable<string>> selector)
412  {
413  return AddUniverseStringSelector<T>(selector, securityType, name, resolution, market, universeSettings);
414  }
415 
416  /// <summary>
417  /// Creates a new universe and adds it to the algorithm
418  /// </summary>
419  /// <typeparam name="T">The data type</typeparam>
420  /// <param name="name">A unique name for this universe</param>
421  /// <param name="resolution">The expected resolution of the universe data</param>
422  /// <param name="market">The market for selected symbols</param>
423  /// <param name="universeSettings">The subscription settings to use for newly created subscriptions</param>
424  /// <param name="selector">Function delegate that performs selection on the universe data</param>
425  [DocumentationAttribute(Universes)]
426  public Universe AddUniverse<T>(string name = null, Resolution? resolution = null, string market = null, UniverseSettings universeSettings = null,
427  Func<IEnumerable<BaseData>, IEnumerable<Symbol>> selector = null)
428  {
429  return AddUniverseSymbolSelector(typeof(T), name, resolution, market, universeSettings, selector);
430  }
431 
432  /// <summary>
433  /// Creates a new universe and adds it to the algorithm. This is for coarse fundamental US Equity data and
434  /// will be executed on day changes in the NewYork time zone (<see cref="TimeZones.NewYork"/>)
435  /// </summary>
436  /// <param name="selector">Defines an initial coarse selection</param>
437  [DocumentationAttribute(Universes)]
438  public Universe AddUniverse(Func<IEnumerable<Fundamental>, IEnumerable<Symbol>> selector)
439  {
440  return AddUniverse(FundamentalUniverse.USA(selector));
441  }
442 
443  /// <summary>
444  /// Creates a new universe and adds it to the algorithm. This is for coarse fundamental US Equity data and
445  /// will be executed based on the provided <see cref="IDateRule"/> in the NewYork time zone (<see cref="TimeZones.NewYork"/>)
446  /// </summary>
447  /// <param name="dateRule">Date rule that will be used to set the <see cref="Data.UniverseSelection.UniverseSettings.Schedule"/></param>
448  /// <param name="selector">Defines an initial coarse selection</param>
449  [DocumentationAttribute(Universes)]
450  public Universe AddUniverse(IDateRule dateRule, Func<IEnumerable<Fundamental>, IEnumerable<Symbol>> selector)
451  {
452  var otherSettings = new UniverseSettings(UniverseSettings);
453  otherSettings.Schedule.On(dateRule);
454  return AddUniverse(FundamentalUniverse.USA(selector, otherSettings));
455  }
456 
457  /// <summary>
458  /// Creates a new universe and adds it to the algorithm. This is for coarse and fine fundamental US Equity data and
459  /// will be executed on day changes in the NewYork time zone (<see cref="TimeZones.NewYork"/>)
460  /// </summary>
461  /// <param name="coarseSelector">Defines an initial coarse selection</param>
462  /// <param name="fineSelector">Defines a more detailed selection with access to more data</param>
463  [DocumentationAttribute(Universes)]
464  public Universe AddUniverse(Func<IEnumerable<CoarseFundamental>, IEnumerable<Symbol>> coarseSelector, Func<IEnumerable<FineFundamental>, IEnumerable<Symbol>> fineSelector)
465  {
466  var coarse = new CoarseFundamentalUniverse(UniverseSettings, coarseSelector);
467 
468  return AddUniverse(new FineFundamentalFilteredUniverse(coarse, fineSelector));
469  }
470 
471  /// <summary>
472  /// Creates a new universe and adds it to the algorithm. This is for fine fundamental US Equity data and
473  /// will be executed on day changes in the NewYork time zone (<see cref="TimeZones.NewYork"/>)
474  /// </summary>
475  /// <param name="universe">The universe to be filtered with fine fundamental selection</param>
476  /// <param name="fineSelector">Defines a more detailed selection with access to more data</param>
477  [DocumentationAttribute(Universes)]
478  public Universe AddUniverse(Universe universe, Func<IEnumerable<Fundamental>, IEnumerable<Symbol>> fineSelector)
479  {
480  return AddUniverse(new FundamentalFilteredUniverse(universe, fineSelector));
481  }
482 
483  /// <summary>
484  /// Creates a new universe and adds it to the algorithm. This can be used to return a list of string
485  /// symbols retrieved from anywhere and will loads those symbols under the US Equity market.
486  /// </summary>
487  /// <param name="name">A unique name for this universe</param>
488  /// <param name="selector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
489  [DocumentationAttribute(Universes)]
490  public Universe AddUniverse(string name, Func<DateTime, IEnumerable<string>> selector)
491  {
492  return AddUniverse(SecurityType.Equity, name, Resolution.Daily, Market.USA, UniverseSettings, selector);
493  }
494 
495  /// <summary>
496  /// Creates a new universe and adds it to the algorithm. This can be used to return a list of string
497  /// symbols retrieved from anywhere and will loads those symbols under the US Equity market.
498  /// </summary>
499  /// <param name="name">A unique name for this universe</param>
500  /// <param name="resolution">The resolution this universe should be triggered on</param>
501  /// <param name="selector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
502  [DocumentationAttribute(Universes)]
503  public Universe AddUniverse(string name, Resolution resolution, Func<DateTime, IEnumerable<string>> selector)
504  {
505  return AddUniverse(SecurityType.Equity, name, resolution, Market.USA, UniverseSettings, selector);
506  }
507 
508  /// <summary>
509  /// Creates a new user defined universe that will fire on the requested resolution during market hours.
510  /// </summary>
511  /// <param name="securityType">The security type of the universe</param>
512  /// <param name="name">A unique name for this universe</param>
513  /// <param name="resolution">The resolution this universe should be triggered on</param>
514  /// <param name="market">The market of the universe</param>
515  /// <param name="universeSettings">The subscription settings used for securities added from this universe</param>
516  /// <param name="selector">Function delegate that accepts a DateTime and returns a collection of string symbols</param>
517  [DocumentationAttribute(Universes)]
518  public Universe AddUniverse(SecurityType securityType, string name, Resolution resolution, string market, UniverseSettings universeSettings, Func<DateTime, IEnumerable<string>> selector)
519  {
520  var marketHoursDbEntry = MarketHoursDatabase.GetEntry(market, name, securityType);
521  var dataTimeZone = marketHoursDbEntry.DataTimeZone;
522  var exchangeTimeZone = marketHoursDbEntry.ExchangeHours.TimeZone;
523  var symbol = QuantConnect.Symbol.Create(name, securityType, market);
524  var config = new SubscriptionDataConfig(typeof(Fundamental), symbol, resolution, dataTimeZone, exchangeTimeZone, false, false, true, isFilteredSubscription: false);
525  return AddUniverse(new UserDefinedUniverse(config, universeSettings, resolution.ToTimeSpan(), selector));
526  }
527 
528  /// <summary>
529  /// Adds a new universe that creates options of the security by monitoring any changes in the Universe the provided security is in.
530  /// Additionally, a filter can be applied to the options generated when the universe of the security changes.
531  /// </summary>
532  /// <param name="underlyingSymbol">Underlying Symbol to add as an option. For Futures, the option chain constructed will be per-contract, as long as a canonical Symbol is provided.</param>
533  /// <param name="optionFilter">User-defined filter used to select the options we want out of the option chain provided.</param>
534  /// <exception cref="InvalidOperationException">The underlying Symbol's universe is not found.</exception>
535  [DocumentationAttribute(Universes)]
536  public void AddUniverseOptions(Symbol underlyingSymbol, Func<OptionFilterUniverse, OptionFilterUniverse> optionFilter)
537  {
538  // We need to load the universe associated with the provided Symbol and provide that universe to the option filter universe.
539  // The option filter universe will subscribe to any changes in the universe of the underlying Symbol,
540  // ensuring that we load the option chain for every asset found in the underlying's Universe.
541  Universe universe;
542  if (!UniverseManager.TryGetValue(underlyingSymbol, out universe))
543  {
544  underlyingSymbol = AddSecurity(underlyingSymbol).Symbol;
545 
546  // Recheck again, we should have a universe addition pending for the provided Symbol
547  if (!UniverseManager.TryGetValue(underlyingSymbol, out universe))
548  {
549  // Should never happen, but it could be that the subscription
550  // created with AddSecurity is not aligned with the Symbol we're using.
551  throw new InvalidOperationException($"Universe not found for underlying Symbol: {underlyingSymbol}.");
552  }
553  }
554 
555  // Allow all option contracts through without filtering if we're provided a null filter.
556  AddUniverseOptions(universe, optionFilter ?? (_ => _));
557  }
558 
559  /// <summary>
560  /// Creates a new universe selection model and adds it to the algorithm. This universe selection model will chain to the security
561  /// changes of a given <see cref="Universe"/> selection output and create a new <see cref="OptionChainUniverse"/> for each of them
562  /// </summary>
563  /// <param name="universe">The universe we want to chain an option universe selection model too</param>
564  /// <param name="optionFilter">The option filter universe to use</param>
565  [DocumentationAttribute(Universes)]
566  public void AddUniverseOptions(Universe universe, Func<OptionFilterUniverse, OptionFilterUniverse> optionFilter)
567  {
568  AddUniverseSelection(new OptionChainedUniverseSelectionModel(universe, optionFilter));
569  }
570 
571  /// <summary>
572  /// Adds the security to the user defined universe
573  /// </summary>
574  /// <param name="security">The security to add</param>
575  /// <param name="configurations">The <see cref="SubscriptionDataConfig"/> instances we want to add</param>
576  private Security AddToUserDefinedUniverse(
577  Security security,
578  List<SubscriptionDataConfig> configurations)
579  {
580  var subscription = configurations.First();
581  // if we are adding a non-internal security which already has an internal feed, we remove it first
582  if (Securities.TryGetValue(security.Symbol, out var existingSecurity))
583  {
584  if (!subscription.IsInternalFeed && existingSecurity.IsInternalFeed())
585  {
586  var securityUniverse = UniverseManager.Select(x => x.Value).OfType<UserDefinedUniverse>().FirstOrDefault(x => x.Members.ContainsKey(security.Symbol));
587  securityUniverse?.Remove(security.Symbol);
588 
589  Securities.Remove(security.Symbol);
590  Securities.Add(security);
591  }
592  else
593  {
594  var isTradable = security.IsTradable;
595  // We will reuse existing so we return it to the user.
596  // We will use the IsTradable flag of the new security, since existing could of been set to false when removed
597  security = existingSecurity;
598  security.IsTradable = isTradable;
599  }
600  }
601  else
602  {
603  Securities.Add(security);
604  }
605 
606  // add this security to the user defined universe
607  Universe universe;
608  var universeSymbol = UserDefinedUniverse.CreateSymbol(security.Type, security.Symbol.ID.Market);
609  if (!UniverseManager.TryGetValue(universeSymbol, out universe))
610  {
611  if (universe == null)
612  {
613  // create a new universe, these subscription settings don't currently get used
614  // since universe selection proper is never invoked on this type of universe
615  var uconfig = new SubscriptionDataConfig(subscription, symbol: universeSymbol, isInternalFeed: true, fillForward: false,
616  exchangeTimeZone: DateTimeZone.Utc,
617  dataTimeZone: DateTimeZone.Utc);
618 
619  // this is the universe symbol, has no real entry in the mhdb, will default to market and security type
620  // set entry in market hours database for the universe subscription to match the config
621  var symbolString = MarketHoursDatabase.GetDatabaseSymbolKey(uconfig.Symbol);
622  MarketHoursDatabase.SetEntry(uconfig.Market, symbolString, uconfig.SecurityType,
623  SecurityExchangeHours.AlwaysOpen(uconfig.ExchangeTimeZone), uconfig.DataTimeZone);
624 
625  universe = new UserDefinedUniverse(uconfig,
626  new UniverseSettings(
627  subscription.Resolution,
628  security.Leverage,
629  subscription.FillDataForward,
630  subscription.ExtendedMarketHours,
631  TimeSpan.Zero),
633  new List<Symbol>());
634 
635  AddUniverse(universe);
636  }
637  }
638 
639  var userDefinedUniverse = universe as UserDefinedUniverse;
640  if (userDefinedUniverse != null)
641  {
642  lock (_pendingUniverseAdditionsLock)
643  {
644  _pendingUserDefinedUniverseSecurityAdditions.Add(
645  new UserDefinedUniverseAddition(userDefinedUniverse, configurations, security));
646  }
647  }
648  else
649  {
650  // should never happen, someone would need to add a non-user defined universe with this symbol
651  throw new Exception($"Expected universe with symbol '{universeSymbol.Value}' to be of type {nameof(UserDefinedUniverse)} but was {universe.GetType().Name}.");
652  }
653 
654  return security;
655  }
656 
657  /// <summary>
658  /// Configures the security to be in raw data mode and ensures that a reasonable default volatility model is supplied
659  /// </summary>
660  /// <param name="security">The underlying security</param>
661  private void ConfigureUnderlyingSecurity(Security security)
662  {
663  // force underlying securities to be raw data mode
665  .GetSubscriptionDataConfigs(security.Symbol);
666  if (configs.DataNormalizationMode() != DataNormalizationMode.Raw)
667  {
668  // Add this symbol to our set of raw normalization warning symbols to alert the user at the end
669  // Set a hard limit to avoid growing this collection unnecessarily large
670  if (_rawNormalizationWarningSymbols != null && _rawNormalizationWarningSymbols.Count <= _rawNormalizationWarningSymbolsMaxCount)
671  {
672  _rawNormalizationWarningSymbols.Add(security.Symbol);
673  }
674 
675  configs.SetDataNormalizationMode(DataNormalizationMode.Raw);
676  // For backward compatibility we need to refresh the security DataNormalizationMode Property
678  }
679  }
680 
681  /// <summary>
682  /// Helper method to create the configuration of a custom universe
683  /// </summary>
684  private SubscriptionDataConfig GetCustomUniverseConfiguration(Type dataType, string name, string market, Resolution? resolution = null)
685  {
686  if (dataType == typeof(CoarseFundamental) || dataType == typeof(FineFundamental))
687  {
688  dataType = typeof(FundamentalUniverse);
689  }
690 
691  if (!TryGetUniverseSymbol(dataType, market, out var universeSymbol))
692  {
693  market ??= Market.USA;
694  if (string.IsNullOrEmpty(name))
695  {
696  name = $"{dataType.Name}-{market}-{Guid.NewGuid()}";
697  }
698  // same as 'AddData<>' 'T' type will be treated as custom/base data type with always open market hours
699  universeSymbol = QuantConnect.Symbol.Create(name, SecurityType.Base, market, baseDataType: dataType);
700  }
701  var marketHoursDbEntry = MarketHoursDatabase.GetEntry(universeSymbol, new[] { dataType });
702  var dataTimeZone = marketHoursDbEntry.DataTimeZone;
703  var exchangeTimeZone = marketHoursDbEntry.ExchangeHours.TimeZone;
704  return new SubscriptionDataConfig(dataType, universeSymbol, resolution ?? Resolution.Daily, dataTimeZone, exchangeTimeZone, false, false, true, true, isFilteredSubscription: false);
705  }
706 
707  private bool TryGetUniverseSymbol(Type dataType, string market, out Symbol symbol)
708  {
709  symbol = null;
710  if (dataType.IsAssignableTo(typeof(BaseDataCollection)))
711  {
712  var instance = dataType.GetBaseDataInstance() as BaseDataCollection;
713  symbol = instance.UniverseSymbol(market);
714  return true;
715  }
716  return false;
717  }
718 
719  private Universe AddUniverseStringSelector<T>(Func<IEnumerable<BaseData>, IEnumerable<string>> selector, SecurityType? securityType = null, string name = null,
720  Resolution? resolution = null, string market = null, UniverseSettings universeSettings = null)
721  {
722  if (market.IsNullOrEmpty())
723  {
724  market = Market.USA;
725  }
726  securityType ??= SecurityType.Equity;
727  Func<IEnumerable<BaseData>, IEnumerable<Symbol>> symbolSelector = data => selector(data).Select(x => QuantConnect.Symbol.Create(x, securityType.Value, market, baseDataType: typeof(T)));
728  return AddUniverse<T>(name, resolution, market, universeSettings, symbolSelector);
729  }
730 
731  private Universe AddUniverseSymbolSelector(Type dataType, string name = null, Resolution? resolution = null, string market = null, UniverseSettings universeSettings = null,
732  Func<IEnumerable<BaseData>, IEnumerable<Symbol>> selector = null)
733  {
734  var config = GetCustomUniverseConfiguration(dataType, name, market, resolution);
735  return AddUniverse(new FuncUniverse(config, universeSettings, selector));
736  }
737 
738  /// <summary>
739  /// Helper class used to store <see cref="UserDefinedUniverse"/> additions.
740  /// They will be consumed at <see cref="OnEndOfTimeStep"/>
741  /// </summary>
742  private class UserDefinedUniverseAddition
743  {
744  public Security Security { get; }
745  public UserDefinedUniverse Universe { get; }
746  public List<SubscriptionDataConfig> SubscriptionDataConfigs { get; }
747 
748  public UserDefinedUniverseAddition(
749  UserDefinedUniverse universe,
750  List<SubscriptionDataConfig> subscriptionDataConfigs,
751  Security security)
752  {
753  Universe = universe;
754  SubscriptionDataConfigs = subscriptionDataConfigs;
755  Security = security;
756  }
757  }
758  }
759 }