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