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