Lean  $LEAN_TAG$
DataQueueOptionChainUniverseDataCollectionEnumerator.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 
17 using System;
18 using System.Collections.Generic;
19 using System.Linq;
20 using QuantConnect.Data;
24 using System.Collections;
25 using QuantConnect.Logging;
26 
28 {
29  /// <summary>
30  /// Enumerates live options symbol universe data into <see cref="BaseDataCollection"/> instances
31  /// </summary>
32  public class DataQueueOptionChainUniverseDataCollectionEnumerator : IEnumerator<BaseDataCollection>
33  {
34  private readonly SubscriptionRequest _subscriptionRequest;
35  private readonly IDataQueueUniverseProvider _universeProvider;
36  private readonly ITimeProvider _timeProvider;
37  private bool _needNewCurrent;
38  private DateTime _lastEmitTime;
39  private BaseDataCollection _currentData;
40 
41  /// <summary>
42  /// Gets the enumerator for the underlying asset
43  /// </summary>
44  public IEnumerator<BaseData> Underlying { get; }
45 
46  /// <summary>
47  /// Initializes a new instance of the <see cref="DataQueueOptionChainUniverseDataCollectionEnumerator"/> class.
48  /// </summary>
49  /// <param name="subscriptionRequest">The subscription request to be used</param>
50  /// <param name="underlying">Underlying enumerator</param>
51  /// <param name="universeProvider">Symbol universe provider of the data queue</param>
52  /// <param name="timeProvider">The time provider to be used</param>
54  SubscriptionRequest subscriptionRequest,
55  IEnumerator<BaseData> underlying,
56  IDataQueueUniverseProvider universeProvider,
57  ITimeProvider timeProvider)
58  {
59  _subscriptionRequest = subscriptionRequest;
60  Underlying = underlying;
61  _universeProvider = universeProvider;
62  _timeProvider = timeProvider;
63 
64  _needNewCurrent = true;
65  }
66 
67  /// <summary>
68  /// Returns current option chain enumerator position
69  /// </summary>
70  public BaseDataCollection Current { get; private set; }
71 
72  /// <summary>
73  /// Returns current option chain enumerator position
74  /// </summary>
75  object IEnumerator.Current => Current;
76 
77  /// <summary>
78  /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
79  /// </summary>
80  public void Dispose()
81  {
82  Underlying.Dispose();
83  }
84 
85  /// <summary>
86  /// Advances the enumerator to the next element of the collection.
87  /// </summary>
88  /// <returns>
89  /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
90  /// </returns>
91  public bool MoveNext()
92  {
93  Underlying.MoveNext();
94 
95  if (Underlying.Current == null)
96  {
97  Current = null;
98  return true;
99  }
100 
101  if (!_needNewCurrent)
102  {
103  // refresh on date change (in exchange time zone)
104  _needNewCurrent = _timeProvider.GetUtcNow().ConvertFromUtc(_subscriptionRequest.Configuration.ExchangeTimeZone).Date != _lastEmitTime.Date;
105  }
106 
107  if (_needNewCurrent)
108  {
109  if (!_universeProvider.CanPerformSelection())
110  {
111  Current = null;
112  return true;
113  }
114 
115  var localTime = _timeProvider.GetUtcNow()
116  .ConvertFromUtc(_subscriptionRequest.Configuration.ExchangeTimeZone)
117  .RoundDown(_subscriptionRequest.Configuration.Increment);
118 
119  // loading the list of futures contracts and converting them into zip entries
120  var symbols = _universeProvider.LookupSymbols(_subscriptionRequest.Security.Symbol, false);
121  var zipEntries = symbols.Select(x => new ZipEntryName { Time = localTime, Symbol = x } as BaseData).ToList();
122  _currentData = new BaseDataCollection
123  {
124  Symbol = _subscriptionRequest.Security.Symbol,
125  Underlying = Underlying.Current,
126  Data = zipEntries,
127  Time = localTime,
128  EndTime = localTime
129  };
130 
131  Log.Trace($"DataQueueOptionChainUniverseDataCollectionEnumerator({_currentData.Symbol}): Emitting data point: {_currentData.EndTime}. " +
132  $"Count: {_currentData.Data.Count}. Underlying: {_currentData.Underlying} Underlying.EndTime: {_currentData.Underlying.EndTime}");
133 
134  _lastEmitTime = localTime;
135 
136  Current = _currentData;
137  _needNewCurrent = false;
138  }
139  else
140  {
141  if (Current == null)
142  {
143  Current = _currentData;
144  }
145 
146  Current = (BaseDataCollection)Current.Clone(fillForward: true);
147  Current.Underlying = Underlying.Current;
148  Current.Time = Underlying.Current.EndTime;
149  Current.EndTime = Underlying.Current.EndTime;
150  }
151 
152  return true;
153  }
154 
155  /// <summary>
156  /// Sets the enumerator to its initial position, which is before the first element in the collection.
157  /// </summary>
158  public void Reset()
159  {
160  Underlying.Reset();
161  _needNewCurrent = true;
162  }
163  }
164 }