/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections; using System.Collections.Generic; using System.Linq; using QuantConnect.Data.Custom; using QuantConnect.Data.Market; namespace QuantConnect.Data { /// /// Provides a data structure for all of an algorithm's data at a single time step /// public class Slice : IEnumerable> { private readonly Ticks _ticks; private readonly TradeBars _bars; private readonly QuoteBars _quoteBars; private readonly OptionChains _optionChains; private readonly FuturesChains _futuresChains; // aux data private readonly Splits _splits; private readonly Dividends _dividends; private readonly Delistings _delistings; private readonly SymbolChangedEvents _symbolChangedEvents; // string -> data for non-tick data // string -> list{data} for tick data private readonly Lazy> _data; // Quandl -> DataDictonary private readonly Dictionary> _dataByType; /// /// Gets the timestamp for this slice of data /// public DateTime Time { get; private set; } /// /// Gets whether or not this slice has data /// public bool HasData { get; private set; } /// /// Gets the for this slice of data /// public TradeBars Bars { get { return _bars; } } /// /// Gets the for this slice of data /// public QuoteBars QuoteBars { get { return _quoteBars; } } /// /// Gets the for this slice of data /// public Ticks Ticks { get { return _ticks; } } /// /// Gets the for this slice of data /// public OptionChains OptionChains { get { return _optionChains; } } /// /// Gets the for this slice of data /// public FuturesChains FuturesChains { get { return _futuresChains; } } /// /// Gets the for this slice of data /// public FuturesChains FutureChains { get { return _futuresChains; } } /// /// Gets the for this slice of data /// public Splits Splits { get { return _splits; } } /// /// Gets the for this slice of data /// public Dividends Dividends { get { return _dividends; } } /// /// Gets the for this slice of data /// public Delistings Delistings { get { return _delistings; } } /// /// Gets the for this slice of data /// public SymbolChangedEvents SymbolChangedEvents { get { return _symbolChangedEvents; } } /// /// Gets the number of symbols held in this slice /// public int Count { get { return _data.Value.Count; } } /// /// Gets all the symbols in this slice /// public IReadOnlyList Keys { get { return new List(_data.Value.Keys); } } /// /// Gets a list of all the data in this slice /// public IReadOnlyList Values { get { return GetKeyValuePairEnumerable().Select(x => x.Value).ToList(); } } /// /// Initializes a new instance of the class, lazily /// instantiating the and /// collections on demand /// /// The timestamp for this slice of data /// The raw data in this slice public Slice(DateTime time, IEnumerable data) : this(time, data, null, null, null, null, null, null, null, null, null) { } /// /// Initializes a new instance of the class /// /// The timestamp for this slice of data /// The raw data in this slice /// The trade bars for this slice /// The quote bars for this slice /// This ticks for this slice /// The option chains for this slice /// The futures chains for this slice /// The splits for this slice /// The dividends for this slice /// The delistings for this slice /// The symbol changed events for this slice /// true if this slice contains data public Slice(DateTime time, IEnumerable data, TradeBars tradeBars, QuoteBars quoteBars, Ticks ticks, OptionChains optionChains, FuturesChains futuresChains, Splits splits, Dividends dividends, Delistings delistings, SymbolChangedEvents symbolChanges, bool? hasData = null) { Time = time; _dataByType = new Dictionary>(); // market data _data = new Lazy>(() => CreateDynamicDataDictionary(data)); HasData = hasData ?? _data.Value.Count > 0; _ticks = CreateTicksCollection(ticks); _bars = CreateCollection(tradeBars); _quoteBars = CreateCollection(quoteBars); _optionChains = CreateCollection(optionChains); _futuresChains = CreateCollection(futuresChains); // auxiliary data _splits = CreateCollection(splits); _dividends = CreateCollection(dividends); _delistings = CreateCollection(delistings); _symbolChangedEvents = CreateCollection(symbolChanges); } /// /// Gets the data corresponding to the specified symbol. If the requested data /// is of , then a will /// be returned, otherwise, it will be the subscribed type, for example, /// or event for custom data. /// /// The data's symbols /// The data for the specified symbol public dynamic this[Symbol symbol] { get { SymbolData value; if (_data.Value.TryGetValue(symbol, out value)) { return value.GetData(); } throw new KeyNotFoundException(string.Format("'{0}' 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(\"{0}\")", symbol)); } } /// /// Gets the for all data of the specified type /// /// The type of data we want, for example, or , ect... /// The containing the data of the specified type public DataDictionary Get() where T : IBaseData { Lazy dictionary; if (!_dataByType.TryGetValue(typeof(T), out dictionary)) { if (typeof(T) == typeof(Tick)) { dictionary = new Lazy(() => new DataDictionary(_data.Value.Values.SelectMany(x => x.GetData()).OfType(), x => x.Symbol)); } else if (typeof(T) == typeof(TradeBar)) { dictionary = new Lazy(() => new DataDictionary( _data.Value.Values.Where(x => x.TradeBar != null).Select(x => x.TradeBar), x => x.Symbol)); } else if (typeof(T) == typeof(QuoteBar)) { dictionary = new Lazy(() => new DataDictionary( _data.Value.Values.Where(x => x.QuoteBar != null).Select(x => x.QuoteBar), x => x.Symbol)); } else { dictionary = new Lazy(() => new DataDictionary(_data.Value.Values.Select(x => x.GetData()).OfType(), x => x.Symbol)); } _dataByType[typeof(T)] = dictionary; } return (DataDictionary)dictionary.Value; } /// /// Gets the data of the specified symbol and type. /// /// The type of data we seek /// The specific symbol was seek /// The data for the requested symbol public T Get(Symbol symbol) where T : BaseData { return Get()[symbol]; } /// /// Determines whether this instance contains data for the specified symbol /// /// The symbol we seek data for /// True if this instance contains data for the symbol, false otherwise public bool ContainsKey(Symbol symbol) { return _data.Value.ContainsKey(symbol); } /// /// Gets the data associated with the specified symbol /// /// The symbol we want data for /// The data for the specifed symbol, or null if no data was found /// True if data was found, false otherwise public bool TryGetValue(Symbol symbol, out dynamic data) { data = null; SymbolData symbolData; if (_data.Value.TryGetValue(symbol, out symbolData)) { data = symbolData.GetData(); return data != null; } return false; } /// /// Produces the dynamic data dictionary from the input data /// private static DataDictionary CreateDynamicDataDictionary(IEnumerable data) { var allData = new DataDictionary(); foreach (var datum in data) { SymbolData symbolData; if (!allData.TryGetValue(datum.Symbol, out symbolData)) { symbolData = new SymbolData(datum.Symbol); allData[datum.Symbol] = symbolData; } switch (datum.DataType) { case MarketDataType.Base: symbolData.Type = SubscriptionType.Custom; symbolData.Custom = datum; break; case MarketDataType.TradeBar: symbolData.Type = SubscriptionType.TradeBar; symbolData.TradeBar = (TradeBar)datum; break; case MarketDataType.QuoteBar: symbolData.Type = SubscriptionType.QuoteBar; symbolData.QuoteBar = (QuoteBar)datum; break; case MarketDataType.Tick: symbolData.Type = SubscriptionType.Tick; symbolData.Ticks.Add((Tick)datum); break; case MarketDataType.Auxiliary: symbolData.AuxilliaryData.Add(datum); break; default: throw new ArgumentOutOfRangeException(); } } return allData; } /// /// Returns the input ticks if non-null, otherwise produces one fom the dynamic data dictionary /// private Ticks CreateTicksCollection(Ticks ticks) { if (ticks != null) return ticks; ticks = new Ticks(Time); foreach (var listTicks in _data.Value.Values.Select(x => x.GetData()).OfType>().Where(x => x.Count != 0)) { ticks[listTicks[0].Symbol] = listTicks; } return ticks; } /// /// Returns the input collection if onon-null, otherwise produces one from the dynamic data dictionary /// /// The data dictionary type /// The item type of the data dictionary /// The input collection, if non-null, returned immediately /// The data dictionary of containing all the data of that type in this slice private T CreateCollection(T collection) where T : DataDictionary, new() where TItem : BaseData { if (collection != null) return collection; collection = new T(); #pragma warning disable 618 // This assignment is left here until the Time property is removed. collection.Time = Time; #pragma warning restore 618 foreach (var item in _data.Value.Values.Select(x => x.GetData()).OfType()) { collection[item.Symbol] = item; } return collection; } /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can be used to iterate through the collection. /// /// 1 public IEnumerator> GetEnumerator() { return GetKeyValuePairEnumerable().GetEnumerator(); } /// /// Returns an enumerator that iterates through a collection. /// /// /// An object that can be used to iterate through the collection. /// /// 2 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } private IEnumerable> GetKeyValuePairEnumerable() { // this will not enumerate auxilliary data! foreach (var kvp in _data.Value) { var data = kvp.Value.GetData(); var dataPoints = data as IEnumerable; if (dataPoints != null) { foreach (var dataPoint in dataPoints) { yield return new KeyValuePair(kvp.Key, dataPoint); } } else if (data != null) { yield return new KeyValuePair(kvp.Key, data); } } } private enum SubscriptionType { TradeBar, QuoteBar, Tick, Custom }; private class SymbolData { public SubscriptionType Type; public readonly Symbol Symbol; // data public BaseData Custom; public TradeBar TradeBar; public QuoteBar QuoteBar; public readonly List Ticks; public readonly List AuxilliaryData; public SymbolData(Symbol symbol) { Symbol = symbol; Ticks = new List(); AuxilliaryData = new List(); } public dynamic GetData() { switch (Type) { case SubscriptionType.TradeBar: return TradeBar; case SubscriptionType.QuoteBar: return QuoteBar; case SubscriptionType.Tick: return Ticks; case SubscriptionType.Custom: return Custom; default: throw new ArgumentOutOfRangeException(); } } } } }