Lean  $LEAN_TAG$
SecurityCacheProvider.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 
17 using System.Collections.Generic;
24 
26 {
27  /// <summary>
28  /// A helper class that will provide <see cref="SecurityCache"/> instances
29  /// </summary>
30  /// <remarks>The value of this class and its logic is performance.
31  /// This class allows for two different <see cref="Security"/> to share the same
32  /// data type cache through different instances of <see cref="SecurityCache"/>.
33  /// This is used to directly access custom data types through their underlying</remarks>
34  public class SecurityCacheProvider
35  {
36  private readonly Dictionary<Symbol, List<Symbol>> _relatedSymbols;
37  private readonly ISecurityProvider _securityProvider;
38 
39  /// <summary>
40  /// Creates a new instance
41  /// </summary>
42  /// <param name="securityProvider">The security provider to use</param>
43  public SecurityCacheProvider(ISecurityProvider securityProvider)
44  {
45  _securityProvider = securityProvider;
46  _relatedSymbols = new ();
47  }
48 
49  /// <summary>
50  /// Will return the <see cref="SecurityCache"/> instance to use for a give Symbol.
51  /// If the provided Symbol is a custom type which has an underlying we will try to use the
52  /// underlying SecurityCache type cache, if the underlying is not present we will keep track
53  /// of the custom Symbol in case it is added later.
54  /// </summary>
55  /// <returns>The cache instance to use</returns>
57  {
58  SecurityCache securityCache;
59  switch (symbol.SecurityType)
60  {
61  case SecurityType.Equity:
62  securityCache = new EquityCache();
63  break;
64  case SecurityType.Option:
65  securityCache = new OptionCache();
66  break;
67  case SecurityType.Forex:
68  securityCache = new ForexCache();
69  break;
70  case SecurityType.Future:
71  securityCache = new FutureCache();
72  break;
73  case SecurityType.Cfd:
74  securityCache = new CfdCache();
75  break;
76  case SecurityType.Index:
77  securityCache = new IndexCache();
78  break;
79  default:
80  securityCache = new SecurityCache();
81  break;
82  }
83 
84  // lock just in case but we do not expect this class be used by multiple consumers
85  lock (_relatedSymbols)
86  {
87  if (symbol.SecurityType == SecurityType.Base && symbol.HasUnderlying)
88  {
89  var underlyingSecurity = _securityProvider.GetSecurity(symbol.Underlying);
90  if (underlyingSecurity != null)
91  {
92  // we found the underlying, lets use its data type cache
93  SecurityCache.ShareTypeCacheInstance(underlyingSecurity.Cache, securityCache);
94  }
95  else
96  {
97  // we didn't find the underlying, lets keep track of the underlying symbol which might get added in the future.
98  // else when it is added, we would have to go through existing Securities and find any which use it as underlying
99  if (!_relatedSymbols.TryGetValue(symbol.Underlying, out var relatedSymbols))
100  {
101  _relatedSymbols[symbol.Underlying] = relatedSymbols = new List<Symbol>();
102  }
103  relatedSymbols.Add(symbol);
104  }
105  }
106  else
107  {
108  if (_relatedSymbols.Remove(symbol, out var customSymbols))
109  {
110  // if we are here it means we added a symbol which is an underlying of some existing custom symbols
111  foreach (var customSymbol in customSymbols)
112  {
113  var customSecurity = _securityProvider.GetSecurity(customSymbol);
114  if (customSecurity != null)
115  {
116  // we make each existing custom security cache, use the new instance data type cache
117  // note that if any data already existed in the custom cache it will be passed
118  SecurityCache.ShareTypeCacheInstance(securityCache, customSecurity.Cache);
119  }
120  }
121  }
122  }
123  }
124 
125  return securityCache;
126  }
127  }
128 }