diff --git a/CryptoExchange.Net/ExchangeSymbolCache.cs b/CryptoExchange.Net/ExchangeSymbolCache.cs
index e3b0fc8b..59c75251 100644
--- a/CryptoExchange.Net/ExchangeSymbolCache.cs
+++ b/CryptoExchange.Net/ExchangeSymbolCache.cs
@@ -33,7 +33,7 @@ namespace CryptoExchange.Net
if (keyedCache != null && DateTime.UtcNow - keyedCache.UpdateTime < TimeSpan.FromMinutes(60))
return;
- exchangeInfo.Set(key, new ExchangeInfo(DateTime.UtcNow, updateData.ToDictionary(x => x.Name, x => x.SharedSymbol)));
+ exchangeInfo.Set(key, new ExchangeInfo(DateTime.UtcNow, updateData.ToDictionary(x => x.Name, x => x)));
}
///
@@ -118,6 +118,22 @@ namespace CryptoExchange.Net
return exchangeInfo.ParseSymbol(key, symbolName);
}
+ ///
+ /// Get a symbol catalog for a specific exchange(topic) and environment. Only available if has been called previously.
+ ///
+ /// Exchange name
+ /// Id for the provided data
+ /// Trade environment
+ /// Additional data set identification key
+ public static SharedSymbolCatalog? GetSymbolCatalog(string exchange, string topicId, string environmentName, string? key)
+ {
+ var id = topicId + environmentName;
+ if (!_symbolInfos.TryGetValue(id, out var exchangeInfo))
+ return null;
+
+ return exchangeInfo.GetSymbolCatalog(exchange, key);
+ }
+
class ExchangeKeyedCache
{
private ExchangeInfo? _noKeyCache;
@@ -163,7 +179,7 @@ namespace CryptoExchange.Net
public SharedSymbol? ParseSymbol(string? key, string symbolName)
{
- SharedSymbol? symbolInfo = null;
+ SharedSpotSymbol? symbolInfo = null;
if (key == null)
{
if (_noKeyCache != null)
@@ -173,7 +189,7 @@ namespace CryptoExchange.Net
return new SharedSymbol(symbolInfo.TradingMode, symbolInfo.BaseAsset, symbolInfo.QuoteAsset, symbolName)
{
- DeliverTime = symbolInfo.DeliverTime
+ DeliverTime = (symbolInfo as SharedFuturesSymbol)?.DeliveryTime
};
}
@@ -183,7 +199,7 @@ namespace CryptoExchange.Net
{
return new SharedSymbol(symbolInfo.TradingMode, symbolInfo.BaseAsset, symbolInfo.QuoteAsset, symbolName)
{
- DeliverTime = symbolInfo.DeliverTime
+ DeliverTime = (symbolInfo as SharedFuturesSymbol)?.DeliveryTime
};
}
}
@@ -199,7 +215,7 @@ namespace CryptoExchange.Net
{
return new SharedSymbol(symbolInfo.TradingMode, symbolInfo.BaseAsset, symbolInfo.QuoteAsset, symbolName)
{
- DeliverTime = symbolInfo.DeliverTime
+ DeliverTime = (symbolInfo as SharedFuturesSymbol)?.DeliveryTime
};
}
@@ -265,7 +281,7 @@ namespace CryptoExchange.Net
{
return _noKeyCache.Symbols
.Where(x => x.Value.BaseAsset.Equals(baseAsset, StringComparison.InvariantCultureIgnoreCase))
- .Select(x => x.Value)
+ .Select(x => x.Value.SharedSymbol)
.ToArray();
}
@@ -274,7 +290,7 @@ namespace CryptoExchange.Net
{
result.AddRange(cache.Symbols
.Where(x => x.Value.BaseAsset.Equals(baseAsset, StringComparison.InvariantCultureIgnoreCase))
- .Select(x => x.Value));
+ .Select(x => x.Value.SharedSymbol));
}
return result.ToArray();
@@ -286,18 +302,63 @@ namespace CryptoExchange.Net
return exchangeInfo.Symbols
.Where(x => x.Value.BaseAsset.Equals(baseAsset, StringComparison.InvariantCultureIgnoreCase))
- .Select(x => x.Value)
+ .Select(x => x.Value.SharedSymbol)
.ToArray();
}
+
+ internal SharedSymbolCatalog? GetSymbolCatalog(string exchange, string? key)
+ {
+ IEnumerable cachedSymbols;
+ if (key == null)
+ {
+ if (_noKeyCache != null)
+ cachedSymbols = _noKeyCache.Symbols.Values;
+ else
+ cachedSymbols = _keyedCache.Values.SelectMany(x => x.Symbols.Values);
+ }
+ else
+ {
+ if (!_keyedCache.TryGetValue(key, out var exchangeInfo) || exchangeInfo == null)
+ return null;
+
+ cachedSymbols = exchangeInfo.Symbols.Values;
+ }
+
+ var assets = new Dictionary();
+ var symbols = new Dictionary();
+ foreach (var symbol in cachedSymbols)
+ {
+ if (!assets.TryGetValue(symbol.BaseAsset, out var baseAssetInfo))
+ {
+ baseAssetInfo = new SharedAssetInfo(symbol.BaseAsset, symbol.BaseAssetType, symbol.BaseAssetSubType);
+ assets.Add(symbol.BaseAsset, baseAssetInfo);
+ }
+
+ if (!assets.TryGetValue(symbol.QuoteAsset, out var quoteAssetInfo))
+ {
+ quoteAssetInfo = new SharedAssetInfo(symbol.QuoteAsset, symbol.QuoteAssetType, symbol.QuoteAssetSubType);
+ assets.Add(symbol.QuoteAsset, quoteAssetInfo);
+ }
+
+ symbols.Add(symbol.Name, symbol);
+ }
+
+ return new SharedSymbolCatalog
+ {
+ Exchange = exchange,
+ Assets = assets,
+ Symbols = symbols
+ };
+ }
}
class ExchangeInfo
{
public DateTime UpdateTime { get; set; }
- public Dictionary Symbols { get; set; }
+ public Dictionary Symbols { get; set; }
- public ExchangeInfo(DateTime updateTime, Dictionary symbols)
+ public ExchangeInfo(DateTime updateTime, Dictionary symbols)
{
UpdateTime = updateTime;
Symbols = symbols;
diff --git a/CryptoExchange.Net/LibraryHelpers.cs b/CryptoExchange.Net/LibraryHelpers.cs
index 63e6e8e8..4c0f66f4 100644
--- a/CryptoExchange.Net/LibraryHelpers.cs
+++ b/CryptoExchange.Net/LibraryHelpers.cs
@@ -4,6 +4,8 @@ using CryptoExchange.Net.Objects.Options;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
+using System.IO.Pipelines;
+using System.Linq;
using System.Net;
using System.Net.Http;
@@ -14,6 +16,61 @@ namespace CryptoExchange.Net
///
public static class LibraryHelpers
{
+ private static readonly HashSet _stableCoins = new HashSet(StringComparer.OrdinalIgnoreCase)
+ {
+ // USD
+ "USDT", "USDC", "DAI", "FDUSD", "USDE", "TUSD", "USDP", "PYUSD", "GUSD",
+ "USDD", "LUSD", "USDJ", "SUSD", "ZUSD", "BUSD", "USTC", "USDX", "USDK",
+ "CUSD", "USD1", "USD0", "XUSD", "BFUSD", "USDS", "RLUSD", "OUSD", "USDH",
+ "APXUSD", "USDQ", "USDPT", "FIDD", "AUSD",
+ // EUR
+ "EURS", "EURC", "EURI", "EURT", "AGEUR", "CEUR", "AEUR", "EURQ", "EUROP",
+ // Other
+ "CNYT", // CNY
+ "CREAL", "BRL1", // BRL
+ "XSGD", // SGD
+ "GYEN", // JPY
+ "KGST", // KGS
+ "QCAD", // CAD
+ "TGBP", // GBP
+ "AUDX", // AUD
+ "MXNB", // MXN
+ };
+
+ private static readonly HashSet _commodities = new HashSet(StringComparer.OrdinalIgnoreCase)
+ {
+ // Metals
+ "XAU", "XAUT", "XAG", "XPT", "XPD", "COPPER", "PAXG", "XNI", "XCU", "XAL", "GOLD", "SILVER",
+ // Energy
+ "BZ", "NATGAS", "NGAS", "CL", "XTI", "UKOIL", "USOIL", "BRENTOIL"
+ };
+
+ private static readonly HashSet _stocks = new HashSet(StringComparer.OrdinalIgnoreCase)
+ {
+ // Top stocks, will need to update periodically
+ "AAAU", "AADR", "AAPL", "ACWI", "ACWX", "AGG", "AMD", "AMLP", "AMZN", "ARKF",
+ "ARKG", "ARKK", "ARKQ", "ARKW", "AVGO", "BA", "BABA", "BND", "BNDX", "BOTZ",
+ "CIBR", "COIN", "DIA", "DIVB", "DVY", "EEM", "EFA", "EFAV", "ESGU", "EWG",
+ "EWJ", "EWT", "EWU", "EWW", "EWY", "EWZ", "FDN", "FEZ", "GLDM", "GOOGL",
+ "HDV", "HOOD", "HYG", "IAU", "IBB", "ICLN", "IEFA", "IEMG", "IGSB", "IJH",
+ "IJR", "INTC", "ITOT", "IUSB", "IUSG", "IUSV", "IWM", "IWO", "IWR", "IYR",
+ "JETS", "JPM", "LIT", "MCHI", "META", "MGK", "MSTR", "MTUM", "MU", "NET",
+ "NFLX", "NOBL", "NVDA", "OIH", "ORCL", "PAVE", "PBW", "PLTR", "QQQ", "QQQM",
+ "SCHB", "SCHD", "SCHF", "SCHG", "SCHH", "SCHV", "SCHX", "SKHY", "SPCX", "SPCXD",
+ "SPLG", "SPY", "SPYG", "SPYV", "SQQQ", "TSLA", "TSM", "TQQQ", "USMV", "VBR",
+ "VCIT", "VCSH", "VEA", "VEU", "VGIT", "VGK", "VGT", "VHT", "VIG", "VNQ",
+ "VOO", "VOT", "VTI", "VTV", "VUG", "VXUS", "XBI", "XLC", "XLE", "XLF",
+ "XLI", "XLK", "XLP", "XLU", "XLV", "XLY", "CSCO", "UBER", "MRVL", "RKLB",
+ "COHR", "SOXL", "HD", "DIS", "CBRS", "V", "BRKB", "FLNC", "LLY", "COST",
+ "ARM", "BMNR", "NBIS", "ASML", "AAOI", "GLW", "SHLD", "BE", "QNTX", "IBM",
+ "AMAT", "NOK", "ASTS", "BBX", "SLX", "SKHYNIX", "SAMSUNG", "HYUNDAI", "NVO",
+ "IREN", "ONDS", "CRM" , "VRT", "ZEST", "BTW", "HPE", "AXTI", "BX", "CRWD",
+ "CRDO", "NOW", "ZM", "DKNG", "RIVN", "URNM", "EBAY", "ADBE", "UVXY", "RDW",
+ "CIEN","PANW", "WIN", "PAYP", "HIMS", "CRWV", "QCOM", "LITE", "DRAM", "ANTHROPIC",
+ "OPENAI", "USAR", "BILL", "SNDK", "NASDAQ100", "SPX500", "BSB", "CRCL", "STRC",
+ "MSFT", "WDC"
+ };
+
private static ILogger? _staticLogger;
///
/// Static logger
@@ -105,6 +162,67 @@ namespace CryptoExchange.Net
return _defaultClientReferences.TryGetValue(key, out var id) ? id : throw new KeyNotFoundException($"{exchange} not found in configuration");
}
+ ///
+ /// Check whether an asset is a known stablecoin. Note that this is not definitive, only large known stocks are checked
+ ///
+ /// Asset name
+ /// Additional stablecoin names for the specific exchange
+ public static bool IsStableCoin(string asset, params HashSet additionalStableCoins)
+ {
+ if (string.IsNullOrEmpty(asset))
+ return false;
+
+ return _stableCoins.Contains(asset) || (additionalStableCoins != null && additionalStableCoins.Contains(asset, StringComparer.OrdinalIgnoreCase));
+ }
+
+ ///
+ /// Check whether an asset is a known commodity. Note that this is not definitive, only large known stocks are checked
+ ///
+ /// Asset name
+ /// Additional commodity names for the specific exchange
+ public static bool IsCommodity(string asset, params HashSet additionalCommodities)
+ {
+ if (string.IsNullOrEmpty(asset))
+ return false;
+
+ return _commodities.Contains(asset) || (additionalCommodities != null && additionalCommodities.Contains(asset, StringComparer.OrdinalIgnoreCase));
+ }
+
+ ///
+ /// Check whether an asset is a known stock. Note that this is not definitive, only large known stocks are checked
+ ///
+ /// Asset name
+ /// Additional stock names for the specific exchange
+ public static bool IsEquity(string asset, params HashSet additionalStocks)
+ => IsEquity(asset, [], additionalStocks);
+
+ ///
+ /// Check whether an asset is a known stock.
+ ///
+ /// Asset name
+ /// Suffixes to check, for example when `X` is a potential suffix both `TSLA` and `TSLAX` will be checked
+ /// Additional stock names for the specific exchange
+ public static bool IsEquity(string asset, string[] potentialSuffixes, params HashSet additionalStocks)
+ {
+ if (string.IsNullOrEmpty(asset))
+ return false;
+
+ if (_stocks.Contains(asset) || (additionalStocks != null && additionalStocks.Contains(asset, StringComparer.OrdinalIgnoreCase)))
+ return true;
+
+ foreach (var suffix in potentialSuffixes)
+ {
+ if (!asset.EndsWith(suffix))
+ continue;
+
+ var suffixAsset = asset.Substring(0, asset.Length - suffix.Length);
+ if (_stocks.Contains(suffixAsset) || (additionalStocks != null && additionalStocks.Contains(suffixAsset, StringComparer.OrdinalIgnoreCase)))
+ return true;
+ }
+
+ return false;
+ }
+
///
/// Create a new HttpMessageHandler instance
///
diff --git a/CryptoExchange.Net/SharedApis/Enums/SharedAssetType.cs b/CryptoExchange.Net/SharedApis/Enums/SharedAssetType.cs
new file mode 100644
index 00000000..ce07bd5d
--- /dev/null
+++ b/CryptoExchange.Net/SharedApis/Enums/SharedAssetType.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace CryptoExchange.Net.SharedApis
+{
+ ///
+ /// Asset type
+ ///
+ public enum SharedAssetType
+ {
+ ///
+ /// Unknown or unspecified asset type
+ ///
+ Unspecified,
+ ///
+ /// Cryptocurrency asset type
+ ///
+ Crypto,
+ ///
+ /// Fiat currency asset type
+ ///
+ Fiat,
+ ///
+ /// Traditional finance asset type
+ ///
+ TradFi
+ }
+
+ ///
+ /// Asset sub type
+ ///
+ public enum SharedAssetSubType
+ {
+ // --- Crypto sub types ---
+ ///
+ /// Stable coin, can be for different fiat currencies
+ ///
+ StableCoin,
+
+ // --- TradFi sub types ---
+ ///
+ /// Equity, can be stocks, ETFs, or indices
+ ///
+ Equity,
+ ///
+ /// Commodity, can be oil, gas, metals, etc.
+ ///
+ Commodity
+ }
+}
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFuturesSymbolRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFuturesSymbolRestClient.cs
index 761c2dcb..7329596d 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFuturesSymbolRestClient.cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFuturesSymbolRestClient.cs
@@ -9,6 +9,11 @@ namespace CryptoExchange.Net.SharedApis
///
public interface IFuturesSymbolRestClient : ISharedClient
{
+ ///
+ /// Get the futures symbol catalog. Only available if has been called previously.
+ ///
+ SharedSymbolCatalog? FuturesSymbolCatalog { get; }
+
///
/// Futures symbol request options.
/// Use and to check for required and optional parameters for the request.
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotSymbolRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotSymbolRestClient.cs
index 30d00092..64e16d02 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotSymbolRestClient.cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotSymbolRestClient.cs
@@ -9,6 +9,11 @@ namespace CryptoExchange.Net.SharedApis
///
public interface ISpotSymbolRestClient : ISharedClient
{
+ ///
+ /// Get the spot symbol catalog. Only available if has been called previously.
+ ///
+ SharedSymbolCatalog? SpotSymbolCatalog { get; }
+
///
/// Spot symbols request options.
/// Use and to check for required and optional parameters for the request.
diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetFuturesSymbolsOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetFuturesSymbolsOptions.cs
index 8663b466..ab2b92a3 100644
--- a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetFuturesSymbolsOptions.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetFuturesSymbolsOptions.cs
@@ -1,4 +1,5 @@
-using System;
+using CryptoExchange.Net.Objects;
+using System;
using System.Collections.Generic;
using System.Text;
@@ -15,5 +16,43 @@ namespace CryptoExchange.Net.SharedApis
public GetFuturesSymbolsOptions(string exchange, bool authenticated) : base(exchange, authenticated, nameof(IFuturesSymbolRestClient.GetFuturesSymbolsAsync))
{
}
+
+ ///
+ public override Error? ValidateRequest(GetSymbolsRequest request, IFuturesSymbolRestClient client)
+ {
+ if (request.BaseAssetType != null && request.BaseAssetSubType != null)
+ {
+ var error = ValidateAssetTypeCombination(request.BaseAssetType.Value, request.BaseAssetSubType.Value);
+ if (error != null)
+ return error;
+ }
+
+ if (request.QuoteAssetType != null && request.QuoteAssetSubType != null)
+ {
+ var error = ValidateAssetTypeCombination(request.QuoteAssetType.Value, request.QuoteAssetSubType.Value);
+ if (error != null)
+ return error;
+ }
+
+ return base.ValidateRequest(request, client);
+ }
+
+ private Error? ValidateAssetTypeCombination(SharedAssetType type, SharedAssetSubType subType)
+ {
+ if (type == SharedAssetType.Crypto
+ && (subType == SharedAssetSubType.Commodity
+ || (subType == SharedAssetSubType.Equity)))
+ {
+ return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
+ }
+
+ if (type == SharedAssetType.TradFi && subType == SharedAssetSubType.StableCoin)
+ return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
+
+ if (type == SharedAssetType.Fiat)
+ return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
+
+ return null;
+ }
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetSpotSymbolsOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetSpotSymbolsOptions.cs
index ac25a78c..db7f463b 100644
--- a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetSpotSymbolsOptions.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetSpotSymbolsOptions.cs
@@ -1,4 +1,5 @@
-using System;
+using CryptoExchange.Net.Objects;
+using System;
using System.Collections.Generic;
using System.Text;
@@ -15,5 +16,44 @@ namespace CryptoExchange.Net.SharedApis
public GetSpotSymbolsOptions(string exchange, bool authenticated) : base(exchange, authenticated, nameof(ISpotSymbolRestClient.GetSpotSymbolsAsync))
{
}
+
+
+ ///
+ public override Error? ValidateRequest(GetSymbolsRequest request, ISpotSymbolRestClient client)
+ {
+ if (request.BaseAssetType != null && request.BaseAssetSubType != null)
+ {
+ var error = ValidateAssetTypeCombination(request.BaseAssetType.Value, request.BaseAssetSubType.Value);
+ if (error != null)
+ return error;
+ }
+
+ if (request.QuoteAssetType != null && request.QuoteAssetSubType != null)
+ {
+ var error = ValidateAssetTypeCombination(request.QuoteAssetType.Value, request.QuoteAssetSubType.Value);
+ if (error != null)
+ return error;
+ }
+
+ return base.ValidateRequest(request, client);
+ }
+
+ private Error? ValidateAssetTypeCombination(SharedAssetType type, SharedAssetSubType subType)
+ {
+ if (type == SharedAssetType.Crypto
+ && (subType == SharedAssetSubType.Commodity
+ || (subType == SharedAssetSubType.Equity)))
+ {
+ return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
+ }
+
+ if (type == SharedAssetType.TradFi && subType == SharedAssetSubType.StableCoin)
+ return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
+
+ if (type == SharedAssetType.Fiat)
+ return ArgumentError.Invalid(nameof(GetSymbolsRequest.BaseAssetSubType), $"Invalid combination of asset type filters: {type} and {subType}");
+
+ return null;
+ }
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Rest/GetSymbolsRequest.cs b/CryptoExchange.Net/SharedApis/Models/Rest/GetSymbolsRequest.cs
index ce71f088..6aa66445 100644
--- a/CryptoExchange.Net/SharedApis/Models/Rest/GetSymbolsRequest.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Rest/GetSymbolsRequest.cs
@@ -5,13 +5,44 @@
///
public record GetSymbolsRequest : SharedRequest
{
+ ///
+ /// Base asset type filter
+ ///
+ public SharedAssetType? BaseAssetType { get; }
+ ///
+ /// Base asset subtype filter
+ ///
+ public SharedAssetSubType? BaseAssetSubType { get; }
+ ///
+ /// Quote asset type filter
+ ///
+ public SharedAssetType? QuoteAssetType { get; }
+ ///
+ /// Quote asset subtype filter
+ ///
+ public SharedAssetSubType? QuoteAssetSubType { get; }
+
///
/// ctor
///
/// Trading mode filter
+ /// Filter by base asset type
+ /// Filter by base asset subtype
+ /// Filter by quote asset type
+ /// Filter by quote asset subtype
/// Exchange specific parameters
- public GetSymbolsRequest(TradingMode? tradingMode = null, ExchangeParameters? exchangeParameters = null) : base(tradingMode, exchangeParameters)
+ public GetSymbolsRequest(
+ TradingMode? tradingMode = null,
+ SharedAssetType? baseAssetType = null,
+ SharedAssetSubType? baseAssetSubType = null,
+ SharedAssetType? quoteAssetType = null,
+ SharedAssetSubType? quoteAssetSubType = null,
+ ExchangeParameters? exchangeParameters = null) : base(tradingMode, exchangeParameters)
{
+ BaseAssetType = baseAssetType;
+ BaseAssetSubType = baseAssetSubType;
+ QuoteAssetType = quoteAssetType;
+ QuoteAssetSubType = quoteAssetSubType;
}
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/SharedSymbolCatalog.cs b/CryptoExchange.Net/SharedApis/Models/SharedSymbolCatalog.cs
new file mode 100644
index 00000000..abd8c422
--- /dev/null
+++ b/CryptoExchange.Net/SharedApis/Models/SharedSymbolCatalog.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+namespace CryptoExchange.Net.SharedApis
+{
+ ///
+ /// Symbol and asset catalog for a shared client
+ ///
+ public class SharedSymbolCatalog
+ {
+ ///
+ /// Exchange name
+ ///
+ public string Exchange { get; set; } = string.Empty;
+ ///
+ /// Assets supported
+ ///
+ public IReadOnlyDictionary Assets { get; set; } = new Dictionary();
+ ///
+ /// Symbols supported
+ ///
+ public IReadOnlyDictionary Symbols { get; set; } = new Dictionary();
+ }
+
+ ///
+ /// Asset info
+ ///
+ [DebuggerDisplay("{DebugView,nq}")]
+ public class SharedAssetInfo
+ {
+ private string DebugView => $"{Name} - {Type}{(SubType == null ? "": $" {SubType}")}";
+
+ ///
+ /// Asset name
+ ///
+ public string Name { get; set; }
+ ///
+ /// Asset type
+ ///
+ public SharedAssetType Type { get; set; }
+ ///
+ /// Asset sub type
+ ///
+ public SharedAssetSubType? SubType { get; set; }
+
+ ///
+ /// ctor
+ ///
+ public SharedAssetInfo(string name, SharedAssetType type, SharedAssetSubType? subType)
+ {
+ Name = name;
+ Type = type;
+ SubType = subType;
+ }
+ }
+}
diff --git a/CryptoExchange.Net/SharedApis/ResponseModels/SharedFuturesSymbol.cs b/CryptoExchange.Net/SharedApis/ResponseModels/SharedFuturesSymbol.cs
index a8718cf2..8db5fb81 100644
--- a/CryptoExchange.Net/SharedApis/ResponseModels/SharedFuturesSymbol.cs
+++ b/CryptoExchange.Net/SharedApis/ResponseModels/SharedFuturesSymbol.cs
@@ -10,7 +10,7 @@ namespace CryptoExchange.Net.SharedApis
[DebuggerDisplay("{DebugView,nq}")]
public record SharedFuturesSymbol : SharedSpotSymbol
{
- private string DebugView => $"{TradingMode} {Name}{(DeliveryTime != null ? $" Delivery: {DeliveryTime:yyyy-MM-dd}": "")}";
+ private string DebugView => $"{TradingMode} {(DisplayName ?? Name)} - {BaseAssetType}{(BaseAssetSubType == null ? "" : " " + BaseAssetSubType)}{(DeliveryTime != null ? $" Delivery: {DeliveryTime:yyyy-MM-dd}": "")}";
///
/// The size of a single contract
diff --git a/CryptoExchange.Net/SharedApis/ResponseModels/SharedSpotSymbol.cs b/CryptoExchange.Net/SharedApis/ResponseModels/SharedSpotSymbol.cs
index 2233f7b7..1eb70235 100644
--- a/CryptoExchange.Net/SharedApis/ResponseModels/SharedSpotSymbol.cs
+++ b/CryptoExchange.Net/SharedApis/ResponseModels/SharedSpotSymbol.cs
@@ -1,13 +1,17 @@
-using System.Diagnostics;
+using System;
+using System.Data;
+using System.Diagnostics;
namespace CryptoExchange.Net.SharedApis
{
///
/// Symbol info
///
- [DebuggerDisplay("{TradingMode} {Name,nq}")]
+ [DebuggerDisplay("{DebugView,nq}")]
public record SharedSpotSymbol
{
+ private string DebugView => $"{TradingMode} {(DisplayName ?? Name)} - {BaseAssetType} {BaseAssetSubType}";
+
///
/// The trading mode of the symbol
///
@@ -25,6 +29,10 @@ namespace CryptoExchange.Net.SharedApis
///
public string Name { get; set; }
///
+ /// The display name of the symbol
+ ///
+ public string? DisplayName { get; set; }
+ ///
/// Minimal quantity of an order in the base asset
///
public decimal? MinTradeQuantity { get; set; }
@@ -60,6 +68,22 @@ namespace CryptoExchange.Net.SharedApis
/// Whether the symbol is currently available for trading
///
public bool Trading { get; set; }
+ ///
+ /// Base asset type
+ ///
+ public SharedAssetType BaseAssetType { get; set; }
+ ///
+ /// Base asset sub type
+ ///
+ public SharedAssetSubType? BaseAssetSubType { get; set; }
+ ///
+ /// Quote asset type
+ ///
+ public SharedAssetType QuoteAssetType { get; set; }
+ ///
+ /// Quote asset sub type
+ ///
+ public SharedAssetSubType? QuoteAssetSubType { get; set; }
///
/// ctor
diff --git a/CryptoExchange.Net/SharedApis/SharedUtils.cs b/CryptoExchange.Net/SharedApis/SharedUtils.cs
index 426c7f09..b4c098b5 100644
--- a/CryptoExchange.Net/SharedApis/SharedUtils.cs
+++ b/CryptoExchange.Net/SharedApis/SharedUtils.cs
@@ -1,5 +1,6 @@
using CryptoExchange.Net.Objects;
using System.Collections.Generic;
+using System.Linq;
namespace CryptoExchange.Net.SharedApis
{
@@ -176,5 +177,21 @@ namespace CryptoExchange.Net.SharedApis
return result.ToArray();
}
+
+ public static T[] ApplySymbolFilter(T[] symbols, GetSymbolsRequest request) where T : SharedSpotSymbol
+ {
+ IEnumerable resultData = symbols;
+ if (request.TradingMode != null)
+ resultData = resultData.Where(x => x.TradingMode == request.TradingMode);
+ if (request.BaseAssetType != null)
+ resultData = resultData.Where(x => x.BaseAssetType == request.BaseAssetType);
+ if (request.QuoteAssetType != null)
+ resultData = resultData.Where(x => x.QuoteAssetType == request.QuoteAssetType);
+ if (request.BaseAssetSubType != null)
+ resultData = resultData.Where(x => x.BaseAssetSubType == request.BaseAssetSubType);
+ if (request.QuoteAssetSubType != null)
+ resultData = resultData.Where(x => x.QuoteAssetSubType == request.QuoteAssetSubType);
+ return resultData.ToArray();
+ }
}
}