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