Lean  $LEAN_TAG$
BaseDataCollection.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.Linq;
19 using System.Collections;
20 using System.Collections.Generic;
21 using QuantConnect.Python;
22 
24 {
25  /// <summary>
26  /// This type exists for transport of data as a single packet
27  /// </summary>
28  public class BaseDataCollection : BaseData, IEnumerable<BaseData>
29  {
30  /// <summary>
31  /// Cache for the symbols to avoid creating them multiple times
32  /// </summary>
33  private static readonly Dictionary<string, Symbol> _symbolsCache = new();
34 
35  private DateTime _endTime;
36 
37  /// <summary>
38  /// The associated underlying price data if any
39  /// </summary>
40  [PandasNonExpandable]
41  public BaseData Underlying { get; set; }
42 
43  /// <summary>
44  /// Gets or sets the contracts selected by the universe
45  /// </summary>
46  [PandasIgnore]
47  public HashSet<Symbol> FilteredContracts { get; set; }
48 
49  /// <summary>
50  /// Gets the data list
51  /// </summary>
52  public List<BaseData> Data { get; set; }
53 
54  /// <summary>
55  /// Gets or sets the end time of this data
56  /// </summary>
57  [PandasIgnore]
58  public override DateTime EndTime
59  {
60  get
61  {
62  if (_endTime == default)
63  {
64  // to be user friendly let's return Time if not set, like BaseData does
65  return Time;
66  }
67  return _endTime;
68  }
69  set
70  {
71  _endTime = value;
72  }
73  }
74 
75  /// <summary>
76  /// Initializes a new default instance of the <see cref="BaseDataCollection"/> c;ass
77  /// </summary>
79  : this(DateTime.MinValue, Symbol.Empty)
80  {
81  }
82 
83  /// <summary>
84  /// Initializes a new instance of the <see cref="BaseDataCollection"/> class
85  /// </summary>
86  /// <param name="time">The time of this data</param>
87  /// <param name="symbol">A common identifier for all data in this packet</param>
88  /// <param name="data">The data to add to this collection</param>
89  public BaseDataCollection(DateTime time, Symbol symbol, IEnumerable<BaseData> data = null)
90  : this(time, time, symbol, data)
91  {
92  }
93 
94  /// <summary>
95  /// Initializes a new instance of the <see cref="BaseDataCollection"/> class
96  /// </summary>
97  /// <param name="time">The start time of this data</param>
98  /// <param name="endTime">The end time of this data</param>
99  /// <param name="symbol">A common identifier for all data in this packet</param>
100  /// <param name="data">The data to add to this collection</param>
101  /// <param name="underlying">The associated underlying price data if any</param>
102  /// <param name="filteredContracts">The contracts selected by the universe</param>
103  public BaseDataCollection(DateTime time, DateTime endTime, Symbol symbol, IEnumerable<BaseData> data = null, BaseData underlying = null, HashSet<Symbol> filteredContracts = null)
104  : this(time, endTime, symbol, data != null ? data.ToList() : new List<BaseData>(), underlying, filteredContracts)
105  {
106  }
107 
108  /// <summary>
109  /// Initializes a new instance of the <see cref="BaseDataCollection"/> class
110  /// </summary>
111  /// <param name="time">The start time of this data</param>
112  /// <param name="endTime">The end time of this data</param>
113  /// <param name="symbol">A common identifier for all data in this packet</param>
114  /// <param name="data">The data to add to this collection</param>
115  /// <param name="underlying">The associated underlying price data if any</param>
116  /// <param name="filteredContracts">The contracts selected by the universe</param>
117  public BaseDataCollection(DateTime time, DateTime endTime, Symbol symbol, List<BaseData> data, BaseData underlying, HashSet<Symbol> filteredContracts)
118  : this(time, endTime, symbol, underlying, filteredContracts)
119  {
120  if (data != null && data.Count == 1 && data[0] is BaseDataCollection collection && collection.Data != null && collection.Data.Count > 0)
121  {
122  // we were given a base data collection, let's be nice and fetch it's data if it has any
123  Data = collection.Data;
124  }
125  else
126  {
127  Data = data ?? new List<BaseData>();
128  }
129  }
130 
131  /// <summary>
132  /// Helper method to create an instance without setting the data list
133  /// </summary>
134  protected BaseDataCollection(DateTime time, DateTime endTime, Symbol symbol, BaseData underlying, HashSet<Symbol> filteredContracts)
135  {
136  Symbol = symbol;
137  Time = time;
138  _endTime = endTime;
139  Underlying = underlying;
140  FilteredContracts = filteredContracts;
141  }
142 
143  /// <summary>
144  /// Copy constructor for <see cref="BaseDataCollection"/>
145  /// </summary>
146  /// <param name="other">The base data collection being copied</param>
148  : this(other.Time, other.EndTime, other.Symbol, other.Underlying, other.FilteredContracts)
149  {
150  Data = other.Data;
151  }
152 
153  /// <summary>
154  /// Creates the universe symbol for the target market
155  /// </summary>
156  /// <returns>The universe symbol to use</returns>
157  public virtual Symbol UniverseSymbol(string market = null)
158  {
159  market ??= QuantConnect.Market.USA;
160  var ticker = $"{GetType().Name}-{market}-{Guid.NewGuid()}";
161  return Symbol.Create(ticker, SecurityType.Base, market, baseDataType: GetType());
162  }
163 
164  /// <summary>
165  /// Indicates whether this contains data that should be stored in the security cache
166  /// </summary>
167  /// <returns>Whether this contains data that should be stored in the security cache</returns>
168  public override bool ShouldCacheToSecurity()
169  {
170  if (Data == null || Data.Count == 0)
171  {
172  return true;
173  }
174  // if we hold the same data type we are, else we ask underlying type
175  return Data[0].GetType() == GetType() || Data[0].ShouldCacheToSecurity();
176  }
177 
178  /// <summary>
179  /// Adds a new data point to this collection
180  /// </summary>
181  /// <param name="newDataPoint">The new data point to add</param>
182  public virtual void Add(BaseData newDataPoint)
183  {
184  Data.Add(newDataPoint);
185  }
186 
187  /// <summary>
188  /// Adds a new data points to this collection
189  /// </summary>
190  /// <param name="newDataPoints">The new data points to add</param>
191  public virtual void AddRange(IEnumerable<BaseData> newDataPoints)
192  {
193  Data.AddRange(newDataPoints);
194  }
195 
196  /// <summary>
197  /// Return a new instance clone of this object, used in fill forward
198  /// </summary>
199  /// <remarks>
200  /// This base implementation uses reflection to copy all public fields and properties
201  /// </remarks>
202  /// <returns>A clone of the current object</returns>
203  public override BaseData Clone()
204  {
205  return new BaseDataCollection(this);
206  }
207 
208  /// <summary>
209  /// Returns an IEnumerator for this enumerable Object. The enumerator provides
210  /// a simple way to access all the contents of a collection.
211  /// </summary>
212  public IEnumerator<BaseData> GetEnumerator()
213  {
214  return (Data ?? Enumerable.Empty<BaseData>()).GetEnumerator();
215  }
216 
217  /// <summary>
218  /// Returns an IEnumerator for this enumerable Object. The enumerator provides
219  /// a simple way to access all the contents of a collection.
220  /// </summary>
221  IEnumerator IEnumerable.GetEnumerator()
222  {
223  return GetEnumerator();
224  }
225 
226  /// <summary>
227  /// Tries to get a symbol from the cache
228  /// </summary>
229  protected static bool TryGetCachedSymbol(string ticker, out Symbol symbol)
230  {
231  lock (_symbolsCache)
232  {
233  return _symbolsCache.TryGetValue(ticker, out symbol);
234  }
235  }
236 
237  /// <summary>
238  /// Caches a symbol
239  /// </summary>
240  protected static void CacheSymbol(string ticker, Symbol symbol)
241  {
242  lock (_symbolsCache)
243  {
244  // limit the cache size to help with memory usage
245  if (_symbolsCache.Count >= 600000)
246  {
247  _symbolsCache.Clear();
248  }
249  _symbolsCache.TryAdd(ticker, symbol);
250  }
251  }
252  }
253 }