/* * 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.Linq; using QuantConnect.Securities; using System.Collections.Generic; namespace QuantConnect.Brokerages { /// /// Provides the mapping between Lean symbols and brokerage symbols using the symbol properties database /// public class SymbolPropertiesDatabaseSymbolMapper : ISymbolMapper { private readonly string _market; // map Lean symbols to symbol properties private readonly Dictionary _symbolPropertiesMap; // map brokerage symbols to Lean symbols we do it per security type because they could overlap, for example binance futures and spot private readonly Dictionary> _symbolMap; /// /// Creates a new instance of the class. /// /// The Lean market public SymbolPropertiesDatabaseSymbolMapper(string market) { _market = market; var symbolPropertiesList = SymbolPropertiesDatabase .FromDataFolder() .GetSymbolPropertiesList(_market) .Where(x => !string.IsNullOrWhiteSpace(x.Value.MarketTicker)) .ToList(); _symbolPropertiesMap = symbolPropertiesList .ToDictionary( x => Symbol.Create(x.Key.Symbol, x.Key.SecurityType, x.Key.Market), x => x.Value); _symbolMap = new(); foreach (var group in _symbolPropertiesMap.GroupBy(x => x.Key.SecurityType)) { _symbolMap[group.Key] = group.ToDictionary( x => x.Value.MarketTicker, x => x.Key); } } /// /// Converts a Lean symbol instance to a brokerage symbol /// /// A Lean symbol instance /// The brokerage symbol public string GetBrokerageSymbol(Symbol symbol) { if (symbol == null || string.IsNullOrWhiteSpace(symbol.Value)) { throw new ArgumentException($"Invalid symbol: {(symbol == null ? "null" : symbol.Value)}"); } if (symbol.ID.Market != _market) { throw new ArgumentException($"Invalid market: {symbol.ID.Market}"); } SymbolProperties symbolProperties; if (!_symbolPropertiesMap.TryGetValue(symbol, out symbolProperties) ) { throw new ArgumentException($"Unknown symbol: {symbol.Value}/{symbol.SecurityType}/{symbol.ID.Market}"); } if (string.IsNullOrWhiteSpace(symbolProperties.MarketTicker)) { throw new ArgumentException($"MarketTicker not found in database for symbol: {symbol.Value}"); } return symbolProperties.MarketTicker; } /// /// Converts a brokerage symbol to a Lean symbol instance /// /// The brokerage symbol /// The security type /// The market /// Expiration date of the security(if applicable) /// The strike of the security (if applicable) /// The option right of the security (if applicable) /// A new Lean Symbol instance public Symbol GetLeanSymbol(string brokerageSymbol, SecurityType securityType, string market, DateTime expirationDate = default(DateTime), decimal strike = 0, OptionRight optionRight = OptionRight.Call) { if (string.IsNullOrWhiteSpace(brokerageSymbol)) { throw new ArgumentException($"Invalid brokerage symbol: {brokerageSymbol}"); } if (market != _market) { throw new ArgumentException($"Invalid market: {market}"); } if (!_symbolMap.TryGetValue(securityType, out var symbols)) { throw new ArgumentException($"Unknown brokerage security type: {securityType}"); } if (!symbols.TryGetValue(brokerageSymbol, out var symbol)) { throw new ArgumentException($"Unknown brokerage symbol: {brokerageSymbol}"); } return symbol; } /// /// Checks if the Lean symbol is supported by the brokerage /// /// The Lean symbol /// True if the brokerage supports the symbol public bool IsKnownLeanSymbol(Symbol symbol) { return !string.IsNullOrWhiteSpace(symbol?.Value) && _symbolPropertiesMap.ContainsKey(symbol); } /// /// Returns the security type for a brokerage symbol /// /// The brokerage symbol /// The security type public SecurityType GetBrokerageSecurityType(string brokerageSymbol) { if (string.IsNullOrWhiteSpace(brokerageSymbol)) { throw new ArgumentException($"Invalid brokerage symbol: {brokerageSymbol}"); } var result = _symbolMap.Select(kvp => { kvp.Value.TryGetValue(brokerageSymbol, out var symbol); return symbol; }).Where(symbol => symbol != null).ToList(); if (result.Count == 0) { throw new ArgumentException($"Unknown brokerage symbol: {brokerageSymbol}"); } if (result.Count > 1) { throw new ArgumentException($"Found multiple brokerage symbols: {string.Join(",", result)}"); } return result[0].SecurityType; } /// /// Checks if the symbol is supported by the brokerage /// /// The brokerage symbol /// True if the brokerage supports the symbol public bool IsKnownBrokerageSymbol(string brokerageSymbol) { if (string.IsNullOrWhiteSpace(brokerageSymbol)) { return false; } return _symbolMap.Any(kvp => kvp.Value.ContainsKey(brokerageSymbol)); } } }