/* * 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.Concurrent; using QuantConnect.Data; using QuantConnect.Data.Market; namespace QuantConnect.Securities { /// /// Base class caching caching spot for security data and any other temporary properties. /// /// /// This class is virtually unused and will soon be made obsolete. /// This comment made in a remark to prevent obsolete errors in all users algorithms /// public class SecurityCache { // this is used to prefer quote bar data over the tradebar data private DateTime _lastQuoteBarUpdate; private BaseData _lastData; private readonly ConcurrentDictionary _dataByType = new ConcurrentDictionary(); /// /// Gets the most recent price submitted to this cache /// public decimal Price { get; private set; } /// /// Gets the most recent open submitted to this cache /// public decimal Open { get; private set; } /// /// Gets the most recent high submitted to this cache /// public decimal High { get; private set; } /// /// Gets the most recent low submitted to this cache /// public decimal Low { get; private set; } /// /// Gets the most recent close submitted to this cache /// public decimal Close { get; private set; } /// /// Gets the most recent bid submitted to this cache /// public decimal BidPrice { get; private set; } /// /// Gets the most recent ask submitted to this cache /// public decimal AskPrice { get; private set; } /// /// Gets the most recent bid size submitted to this cache /// public decimal BidSize { get; private set; } /// /// Gets the most recent ask size submitted to this cache /// public decimal AskSize { get; private set; } /// /// Gets the most recent volume submitted to this cache /// public decimal Volume { get; private set; } /// /// Gets the most recent open interest submitted to this cache /// public long OpenInterest { get; private set; } /// /// Add a new market data point to the local security cache for the current market price. /// Rules: /// Don't cache fill forward data. /// Always return the last observation. /// If two consecutive data has the same time stamp and one is Quotebars and the other Tradebar, prioritize the Quotebar. /// public void AddData(BaseData data) { var openInterest = data as OpenInterest; if (openInterest != null) { OpenInterest = (long)openInterest.Value; return; } var tick = data as Tick; if (tick?.TickType == TickType.OpenInterest) { OpenInterest = (long)tick.Value; return; } // Only cache non fill-forward data. if (data.IsFillForward) return; // Always keep track of the last obesrvation _dataByType[data.GetType()] = data; // don't set _lastData if receive quotebar then tradebar w/ same end time. this // was implemented to grant preference towards using quote data in the fill // models and provide a level of determinism on the values exposed via the cache. if (_lastData == null || _lastQuoteBarUpdate != data.EndTime || data.DataType != MarketDataType.TradeBar ) { _lastData = data; } if (tick != null) { if (tick.Value != 0) Price = tick.Value; if (tick.TickType == TickType.Trade && tick.Quantity != 0) { Volume = tick.Quantity; } if (tick.TickType == TickType.Quote) { if (tick.BidPrice != 0) BidPrice = tick.BidPrice; if (tick.BidSize != 0) BidSize = tick.BidSize; if (tick.AskPrice != 0) AskPrice = tick.AskPrice; if (tick.AskSize != 0) AskSize = tick.AskSize; } return; } var bar = data as IBar; if (bar != null) { if (_lastQuoteBarUpdate != data.EndTime) { if (bar.Open != 0) Open = bar.Open; if (bar.High != 0) High = bar.High; if (bar.Low != 0) Low = bar.Low; if (bar.Close != 0) { Price = bar.Close; Close = bar.Close; } } var tradeBar = bar as TradeBar; if (tradeBar != null) { if (tradeBar.Volume != 0) Volume = tradeBar.Volume; } var quoteBar = bar as QuoteBar; if (quoteBar != null) { _lastQuoteBarUpdate = quoteBar.EndTime; if (quoteBar.Ask != null && quoteBar.Ask.Close != 0) AskPrice = quoteBar.Ask.Close; if (quoteBar.Bid != null && quoteBar.Bid.Close != 0) BidPrice = quoteBar.Bid.Close; if (quoteBar.LastBidSize != 0) BidSize = quoteBar.LastBidSize; if (quoteBar.LastAskSize != 0) AskSize = quoteBar.LastAskSize; } } else if (data.DataType != MarketDataType.Auxiliary) { Price = data.Price; } } /// /// Stores the specified data instance in the cache WITHOUT updating any of the cache properties, such as Price /// /// public void StoreData(BaseData data) { _dataByType[data.GetType()] = data; } /// /// Get last data packet recieved for this security /// /// BaseData type of the security public BaseData GetData() { return _lastData; } /// /// Get last data packet recieved for this security of the specified ty[e /// /// The data type /// The last data packet, null if none received of type public T GetData() where T : BaseData { BaseData data; _dataByType.TryGetValue(typeof(T), out data); return data as T; } /// /// Reset cache storage and free memory /// public void Reset() { _dataByType.Clear(); } } }