From 726182ad5cd9818aa3448b4baaee6cb187bd3202 Mon Sep 17 00:00:00 2001 From: Dmitry Tarakanov Date: Mon, 23 Mar 2026 22:35:31 +0300 Subject: [PATCH 1/3] #21 correct run --- .../SymbolProviderUpdateDatabaseQueueService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sources/core/Crypto.Compare.Services/BackgroundJobs/SymbolProviderUpdateDatabaseQueueService.cs b/sources/core/Crypto.Compare.Services/BackgroundJobs/SymbolProviderUpdateDatabaseQueueService.cs index b79a431..db2f2ad 100644 --- a/sources/core/Crypto.Compare.Services/BackgroundJobs/SymbolProviderUpdateDatabaseQueueService.cs +++ b/sources/core/Crypto.Compare.Services/BackgroundJobs/SymbolProviderUpdateDatabaseQueueService.cs @@ -16,7 +16,7 @@ public class SymbolProviderUpdateDatabaseQueueService : BackgroundService /// private const int WaitTimeout = 3000; - private static List propertyExclude = new() { "Symbol" }; + //private static List propertyExclude = new() { "Symbol" }; private readonly ISymbolProviderUpdateDatabaseQueue _symbolProviderUpdateDatabaseQueue; @@ -51,7 +51,7 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) await dbContext.BulkUpdateAsync(models, option => { - option.PropertiesToExclude = propertyExclude; + // option.PropertiesToExclude = propertyExclude; }, cancellationToken: stoppingToken); _logger.LogDebug("Update prices database for: {Count} symbols", models.Count); From c1506817e619ad5cad49f05d8dc627108af04a35 Mon Sep 17 00:00:00 2001 From: Dmitry Tarakanov Date: Wed, 1 Apr 2026 21:33:21 +0300 Subject: [PATCH 2/3] #22 new binance provider --- .../Crypto.Compare.Data/SymbolProvider.cs | 4 +- .../BinanceOrderBookListener.cs | 227 ++++++++++++++++++ .../Crypto.Comapre.Binance/Consts.cs | 6 + .../Crypto.Comapre.Binance.csproj | 9 + 4 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 sources/integrations/Crypto.Comapre.Binance/BinanceOrderBookListener.cs create mode 100644 sources/integrations/Crypto.Comapre.Binance/Consts.cs create mode 100644 sources/integrations/Crypto.Comapre.Binance/Crypto.Comapre.Binance.csproj diff --git a/sources/core/Crypto.Compare.Data/SymbolProvider.cs b/sources/core/Crypto.Compare.Data/SymbolProvider.cs index da46027..08cb9a0 100644 --- a/sources/core/Crypto.Compare.Data/SymbolProvider.cs +++ b/sources/core/Crypto.Compare.Data/SymbolProvider.cs @@ -41,11 +41,11 @@ public class SymbolProvider /// Last date get quotes /// public DateTime UpdatedAt { get; set; } - + /// /// id symbol /// public long SymbolId { get; set; } - + public virtual Symbol? Symbol { get; set; } } diff --git a/sources/integrations/Crypto.Comapre.Binance/BinanceOrderBookListener.cs b/sources/integrations/Crypto.Comapre.Binance/BinanceOrderBookListener.cs new file mode 100644 index 0000000..28f9b3e --- /dev/null +++ b/sources/integrations/Crypto.Comapre.Binance/BinanceOrderBookListener.cs @@ -0,0 +1,227 @@ +using Binance.Net.Clients; +using Binance.Net.Interfaces.Clients; +using Binance.Net.Objects.Models.Spot; +using Binance.Net.Objects.Options; +using BingX.Net.Clients; +using BingX.Net.Enums; +using BingX.Net.Interfaces.Clients; +using BingX.Net.Objects.Models; +using BingX.Net.Objects.Options; +using Crypto.Compare.Adapter; +using Crypto.Compare.Adapter.AdaptersObservable; +using Crypto.Compare.Adapter.Impl; +using Crypto.Compare.Data; +using CryptoExchange.Net.Authentication; +using CryptoExchange.Net.Objects.Errors; +using CryptoExchange.Net.Objects.Options; +using CryptoExchange.Net.Objects.Sockets; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + + +namespace Crypto.Compare.BingX; + +public class BinanceOrderBookListener : IListenerAdapter +{ + private const string LogPrefix = "Binance:"; + private Provider _provider; + private bool _isStarted; + private readonly IAdaptersObservable _adaptersObservable; + private readonly IBinanceSocketClient _socketClient; + private readonly IBinanceRestClient _restClient; + private readonly ILogger _logger; + private readonly SortedDictionary _symbols = new (); + private readonly List _sockets = new (); + private readonly ILoggerFactory _loggerFactory; + private readonly IOptions _options; + + public BinanceOrderBookListener(IBinanceSocketClient socketClient, IBinanceRestClient restClient, ILogger logger, + IAdaptersObservable adaptersObservable, ILoggerFactory loggerFactory, IOptions options) + { + _socketClient = socketClient; + _restClient = restClient; + _logger = logger; + _adaptersObservable = adaptersObservable; + _loggerFactory = loggerFactory; + _options = options; + } + + public async Task StartAsync(Provider provider, CancellationToken cancellationToken) + { + _provider = provider; + + // get all symbols + if (!await LoadSymbolsAsync(cancellationToken)) + { + return; + } + + // subscribe on events + if (!await SubscribeSymbolsAsync(cancellationToken)) + { + return; + } + + // started + _isStarted = true; + } + + private async Task SubscribeSymbolsAsync(CancellationToken cancellationToken) + { + try + { + var socketConnection = GetConnection(); + + foreach (var symbol in _symbols) + { + (socketConnection, var result) = await TrySubscribeBatchesAsync(symbol.Value.Name, socketConnection, cancellationToken); + if (!result) + { + return _sockets.Count >= 1; + } + } + + + return true; + } + catch (Exception e) + { + _logger.LogError(e, LogPrefix + " Subscribe on symbols failed"); + return false; + } + } + + private async Task<(BinanceSocketClient bybitConnection, bool subscribeSymbolsAsync)> TrySubscribeBatchesAsync(string symbol, BinanceSocketClient socketConnection, + CancellationToken cancellationToken) + { + var result = await socketConnection.SpotApi.SubscribeToBookPriceUpdatesAsync(symbol, HandlerAction, cancellationToken); + + if (!result.Success) + { + if (result.Error.ErrorType == ErrorType.Unknown) + { + // try create new connection and subscribing + socketConnection = GetConnection(); + result = await socketConnection.SpotApi.SubscribeToBookPriceUpdatesAsync(symbol, HandlerAction, cancellationToken); + if (result.Success) + { + return (socketConnection, true); + } + + _logger.LogWarning(LogPrefix + " Not subscribe on ticker: {Symbol}", symbol); + return (socketConnection, false); + } + + _logger.LogWarning(LogPrefix + " Not subscribe on tickers: {Symbols}", symbol); + return (socketConnection, false); + } + + _logger.LogInformation(LogPrefix + " subscribed success, connection: {Number}, {Symbols}", _sockets.Count, symbol); + return (socketConnection, true); + } + + + private BinanceSocketClient GetConnection() + { + var connection = new BinanceSocketClient(_options, _loggerFactory); + connection.SetOptions(new UpdateOptions + { + ApiCredentials = new ApiCredentials(_provider.AccessKey, _provider.SecretKey) + }); + _sockets.Add(connection); + return connection; + } + + + private async Task LoadSymbolsAsync(CancellationToken cancellationToken) + { + try + { + var exchangeInfo = await _restClient.SpotApi.ExchangeData.GetSymbolsAsync(ct: cancellationToken); + + if (!exchangeInfo.Success) + { + _logger.LogError(LogPrefix + " Get symbols failed"); + return false; + } + + foreach (var symbol in exchangeInfo.Data) + { + if (symbol.Status != SymbolStatus.Online) + { + continue; + } + + _symbols.Add(symbol.Name.ToLowerInvariant(), symbol); + } + } + catch (Exception e) + { + _logger.LogError(e, LogPrefix + " Load symbols failed"); + return false; + } + + return true; + } + + /// + /// Handler event change book of currency + /// + /// Data of event + private void HandlerAction(DataEventBinanceBookTickerUpdate> dataEvent) + { + var askPrice = 0m; + var bidPrice = 0m; + var askQuantity = 0m; + var bidQuantity = 0m; + if (string.IsNullOrEmpty(dataEvent.Symbol)) + { + return; + } + + if (!_symbols.TryGetValue(dataEvent.Symbol.ToLowerInvariant(), out var symbol)) + { + _logger.LogWarning("Symbol not found: {Symbol}", dataEvent.Symbol); + return; + } + var parts = symbol.Name.Split('-', 2); + var (baseSymbol, quoteSymbol) = (parts[0].ToLowerInvariant(), parts.Length > 1 ? parts[1].ToLowerInvariant() : string.Empty); + if (dataEvent.Data?.BestAskPrice > 0) + { + askPrice = dataEvent.Data.BestAskPrice; + askQuantity = dataEvent.Data.BestAskQuantity; + } + + if (dataEvent.Data?.BestBidPrice > 0) + { + bidPrice = dataEvent.Data.BestBidPrice; + bidQuantity = dataEvent.Data.BestBidQuantity; + } + + _adaptersObservable.OnNext(new SymbolData(ticker: dataEvent.Symbol, + providerId: _provider.Id, + askPrice: askPrice, + bidPrice: bidPrice, + askQuantity: askQuantity, + bidQuantity: bidQuantity, + baseSymbol: baseSymbol, + quoteSymbol: quoteSymbol)); + } + + public Task StopAsync(CancellationToken cancellationToken) + { + _socketClient?.Dispose(); + foreach (var socketClient in _sockets) + { + socketClient?.Dispose(); + } + + return Task.CompletedTask; + } + + public bool IsSupported(string providerName) + => string.Equals(providerName, Consts.ProviderName, StringComparison.OrdinalIgnoreCase); + + public bool IsStarted() + => _isStarted; +} diff --git a/sources/integrations/Crypto.Comapre.Binance/Consts.cs b/sources/integrations/Crypto.Comapre.Binance/Consts.cs new file mode 100644 index 0000000..b414d0c --- /dev/null +++ b/sources/integrations/Crypto.Comapre.Binance/Consts.cs @@ -0,0 +1,6 @@ +namespace Crypto.Compare.BingX; + +public class Consts +{ + public const string ProviderName = "BingX"; +} \ No newline at end of file diff --git a/sources/integrations/Crypto.Comapre.Binance/Crypto.Comapre.Binance.csproj b/sources/integrations/Crypto.Comapre.Binance/Crypto.Comapre.Binance.csproj new file mode 100644 index 0000000..b760144 --- /dev/null +++ b/sources/integrations/Crypto.Comapre.Binance/Crypto.Comapre.Binance.csproj @@ -0,0 +1,9 @@ + + + + net10.0 + enable + enable + + + From 58664dc3a08203917bf9663218227bcbbb14a7f2 Mon Sep 17 00:00:00 2001 From: Dmitry Tarakanov Date: Mon, 27 Apr 2026 21:06:00 +0300 Subject: [PATCH 3/3] #22 added binance market --- Crypto.Compare.sln | 7 ++ README.md | 23 +++++++ .../BinanceOrderBookListener.cs | 68 +++++++++++-------- .../Crypto.Comapre.Binance/Consts.cs | 2 +- .../Crypto.Comapre.Binance.csproj | 8 +++ .../BingXOrderBookListener.cs | 13 ++-- .../Crypto.Compare.BingX.csproj | 2 +- .../BitMartOrderBookListener.cs | 5 +- .../Crypto.Compare.BitMart.csproj | 2 +- .../BitgetOrderBookListener.cs | 18 +---- .../Crypto.Compare.Bitget.csproj | 2 +- .../ByBitOrderBookListener.cs | 15 ++-- .../Crypto.Compare.ByBit.csproj | 2 +- .../Crypto.Compare.GateIo.csproj | 2 +- .../GateIoOrderBookListener.cs | 10 +-- .../Crypto.Compare.Mexc.csproj | 2 +- .../MexcOrderBookListener.cs | 6 +- .../Crypto.Compare.Xtcom.csproj | 2 +- .../XtcomOrderBookListener.cs | 15 ++-- .../Crypto.Compare.PublicApi.csproj | 13 ++-- .../Ioc/ServicesRegistry.cs | 50 ++++++++++---- .../Crypto.Compare.PublicApi.Tests.csproj | 8 +-- 22 files changed, 166 insertions(+), 109 deletions(-) diff --git a/Crypto.Compare.sln b/Crypto.Compare.sln index 470a8ab..114c666 100644 --- a/Crypto.Compare.sln +++ b/Crypto.Compare.sln @@ -45,6 +45,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crypto.Compare.GateIo", "so EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crypto.Compare.BitMart", "sources\integrations\Crypto.Compare.BitMart\Crypto.Compare.BitMart.csproj", "{B6196161-CEF3-48D7-8F56-692472A5E4FB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Crypto.Comapre.Binance", "sources\integrations\Crypto.Comapre.Binance\Crypto.Comapre.Binance.csproj", "{A62F8D6B-37A8-4D7A-A759-03E3C883239B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -111,6 +113,10 @@ Global {B6196161-CEF3-48D7-8F56-692472A5E4FB}.Debug|Any CPU.Build.0 = Debug|Any CPU {B6196161-CEF3-48D7-8F56-692472A5E4FB}.Release|Any CPU.ActiveCfg = Release|Any CPU {B6196161-CEF3-48D7-8F56-692472A5E4FB}.Release|Any CPU.Build.0 = Release|Any CPU + {A62F8D6B-37A8-4D7A-A759-03E3C883239B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A62F8D6B-37A8-4D7A-A759-03E3C883239B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A62F8D6B-37A8-4D7A-A759-03E3C883239B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A62F8D6B-37A8-4D7A-A759-03E3C883239B}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -135,6 +141,7 @@ Global {410272B7-D024-49E8-9435-DDF0F309A134} = {A9E9246F-B758-4D14-ADAD-1EF937DCC5E8} {A2DB814C-895A-4D09-AFC1-FDD0C988F2FD} = {A9E9246F-B758-4D14-ADAD-1EF937DCC5E8} {B6196161-CEF3-48D7-8F56-692472A5E4FB} = {A9E9246F-B758-4D14-ADAD-1EF937DCC5E8} + {A62F8D6B-37A8-4D7A-A759-03E3C883239B} = {A9E9246F-B758-4D14-ADAD-1EF937DCC5E8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D179164C-BFE5-45FD-BD60-476E93A84589} diff --git a/README.md b/README.md index dbfd376..e0c97b3 100644 --- a/README.md +++ b/README.md @@ -186,6 +186,17 @@ INSERT INTO public."Providers"( Need to replace in the request: AccessKey and SecretKey - for keys from the exchange's personal account +### BINANCE + +```sql +INSERT INTO public."Providers"( + "Name", "WebSite", "BaseUrl", "AccessKey", "SecretKey", "Status", "CreatedAt", "UpdatedAt") + VALUES ('binance', 'https://binance.com', 'https://api.binance.com', 'AccessKey', 'SecretKey', 1,NOW(), NOW()); +``` + +Need to replace in the request: +AccessKey and SecretKey - for keys from the exchange's personal account + ## Getting API keys for exchanges - **ByBit:** https://www.bybit.com/en/help-center/article/How-to-create-your-API-key?category=ae1012f19fad1c184e @@ -502,6 +513,18 @@ INSERT INTO public."Providers"( "Name", "WebSite", "BaseUrl", "AccessKey", "SecretKey", "Status", "CreatedAt", "UpdatedAt", "PasswordKey") VALUES ( 'bitmart', 'https://bitmart.com', 'https://api-cloud.bitmart.com', 'AccessKey', 'SecretKey', 1,NOW(), NOW(), ''); ``` + +Нужно заменить в запросе: +AccessKey и SecretKey - на ключи с личного кабинета биржи + +### BINANCE + +```sql +INSERT INTO public."Providers"( + "Name", "WebSite", "BaseUrl", "AccessKey", "SecretKey", "Status", "CreatedAt", "UpdatedAt") + VALUES ('binance', 'https://binance.com', 'https://api.binance.com', 'AccessKey', 'SecretKey', 1,NOW(), NOW()); +``` + Нужно заменить в запросе: AccessKey и SecretKey - на ключи с личного кабинета биржи diff --git a/sources/integrations/Crypto.Comapre.Binance/BinanceOrderBookListener.cs b/sources/integrations/Crypto.Comapre.Binance/BinanceOrderBookListener.cs index 28f9b3e..770142e 100644 --- a/sources/integrations/Crypto.Comapre.Binance/BinanceOrderBookListener.cs +++ b/sources/integrations/Crypto.Comapre.Binance/BinanceOrderBookListener.cs @@ -1,20 +1,16 @@ -using Binance.Net.Clients; +using Binance.Net; +using Binance.Net.Clients; +using Binance.Net.Interfaces; using Binance.Net.Interfaces.Clients; -using Binance.Net.Objects.Models.Spot; +using Binance.Net.Objects.Models.Spot.Socket; using Binance.Net.Objects.Options; -using BingX.Net.Clients; -using BingX.Net.Enums; -using BingX.Net.Interfaces.Clients; -using BingX.Net.Objects.Models; -using BingX.Net.Objects.Options; using Crypto.Compare.Adapter; using Crypto.Compare.Adapter.AdaptersObservable; using Crypto.Compare.Adapter.Impl; using Crypto.Compare.Data; -using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Objects.Errors; -using CryptoExchange.Net.Objects.Options; using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.SharedApis; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -30,8 +26,8 @@ public class BinanceOrderBookListener : IListenerAdapter private readonly IBinanceSocketClient _socketClient; private readonly IBinanceRestClient _restClient; private readonly ILogger _logger; - private readonly SortedDictionary _symbols = new (); - private readonly List _sockets = new (); + private readonly SortedDictionary _symbols = new(); + private readonly List _sockets = new(); private readonly ILoggerFactory _loggerFactory; private readonly IOptions _options; @@ -44,6 +40,10 @@ public BinanceOrderBookListener(IBinanceSocketClient socketClient, IBinanceRestC _adaptersObservable = adaptersObservable; _loggerFactory = loggerFactory; _options = options; + BinanceSocketClient.SetDefaultOptions(x => + { + x.ApiCredentials = new BinanceCredentials(_provider.AccessKey, _provider.SecretKey); + }); } public async Task StartAsync(Provider provider, CancellationToken cancellationToken) @@ -71,10 +71,11 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok try { var socketConnection = GetConnection(); + var keys = _symbols.Values.Select(x => x.Name).ToList(); - foreach (var symbol in _symbols) + foreach (var symbols in SplitIntoBatches(keys, 15)) { - (socketConnection, var result) = await TrySubscribeBatchesAsync(symbol.Value.Name, socketConnection, cancellationToken); + (socketConnection, var result) = await TrySubscribeBatchesAsync(symbols, socketConnection, cancellationToken); if (!result) { return _sockets.Count >= 1; @@ -91,10 +92,18 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok } } - private async Task<(BinanceSocketClient bybitConnection, bool subscribeSymbolsAsync)> TrySubscribeBatchesAsync(string symbol, BinanceSocketClient socketConnection, - CancellationToken cancellationToken) + private static IEnumerable> SplitIntoBatches(List source, int batchSize) + { + for (var i = 0; i < source.Count; i += batchSize) + { + yield return source.GetRange(i, Math.Min(batchSize, source.Count - i)); + } + } + + private async Task<(BinanceSocketClient connection, bool subscribeSymbolsAsync)> + TrySubscribeBatchesAsync(List symbols, BinanceSocketClient socketConnection, CancellationToken cancellationToken) { - var result = await socketConnection.SpotApi.SubscribeToBookPriceUpdatesAsync(symbol, HandlerAction, cancellationToken); + var result = await socketConnection.SpotApi.ExchangeData.SubscribeToOrderBookUpdatesAsync(symbols, 1, HandlerAction, cancellationToken).ConfigureAwait(false); if (!result.Success) { @@ -102,32 +111,34 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok { // try create new connection and subscribing socketConnection = GetConnection(); - result = await socketConnection.SpotApi.SubscribeToBookPriceUpdatesAsync(symbol, HandlerAction, cancellationToken); + result = await socketConnection.SpotApi.ExchangeData.SubscribeToOrderBookUpdatesAsync(symbols, 1, HandlerAction, cancellationToken); if (result.Success) { return (socketConnection, true); } - _logger.LogWarning(LogPrefix + " Not subscribe on ticker: {Symbol}", symbol); + _logger.LogWarning(LogPrefix + " Not subscribe on ticker: {Symbols}", string.Join(',', symbols)); return (socketConnection, false); } - _logger.LogWarning(LogPrefix + " Not subscribe on tickers: {Symbols}", symbol); + _logger.LogWarning(LogPrefix + " Not subscribe on tickers: {Symbols}", string.Join(',', symbols)); return (socketConnection, false); } - _logger.LogInformation(LogPrefix + " subscribed success, connection: {Number}, {Symbols}", _sockets.Count, symbol); + _logger.LogInformation(LogPrefix + " subscribed success, connection: {Number}, {Symbols}", _sockets.Count, string.Join(',', symbols)); return (socketConnection, true); } + private void HandlerAction(DataEvent @event) + { + throw new NotImplementedException(); + } private BinanceSocketClient GetConnection() { var connection = new BinanceSocketClient(_options, _loggerFactory); - connection.SetOptions(new UpdateOptions - { - ApiCredentials = new ApiCredentials(_provider.AccessKey, _provider.SecretKey) - }); + connection.SetApiCredentials(new BinanceCredentials(_provider.AccessKey, _provider.SecretKey)); + _sockets.Add(connection); return connection; } @@ -137,7 +148,9 @@ private async Task LoadSymbolsAsync(CancellationToken cancellationToken) { try { - var exchangeInfo = await _restClient.SpotApi.ExchangeData.GetSymbolsAsync(ct: cancellationToken); + + var exchangeInfo = await _restClient.SpotApi.SharedClient.GetSpotSymbolsAsync( + new GetSymbolsRequest(tradingMode:TradingMode.Spot), ct: cancellationToken); if (!exchangeInfo.Success) { @@ -147,7 +160,8 @@ private async Task LoadSymbolsAsync(CancellationToken cancellationToken) foreach (var symbol in exchangeInfo.Data) { - if (symbol.Status != SymbolStatus.Online) + + if (!symbol.Trading) { continue; } @@ -168,7 +182,7 @@ private async Task LoadSymbolsAsync(CancellationToken cancellationToken) /// Handler event change book of currency /// /// Data of event - private void HandlerAction(DataEventBinanceBookTickerUpdate> dataEvent) + private void HandlerAction(DataEvent dataEvent) { var askPrice = 0m; var bidPrice = 0m; diff --git a/sources/integrations/Crypto.Comapre.Binance/Consts.cs b/sources/integrations/Crypto.Comapre.Binance/Consts.cs index b414d0c..256751a 100644 --- a/sources/integrations/Crypto.Comapre.Binance/Consts.cs +++ b/sources/integrations/Crypto.Comapre.Binance/Consts.cs @@ -2,5 +2,5 @@ public class Consts { - public const string ProviderName = "BingX"; + public const string ProviderName = "Binance"; } \ No newline at end of file diff --git a/sources/integrations/Crypto.Comapre.Binance/Crypto.Comapre.Binance.csproj b/sources/integrations/Crypto.Comapre.Binance/Crypto.Comapre.Binance.csproj index b760144..91faeb8 100644 --- a/sources/integrations/Crypto.Comapre.Binance/Crypto.Comapre.Binance.csproj +++ b/sources/integrations/Crypto.Comapre.Binance/Crypto.Comapre.Binance.csproj @@ -6,4 +6,12 @@ enable + + + + + + + + diff --git a/sources/integrations/Crypto.Compare.BingX/BingXOrderBookListener.cs b/sources/integrations/Crypto.Compare.BingX/BingXOrderBookListener.cs index ad8236a..d250266 100644 --- a/sources/integrations/Crypto.Compare.BingX/BingXOrderBookListener.cs +++ b/sources/integrations/Crypto.Compare.BingX/BingXOrderBookListener.cs @@ -1,4 +1,5 @@ -using BingX.Net.Clients; +using BingX.Net; +using BingX.Net.Clients; using BingX.Net.Enums; using BingX.Net.Interfaces.Clients; using BingX.Net.Objects.Models; @@ -26,8 +27,8 @@ public class BingXOrderBookListener : IListenerAdapter private readonly IBingXSocketClient _socketClient; private readonly IBingXRestClient _restClient; private readonly ILogger _logger; - private readonly SortedDictionary _symbols = new (); - private readonly List _sockets = new (); + private readonly SortedDictionary _symbols = new(); + private readonly List _sockets = new(); private readonly ILoggerFactory _loggerFactory; private readonly IOptions _options; @@ -120,10 +121,8 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok private BingXSocketClient GetConnection() { var connection = new BingXSocketClient(_options, _loggerFactory); - connection.SetOptions(new UpdateOptions - { - ApiCredentials = new ApiCredentials(_provider.AccessKey, _provider.SecretKey) - }); + connection.SetApiCredentials(new BingXCredentials(_provider.AccessKey, _provider.SecretKey)); + _sockets.Add(connection); return connection; } diff --git a/sources/integrations/Crypto.Compare.BingX/Crypto.Compare.BingX.csproj b/sources/integrations/Crypto.Compare.BingX/Crypto.Compare.BingX.csproj index 1941b03..424ef34 100644 --- a/sources/integrations/Crypto.Compare.BingX/Crypto.Compare.BingX.csproj +++ b/sources/integrations/Crypto.Compare.BingX/Crypto.Compare.BingX.csproj @@ -7,7 +7,7 @@ - + diff --git a/sources/integrations/Crypto.Compare.BitMart/BitMartOrderBookListener.cs b/sources/integrations/Crypto.Compare.BitMart/BitMartOrderBookListener.cs index 1645169..c615bdb 100644 --- a/sources/integrations/Crypto.Compare.BitMart/BitMartOrderBookListener.cs +++ b/sources/integrations/Crypto.Compare.BitMart/BitMartOrderBookListener.cs @@ -120,10 +120,7 @@ protected override async Task SubscribeSymbolsAsync(CancellationToken canc private BitMartSocketClient GetConnection() { var connection = new BitMartSocketClient(_options, _loggerFactory); - connection.SetOptions(new UpdateOptions - { - ApiCredentials = new ApiCredentials(Provider.AccessKey, Provider.SecretKey, Provider.PasswordKey) - }); + _sockets.Add(connection); return connection; } diff --git a/sources/integrations/Crypto.Compare.BitMart/Crypto.Compare.BitMart.csproj b/sources/integrations/Crypto.Compare.BitMart/Crypto.Compare.BitMart.csproj index 3a30df7..e3e7a76 100644 --- a/sources/integrations/Crypto.Compare.BitMart/Crypto.Compare.BitMart.csproj +++ b/sources/integrations/Crypto.Compare.BitMart/Crypto.Compare.BitMart.csproj @@ -12,7 +12,7 @@ - + diff --git a/sources/integrations/Crypto.Compare.Bitget/BitgetOrderBookListener.cs b/sources/integrations/Crypto.Compare.Bitget/BitgetOrderBookListener.cs index be0804f..0db4d82 100644 --- a/sources/integrations/Crypto.Compare.Bitget/BitgetOrderBookListener.cs +++ b/sources/integrations/Crypto.Compare.Bitget/BitgetOrderBookListener.cs @@ -26,7 +26,7 @@ public class BitgetOrderBookListener : IListenerAdapter private readonly IBitgetRestClient _restClient; private readonly ILogger _logger; private readonly Dictionary _symbols = new Dictionary(); - private readonly List _sockets = new (); + private readonly List _sockets = new(); private readonly ILoggerFactory _loggerFactory; private readonly IOptions _options; @@ -43,7 +43,7 @@ public BitgetOrderBookListener(IBitgetSocketClient bitgetSocketClient, IBitgetRe public async Task StartAsync(Provider provider, CancellationToken cancellationToken) { - + _provider = provider; // get all symbols @@ -121,23 +121,11 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok private BitgetSocketClient GetConnection() { var connection = new BitgetSocketClient(_options, _loggerFactory); - connection.SetOptions(new UpdateOptions - { - ApiCredentials = new ApiCredentials(_provider.AccessKey, _provider.SecretKey, _provider.PasswordKey) - }); + _sockets.Add(connection); return connection; } - - private static IEnumerable> SplitIntoBatches(List source, int batchSize) - { - for (var i = 0; i < source.Count; i += batchSize) - { - yield return source.GetRange(i, Math.Min(batchSize, source.Count - i)); - } - } - private async Task LoadSymbolsAsync(CancellationToken cancellationToken) { try diff --git a/sources/integrations/Crypto.Compare.Bitget/Crypto.Compare.Bitget.csproj b/sources/integrations/Crypto.Compare.Bitget/Crypto.Compare.Bitget.csproj index ddcf034..652f48a 100644 --- a/sources/integrations/Crypto.Compare.Bitget/Crypto.Compare.Bitget.csproj +++ b/sources/integrations/Crypto.Compare.Bitget/Crypto.Compare.Bitget.csproj @@ -7,7 +7,7 @@ - + diff --git a/sources/integrations/Crypto.Compare.ByBit/ByBitOrderBookListener.cs b/sources/integrations/Crypto.Compare.ByBit/ByBitOrderBookListener.cs index 5e778fc..5b8f9bb 100644 --- a/sources/integrations/Crypto.Compare.ByBit/ByBitOrderBookListener.cs +++ b/sources/integrations/Crypto.Compare.ByBit/ByBitOrderBookListener.cs @@ -1,4 +1,5 @@ -using Bybit.Net.Clients; +using Bybit.Net; +using Bybit.Net.Clients; using Bybit.Net.Enums; using Bybit.Net.Interfaces.Clients; using Bybit.Net.Objects.Models.V5; @@ -27,7 +28,7 @@ public class ByBitOrderBookListener : IListenerAdapter private readonly IBybitRestClient _restClient; private readonly ILogger _logger; private readonly IDictionary _symbols = new Dictionary(); - private readonly List _sockets = new (); + private readonly List _sockets = new(); private readonly ILoggerFactory _loggerFactory; private readonly IOptions _options; @@ -91,7 +92,7 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok private async Task<(BybitSocketClient bybitConnection, bool subscribeSymbolsAsync)> TrySubscribeBatchesAsync(CancellationToken cancellationToken, List symbols, BybitSocketClient bybitConnection) { - var result = await bybitConnection.V5SpotApi.SubscribeToOrderbookUpdatesAsync(symbols, 1, HandlerAction, cancellationToken); + var result = await bybitConnection.V5SpotApi.SubscribeToOrderbookUpdatesAsync(symbols, 100, HandlerAction, cancellationToken); if (!result.Success) { @@ -99,7 +100,7 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok { // try create new connection and subscribing bybitConnection = GetConnection(); - result = await bybitConnection.V5SpotApi.SubscribeToOrderbookUpdatesAsync(symbols, 1, HandlerAction, cancellationToken); + result = await bybitConnection.V5SpotApi.SubscribeToOrderbookUpdatesAsync(symbols, 100, HandlerAction, cancellationToken); if (result.Success) { return (bybitConnection, true); @@ -120,10 +121,8 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok private BybitSocketClient GetConnection() { var connection = new BybitSocketClient(_options, _loggerFactory); - connection.SetOptions(new UpdateOptions - { - ApiCredentials = new ApiCredentials(_provider.AccessKey, _provider.SecretKey) - }); + connection.SetApiCredentials(new BybitCredentials(_provider.AccessKey, _provider.SecretKey)); + _sockets.Add(connection); return connection; } diff --git a/sources/integrations/Crypto.Compare.ByBit/Crypto.Compare.ByBit.csproj b/sources/integrations/Crypto.Compare.ByBit/Crypto.Compare.ByBit.csproj index c264857..a995d8c 100644 --- a/sources/integrations/Crypto.Compare.ByBit/Crypto.Compare.ByBit.csproj +++ b/sources/integrations/Crypto.Compare.ByBit/Crypto.Compare.ByBit.csproj @@ -7,7 +7,7 @@ - + diff --git a/sources/integrations/Crypto.Compare.GateIo/Crypto.Compare.GateIo.csproj b/sources/integrations/Crypto.Compare.GateIo/Crypto.Compare.GateIo.csproj index 13f1932..33d9141 100644 --- a/sources/integrations/Crypto.Compare.GateIo/Crypto.Compare.GateIo.csproj +++ b/sources/integrations/Crypto.Compare.GateIo/Crypto.Compare.GateIo.csproj @@ -7,7 +7,7 @@ - + diff --git a/sources/integrations/Crypto.Compare.GateIo/GateIoOrderBookListener.cs b/sources/integrations/Crypto.Compare.GateIo/GateIoOrderBookListener.cs index 015db04..7229efc 100644 --- a/sources/integrations/Crypto.Compare.GateIo/GateIoOrderBookListener.cs +++ b/sources/integrations/Crypto.Compare.GateIo/GateIoOrderBookListener.cs @@ -6,6 +6,7 @@ using CryptoExchange.Net.Objects.Errors; using CryptoExchange.Net.Objects.Options; using CryptoExchange.Net.Objects.Sockets; +using GateIo.Net; using GateIo.Net.Clients; using GateIo.Net.Enums; using GateIo.Net.Interfaces.Clients; @@ -119,10 +120,11 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok private GateIoSocketClient GetConnection() { var connection = new GateIoSocketClient(_options, _loggerFactory); - connection.SetOptions(new UpdateOptions - { - ApiCredentials = new ApiCredentials(_provider.AccessKey, _provider.SecretKey, _provider.PasswordKey) - }); + connection.SetApiCredentials(new GateIoCredentials(_provider.AccessKey, _provider.SecretKey)); + //connection.SetOptions(new UpdateOptions + //{ + // ApiCredentials = new ApiCredentials(_provider.AccessKey, _provider.SecretKey, _provider.PasswordKey) + //}); _sockets.Add(connection); return connection; } diff --git a/sources/integrations/Crypto.Compare.Mexc/Crypto.Compare.Mexc.csproj b/sources/integrations/Crypto.Compare.Mexc/Crypto.Compare.Mexc.csproj index 4a34681..5baed1e 100644 --- a/sources/integrations/Crypto.Compare.Mexc/Crypto.Compare.Mexc.csproj +++ b/sources/integrations/Crypto.Compare.Mexc/Crypto.Compare.Mexc.csproj @@ -11,7 +11,7 @@ - + diff --git a/sources/integrations/Crypto.Compare.Mexc/MexcOrderBookListener.cs b/sources/integrations/Crypto.Compare.Mexc/MexcOrderBookListener.cs index eda55cf..ebfcb42 100644 --- a/sources/integrations/Crypto.Compare.Mexc/MexcOrderBookListener.cs +++ b/sources/integrations/Crypto.Compare.Mexc/MexcOrderBookListener.cs @@ -6,6 +6,7 @@ using CryptoExchange.Net.Objects.Errors; using CryptoExchange.Net.Objects.Options; using CryptoExchange.Net.Objects.Sockets; +using Mexc.Net; using Mexc.Net.Clients; using Mexc.Net.Enums; using Mexc.Net.Interfaces.Clients; @@ -119,10 +120,7 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok private MexcSocketClient GetConnection() { var mexcConnection = new MexcSocketClient(_options, _loggerFactory); - mexcConnection.SetOptions(new UpdateOptions - { - ApiCredentials = new ApiCredentials(_provider.AccessKey, _provider.SecretKey) - }); + mexcConnection.SetApiCredentials(new MexcCredentials(_provider.AccessKey, _provider.SecretKey)); _mexcSockets.Add(mexcConnection); return mexcConnection; } diff --git a/sources/integrations/Crypto.Compare.Xtcom/Crypto.Compare.Xtcom.csproj b/sources/integrations/Crypto.Compare.Xtcom/Crypto.Compare.Xtcom.csproj index 700b47f..1b52b6d 100644 --- a/sources/integrations/Crypto.Compare.Xtcom/Crypto.Compare.Xtcom.csproj +++ b/sources/integrations/Crypto.Compare.Xtcom/Crypto.Compare.Xtcom.csproj @@ -10,7 +10,7 @@ - + diff --git a/sources/integrations/Crypto.Compare.Xtcom/XtcomOrderBookListener.cs b/sources/integrations/Crypto.Compare.Xtcom/XtcomOrderBookListener.cs index e81122c..10b2952 100644 --- a/sources/integrations/Crypto.Compare.Xtcom/XtcomOrderBookListener.cs +++ b/sources/integrations/Crypto.Compare.Xtcom/XtcomOrderBookListener.cs @@ -7,6 +7,7 @@ using CryptoExchange.Net.Objects.Sockets; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; +using XT.Net; using XT.Net.Clients; using XT.Net.Enums; using XT.Net.Interfaces.Clients; @@ -23,7 +24,7 @@ public class XtcomOrderBookListener : IListenerAdapter private readonly IXTSocketClient _xtSocketClient; private readonly IXTRestClient _restClient; private readonly ILogger _logger; - private readonly SortedDictionary _symbols = new (); + private readonly SortedDictionary _symbols = new(); private readonly List _xtSockets = new(); private readonly ILoggerFactory _loggerFactory; private readonly IOptions _options; @@ -65,7 +66,7 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok { var xtConnection = GetConnection(); - var keys = _symbols.Values.Select(x=>x.Symbol).ToList(); + var keys = _symbols.Values.Select(x => x.Symbol).ToList(); foreach (var symbols in SplitIntoBatches(keys, 15)) { (xtConnection, var result) = await TrySubscribeBatchesAsync(cancellationToken, symbols, xtConnection); @@ -117,10 +118,8 @@ private async Task SubscribeSymbolsAsync(CancellationToken cancellationTok private XTSocketClient GetConnection() { var xtConnection = new XTSocketClient(_options, _loggerFactory); - xtConnection.SetOptions(new UpdateOptions - { - ApiCredentials = new ApiCredentials(_provider.AccessKey, _provider.SecretKey) - }); + xtConnection.SetApiCredentials(new XTCredentials(_provider.AccessKey, _provider.SecretKey)); + _xtSockets.Add(xtConnection); return xtConnection; } @@ -176,7 +175,7 @@ private void HandlerAction(DataEvent dataEvent) var bidPrice = 0m; var askQuantity = 0m; var bidQuantity = 0m; - + if (string.IsNullOrEmpty(dataEvent.Symbol)) { return; @@ -187,7 +186,7 @@ private void HandlerAction(DataEvent dataEvent) _logger.LogWarning("Symbol not found: {Symbol}", dataEvent.Symbol); return; } - + if (dataEvent.Data?.Asks.Length > 0) { askPrice = dataEvent.Data.Asks[0].Price; diff --git a/sources/presentation/Crypto.Compare.PublicApi/Crypto.Compare.PublicApi.csproj b/sources/presentation/Crypto.Compare.PublicApi/Crypto.Compare.PublicApi.csproj index e88ea21..7dfeae4 100644 --- a/sources/presentation/Crypto.Compare.PublicApi/Crypto.Compare.PublicApi.csproj +++ b/sources/presentation/Crypto.Compare.PublicApi/Crypto.Compare.PublicApi.csproj @@ -11,17 +11,17 @@ - + - - - + + + - - + + @@ -36,6 +36,7 @@ + diff --git a/sources/presentation/Crypto.Compare.PublicApi/Ioc/ServicesRegistry.cs b/sources/presentation/Crypto.Compare.PublicApi/Ioc/ServicesRegistry.cs index 64ea9f7..f15bb4a 100644 --- a/sources/presentation/Crypto.Compare.PublicApi/Ioc/ServicesRegistry.cs +++ b/sources/presentation/Crypto.Compare.PublicApi/Ioc/ServicesRegistry.cs @@ -1,4 +1,9 @@ -using Crypto.Compare.Adapter; +using Binance.Net; +using BingX.Net; +using Bitget.Net; +using BitMart.Net; +using Bybit.Net; +using Crypto.Compare.Adapter; using Crypto.Compare.Adapter.AdaptersObservable; using Crypto.Compare.Adapter.Impl; using Crypto.Compare.BingX; @@ -33,11 +38,14 @@ using Crypto.Compare.Xtcom; using CryptoExchange.Net.Authentication; using FluentResults; +using GateIo.Net; using Mapster; using MapsterMapper; using MediatR; +using Mexc.Net; using Microsoft.EntityFrameworkCore; using System.Reflection; +using XT.Net; namespace Crypto.Compare.PublicApi.Ioc; @@ -106,7 +114,7 @@ private static IServiceCollection AddAdapters(this IServiceCollection services, if (!string.IsNullOrEmpty(apiSecret) && !string.IsNullOrEmpty(apiKey)) { - services.AddMexc(options => { options.Socket.ApiCredentials = new ApiCredentials(apiKey, apiSecret); }); + services.AddMexc(options => { options.Socket.ApiCredentials = new MexcCredentials(apiKey, apiSecret); }); } else { @@ -118,8 +126,8 @@ private static IServiceCollection AddAdapters(this IServiceCollection services, { services.AddXT(options => { - options.ApiCredentials = new ApiCredentials(apiKey, apiSecret); - options.Socket.ApiCredentials = new ApiCredentials(apiKey, apiSecret); + options.ApiCredentials = new XTCredentials(apiKey, apiSecret); + options.Socket.ApiCredentials = new XTCredentials(apiKey, apiSecret); options.Rest.RequestTimeout = TimeSpan.FromMinutes(5); }); } @@ -133,8 +141,8 @@ private static IServiceCollection AddAdapters(this IServiceCollection services, { services.AddBybit(options => { - options.ApiCredentials = new ApiCredentials(apiKey, apiSecret); - options.Socket.ApiCredentials = new ApiCredentials(apiKey, apiSecret); + options.ApiCredentials = new BybitCredentials(apiKey, apiSecret); + options.Socket.ApiCredentials = new BybitCredentials(apiKey, apiSecret); options.Rest.RequestTimeout = TimeSpan.FromMinutes(5); }); } @@ -148,8 +156,8 @@ private static IServiceCollection AddAdapters(this IServiceCollection services, { services.AddBingX(options => { - options.ApiCredentials = new ApiCredentials(apiKey, apiSecret); - options.Socket.ApiCredentials = new ApiCredentials(apiKey, apiSecret); + options.ApiCredentials = new BingXCredentials(apiKey, apiSecret); + options.Socket.ApiCredentials = new BingXCredentials(apiKey, apiSecret); options.Rest.RequestTimeout = TimeSpan.FromMinutes(5); }); } @@ -163,8 +171,8 @@ private static IServiceCollection AddAdapters(this IServiceCollection services, { services.AddBitget(options => { - options.ApiCredentials = new ApiCredentials(apiKey, apiSecret, passwordKey); - options.Socket.ApiCredentials = new ApiCredentials(apiKey, apiSecret, passwordKey); + options.ApiCredentials = new BitgetCredentials(apiKey, apiSecret, passwordKey); + options.Socket.ApiCredentials = new BitgetCredentials(apiKey, apiSecret, passwordKey); options.Rest.RequestTimeout = TimeSpan.FromMinutes(5); }); } @@ -178,8 +186,8 @@ private static IServiceCollection AddAdapters(this IServiceCollection services, { services.AddGateIo(options => { - options.ApiCredentials = new ApiCredentials(apiKey, apiSecret); - options.Socket.ApiCredentials = new ApiCredentials(apiKey, apiSecret); + options.ApiCredentials = new GateIoCredentials(apiKey, apiSecret); + options.Socket.ApiCredentials = new GateIoCredentials(apiKey, apiSecret); options.Rest.RequestTimeout = TimeSpan.FromMinutes(5); }); } @@ -194,8 +202,8 @@ private static IServiceCollection AddAdapters(this IServiceCollection services, { services.AddBitMart(options => { - options.ApiCredentials = new ApiCredentials(apiKey, apiSecret, passwordKey); - options.Socket.ApiCredentials = new ApiCredentials(apiKey, apiSecret, passwordKey); + options.ApiCredentials = new BitMartCredentials(apiKey, apiSecret, passwordKey); + options.Socket.ApiCredentials = new BitMartCredentials(apiKey, apiSecret, passwordKey); options.Rest.RequestTimeout = TimeSpan.FromMinutes(5); }); } @@ -204,6 +212,20 @@ private static IServiceCollection AddAdapters(this IServiceCollection services, services.AddBitMart(); } + (apiKey, apiSecret, _) = LoadCredentialsSync("binance", configuration); + if (!string.IsNullOrEmpty(apiSecret) && !string.IsNullOrEmpty(apiKey)) + { + services.AddBinance(options => + { + options.ApiCredentials = new BinanceCredentials(apiKey, apiSecret); + options.Socket.ApiCredentials = new BinanceCredentials(apiKey, apiSecret); + options.Rest.RequestTimeout = TimeSpan.FromMinutes(5); + }); + } + else + { + services.AddBinance(); + } return services; } diff --git a/tests/Crypto.Compare.PublicApi.Tests/Crypto.Compare.PublicApi.Tests.csproj b/tests/Crypto.Compare.PublicApi.Tests/Crypto.Compare.PublicApi.Tests.csproj index aafbce2..d3f6736 100644 --- a/tests/Crypto.Compare.PublicApi.Tests/Crypto.Compare.PublicApi.Tests.csproj +++ b/tests/Crypto.Compare.PublicApi.Tests/Crypto.Compare.PublicApi.Tests.csproj @@ -10,11 +10,11 @@ - + - - - + + + all