Lean  $LEAN_TAG$
SliceExtensions.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;
24 using QuantConnect.Util;
25 
26 namespace QuantConnect.Data
27 {
28  /// <summary>
29  /// Provides extension methods to slices and slice enumerables
30  /// </summary>
31  public static class SliceExtensions
32  {
33  /// <summary>
34  /// Selects into the slice and returns the TradeBars that have data in order
35  /// </summary>
36  /// <param name="slices">The enumerable of slice</param>
37  /// <returns>An enumerable of TradeBars</returns>
38  public static IEnumerable<TradeBars> TradeBars(this IEnumerable<Slice> slices)
39  {
40  return slices.Where(x => x.Bars.Count > 0).Select(x => x.Bars);
41  }
42 
43  /// <summary>
44  /// Selects into the slice and returns the Ticks that have data in order
45  /// </summary>
46  /// <param name="slices">The enumerable of slice</param>
47  /// <returns>An enumerable of Ticks</returns>
48  public static IEnumerable<Ticks> Ticks(this IEnumerable<Slice> slices)
49  {
50  return slices.Where(x => x.Ticks.Count > 0).Select(x => x.Ticks);
51  }
52 
53  /// <summary>
54  /// Gets the data dictionaries or points of the requested type in each slice
55  /// </summary>
56  /// <param name="slices">The enumerable of slice</param>
57  /// <returns>An enumerable of data dictionary or data point of the requested type</returns>
58  public static IEnumerable<DataDictionary<BaseDataCollection>> GetUniverseData(this IEnumerable<Slice> slices)
59  {
60  return slices.SelectMany(x => x.AllData).Select(x =>
61  {
62  // we wrap the universe data collection into a data dictionary so it fits the api pattern
63  return new DataDictionary<BaseDataCollection>(new[] { (BaseDataCollection)x }, (y) => y.Symbol);
64  });
65  }
66 
67  /// <summary>
68  /// Gets the data dictionaries or points of the requested type in each slice
69  /// </summary>
70  /// <param name="slices">The enumerable of slice</param>
71  /// <param name="type">Data type of the data that will be fetched</param>
72  /// <param name="symbol">The symbol to retrieve</param>
73  /// <returns>An enumerable of data dictionary or data point of the requested type</returns>
74  public static IEnumerable<dynamic> Get(this IEnumerable<Slice> slices, Type type, Symbol symbol = null)
75  {
76  var result = slices.Select(x => x.Get(type));
77 
78  if (symbol == null)
79  {
80  return result;
81  }
82 
83  return result.Where(x => x.ContainsKey(symbol)).Select(x => x[symbol]);
84  }
85 
86  /// <summary>
87  /// Gets an enumerable of TradeBar for the given symbol. This method does not verify
88  /// that the specified symbol points to a TradeBar
89  /// </summary>
90  /// <param name="slices">The enumerable of slice</param>
91  /// <param name="symbol">The symbol to retrieve</param>
92  /// <returns>An enumerable of TradeBar for the matching symbol, of no TradeBar found for symbol, empty enumerable is returned</returns>
93  public static IEnumerable<TradeBar> Get(this IEnumerable<Slice> slices, Symbol symbol)
94  {
95  return slices.TradeBars().Where(x => x.ContainsKey(symbol)).Select(x => x[symbol]);
96  }
97 
98  /// <summary>
99  /// Gets an enumerable of T for the given symbol. This method does not vify
100  /// that the specified symbol points to a T
101  /// </summary>
102  /// <typeparam name="T">The data type</typeparam>
103  /// <param name="dataDictionaries">The data dictionary enumerable to access</param>
104  /// <param name="symbol">The symbol to retrieve</param>
105  /// <returns>An enumerable of T for the matching symbol, if no T is found for symbol, empty enumerable is returned</returns>
106  public static IEnumerable<T> Get<T>(this IEnumerable<DataDictionary<T>> dataDictionaries, Symbol symbol)
107  where T : IBaseData
108  {
109  return dataDictionaries.Where(x => x.ContainsKey(symbol)).Select(x => x[symbol]);
110  }
111 
112  /// <summary>
113  /// Gets an enumerable of decimals by accessing the specified field on data for the symbol
114  /// </summary>
115  /// <typeparam name="T">The data type</typeparam>
116  /// <param name="dataDictionaries">An enumerable of data dictionaries</param>
117  /// <param name="symbol">The symbol to retrieve</param>
118  /// <param name="field">The field to access</param>
119  /// <returns>An enumerable of decimals</returns>
120  public static IEnumerable<decimal> Get<T>(this IEnumerable<DataDictionary<T>> dataDictionaries, Symbol symbol, string field)
121  {
122  Func<T, decimal> selector;
123  if (typeof (DynamicData).IsAssignableFrom(typeof (T)))
124  {
125  selector = data =>
126  {
127  var dyn = (DynamicData) (object) data;
128  return (decimal) dyn.GetProperty(field);
129  };
130  }
131  else if (typeof (T) == typeof (List<Tick>))
132  {
133  // perform the selection on the last tick
134  // NOTE: This is a known bug, should be updated to perform the selection on each item in the list
135  var dataSelector = (Func<Tick, decimal>) ExpressionBuilder.MakePropertyOrFieldSelector(typeof (Tick), field).Compile();
136  selector = ticks => dataSelector(((List<Tick>) (object) ticks).Last());
137  }
138  else
139  {
140  selector = (Func<T, decimal>) ExpressionBuilder.MakePropertyOrFieldSelector(typeof (T), field).Compile();
141  }
142 
143  foreach (var dataDictionary in dataDictionaries)
144  {
145  T item;
146  if (dataDictionary.TryGetValue(symbol, out item))
147  {
148  yield return selector(item);
149  }
150  }
151  }
152 
153  /// <summary>
154  /// Gets the data dictionaries of the requested type in each slice
155  /// </summary>
156  /// <typeparam name="T">The data type</typeparam>
157  /// <param name="slices">The enumerable of slice</param>
158  /// <returns>An enumerable of data dictionary of the requested type</returns>
159  public static IEnumerable<DataDictionary<T>> Get<T>(this IEnumerable<Slice> slices)
160  where T : IBaseData
161  {
162  return slices.Select(x => x.Get<T>()).Where(x => x.Count > 0);
163  }
164 
165  /// <summary>
166  /// Gets an enumerable of T by accessing the slices for the requested symbol
167  /// </summary>
168  /// <typeparam name="T">The data type</typeparam>
169  /// <param name="slices">The enumerable of slice</param>
170  /// <param name="symbol">The symbol to retrieve</param>
171  /// <returns>An enumerable of T by accessing each slice for the requested symbol</returns>
172  public static IEnumerable<T> Get<T>(this IEnumerable<Slice> slices, Symbol symbol)
173  where T : IBaseData
174  {
175  return slices.Select(x => x.Get<T>()).Where(x => x.ContainsKey(symbol)).Select(x => x[symbol]);
176  }
177 
178  /// <summary>
179  /// Gets an enumerable of decimal by accessing the slice for the symbol and then retrieving the specified
180  /// field on each piece of data
181  /// </summary>
182  /// <param name="slices">The enumerable of slice</param>
183  /// <param name="symbol">The symbol to retrieve</param>
184  /// <param name="field">The field selector used to access the dats</param>
185  /// <returns>An enumerable of decimal</returns>
186  public static IEnumerable<decimal> Get(this IEnumerable<Slice> slices, Symbol symbol, Func<BaseData, decimal> field)
187  {
188  foreach (var slice in slices)
189  {
190  dynamic item;
191  if (slice.TryGetValue(symbol, out item))
192  {
193  if (item is List<Tick>) yield return field(item.Last());
194  else yield return field(item);
195  }
196  }
197  }
198 
199  /// <summary>
200  /// Tries to get the data for the specified symbol and type
201  /// </summary>
202  /// <typeparam name="T">The type of data we want, for example, <see cref="TradeBar"/> or <see cref="UnlinkedData"/>, etc...</typeparam>
203  /// <param name="slice">The slice</param>
204  /// <param name="symbol">The symbol data is sought for</param>
205  /// <param name="data">The found data</param>
206  /// <returns>True if data was found for the specified type and symbol</returns>
207  public static bool TryGet<T>(this Slice slice, Symbol symbol, out T data)
208  where T : IBaseData
209  {
210  data = default(T);
211  var typeData = slice.Get(typeof(T)) as DataDictionary<T>;
212  if (typeData.ContainsKey(symbol))
213  {
214  data = typeData[symbol];
215  return true;
216  }
217 
218  return false;
219  }
220 
221  /// <summary>
222  /// Tries to get the data for the specified symbol and type
223  /// </summary>
224  /// <param name="slice">The slice</param>
225  /// <param name="type">The type of data we seek</param>
226  /// <param name="symbol">The symbol data is sought for</param>
227  /// <param name="data">The found data</param>
228  /// <returns>True if data was found for the specified type and symbol</returns>
229  public static bool TryGet(this Slice slice, Type type, Symbol symbol, out dynamic data)
230  {
231  data = null;
232  var typeData = slice.Get(type);
233  if (typeData.ContainsKey(symbol))
234  {
235  data = typeData[symbol];
236  return true;
237  }
238 
239  return false;
240  }
241 
242  /// <summary>
243  /// Converts the specified enumerable of decimals into a double array
244  /// </summary>
245  /// <param name="decimals">The enumerable of decimal</param>
246  /// <returns>Double array representing the enumerable of decimal</returns>
247  public static double[] ToDoubleArray(this IEnumerable<decimal> decimals)
248  {
249  return decimals.Select(x => (double) x).ToArray();
250  }
251 
252  /// <summary>
253  /// Loops through the specified slices and pushes the data into the consolidators. This can be used to
254  /// easily warm up indicators from a history call that returns slice objects.
255  /// </summary>
256  /// <param name="slices">The data to send into the consolidators, likely result of a history request</param>
257  /// <param name="consolidatorsBySymbol">Dictionary of consolidators keyed by symbol</param>
258  public static void PushThroughConsolidators(this IEnumerable<Slice> slices, Dictionary<Symbol, IDataConsolidator> consolidatorsBySymbol)
259  {
260  PushThroughConsolidators(slices, symbol =>
261  {
262  IDataConsolidator consolidator;
263  consolidatorsBySymbol.TryGetValue(symbol, out consolidator);
264  return consolidator;
265  });
266  }
267 
268  /// <summary>
269  /// Loops through the specified slices and pushes the data into the consolidators. This can be used to
270  /// easily warm up indicators from a history call that returns slice objects.
271  /// </summary>
272  /// <param name="slices">The data to send into the consolidators, likely result of a history request</param>
273  /// <param name="consolidatorsProvider">Delegate that fetches the consolidators by a symbol</param>
274  public static void PushThroughConsolidators(this IEnumerable<Slice> slices, Func<Symbol, IDataConsolidator> consolidatorsProvider)
275  {
276  slices.PushThrough(data => consolidatorsProvider(data?.Symbol)?.Update(data));
277  }
278 
279  /// <summary>
280  /// Loops through the specified slices and pushes the data into the consolidators. This can be used to
281  /// easily warm up indicators from a history call that returns slice objects.
282  /// </summary>
283  /// <param name="slices">The data to send into the consolidators, likely result of a history request</param>
284  /// <param name="handler">Delegate handles each data piece from the slice</param>
285  /// <param name="dataType">Defines the type of the data that should be pushed</param>
286  public static void PushThrough(this IEnumerable<Slice> slices, Action<BaseData> handler, Type dataType = null)
287  {
288  if (dataType != null)
289  {
290  Func<Slice, IEnumerable<BaseData>> dataSelector = default;
291  if (dataType == typeof(QuoteBar))
292  {
293  dataSelector = slice => slice.QuoteBars.Values;
294  }
295  else if (dataType == typeof(Tick))
296  {
297  dataSelector = slice => slice.Ticks.Values.Select(x => x.Last());
298  }
299  else if (dataType == typeof(TradeBar))
300  {
301  dataSelector = slice => slice.Bars.Values;
302  }
303  else
304  {
305  dataSelector = slice => slice.Get(dataType).Values;
306  }
307 
308  foreach (var slice in slices)
309  {
310  foreach (BaseData baseData in dataSelector(slice))
311  {
312  handler(baseData);
313  }
314  }
315  }
316  else
317  {
318  foreach (var slice in slices)
319  {
320  foreach (var symbol in slice.Keys)
321  {
322  dynamic value;
323  if (!slice.TryGetValue(symbol, out value))
324  {
325  continue;
326  }
327 
328  var list = value as IList;
329  var data = (BaseData)(list != null ? list[list.Count - 1] : value);
330 
331  handler(data);
332  }
333  }
334  }
335  }
336  }
337 }