Lean  $LEAN_TAG$
SecurityService.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;
18 using System.Linq;
19 using QuantConnect.Util;
20 using QuantConnect.Data;
22 using System.Collections.Generic;
23 
25 {
26  /// <summary>
27  /// This class implements interface <see cref="ISecurityService"/> providing methods for creating new <see cref="Security"/>
28  /// </summary>
30  {
31  private readonly CashBook _cashBook;
32  private readonly MarketHoursDatabase _marketHoursDatabase;
33  private readonly SymbolPropertiesDatabase _symbolPropertiesDatabase;
34  private readonly IRegisteredSecurityDataTypesProvider _registeredTypes;
35  private readonly ISecurityInitializerProvider _securityInitializerProvider;
36  private readonly SecurityCacheProvider _cacheProvider;
37  private readonly IPrimaryExchangeProvider _primaryExchangeProvider;
38  private readonly IAlgorithm _algorithm;
39  private bool _isLiveMode;
40  private bool _modelsMismatchWarningSent;
41 
42  /// <summary>
43  /// Creates a new instance of the SecurityService class
44  /// </summary>
45  public SecurityService(CashBook cashBook,
46  MarketHoursDatabase marketHoursDatabase,
47  SymbolPropertiesDatabase symbolPropertiesDatabase,
48  ISecurityInitializerProvider securityInitializerProvider,
50  SecurityCacheProvider cacheProvider,
51  IPrimaryExchangeProvider primaryExchangeProvider = null,
52  IAlgorithm algorithm = null)
53  {
54  _cashBook = cashBook;
55  _registeredTypes = registeredTypes;
56  _marketHoursDatabase = marketHoursDatabase;
57  _symbolPropertiesDatabase = symbolPropertiesDatabase;
58  _securityInitializerProvider = securityInitializerProvider;
59  _cacheProvider = cacheProvider;
60  _primaryExchangeProvider = primaryExchangeProvider;
61  _algorithm = algorithm;
62  }
63 
64  /// <summary>
65  /// Creates a new security
66  /// </summary>
67  /// <remarks>Following the obsoletion of Security.Subscriptions,
68  /// both overloads will be merged removing <see cref="SubscriptionDataConfig"/> arguments</remarks>
69  private Security CreateSecurity(Symbol symbol,
70  List<SubscriptionDataConfig> subscriptionDataConfigList,
71  decimal leverage,
72  bool addToSymbolCache,
73  Security underlying,
74  bool initializeSecurity)
75  {
76  var configList = new SubscriptionDataConfigList(symbol);
77  configList.AddRange(subscriptionDataConfigList);
78 
79  var dataTypes = Enumerable.Empty<Type>();
80  if(symbol.SecurityType == SecurityType.Base && SecurityIdentifier.TryGetCustomDataTypeInstance(symbol.ID.Symbol, out var type))
81  {
82  dataTypes = new[] { type };
83  }
84  var exchangeHours = _marketHoursDatabase.GetEntry(symbol, dataTypes).ExchangeHours;
85 
86  var defaultQuoteCurrency = _cashBook.AccountCurrency;
87  if (symbol.ID.SecurityType == SecurityType.Forex)
88  {
89  defaultQuoteCurrency = symbol.Value.Substring(3);
90  }
91 
92  if (symbol.ID.SecurityType == SecurityType.Crypto && !_symbolPropertiesDatabase.ContainsKey(symbol.ID.Market, symbol, symbol.ID.SecurityType))
93  {
94  throw new ArgumentException(Messages.SecurityService.SymbolNotFoundInSymbolPropertiesDatabase(symbol));
95  }
96 
97  // For Futures Options that don't have a SPDB entry, the futures entry will be used instead.
98  var symbolProperties = _symbolPropertiesDatabase.GetSymbolProperties(
99  symbol.ID.Market,
100  symbol,
101  symbol.SecurityType,
102  defaultQuoteCurrency);
103 
104  // add the symbol to our cache
105  if (addToSymbolCache)
106  {
107  SymbolCache.Set(symbol.Value, symbol);
108  }
109 
110  // verify the cash book is in a ready state
111  var quoteCurrency = symbolProperties.QuoteCurrency;
112  if (!_cashBook.TryGetValue(quoteCurrency, out var quoteCash))
113  {
114  // since we have none it's safe to say the conversion is zero
115  quoteCash = _cashBook.Add(quoteCurrency, 0, 0);
116  }
117 
118  Cash baseCash = null;
119  // we skip cfd because we don't need to add the base cash
120  if (symbol.SecurityType != SecurityType.Cfd && CurrencyPairUtil.TryDecomposeCurrencyPair(symbol, out var baseCurrencySymbol, out _))
121  {
122  if (!_cashBook.TryGetValue(baseCurrencySymbol, out baseCash))
123  {
124  // since we have none it's safe to say the conversion is zero
125  baseCash = _cashBook.Add(baseCurrencySymbol, 0, 0);
126  }
127  }
128 
129  var cache = _cacheProvider.GetSecurityCache(symbol);
130 
131  Security security;
132  switch (symbol.ID.SecurityType)
133  {
134  case SecurityType.Equity:
135  var primaryExchange =
136  _primaryExchangeProvider?.GetPrimaryExchange(symbol.ID) ??
137  Exchange.UNKNOWN;
138  security = new Equity.Equity(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook, _registeredTypes, cache, primaryExchange);
139  break;
140 
141  case SecurityType.Option:
142  if (addToSymbolCache) SymbolCache.Set(symbol.Underlying.Value, symbol.Underlying);
143  security = new Option.Option(symbol, exchangeHours, quoteCash, new Option.OptionSymbolProperties(symbolProperties), _cashBook, _registeredTypes, cache, underlying);
144  break;
145 
146  case SecurityType.IndexOption:
147  if (addToSymbolCache) SymbolCache.Set(symbol.Underlying.Value, symbol.Underlying);
148  security = new IndexOption.IndexOption(symbol, exchangeHours, quoteCash, new IndexOption.IndexOptionSymbolProperties(symbolProperties), _cashBook, _registeredTypes, cache, underlying);
149  break;
150 
151  case SecurityType.FutureOption:
152  if (addToSymbolCache) SymbolCache.Set(symbol.Underlying.Value, symbol.Underlying);
153  var optionSymbolProperties = new Option.OptionSymbolProperties(symbolProperties);
154 
155  // Future options exercised only gives us one contract back, rather than the
156  // 100x seen in equities.
157  optionSymbolProperties.SetContractUnitOfTrade(1);
158 
159  security = new FutureOption.FutureOption(symbol, exchangeHours, quoteCash, optionSymbolProperties, _cashBook, _registeredTypes, cache, underlying);
160  break;
161 
162  case SecurityType.Future:
163  security = new Future.Future(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook, _registeredTypes, cache, underlying);
164  break;
165 
166  case SecurityType.Forex:
167  security = new Forex.Forex(symbol, exchangeHours, quoteCash, baseCash, symbolProperties, _cashBook, _registeredTypes, cache);
168  break;
169 
170  case SecurityType.Cfd:
171  security = new Cfd.Cfd(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook, _registeredTypes, cache);
172  break;
173 
174  case SecurityType.Index:
175  security = new Index.Index(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook, _registeredTypes, cache);
176  break;
177 
178  case SecurityType.Crypto:
179  security = new Crypto.Crypto(symbol, exchangeHours, quoteCash, baseCash, symbolProperties, _cashBook, _registeredTypes, cache);
180  break;
181 
182  case SecurityType.CryptoFuture:
183  security = new CryptoFuture.CryptoFuture(symbol, exchangeHours, quoteCash, baseCash, symbolProperties, _cashBook, _registeredTypes, cache);
184  break;
185 
186  default:
187  case SecurityType.Base:
188  security = new Security(symbol, exchangeHours, quoteCash, symbolProperties, _cashBook, _registeredTypes, cache);
189  break;
190  }
191 
192  // if we're just creating this security and it only has an internal
193  // feed, mark it as non-tradable since the user didn't request this data
194  if (security.IsTradable)
195  {
196  security.IsTradable = !configList.IsInternalFeed;
197  }
198 
199  security.AddData(configList);
200 
201  // invoke the security initializer
202  if (initializeSecurity)
203  {
204  _securityInitializerProvider.SecurityInitializer.Initialize(security);
205  }
206 
207  CheckCanonicalSecurityModels(security);
208 
209  // if leverage was specified then apply to security after the initializer has run, parameters of this
210  // method take precedence over the intializer
211  if (leverage != Security.NullLeverage)
212  {
213  security.SetLeverage(leverage);
214  }
215 
216  var isNotNormalized = configList.DataNormalizationMode() == DataNormalizationMode.Raw;
217 
218  // In live mode and non normalized data, equity assumes specific price variation model
219  if ((_isLiveMode || isNotNormalized) && security.Type == SecurityType.Equity)
220  {
221  security.PriceVariationModel = new EquityPriceVariationModel();
222  }
223 
224  return security;
225  }
226 
227  /// <summary>
228  /// Creates a new security
229  /// </summary>
230  /// <remarks>Following the obsoletion of Security.Subscriptions,
231  /// both overloads will be merged removing <see cref="SubscriptionDataConfig"/> arguments</remarks>
233  List<SubscriptionDataConfig> subscriptionDataConfigList,
234  decimal leverage = 0,
235  bool addToSymbolCache = true,
236  Security underlying = null)
237  {
238  return CreateSecurity(symbol, subscriptionDataConfigList, leverage, addToSymbolCache, underlying, initializeSecurity: true);
239  }
240 
241  /// <summary>
242  /// Creates a new security
243  /// </summary>
244  /// <remarks>Following the obsoletion of Security.Subscriptions,
245  /// both overloads will be merged removing <see cref="SubscriptionDataConfig"/> arguments</remarks>
246  public Security CreateSecurity(Symbol symbol, SubscriptionDataConfig subscriptionDataConfig, decimal leverage = 0, bool addToSymbolCache = true, Security underlying = null)
247  {
248  return CreateSecurity(symbol, new List<SubscriptionDataConfig> { subscriptionDataConfig }, leverage, addToSymbolCache, underlying);
249  }
250 
251  /// <summary>
252  /// Creates a new security
253  /// </summary>
254  /// <remarks>Following the obsoletion of Security.Subscriptions,
255  /// both overloads will be merged removing <see cref="SubscriptionDataConfig"/> arguments</remarks>
257  {
258  return CreateSecurity(symbol,
259  new List<SubscriptionDataConfig>(),
260  leverage: 1,
261  addToSymbolCache: false,
262  underlying: null,
263  initializeSecurity: false);
264  }
265 
266  /// <summary>
267  /// Set live mode state of the algorithm
268  /// </summary>
269  /// <param name="isLiveMode">True, live mode is enabled</param>
270  public void SetLiveMode(bool isLiveMode)
271  {
272  _isLiveMode = isLiveMode;
273  }
274 
275  /// <summary>
276  /// Checks whether the created security has the same models as its canonical security (in case it has one)
277  /// and sends a one-time warning if it doesn't.
278  /// </summary>
279  private void CheckCanonicalSecurityModels(Security security)
280  {
281  if (!_modelsMismatchWarningSent &&
282  _algorithm != null &&
283  security.Symbol.HasCanonical() &&
284  _algorithm.Securities.TryGetValue(security.Symbol.Canonical, out var canonicalSecurity))
285  {
286  if (security.FillModel.GetType() != canonicalSecurity.FillModel.GetType() ||
287  security.FeeModel.GetType() != canonicalSecurity.FeeModel.GetType() ||
288  security.BuyingPowerModel.GetType() != canonicalSecurity.BuyingPowerModel.GetType() ||
289  security.MarginInterestRateModel.GetType() != canonicalSecurity.MarginInterestRateModel.GetType() ||
290  security.SlippageModel.GetType() != canonicalSecurity.SlippageModel.GetType() ||
291  security.VolatilityModel.GetType() != canonicalSecurity.VolatilityModel.GetType() ||
292  security.SettlementModel.GetType() != canonicalSecurity.SettlementModel.GetType())
293  {
294  _modelsMismatchWarningSent = true;
295  _algorithm.Debug($"Warning: Security {security.Symbol} its canonical security {security.Symbol.Canonical} have at least one model of different types (fill, fee, buying power, margin interest rate, slippage, volatility, settlement). To avoid this, consider using a security initializer to set the right models to each security type according to your algorithm's requirements.");
296  }
297  }
298  }
299  }
300 }