diff --git a/CryptoCom.Net/Clients/ExchangeApi/CryptoComRestClientExchangeApiShared.cs b/CryptoCom.Net/Clients/ExchangeApi/CryptoComRestClientExchangeApiShared.cs index 6971711..b83886e 100644 --- a/CryptoCom.Net/Clients/ExchangeApi/CryptoComRestClientExchangeApiShared.cs +++ b/CryptoCom.Net/Clients/ExchangeApi/CryptoComRestClientExchangeApiShared.cs @@ -26,6 +26,7 @@ internal partial class CryptoComRestClientExchangeApi : ICryptoComRestClientExch public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters(); public SharedClientInfo Discover() => SharedUtils.GetClientInfo(CryptoComExchange.Metadata, this); + private readonly static HashSet _knownExchangeFiat = ["EUR", "USD", "BRL", "GBP", "CAD", "HKD", "KRW", "TWD", "RUB", "SGD"]; #region Asset client GetAssetsOptions IAssetsRestClient.GetAssetsOptions { get; } = new GetAssetsOptions(_exchangeName, true); @@ -388,6 +389,7 @@ async Task> IWithdrawRestClient.WithdrawAsync(WithdrawReque #endregion #region Spot Symbol client + SharedSymbolCatalog? ISpotSymbolRestClient.SpotSymbolCatalog => ExchangeSymbolCache.GetSymbolCatalog(_exchangeName, _topicSpotId, EnvironmentName, null); GetSpotSymbolsOptions ISpotSymbolRestClient.GetSpotSymbolsOptions { get; } = new GetSpotSymbolsOptions(_exchangeName, false); async Task> ISpotSymbolRestClient.GetSpotSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) @@ -400,18 +402,61 @@ async Task> ISpotSymbolRestClient.GetSpotSymbolsA if (!result.Success) return HttpResult.Fail(result); - var data = result.Data.Where(x => x.SymbolType == Enums.SymbolType.Spot); + var data = result.Data + .Where(x => x.SymbolType == Enums.SymbolType.Spot) + .Select(x => ParseSymbol(x)) + .ToArray(); - var response = HttpResult.Ok(result, data.Select(s => new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Symbol, s.Tradable) + ExchangeSymbolCache.UpdateSymbolInfo(_topicSpotId, EnvironmentName, null, data); + return HttpResult.Ok(result, SharedUtils.ApplySymbolFilter(data, request)); + } + + private SharedSpotSymbol ParseSymbol(CryptoComSymbol s) + { + var result = new SharedSpotSymbol(s.BaseAsset, s.QuoteAsset, s.Symbol, s.Tradable) { QuantityStep = s.QuantityTickSize, PriceStep = s.PriceTickSize, PriceDecimals = s.PriceDecimals, - QuantityDecimals = s.QuantityDecimals - }).ToArray()); + QuantityDecimals = s.QuantityDecimals, + DisplayName = s.DisplayName + }; - ExchangeSymbolCache.UpdateSymbolInfo(_topicSpotId, EnvironmentName, null, response.Data!); - return response; + if (s.ProductType == ProductType.Equity || + s.ProductType == ProductType.EquityIndex) + { + result.BaseAssetType = SharedAssetType.TradFi; + result.BaseAssetSubType = SharedAssetSubType.Equity; + } + else if (s.ProductType == ProductType.Commodities) + { + result.BaseAssetType = SharedAssetType.TradFi; + result.BaseAssetSubType = SharedAssetSubType.Commodity; + } + else if (s.ProductType == ProductType.Currencies) + { + result.BaseAssetType = SharedAssetType.Fiat; + } + else if (s.ProductType == ProductType.DigitalCurrencies) + { + result.BaseAssetType = SharedAssetType.Crypto; + if (LibraryHelpers.IsStableCoin(result.BaseAsset)) + result.BaseAssetSubType = SharedAssetSubType.StableCoin; + } + + if (_knownExchangeFiat.Contains(s.QuoteAsset)) + { + result.QuoteAssetType = SharedAssetType.Fiat; + } + else + { + result.QuoteAssetType = SharedAssetType.Crypto; + + if (LibraryHelpers.IsStableCoin(s.QuoteAsset)) + result.QuoteAssetSubType = SharedAssetSubType.StableCoin; + } + + return result; } async Task> ISpotSymbolRestClient.GetSpotSymbolsForBaseAssetAsync(string baseAsset) @@ -882,7 +927,7 @@ async Task> IFundingRateRestClient.GetFundingRat #endregion #region Futures Symbol client - + SharedSymbolCatalog? IFuturesSymbolRestClient.FuturesSymbolCatalog => ExchangeSymbolCache.GetSymbolCatalog(_exchangeName, _topicFuturesId, EnvironmentName, null); GetFuturesSymbolsOptions IFuturesSymbolRestClient.GetFuturesSymbolsOptions { get; } = new GetFuturesSymbolsOptions(_exchangeName, false); async Task> IFuturesSymbolRestClient.GetFuturesSymbolsAsync(GetSymbolsRequest request, CancellationToken ct) { @@ -894,10 +939,18 @@ async Task> IFuturesSymbolRestClient.GetFuture if (!result.Success) return HttpResult.Fail(result); - var data = result.Data.Where(x => x.SymbolType != SymbolType.Spot && x.SymbolType != SymbolType.CroStake); - if (request.TradingMode != null) - data = data.Where(x => request.TradingMode == TradingMode.PerpetualLinear ? x.SymbolType == SymbolType.PerpetualSwap : x.SymbolType == SymbolType.DeliveryFuture); - var response = HttpResult.Ok(result, data.Select(s => new SharedFuturesSymbol( + var data = result.Data + .Where(x => x.SymbolType != SymbolType.Spot && x.SymbolType != SymbolType.CroStake) + .Select(x => ParseFuturesSymbol(x)) + .ToArray(); + + ExchangeSymbolCache.UpdateSymbolInfo(_topicFuturesId, EnvironmentName, null, data); + return HttpResult.Ok(result, SharedUtils.ApplySymbolFilter(data, request)); + } + + private SharedFuturesSymbol ParseFuturesSymbol(CryptoComSymbol s) + { + var result = new SharedFuturesSymbol( s.SymbolType == SymbolType.PerpetualSwap ? TradingMode.PerpetualLinear : TradingMode.DeliveryLinear, s.BaseAsset, s.QuoteAsset, s.Symbol, s.Tradable) { QuantityStep = s.QuantityTickSize, @@ -907,11 +960,46 @@ async Task> IFuturesSymbolRestClient.GetFuture DeliveryTime = s.ExpiryTime, ContractSize = s.ContractSize > 0 ? s.ContractSize.Value : 1m, MaxLongLeverage = s.MaxLeverage, - MaxShortLeverage = s.MaxLeverage - }).ToArray()); + MaxShortLeverage = s.MaxLeverage, + DisplayName = s.DisplayName + }; + + if (s.ProductType == ProductType.Equity + || (s.ProductType == ProductType.PreIpo) // pre-ipo + || (s.ProductType == ProductType.EquityIndex)) // etfs + { + result.BaseAssetType = SharedAssetType.TradFi; + result.BaseAssetSubType = SharedAssetSubType.Equity; + } + else if (s.ProductType == ProductType.Commodities) + { + result.BaseAssetType = SharedAssetType.TradFi; + result.BaseAssetSubType = SharedAssetSubType.Commodity; + } + else if (s.ProductType == ProductType.Currencies) + { + result.BaseAssetType = SharedAssetType.Fiat; + } + else if (s.ProductType == ProductType.DigitalCurrencies) + { + result.BaseAssetType = SharedAssetType.Crypto; + if (LibraryHelpers.IsStableCoin(result.BaseAsset)) + result.BaseAssetSubType = SharedAssetSubType.StableCoin; + } + + if (_knownExchangeFiat.Contains(s.QuoteAsset)) + { + result.QuoteAssetType = SharedAssetType.Fiat; + } + else + { + result.QuoteAssetType = SharedAssetType.Crypto; + + if (LibraryHelpers.IsStableCoin(s.QuoteAsset)) + result.QuoteAssetSubType = SharedAssetSubType.StableCoin; + } - ExchangeSymbolCache.UpdateSymbolInfo(_topicFuturesId, EnvironmentName, null, response.Data!); - return response; + return result; } async Task> IFuturesSymbolRestClient.GetFuturesSymbolsForBaseAssetAsync(string baseAsset) diff --git a/CryptoCom.Net/CryptoCom.Net.csproj b/CryptoCom.Net/CryptoCom.Net.csproj index 1c783d6..14419c7 100644 --- a/CryptoCom.Net/CryptoCom.Net.csproj +++ b/CryptoCom.Net/CryptoCom.Net.csproj @@ -53,7 +53,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/CryptoCom.Net/Objects/Models/CryptoComSymbol.cs b/CryptoCom.Net/Objects/Models/CryptoComSymbol.cs index d3e1eaa..3de95ef 100644 --- a/CryptoCom.Net/Objects/Models/CryptoComSymbol.cs +++ b/CryptoCom.Net/Objects/Models/CryptoComSymbol.cs @@ -85,7 +85,7 @@ public record CryptoComSymbol /// ["expiry_timestamp_ms"] Expiry timestamp /// [JsonPropertyName("expiry_timestamp_ms")] - public DateTime ExpiryTime { get; set; } + public DateTime? ExpiryTime { get; set; } /// /// ["underlying_symbol"] Underlying symbol ///