/* * 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.IO; using System.Linq; using QuantConnect.Util; using QuantConnect.Logging; using QuantConnect.Interfaces; using QuantConnect.Configuration; using System.Collections.Generic; using QuantConnect.Data.Auxiliary; namespace QuantConnect.Securities { /// /// Resolves standardized security definitions such as FIGI, CUSIP, ISIN, SEDOL into /// a properly mapped Lean , and vice-versa. /// public class SecurityDefinitionSymbolResolver { private static SecurityDefinitionSymbolResolver _securityDefinitionSymbolResolver; private static readonly object _lock = new object(); private List _securityDefinitions; private readonly IMapFileProvider _mapFileProvider; private readonly string _securitiesDefinitionKey; private readonly IDataProvider _dataProvider; /// /// Creates an instance of the symbol resolver /// /// Data provider used to obtain symbol mappings data /// Location to read the securities definition data from private SecurityDefinitionSymbolResolver(IDataProvider dataProvider = null, string securitiesDefinitionKey = null) { _securitiesDefinitionKey = securitiesDefinitionKey ?? Path.Combine(Globals.GetDataFolderPath("symbol-properties"), "security-database.csv"); _dataProvider = dataProvider ?? Composer.Instance.GetPart(); _mapFileProvider = Composer.Instance.GetPart(); _mapFileProvider.Initialize(_dataProvider); } /// /// Converts CUSIP into a Lean /// /// /// The Committee on Uniform Securities Identification Procedures (CUSIP) number of a security /// /// /// The date that the stock was trading at with the CUSIP provided. This is used /// to get the ticker of the symbol on this date. /// /// The Lean Symbol corresponding to the CUSIP number on the trading date provided public Symbol CUSIP(string cusip, DateTime tradingDate) { if (string.IsNullOrWhiteSpace(cusip)) { return null; } return SecurityDefinitionToSymbol( GetSecurityDefinitions().FirstOrDefault(x => x.CUSIP != null && x.CUSIP.Equals(cusip, StringComparison.InvariantCultureIgnoreCase)), tradingDate); } /// /// Converts a Lean to its CUSIP number /// /// The Lean /// The Committee on Uniform Securities Identification Procedures (CUSIP) number corresponding to the given Lean public string CUSIP(Symbol symbol) { return SymbolToSecurityDefinition(symbol)?.CUSIP; } /// /// Converts an asset's composite FIGI into a Lean /// /// /// The composite Financial Instrument Global Identifier (FIGI) of a security /// /// /// The date that the stock was trading at with the composite FIGI provided. This is used /// to get the ticker of the symbol on this date. /// /// The Lean Symbol corresponding to the composite FIGI on the trading date provided public Symbol CompositeFIGI(string compositeFigi, DateTime tradingDate) { if (string.IsNullOrWhiteSpace(compositeFigi)) { return null; } return SecurityDefinitionToSymbol( GetSecurityDefinitions().FirstOrDefault(x => x.CompositeFIGI != null && x.CompositeFIGI.Equals(compositeFigi, StringComparison.InvariantCultureIgnoreCase)), tradingDate); } /// /// Converts a Lean to its composite FIGI representation /// /// The Lean /// The composite Financial Instrument Global Identifier (FIGI) corresponding to the given Lean public string CompositeFIGI(Symbol symbol) { return SymbolToSecurityDefinition(symbol)?.CompositeFIGI; } /// /// Converts SEDOL into a Lean /// /// /// The Stock Exchange Daily Official List (SEDOL) security identifier of a security /// /// /// The date that the stock was trading at with the SEDOL provided. This is used /// to get the ticker of the symbol on this date. /// /// The Lean Symbol corresponding to the SEDOL on the trading date provided public Symbol SEDOL(string sedol, DateTime tradingDate) { if (string.IsNullOrWhiteSpace(sedol)) { return null; } return SecurityDefinitionToSymbol( GetSecurityDefinitions().FirstOrDefault(x => x.SEDOL != null && x.SEDOL.Equals(sedol, StringComparison.InvariantCultureIgnoreCase)), tradingDate); } /// /// Converts a Lean to its SEDOL representation /// /// The Lean /// The Stock Exchange Daily Official List (SEDOL) security identifier corresponding to the given Lean public string SEDOL(Symbol symbol) { return SymbolToSecurityDefinition(symbol)?.SEDOL; } /// /// Converts ISIN into a Lean /// /// /// The International Securities Identification Number (ISIN) of a security /// /// /// The date that the stock was trading at with the ISIN provided. This is used /// to get the ticker of the symbol on this date. /// /// The Lean Symbol corresponding to the ISIN on the trading date provided public Symbol ISIN(string isin, DateTime tradingDate) { if (string.IsNullOrWhiteSpace(isin)) { return null; } return SecurityDefinitionToSymbol( GetSecurityDefinitions().FirstOrDefault(x => x.ISIN != null && x.ISIN.Equals(isin, StringComparison.InvariantCultureIgnoreCase)), tradingDate); } /// /// Converts a Lean to its ISIN representation /// /// The Lean /// The International Securities Identification Number (ISIN) corresponding to the given Lean public string ISIN(Symbol symbol) { return SymbolToSecurityDefinition(symbol)?.ISIN; } /// /// Get's the CIK value associated with the given /// /// The Lean /// The Central Index Key number (CIK) corresponding to the given Lean if any, else null public int? CIK(Symbol symbol) { return SymbolToSecurityDefinition(symbol)?.CIK; } /// /// Converts CIK into a Lean array /// /// /// The Central Index Key (CIK) of a company /// /// /// The date that the stock was trading at with the CIK provided. This is used /// to get the ticker of the symbol on this date. /// /// The Lean Symbols corresponding to the CIK on the trading date provided public Symbol[] CIK(int cik, DateTime tradingDate) { if (cik == 0) { return Array.Empty(); } return GetSecurityDefinitions() .Where(x => x.CIK != null && x.CIK == cik) .Select(securityDefinition => SecurityDefinitionToSymbol(securityDefinition, tradingDate)) .Where(x => x != null) .ToArray(); } /// /// Converts a SecurityDefinition to a /// /// Security definition /// /// The date that the stock was being traded. This is used to resolve /// the ticker that the stock was trading under on this date. /// /// Symbol if matching Lean Symbol was found on the trading date, null otherwise private Symbol SecurityDefinitionToSymbol(SecurityDefinition securityDefinition, DateTime tradingDate) { if (securityDefinition == null) { return null; } var mapFileResolver = _mapFileProvider.Get(AuxiliaryDataKey.Create(securityDefinition.SecurityIdentifier)); // Get the first ticker the symbol traded under, and then lookup the // trading date to get the ticker on the trading date. var mapFile = mapFileResolver .ResolveMapFile(securityDefinition.SecurityIdentifier.Symbol, securityDefinition.SecurityIdentifier.Date); // The mapped ticker will be null if the map file is null or there's // no entry found for the given trading date. var mappedTicker = mapFile?.GetMappedSymbol(tradingDate, null); // If we're null, then try again; get the last entry of the map file and use // it as the Symbol we return to the caller. mappedTicker ??= mapFile? .LastOrDefault()? .MappedSymbol; return string.IsNullOrWhiteSpace(mappedTicker) ? null : new Symbol(securityDefinition.SecurityIdentifier, mappedTicker); } /// /// Gets the SecurityDefinition corresponding to the given Lean /// private SecurityDefinition SymbolToSecurityDefinition(Symbol symbol) { if (symbol == null) { return null; } return GetSecurityDefinitions().FirstOrDefault(x => x.SecurityIdentifier.Equals(symbol.ID)); } /// /// Get's the security definitions using a lazy initialization /// private IEnumerable GetSecurityDefinitions() { lock (_lock) { if (_securityDefinitions == null && !SecurityDefinition.TryRead(_dataProvider, _securitiesDefinitionKey, out _securityDefinitions)) { _securityDefinitions = new List(); Log.Error($"SecurityDefinitionSymbolResolver(): No security definitions data loaded from file: {_securitiesDefinitionKey}"); } } return _securityDefinitions; } /// /// Gets the single instance of the symbol resolver /// /// Data provider used to obtain symbol mappings data /// Location to read the securities definition data from /// The single instance of the symbol resolver public static SecurityDefinitionSymbolResolver GetInstance(IDataProvider dataProvider = null, string securitiesDefinitionKey = null) { lock (_lock) { if (_securityDefinitionSymbolResolver == null) { _securityDefinitionSymbolResolver = new SecurityDefinitionSymbolResolver(dataProvider, securitiesDefinitionKey); } } return _securityDefinitionSymbolResolver; } /// /// Resets the security definition symbol resolver, forcing a reload when reused. /// Called in tests where multiple algorithms are run sequentially, /// and we need to guarantee that every test starts with the same environment. /// public static void Reset() { lock (_lock) { _securityDefinitionSymbolResolver = null; } } } }