/*
* 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.Collections.Generic;
using QuantConnect.Securities.Cfd;
using QuantConnect.Securities.Forex;
using QuantConnect.Securities.Index;
using QuantConnect.Securities.Option;
using QuantConnect.Securities.Future;
using QuantConnect.Securities.Equity;
namespace QuantConnect.Securities
{
///
/// A helper class that will provide instances
///
/// The value of this class and its logic is performance.
/// This class allows for two different to share the same
/// data type cache through different instances of .
/// This is used to directly access custom data types through their underlying
public class SecurityCacheProvider
{
private readonly Dictionary> _relatedSymbols;
private readonly ISecurityProvider _securityProvider;
///
/// Creates a new instance
///
/// The security provider to use
public SecurityCacheProvider(ISecurityProvider securityProvider)
{
_securityProvider = securityProvider;
_relatedSymbols = new ();
}
///
/// Will return the instance to use for a give Symbol.
/// If the provided Symbol is a custom type which has an underlying we will try to use the
/// underlying SecurityCache type cache, if the underlying is not present we will keep track
/// of the custom Symbol in case it is added later.
///
/// The cache instance to use
public SecurityCache GetSecurityCache(Symbol symbol)
{
SecurityCache securityCache;
switch (symbol.SecurityType)
{
case SecurityType.Equity:
securityCache = new EquityCache();
break;
case SecurityType.Option:
securityCache = new OptionCache();
break;
case SecurityType.Forex:
securityCache = new ForexCache();
break;
case SecurityType.Future:
securityCache = new FutureCache();
break;
case SecurityType.Cfd:
securityCache = new CfdCache();
break;
case SecurityType.Index:
securityCache = new IndexCache();
break;
default:
securityCache = new SecurityCache();
break;
}
// lock just in case but we do not expect this class be used by multiple consumers
lock (_relatedSymbols)
{
if (symbol.SecurityType == SecurityType.Base && symbol.HasUnderlying)
{
var underlyingSecurity = _securityProvider.GetSecurity(symbol.Underlying);
if (underlyingSecurity != null)
{
// we found the underlying, lets use its data type cache
SecurityCache.ShareTypeCacheInstance(underlyingSecurity.Cache, securityCache);
}
else
{
// we didn't find the underlying, lets keep track of the underlying symbol which might get added in the future.
// else when it is added, we would have to go through existing Securities and find any which use it as underlying
if (!_relatedSymbols.TryGetValue(symbol.Underlying, out var relatedSymbols))
{
_relatedSymbols[symbol.Underlying] = relatedSymbols = new List();
}
relatedSymbols.Add(symbol);
}
}
else
{
if (_relatedSymbols.Remove(symbol, out var customSymbols))
{
// if we are here it means we added a symbol which is an underlying of some existing custom symbols
foreach (var customSymbol in customSymbols)
{
var customSecurity = _securityProvider.GetSecurity(customSymbol);
if (customSecurity != null)
{
// we make each existing custom security cache, use the new instance data type cache
// note that if any data already existed in the custom cache it will be passed
SecurityCache.ShareTypeCacheInstance(securityCache, customSecurity.Cache);
}
}
}
}
}
return securityCache;
}
}
}