17 using System.Collections;
18 using System.Collections.Generic;
20 using System.Reflection;
49 private Lazy<DataDictionary<SymbolData>> _data;
51 private Dictionary<Type, object> _dataByType;
56 public List<BaseData>
AllData {
get;
private set; }
95 get {
return _quoteBars; }
103 get {
return _ticks; }
111 get {
return _optionChains; }
119 get {
return _futuresChains; }
127 get {
return _futuresChains; }
135 get {
return _splits; }
143 get {
return _dividends; }
151 get {
return _delistings; }
159 get {
return _symbolChangedEvents; }
167 get {
return _marginInterestRates; }
173 public virtual int Count
175 get {
return _data.Value.Count; }
181 public virtual IReadOnlyList<Symbol>
Keys
183 get {
return new List<Symbol>(_data.Value.Keys); }
192 protected override IEnumerable<Symbol>
GetKeys => _data.Value.Keys;
200 protected override IEnumerable<dynamic>
GetValues => GetKeyValuePairEnumerable().Select(data => (dynamic)data.Value);
205 public virtual IReadOnlyList<BaseData>
Values
207 get {
return GetKeyValuePairEnumerable().Select(x => x.Value).ToList(); }
218 public Slice(DateTime time, IEnumerable<BaseData> data, DateTime utcTime)
219 : this(time, data.ToList(), utcTime: utcTime)
231 public Slice(DateTime time, List<BaseData> data, DateTime utcTime)
234 CreateTicksCollection(time, data),
256 _dataByType = slice._dataByType;
262 _ticks = slice._ticks;
264 _quoteBars = slice._quoteBars;
265 _optionChains = slice._optionChains;
266 _futuresChains = slice._futuresChains;
269 _splits = slice._splits;
270 _dividends = slice._dividends;
271 _delistings = slice._delistings;
272 _symbolChangedEvents = slice._symbolChangedEvents;
273 _marginInterestRates = slice._marginInterestRates;
293 public Slice(DateTime time, List<BaseData> data,
TradeBars tradeBars,
QuoteBars quoteBars,
Ticks ticks,
OptionChains optionChains,
FuturesChains futuresChains,
Splits splits,
Dividends dividends,
Delistings delistings,
SymbolChangedEvents symbolChanges,
MarginInterestRates marginInterestRates, DateTime utcTime,
bool? hasData =
null)
299 _data =
new Lazy<DataDictionary<SymbolData>>(() => CreateDynamicDataDictionary(
AllData));
301 HasData = hasData ?? _data.Value.Count > 0;
305 _quoteBars = quoteBars;
306 _optionChains = optionChains;
307 _futuresChains = futuresChains;
311 _dividends = dividends;
312 _delistings = delistings;
313 _symbolChangedEvents = symbolChanges;
314 _marginInterestRates = marginInterestRates;
325 public override dynamic
this[
Symbol symbol]
330 if (_data.Value.TryGetValue(symbol, out value))
332 return value.GetData();
334 throw new KeyNotFoundException($
"'{symbol}' wasn't found in the Slice object, likely because there was no-data at this moment in time and it wasn't possible to fillforward historical data. Please check the data exists before accessing it with data.ContainsKey(\"{symbol}\")");
346 return GetImpl(typeof(T),
this);
354 public dynamic
Get(Type type)
376 if (instance._dataByType ==
null)
379 instance._dataByType =
new Dictionary<Type, object>(1);
383 if (!instance._dataByType.TryGetValue(type, out dictionary))
385 var requestedOpenInterest = type == typeof(
OpenInterest);
386 if (type == typeof(
Tick) || requestedOpenInterest)
388 var dataDictionaryCache = GenericDataDictionary.Get(type, isPythonData:
false);
389 dictionary = Activator.CreateInstance(dataDictionaryCache.GenericType);
390 ((dynamic)dictionary).Time =
Time;
392 foreach (var data
in instance.
Ticks)
394 var symbol = data.Key;
397 var lastDataPoint = data.Value.LastOrDefault(tick => requestedOpenInterest && tick.TickType ==
TickType.OpenInterest || !requestedOpenInterest && tick.TickType !=
TickType.OpenInterest);
398 if (lastDataPoint ==
null)
402 dataDictionaryCache.MethodInfo.Invoke(dictionary,
new object[] { symbol, lastDataPoint });
407 dictionary = instance.
Bars;
417 else if (type == typeof(
Split))
419 dictionary = instance.
Splits;
443 var isPythonData = type.IsAssignableTo(typeof(
PythonData));
445 var dataDictionaryCache = GenericDataDictionary.Get(type, isPythonData);
446 dictionary = Activator.CreateInstance(dataDictionaryCache.GenericType);
449 foreach (var data
in instance._data.Value.Values)
452 if (IsDataPointOfType(data.Custom, type, isPythonData))
454 dataDictionaryCache.MethodInfo.Invoke(dictionary,
new object[] { data.Symbol, data.Custom });
458 foreach (var auxiliaryData
in data.AuxilliaryData.Where(x => IsDataPointOfType(x, type, isPythonData)))
460 dataDictionaryCache.MethodInfo.Invoke(dictionary,
new object[] { data.Symbol, auxiliaryData });
466 instance._dataByType[type] = dictionary;
490 return _data.Value.ContainsKey(symbol);
502 SymbolData symbolData;
503 if (_data.Value.TryGetValue(symbol, out symbolData))
505 data = symbolData.GetData();
520 throw new InvalidOperationException($
"Slice with time {UtcTime} can't be merged with given slice with different {inputSlice.UtcTime}");
525 _ticks = (
Ticks)UpdateCollection(_ticks, inputSlice.
Ticks);
528 _splits = (
Splits)UpdateCollection(_splits, inputSlice.
Splits);
534 if (inputSlice.
AllData.Count != 0)
539 _data = inputSlice._data;
547 _data =
new Lazy<DataDictionary<SymbolData>>(() => CreateDynamicDataDictionary(
AllData));
554 if (baseCollection ==
null || baseCollection.
Count == 0)
556 return inputCollection;
558 if (inputCollection?.
Count > 0)
560 foreach (var kvp
in inputCollection)
564 baseCollection.
Add(kvp.Key, kvp.Value);
568 return baseCollection;
577 foreach (var datum
in data)
580 if (!SubscriptionManager.IsDefaultDataType(datum))
584 SymbolData symbolData;
585 if (!allData.TryGetValue(datum.Symbol, out symbolData))
587 symbolData =
new SymbolData(datum.Symbol);
588 allData[datum.Symbol] = symbolData;
591 switch (datum.DataType)
594 symbolData.Type = SubscriptionType.Custom;
595 symbolData.Custom = datum;
599 symbolData.Type = SubscriptionType.TradeBar;
600 symbolData.TradeBar = (
TradeBar)datum;
604 symbolData.Type = SubscriptionType.QuoteBar;
605 symbolData.QuoteBar = (
QuoteBar)datum;
609 symbolData.Type = SubscriptionType.Tick;
610 symbolData.Ticks.Add((
Tick)datum);
614 symbolData.AuxilliaryData.Add(datum);
618 throw new ArgumentOutOfRangeException();
627 private static Ticks CreateTicksCollection(DateTime time, IEnumerable<BaseData> data)
629 var ticks =
new Ticks(time);
630 foreach (var tick
in data.OfType<
Tick>())
632 List<Tick> listTicks;
633 if (!ticks.TryGetValue(tick.Symbol, out listTicks))
635 ticks[tick.Symbol] = listTicks =
new List<Tick>();
650 private static T CreateCollection<T, TItem>(DateTime time, IEnumerable<BaseData> data)
652 where TItem : BaseData
654 var collection =
new T
656 #pragma warning disable 618 // This assignment is left here until the Time property is removed.
658 #pragma warning restore 618
660 foreach (var item
in data.OfType<TItem>())
662 collection[item.Symbol] = item;
676 return GetKeyValuePairEnumerable().GetEnumerator();
686 IEnumerator IEnumerable.GetEnumerator()
691 private IEnumerable<KeyValuePair<Symbol, BaseData>> GetKeyValuePairEnumerable()
695 foreach (var kvp
in _data.Value)
697 var data = kvp.Value.GetData();
699 var dataPoints = data as IEnumerable<BaseData>;
700 if (dataPoints !=
null)
702 foreach (var dataPoint
in dataPoints)
704 yield
return new KeyValuePair<Symbol, BaseData>(kvp.Key, dataPoint);
707 else if (data !=
null)
709 yield
return new KeyValuePair<Symbol, BaseData>(kvp.Key, data);
717 private static bool IsDataPointOfType(BaseData o, Type type,
bool isPythonData)
725 return data.IsOfType(type);
727 return o.GetType() == type;
731 private class SymbolData
733 public SubscriptionType Type;
734 public readonly Symbol Symbol;
737 public BaseData Custom;
740 public readonly List<Tick>
Ticks;
741 public readonly List<BaseData> AuxilliaryData;
743 public SymbolData(Symbol symbol)
746 Ticks =
new List<Tick>();
747 AuxilliaryData =
new List<BaseData>();
750 public dynamic GetData()
754 case SubscriptionType.TradeBar:
756 case SubscriptionType.QuoteBar:
758 case SubscriptionType.Tick:
760 case SubscriptionType.Custom:
763 throw new ArgumentOutOfRangeException();
773 private class GenericDataDictionary
775 private static Dictionary<Type, GenericDataDictionary> _genericCache =
new Dictionary<Type, GenericDataDictionary>();
780 public MethodInfo MethodInfo {
get; }
785 public Type GenericType {
get; }
787 private GenericDataDictionary(Type genericType, MethodInfo methodInfo)
789 GenericType = genericType;
790 MethodInfo = methodInfo;
799 public static GenericDataDictionary
Get(Type type,
bool isPythonData)
801 if (!_genericCache.TryGetValue(type, out var dataDictionaryCache))
803 var dictionaryType = type;
810 var method =
generic.GetMethod(
"Add",
new[] { typeof(Symbol), dictionaryType });
813 var temp =
new Dictionary<Type, GenericDataDictionary>(_genericCache);
814 temp[type] = dataDictionaryCache =
new GenericDataDictionary(
generic, method);
815 _genericCache = temp;
818 return dataDictionaryCache;