Lean  $LEAN_TAG$
OptionChainedUniverseSelectionModel.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.Linq;
20 using System.Collections.Generic;
24 using Python.Runtime;
25 
27 {
28  /// <summary>
29  /// This universe selection model will chain to the security changes of a given <see cref="Universe"/> selection
30  /// output and create a new <see cref="OptionChainUniverse"/> for each of them
31  /// </summary>
33  {
34  private DateTime _nextRefreshTimeUtc;
35  private IEnumerable<Symbol> _currentSymbols;
36  private readonly UniverseSettings _universeSettings;
37  private readonly Func<OptionFilterUniverse, OptionFilterUniverse> _optionFilter;
38 
39  /// <summary>
40  /// Gets the next time the framework should invoke the `CreateUniverses` method to refresh the set of universes.
41  /// </summary>
42  public override DateTime GetNextRefreshTimeUtc() => _nextRefreshTimeUtc;
43 
44  /// <summary>
45  /// Creates a new instance of <see cref="OptionChainedUniverseSelectionModel"/>
46  /// </summary>
47  /// <param name="universe">The universe we want to chain to</param>
48  /// <param name="optionFilter">The option filter universe to use</param>
49  /// <param name="universeSettings">Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed</param>
51  Func<OptionFilterUniverse, OptionFilterUniverse> optionFilter,
52  UniverseSettings universeSettings = null)
53  {
54  _optionFilter = optionFilter;
55  _universeSettings = universeSettings;
56  _nextRefreshTimeUtc = DateTime.MaxValue;
57 
58  _currentSymbols = Enumerable.Empty<Symbol>();
59  universe.SelectionChanged += (sender, args) =>
60  {
61  // the universe we were watching changed, this will trigger a call to CreateUniverses
62  _nextRefreshTimeUtc = DateTime.MinValue;
63 
64  // We must create the new option Symbol using the CreateOption(Symbol, ...) overload.
65  // Otherwise, we'll end up loading equity data for the selected Symbol, which won't
66  // work whenever we're loading options data for any non-equity underlying asset class.
67  _currentSymbols = ((Universe.SelectionEventArgs)args).CurrentSelection
68  .Select(symbol => Symbol.CreateOption(
69  symbol,
70  symbol.ID.Market,
71  symbol.SecurityType.DefaultOptionStyle(),
72  default(OptionRight),
73  0m,
75  .ToList();
76  };
77  }
78 
79  /// <summary>
80  /// Creates a new instance of <see cref="OptionChainedUniverseSelectionModel"/>
81  /// </summary>
82  /// <param name="universe">The universe we want to chain to</param>
83  /// <param name="optionFilter">The python option filter universe to use</param>
84  /// <param name="universeSettings">Universe settings define attributes of created subscriptions, such as their resolution and the minimum time in universe before they can be removed</param>
86  PyObject optionFilter,
87  UniverseSettings universeSettings = null): this(universe, ConvertOptionFilter(optionFilter), universeSettings)
88  {
89  }
90 
91  /// <summary>
92  /// Creates the universes for this algorithm. Called once after <see cref="IAlgorithm.Initialize"/>
93  /// </summary>
94  /// <param name="algorithm">The algorithm instance to create universes for</param>
95  /// <returns>The universes to be used by the algorithm</returns>
96  public override IEnumerable<Universe> CreateUniverses(QCAlgorithm algorithm)
97  {
98  _nextRefreshTimeUtc = DateTime.MaxValue;
99 
100  foreach (var optionSymbol in _currentSymbols)
101  {
102  yield return algorithm.CreateOptionChain(optionSymbol, _optionFilter, _universeSettings);
103  }
104  }
105 
106  private static Func<OptionFilterUniverse, OptionFilterUniverse> ConvertOptionFilter(PyObject optionFilter)
107  {
108  using (Py.GIL())
109  {
110  return optionFilter.ConvertToDelegate<Func<OptionFilterUniverse, OptionFilterUniverse>>();
111  }
112  }
113  }
114 }