diff --git a/Examples/BlazorClient/BlazorClient.csproj b/Examples/BlazorClient/BlazorClient.csproj index a7348ce..b9bf64f 100644 --- a/Examples/BlazorClient/BlazorClient.csproj +++ b/Examples/BlazorClient/BlazorClient.csproj @@ -15,6 +15,7 @@ + diff --git a/Examples/BlazorClient/Pages/Index.razor b/Examples/BlazorClient/Pages/Index.razor index 38aa9d5..3772236 100644 --- a/Examples/BlazorClient/Pages/Index.razor +++ b/Examples/BlazorClient/Pages/Index.razor @@ -5,6 +5,7 @@ @inject IBitMartRestClient bitmartClient @inject IBitgetRestClient bitgetClient @inject IBybitRestClient bybitClient +@inject ICoinbaseRestClient coinbaseClient @inject ICoinExRestClient coinexClient @inject IGateIoRestClient gateioClient @inject IHTXRestClient huobiClient @@ -30,6 +31,7 @@ var bitgetTask = bitgetClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT_SPBL"); var bitmartTask = bitmartClient.SpotApi.ExchangeData.GetTickerAsync("BTC_USDT"); var bybitTask = bybitClient.V5Api.ExchangeData.GetSpotTickersAsync("BTCUSDT"); + var coinbaseTask = coinbaseClient.AdvancedTradeApi.ExchangeData.GetSymbolAsync("BTC-USDT"); var coinexTask = coinexClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT"); var gateioTask = gateioClient.SpotApi.ExchangeData.GetTickersAsync("BTC_USDT"); var htxTask = huobiClient.SpotApi.ExchangeData.GetTickerAsync("btcusdt"); @@ -58,6 +60,9 @@ if (bybitTask.Result.Success) _prices.Add("Bybit", bybitTask.Result.Data.List.First().LastPrice); + if (coinbaseTask.Result.Success) + _prices.Add("Coinbase", coinbaseTask.Result.Data.LastPrice ?? 0); + if (coinexTask.Result.Success) _prices.Add("CoinEx", coinexTask.Result.Data.Ticker.LastPrice); diff --git a/Examples/BlazorClient/Pages/LiveData.razor b/Examples/BlazorClient/Pages/LiveData.razor index b1d2e4c..ec5f879 100644 --- a/Examples/BlazorClient/Pages/LiveData.razor +++ b/Examples/BlazorClient/Pages/LiveData.razor @@ -5,6 +5,7 @@ @inject IBitgetSocketClient bitgetSocketClient @inject IBitMartSocketClient bitmartSocketClient @inject IBybitSocketClient bybitSocketClient +@inject ICoinbaseSocketClient coinbaseSocketClient @inject ICoinExSocketClient coinExSocketClient @inject IGateIoSocketClient gateioSocketClient @inject IHTXSocketClient htxSocketClient @@ -39,6 +40,7 @@ bitmartSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH_BTC", data => UpdateData("BitMart", data.Data.LastPrice)), bybitSocketClient.V5SpotApi.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Bybit", data.Data.LastPrice)), coinExSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("CoinEx", data.Data.LastPrice)), + coinbaseSocketClient.AdvancedTradeApi.SubscribeToTickerUpdatesAsync("ETH-BTC", data => UpdateData("Coinbase", data.Data.LastPrice)), gateioSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH_BTC", data => UpdateData("GateIo", data.Data.LastPrice)), htxSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ethbtc", data => UpdateData("HTX", data.Data.ClosePrice ?? 0)), krakenSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH/XBT", data => UpdateData("Kraken", data.Data.LastTrade.Price)), diff --git a/Examples/BlazorClient/Pages/OrderBooks.razor b/Examples/BlazorClient/Pages/OrderBooks.razor index d32dbf9..e102bcd 100644 --- a/Examples/BlazorClient/Pages/OrderBooks.razor +++ b/Examples/BlazorClient/Pages/OrderBooks.razor @@ -8,6 +8,7 @@ @using BitMart.Net.Interfaces; @using Bybit.Net.Interfaces @using CoinEx.Net.Interfaces +@using Coinbase.Net.Interfaces @using CryptoExchange.Net.Interfaces @using GateIo.Net.Interfaces @using HTX.Net.Interfaces @@ -22,6 +23,7 @@ @inject IBitgetOrderBookFactory bitgetFactory @inject IBitMartOrderBookFactory bitmartFactory @inject IBybitOrderBookFactory bybitFactory +@inject ICoinbaseOrderBookFactory coinbaseFactory @inject ICoinExOrderBookFactory coinExFactory @inject IGateIoOrderBookFactory gateioFactory @inject IHTXOrderBookFactory htxFactory @@ -68,6 +70,7 @@ { "Bitget", bitgetFactory.CreateSpot("ETHBTC") }, { "BitMart", bitmartFactory.CreateSpot("ETH_BTC", null) }, { "Bybit", bybitFactory.Create("ETHBTC", Bybit.Net.Enums.Category.Spot) }, + { "Coinbase", coinbaseFactory.Create("ETH-BTC", null) }, { "CoinEx", coinExFactory.CreateSpot("ETHBTC") }, { "GateIo", gateioFactory.CreateSpot("ETH_BTC") }, { "HTX", htxFactory.CreateSpot("ethbtc") }, diff --git a/Examples/BlazorClient/Startup.cs b/Examples/BlazorClient/Startup.cs index 972bb48..2d1749e 100644 --- a/Examples/BlazorClient/Startup.cs +++ b/Examples/BlazorClient/Startup.cs @@ -41,6 +41,7 @@ namespace BlazorClient services.AddBitget(); services.AddBitMart(); services.AddBybit(); + services.AddCoinbase(); services.AddCoinEx(); services.AddGateIo(); services.AddHTX(); diff --git a/Examples/BlazorClient/_Imports.razor b/Examples/BlazorClient/_Imports.razor index c178854..792d814 100644 --- a/Examples/BlazorClient/_Imports.razor +++ b/Examples/BlazorClient/_Imports.razor @@ -14,6 +14,7 @@ @using Bitget.Net.Interfaces.Clients; @using BitMart.Net.Interfaces.Clients; @using Bybit.Net.Interfaces.Clients; +@using Coinbase.Net.Interfaces.Clients; @using CoinEx.Net.Interfaces.Clients; @using GateIo.Net.Interfaces.Clients; @using HTX.Net.Interfaces.Clients; diff --git a/Examples/ConsoleClient/ConsoleClient.csproj b/Examples/ConsoleClient/ConsoleClient.csproj index 6287483..4a5bf53 100644 --- a/Examples/ConsoleClient/ConsoleClient.csproj +++ b/Examples/ConsoleClient/ConsoleClient.csproj @@ -15,6 +15,7 @@ + diff --git a/README.md b/README.md index 956919a..a665aca 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ The following API's are directly supported. Note that there are 3rd party implem |Bitget|[JKorf/Bitget.Net](https://github.com/JKorf/Bitget.Net)|[![Nuget version](https://img.shields.io/nuget/v/JK.Bitget.net.svg?style=flat-square)](https://www.nuget.org/packages/JK.Bitget.Net)| |BitMart|[JKorf/BitMart.Net](https://github.com/JKorf/BitMart.Net)|[![Nuget version](https://img.shields.io/nuget/v/BitMart.net.svg?style=flat-square)](https://www.nuget.org/packages/BitMart.Net)| |Bybit|[JKorf/Bybit.Net](https://github.com/JKorf/Bybit.Net)|[![Nuget version](https://img.shields.io/nuget/v/Bybit.net.svg?style=flat-square)](https://www.nuget.org/packages/Bybit.Net)| +|Coinbase|[JKorf/Coinbase.Net](https://github.com/JKorf/Coinbase.Net)|[![Nuget version](https://img.shields.io/nuget/v/JKorf.Coinbase.Net.svg?style=flat-square)](https://www.nuget.org/packages/JKorf.Coinbase.Net)| |CoinEx|[JKorf/CoinEx.Net](https://github.com/JKorf/CoinEx.Net)|[![Nuget version](https://img.shields.io/nuget/v/CoinEx.net.svg?style=flat-square)](https://www.nuget.org/packages/CoinEx.Net)| |CoinGecko|[JKorf/CoinGecko.Net](https://github.com/JKorf/CoinGecko.Net)|[![Nuget version](https://img.shields.io/nuget/v/CoinGecko.net.svg?style=flat-square)](https://www.nuget.org/packages/CoinGecko.Net)| |Gate.io|[JKorf/GateIo.Net](https://github.com/JKorf/GateIo.Net)|[![Nuget version](https://img.shields.io/nuget/v/GateIo.net.svg?style=flat-square)](https://www.nuget.org/packages/GateIo.Net)| @@ -34,7 +35,7 @@ Any of these can be installed independently or install [CryptoClients.Net](https A Discord server is available [here](https://discord.gg/MSpeEtSY8t). Feel free to join for discussion and/or questions around the CryptoExchange.Net and implementation libraries. ## Support the project -I develop and maintain this package on my own for free in my spare time, any support is greatly appreciated. +Any support is greatly appreciated. ### Donate Make a one time donation in a crypto currency of your choice. If you prefer to donate a currency not listed here please contact me. @@ -53,7 +54,7 @@ Alternatively, sponsor me on Github using [Github Sponsors](https://github.com/s * Added ToRfc3339String extension method for DateTime type * Version 8.0.0 - 27 Sep 2024 - * Added new cross exchange interfaces implementation + * Added new cross exchange interfaces implementation * Supports REST, WebSocket, Spot and Futures API's * Added various client interfaces for specific functionality * Added SharedSymbol type, taking care of symbol formatting for different exchanges diff --git a/docs/index.html b/docs/index.html index 6585d9a..16bd78f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -151,6 +151,7 @@ BitgetJKorf/Bitget.Net BitMartJKorf/BitMart.Net BybitJKorf/Bybit.Net + CoinbaseJKorf/Coinbase.Net CoinExJKorf/CoinEx.Net CoinGeckoJKorf/CoinGecko.Net Gate.ioJKorf/GateIo.Net @@ -240,12 +241,15 @@ + - CoinGecko + Coinbase + + @@ -403,6 +413,9 @@
builder.Services.AddBybit();
+
+
+
builder.Services.AddCoinbase();
builder.Services.AddCoinGecko();
@@ -455,6 +468,9 @@ + @@ -688,6 +704,35 @@
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
InterfaceDescription
ICoinbaseRestClientThe client for accessing the Coinbase REST API
ICoinbaseSocketClientThe client for accessing the Coinbase Websocket API
ICoinbaseOrderBookFactoryA factory for creating SymbolOrderBook instances for the Coinbase API
ICryptoRestClientAn aggregating client from which multiple different library REST clients can be accessed
ICryptoSocketClientAn aggregating client from which multiple different library Websocket clients can be accessed
ISharedClientVarious interfaces deriving from ISharedClient which can be used for common functionality
+
@@ -949,6 +994,9 @@ + + @@ -1349,6 +1412,17 @@ if (!subscribeResult.Success) { // Handle error, subscribeResult.Error contains more information on why the subscription failed } +// Subscribing was successfull, the data will now be streamed into the data handler + +
+
var client = new CoinbaseSocketClient();
+var subscribeResult = await sclient.AdvancedTradeApi.SubscribeToTickerUpdatesAsync("ETHUSDT", update => {
+    // Handle the data update, update.Data will contain the actual data
+});
+if (!subscribeResult.Success)
+{
+    // Handle error, subscribeResult.Error contains more information on why the subscription failed
+}
 // Subscribing was successfull, the data will now be streamed into the data handler
@@ -1598,6 +1672,9 @@ var binanceTriggered = CheckForTrigger(lastBinanceTicker); + @@ -1702,6 +1779,13 @@ var inverseFuturesspotSharedSocketClient = bybitSocketClient.V5InverseApi.Shared // Private Futures API common functionality socket client var privateFuturesSharedSocketClient = bybitSocketClient.V5PrivateApi.SharedClient;
+
+
// Advanced Trade API common functionality rest client
+var spotSharedRestClients = coinbaseRestClient.AdvancedTradeApi.SharedClient;
+
+// Advanced Trade API common functionality socket client
+var spotSharedSocketClient = coinbaseRestClient.AdvancedTradeApi.SharedClient;
+
// Spot API common functionality rest client
 var spotSharedRestClients = coinExRestClient.SpotApiV2.SharedClient;
@@ -2033,6 +2117,9 @@ options.ApiCredentials = new ApiCredentials("YOUR PUBLIC KEY", "YOUR PRIVATE KEY
 			  
+			  
 			  
@@ -2115,6 +2202,15 @@ options.ApiCredentials = new ApiCredentials("YOUR PUBLIC KEY", "YOUR PRIVATE KEY
 			  
builder.Services.AddBybit(
+  restOptions => {
+    restOptions.RequestTimeout = TimeSpan.FromSeconds(30);
+  },
+  socketOptions => {
+    socketOptions.RequestTimeout = TimeSpan.FromSeconds(10);
+  });
+
+
+
builder.Services.AddCoinbase(
   restOptions => {
     restOptions.RequestTimeout = TimeSpan.FromSeconds(30);
   },
@@ -2219,6 +2315,9 @@ options.ApiCredentials = new ApiCredentials("YOUR PUBLIC KEY", "YOUR PRIVATE KEY
 			  
+			  
 			  
@@ -2283,6 +2382,12 @@ options.ApiCredentials = new ApiCredentials("YOUR PUBLIC KEY", "YOUR PRIVATE KEY
 			  
var client = new BybitRestClient(opts =>
+{
+    opts.RequestTimeout = TimeSpan.FromSeconds(30);
+});
+
+
+
var client = new CoinbaseRestClient(opts =>
 {
     opts.RequestTimeout = TimeSpan.FromSeconds(30);
 });
@@ -2360,6 +2465,9 @@ options.ApiCredentials = new ApiCredentials("YOUR PUBLIC KEY", "YOUR PRIVATE KEY + @@ -2427,6 +2535,13 @@ var client = new BitMartRestClient();
options.RequestTimeout = TimeSpan.FromSeconds(30); }); var client = new BybitRestClient();
+
+
+
CoinbaseClient.SetDefaultOptions(options =>
+{
+    options.RequestTimeout = TimeSpan.FromSeconds(30);
+});
+var client = new CoinbaseRestClient();
CoinGeckoRestClient.SetDefaultOptions(options =>
@@ -2688,6 +2803,9 @@ var client = new OKXRestClient();
+ @@ -2799,6 +2917,19 @@ if (!startResult.Success) } // Book has successfully started and synchronized +// Once no longer needed you can stop the live sync functionality by calling StopAsync() +await book.StopAsync(); + +
+
+
var book = new CoinbaseSymbolOrderBook("ETH-USDT");
+var startResult = await book.StartAsync();
+if (!startResult.Success)
+{
+  // Handle error, error info available in startResult.Error
+}
+// Book has successfully started and synchronized
+
 // Once no longer needed you can stop the live sync functionality by calling StopAsync()
 await book.StopAsync();
 
@@ -3069,6 +3200,9 @@ var binanceClient = new BinanceRestClient(new HttpClient(), logFactory, options + @@ -3155,6 +3289,20 @@ var binanceClient = new BinanceRestClient(new HttpClient(), logFactory, options

To be notified of when a rate limit is hit the static BitMartExchange.RateLimiter exposes an event which triggers when a rate limit is reached

BitMartExchange.RateLimiter.RateLimitTriggered += (rateLimitEvent) => Console.WriteLine("Limit triggered: " + rateLimitEvent);
 
+
+
+
+
services.AddCoinbase(x =>
+    x.RatelimiterEnabled = true;
+    x.RateLimitingBehaviour = RateLimitingBehaviour.Wait;
+}, x =>
+{
+    x.RatelimiterEnabled = true;
+    x.RateLimitingBehaviour = RateLimitingBehaviour.Wait;
+});
+

To be notified of when a rate limit is hit the static CoinbaseExchange.RateLimiter exposes an event which triggers when a rate limit is reached

+
CoinbaseExchange.RateLimiter.RateLimitTriggered += (rateLimitEvent) => Console.WriteLine("Limit triggered: " + rateLimitEvent);
+
 
@@ -3317,6 +3465,9 @@ var responseSource = result.DataSource; + @@ -3361,6 +3512,9 @@ await exchangeRestClient.Binance.SpotApi.ExchangeData.GetExchangeInfoAsync();
await bybitClient.V5Api.ExchangeData.GetSpotSymbolsAsync();
+
+
+
await coinbaseClient.AdvancedTradeApi.ExchangeData.GetSymbolsAsync();
await coinExClient.SpotApiV2.ExchangeData.GetSymbolsAsync();
@@ -3422,6 +3576,9 @@ await exchangeRestClient.Binance.SpotApi.ExchangeData.GetExchangeInfoAsync(); Bybit + @@ -3466,6 +3623,10 @@ await exchangeRestClient.Binance.SpotApi.ExchangeData.GetTickerAsync(spotClient.
await bybitClient.V5Api.ExchangeData.GetSpotTickersAsync("BTCUSDT");
+
+
+
// Symbol endpoint and ticker endpoints are combined for Coinbase
+await coinbaseClient.AdvancedTradeApi.ExchangeData.GetSymbolAsync("BTC-USDT");
await coinExClient.SpotApiV2.ExchangeData.GetTickersAsync(new[] { "BTCUSDT" });
@@ -3527,6 +3688,9 @@ await exchangeRestClient.Binance.SpotApi.ExchangeData.GetTickerAsync(spotClient. + @@ -3571,6 +3735,9 @@ await exchangeRestClient.Binance.SpotApi.Account.GetBalancesAsync();
await bybitClient.V5Api.Account.GetBalancesAsync(AccountType.Spot);
+
+
+
await coinbaseClient.AdvancedTradeApi.Account.GetAccountsAsync();
await coinExClient.SpotApiV2.Account.GetBalancesAsync();
@@ -3636,6 +3803,9 @@ var result = await htxClient.SpotApi.Account.GetBalancesAsync(); + @@ -3682,6 +3852,9 @@ await exchangeRestClient.Binance.SpotApi.Trading.PlaceOrderAsync("BTCUSDT", Orde
await bybitClient.V5Api.Trading.PlaceOrderAsync(Category.Spot, "BTCUSDT", OrderSide.Buy, NewOrderType.Limit, 0.1m, price: 50000);
+
await coinbaseClient.AdvancedTradeApi.Trading.PlaceOrderAsync("BTC-USDT", OrderSide.Buy, NewOrderType.Limit, 0.1m, price: 50000);
+
+
await coinExClient.SpotApiV2.Trading.PlaceOrderAsync("BTCUSDT", AccountType.Spot, OrderSide.Buy, OrderTypeV2.Limit, 0.1m, 50000);
@@ -3745,6 +3918,9 @@ var result = await htxClient.SpotApi.Trading.PlaceOrderAsync(account.Id, "BTCUSD + @@ -3802,6 +3978,11 @@ await exchangeSocketClient.Binance.SpotApi.ExchangeData.SubscribeToTickerUpdates
await bybitSocketClient.V5SpotApi.SubscribeToTickerUpdatesAsync("ETHUSDT", data => {
     // Handle update
+});
+
+
+
await coinbaseSocketClient.AdvancedTradeApi.SubscribeToTickerUpdatesAsync("ETH-USDT", data => {
+    // Handle update
 });
@@ -3879,6 +4060,9 @@ await exchangeSocketClient.Binance.SpotApi.ExchangeData.SubscribeToTickerUpdates + @@ -3979,6 +4163,11 @@ _ = Task.Run(async () => {
await bybitSocketClient.V5PrivateApi.SubscribeToOrderUpdatesAsync(data => {
     // Handle update
+});
+
+
+
await coinbaseSocketClient.AdvancedTradeApi.SubscribeToUserUpdatesAsync(data => {
+    // Handle update
 });
@@ -4043,7 +4232,7 @@ _ = Task.Run(async () => { Minimal API
-

A minimal API example allowing the caller to retrieve ticker information for a specific exchange and asset pair
+

A minimal API example allowing the caller to retrieve ticker information for a specific exchange and asset pair. This is using the CryptoClient.Net Nuget package.

@@ -4066,8 +4255,8 @@ var app = builder.Build(); app.MapGet("Ticker/{exchange}/{baseAsset}/{quoteAsset}", async ([FromServices] IExchangeRestClient client, Exchange exchange, string baseAsset, string quoteAsset) => { - var spotClient = client.GetUnifiedSpotClient(exchange)!; - var result = await spotClient.GetTickerAsync(spotClient.GetSymbolName(baseAsset, quoteAsset)); + var spotClient = client.GetSpotTickerClient(exchange)!; + var result = await spotClient.GetSpotTickerAsync(new GetTickerRequest(new SharedSymbol(TradingMode.Spot, baseAsset, quoteAsset))); return result.Data; });
InterfaceDescription