Lean  $LEAN_TAG$
OptionChain.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;
18 using System.Collections.Generic;
19 using System.Linq;
20 using Python.Runtime;
22 using QuantConnect.Python;
25 using QuantConnect.Util;
26 
28 {
29  /// <summary>
30  /// Represents an entire chain of option contracts for a single underying security.
31  /// This type is <see cref="IEnumerable{OptionContract}"/>
32  /// </summary>
33  public class OptionChain : BaseData, IEnumerable<OptionContract>
34  {
35  private readonly Dictionary<Type, Dictionary<Symbol, List<BaseData>>> _auxiliaryData = new Dictionary<Type, Dictionary<Symbol, List<BaseData>>>();
36  private readonly Lazy<PyObject> _dataframe;
37  private readonly bool _flatten;
38 
39  /// <summary>
40  /// Gets the most recent trade information for the underlying. This may
41  /// be a <see cref="Tick"/> or a <see cref="TradeBar"/>
42  /// </summary>
43  [PandasIgnore]
44  public BaseData Underlying
45  {
46  get; internal set;
47  }
48 
49  /// <summary>
50  /// Gets all ticks for every option contract in this chain, keyed by option symbol
51  /// </summary>
52  [PandasIgnore]
53  public Ticks Ticks
54  {
55  get; private set;
56  }
57 
58  /// <summary>
59  /// Gets all trade bars for every option contract in this chain, keyed by option symbol
60  /// </summary>
61  [PandasIgnore]
62  public TradeBars TradeBars
63  {
64  get; private set;
65  }
66 
67  /// <summary>
68  /// Gets all quote bars for every option contract in this chain, keyed by option symbol
69  /// </summary>
70  [PandasIgnore]
71  public QuoteBars QuoteBars
72  {
73  get; private set;
74  }
75 
76  /// <summary>
77  /// Gets all contracts in the chain, keyed by option symbol
78  /// </summary>
80  {
81  get; private set;
82  }
83 
84  /// <summary>
85  /// Gets the set of symbols that passed the <see cref="Option.ContractFilter"/>
86  /// </summary>
87  [PandasIgnore]
88  public HashSet<Symbol> FilteredContracts
89  {
90  get; private set;
91  }
92 
93  /// <summary>
94  /// The data frame representation of the option chain
95  /// </summary>
96  [PandasIgnore]
97  public PyObject DataFrame => _dataframe.Value;
98 
99  /// <summary>
100  /// Initializes a new default instance of the <see cref="OptionChain"/> class
101  /// </summary>
102  private OptionChain(bool flatten)
103  {
104  DataType = MarketDataType.OptionChain;
105  _flatten = flatten;
106  _dataframe = new Lazy<PyObject>(
107  () =>
108  {
109  if (!PythonEngine.IsInitialized)
110  {
111  return null;
112  }
113  return new PandasConverter().GetDataFrame(new[] { this }, symbolOnlyIndex: true, flatten: _flatten);
114  },
115  isThreadSafe: false);
116  }
117 
118  /// <summary>
119  /// Initializes a new instance of the <see cref="OptionChain"/> class
120  /// </summary>
121  /// <param name="canonicalOptionSymbol">The symbol for this chain.</param>
122  /// <param name="time">The time of this chain</param>
123  /// <param name="flatten">Whether to flatten the data frame</param>
124  public OptionChain(Symbol canonicalOptionSymbol, DateTime time, bool flatten = true)
125  : this(flatten)
126  {
127  Time = time;
128  Symbol = canonicalOptionSymbol;
129  DataType = MarketDataType.OptionChain;
130  Ticks = new Ticks(time);
131  TradeBars = new TradeBars(time);
132  QuoteBars = new QuoteBars(time);
133  Contracts = new OptionContracts(time);
134  FilteredContracts = new HashSet<Symbol>();
135  Underlying = new QuoteBar();
136  }
137 
138  /// <summary>
139  /// Initializes a new instance of the <see cref="OptionChain"/> class
140  /// </summary>
141  /// <param name="canonicalOptionSymbol">The symbol for this chain.</param>
142  /// <param name="time">The time of this chain</param>
143  /// <param name="underlying">The most recent underlying trade data</param>
144  /// <param name="trades">All trade data for the entire option chain</param>
145  /// <param name="quotes">All quote data for the entire option chain</param>
146  /// <param name="contracts">All contracts for this option chain</param>
147  /// <param name="filteredContracts">The filtered list of contracts for this option chain</param>
148  /// <param name="flatten">Whether to flatten the data frame</param>
149  public OptionChain(Symbol canonicalOptionSymbol, DateTime time, BaseData underlying, IEnumerable<BaseData> trades,
150  IEnumerable<BaseData> quotes, IEnumerable<OptionContract> contracts, IEnumerable<Symbol> filteredContracts, bool flatten = true)
151  : this(flatten)
152  {
153  Time = time;
154  Underlying = underlying;
155  Symbol = canonicalOptionSymbol;
156  DataType = MarketDataType.OptionChain;
157  FilteredContracts = filteredContracts.ToHashSet();
158 
159  Ticks = new Ticks(time);
160  TradeBars = new TradeBars(time);
161  QuoteBars = new QuoteBars(time);
162  Contracts = new OptionContracts(time);
163 
164  foreach (var trade in trades)
165  {
166  var tick = trade as Tick;
167  if (tick != null)
168  {
169  List<Tick> ticks;
170  if (!Ticks.TryGetValue(tick.Symbol, out ticks))
171  {
172  ticks = new List<Tick>();
173  Ticks[tick.Symbol] = ticks;
174  }
175  ticks.Add(tick);
176  continue;
177  }
178  var bar = trade as TradeBar;
179  if (bar != null)
180  {
181  TradeBars[trade.Symbol] = bar;
182  }
183  }
184 
185  foreach (var quote in quotes)
186  {
187  var tick = quote as Tick;
188  if (tick != null)
189  {
190  List<Tick> ticks;
191  if (!Ticks.TryGetValue(tick.Symbol, out ticks))
192  {
193  ticks = new List<Tick>();
194  Ticks[tick.Symbol] = ticks;
195  }
196  ticks.Add(tick);
197  continue;
198  }
199  var bar = quote as QuoteBar;
200  if (bar != null)
201  {
202  QuoteBars[quote.Symbol] = bar;
203  }
204  }
205 
206  foreach (var contract in contracts)
207  {
208  Contracts[contract.Symbol] = contract;
209  }
210  }
211 
212  /// <summary>
213  /// Initializes a new option chain for a list of contracts as <see cref="OptionUniverse"/> instances
214  /// </summary>
215  /// <param name="canonicalOptionSymbol">The canonical option symbol</param>
216  /// <param name="time">The time of this chain</param>
217  /// <param name="contracts">The list of contracts data</param>
218  /// <param name="symbolProperties">The option symbol properties</param>
219  /// <param name="flatten">Whether to flatten the data frame</param>
220  public OptionChain(Symbol canonicalOptionSymbol, DateTime time, IEnumerable<OptionUniverse> contracts, SymbolProperties symbolProperties,
221  bool flatten = true)
222  : this(canonicalOptionSymbol, time, flatten)
223  {
224  Time = time;
225  Symbol = canonicalOptionSymbol;
226  DataType = MarketDataType.OptionChain;
227 
228  Ticks = new Ticks(time);
229  TradeBars = new TradeBars(time);
230  QuoteBars = new QuoteBars(time);
231  Contracts = new OptionContracts(time);
232 
233  foreach (var contractData in contracts)
234  {
235  Contracts[contractData.Symbol] = OptionContract.Create(contractData, symbolProperties);
236  Underlying ??= contractData.Underlying;
237  }
238  }
239 
240  /// <summary>
241  /// Gets the auxiliary data with the specified type and symbol
242  /// </summary>
243  /// <typeparam name="T">The type of auxiliary data</typeparam>
244  /// <param name="symbol">The symbol of the auxiliary data</param>
245  /// <returns>The last auxiliary data with the specified type and symbol</returns>
246  public T GetAux<T>(Symbol symbol)
247  {
248  List<BaseData> list;
249  Dictionary<Symbol, List<BaseData>> dictionary;
250  if (!_auxiliaryData.TryGetValue(typeof(T), out dictionary) || !dictionary.TryGetValue(symbol, out list))
251  {
252  return default(T);
253  }
254  return list.OfType<T>().LastOrDefault();
255  }
256 
257  /// <summary>
258  /// Gets all auxiliary data of the specified type as a dictionary keyed by symbol
259  /// </summary>
260  /// <typeparam name="T">The type of auxiliary data</typeparam>
261  /// <returns>A dictionary containing all auxiliary data of the specified type</returns>
263  {
264  Dictionary<Symbol, List<BaseData>> d;
265  if (!_auxiliaryData.TryGetValue(typeof(T), out d))
266  {
267  return new DataDictionary<T>();
268  }
269  var dictionary = new DataDictionary<T>();
270  foreach (var kvp in d)
271  {
272  var item = kvp.Value.OfType<T>().LastOrDefault();
273  if (item != null)
274  {
275  dictionary.Add(kvp.Key, item);
276  }
277  }
278  return dictionary;
279  }
280 
281  /// <summary>
282  /// Gets all auxiliary data of the specified type as a dictionary keyed by symbol
283  /// </summary>
284  /// <typeparam name="T">The type of auxiliary data</typeparam>
285  /// <returns>A dictionary containing all auxiliary data of the specified type</returns>
286  public Dictionary<Symbol, List<BaseData>> GetAuxList<T>()
287  {
288  Dictionary<Symbol, List<BaseData>> dictionary;
289  if (!_auxiliaryData.TryGetValue(typeof(T), out dictionary))
290  {
291  return new Dictionary<Symbol, List<BaseData>>();
292  }
293  return dictionary;
294  }
295 
296  /// <summary>
297  /// Gets a list of auxiliary data with the specified type and symbol
298  /// </summary>
299  /// <typeparam name="T">The type of auxiliary data</typeparam>
300  /// <param name="symbol">The symbol of the auxiliary data</param>
301  /// <returns>The list of auxiliary data with the specified type and symbol</returns>
302  public List<T> GetAuxList<T>(Symbol symbol)
303  {
304  List<BaseData> list;
305  Dictionary<Symbol, List<BaseData>> dictionary;
306  if (!_auxiliaryData.TryGetValue(typeof(T), out dictionary) || !dictionary.TryGetValue(symbol, out list))
307  {
308  return new List<T>();
309  }
310  return list.OfType<T>().ToList();
311  }
312 
313  /// <summary>
314  /// Returns an enumerator that iterates through the collection.
315  /// </summary>
316  /// <returns>
317  /// An enumerator that can be used to iterate through the collection.
318  /// </returns>
319  public IEnumerator<OptionContract> GetEnumerator()
320  {
321  return Contracts.Values.GetEnumerator();
322  }
323 
324  /// <summary>
325  /// Returns an enumerator that iterates through a collection.
326  /// </summary>
327  /// <returns>
328  /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
329  /// </returns>
330  IEnumerator IEnumerable.GetEnumerator()
331  {
332  return GetEnumerator();
333  }
334 
335  /// <summary>
336  /// Return a new instance clone of this object, used in fill forward
337  /// </summary>
338  /// <returns>A clone of the current object</returns>
339  public override BaseData Clone()
340  {
341  return new OptionChain(_flatten)
342  {
344  Ticks = Ticks,
349  Symbol = Symbol,
350  Time = Time,
351  DataType = DataType,
352  Value = Value
353  };
354  }
355 
356  /// <summary>
357  /// Adds the specified auxiliary data to this option chain
358  /// </summary>
359  /// <param name="baseData">The auxiliary data to be added</param>
360  internal void AddAuxData(BaseData baseData)
361  {
362  var type = baseData.GetType();
363  Dictionary<Symbol, List<BaseData>> dictionary;
364  if (!_auxiliaryData.TryGetValue(type, out dictionary))
365  {
366  dictionary = new Dictionary<Symbol, List<BaseData>>();
367  _auxiliaryData[type] = dictionary;
368  }
369 
370  List<BaseData> list;
371  if (!dictionary.TryGetValue(baseData.Symbol, out list))
372  {
373  list = new List<BaseData>();
374  dictionary[baseData.Symbol] = list;
375  }
376  list.Add(baseData);
377  }
378  }
379 }