/*
* 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;
}
}
}
}