1
0
mirror of https://github.com/JKorf/CryptoExchange.Net.git synced 2026-08-13 01:12:59 +00:00

Compare commits

..

13 Commits

Author SHA1 Message Date
Jkorf 84d36544e4 Updated to version 8.0.2 2024-10-09 08:49:19 +02:00
Jkorf a71f57ae7f Updated dependency versions, including System.Text.Json containing a vulnerability fix 2024-10-09 08:46:15 +02:00
Jkorf 6e5bcd5e9a Some small doc fixes 2024-10-07 15:30:09 +02:00
Jkorf 4131e563c3 Added Coinbase reference, updated examples 2024-10-07 15:20:12 +02:00
Jkorf 613766dbca Updated to version 8.0.1 2024-10-07 13:03:08 +02:00
Jkorf 23b07d709e Added testing check for year 1 datetime 2024-10-07 12:57:23 +02:00
Jkorf bbbdac2fd3 Added ToRfc3339String extension method for DateTime 2024-10-07 12:57:04 +02:00
Jkorf c614b7869c Added check for datetime year 1 to be deserialized as null 2024-10-04 18:50:27 +02:00
Jkorf 1f31e4a9d7 Added cached lib versions properties 2024-10-04 18:49:58 +02:00
Jkorf 6cb6cd6b11 Note 2024-10-03 16:33:00 +02:00
Jkorf 17ffec329f Fixed typo 2024-09-27 15:15:09 +02:00
Jkorf 7a3927ef49 Add parameters documentation for shared clients 2024-09-27 15:13:50 +02:00
Jkorf c1b0437c93 Updated examples 2024-09-27 13:53:33 +02:00
21 changed files with 448 additions and 65 deletions
+8 -1
View File
@@ -11,7 +11,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorClient", "Examples\Bl
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Examples", "Examples", "{5734C2A9-F12C-4754-A8B9-640C24DC4E02}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleClient", "Examples\ConsoleClient\ConsoleClient.csproj", "{23480C58-23BF-4EBF-A173-B7F51A043A99}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleClient", "Examples\ConsoleClient\ConsoleClient.csproj", "{23480C58-23BF-4EBF-A173-B7F51A043A99}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedClients", "Examples\SharedClients\SharedClients.csproj", "{988A87EF-EAEA-4313-A6CF-FA869813D5AB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -35,6 +37,10 @@ Global
{23480C58-23BF-4EBF-A173-B7F51A043A99}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23480C58-23BF-4EBF-A173-B7F51A043A99}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23480C58-23BF-4EBF-A173-B7F51A043A99}.Release|Any CPU.Build.0 = Release|Any CPU
{988A87EF-EAEA-4313-A6CF-FA869813D5AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{988A87EF-EAEA-4313-A6CF-FA869813D5AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{988A87EF-EAEA-4313-A6CF-FA869813D5AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{988A87EF-EAEA-4313-A6CF-FA869813D5AB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -42,6 +48,7 @@ Global
GlobalSection(NestedProjects) = preSolution
{AF4F5C19-162E-48F4-8B0B-BA5A2D7CE06A} = {5734C2A9-F12C-4754-A8B9-640C24DC4E02}
{23480C58-23BF-4EBF-A173-B7F51A043A99} = {5734C2A9-F12C-4754-A8B9-640C24DC4E02}
{988A87EF-EAEA-4313-A6CF-FA869813D5AB} = {5734C2A9-F12C-4754-A8B9-640C24DC4E02}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0D1B9CE9-E0B7-4B8B-88BF-6EA2CC8CA3D7}
@@ -11,12 +11,12 @@ namespace CryptoExchange.Net.Authentication
public class ApiCredentials
{
/// <summary>
/// The api key to authenticate requests
/// The api key / label to authenticate requests
/// </summary>
public string Key { get; }
/// <summary>
/// The api secret to authenticate requests
/// The api secret or private key to authenticate requests
/// </summary>
public string Secret { get; }
@@ -28,8 +28,8 @@ namespace CryptoExchange.Net.Authentication
/// <summary>
/// Create Api credentials providing an api key and secret for authentication
/// </summary>
/// <param name="key">The api key used for identification</param>
/// <param name="secret">The api secret used for signing</param>
/// <param name="key">The api key / label used for identification</param>
/// <param name="secret">The api secret or private key used for signing</param>
public ApiCredentials(string key, string secret) : this(key, secret, ApiCredentialsType.Hmac)
{
}
@@ -37,8 +37,8 @@ namespace CryptoExchange.Net.Authentication
/// <summary>
/// Create Api credentials providing an api key and secret for authentication
/// </summary>
/// <param name="key">The api key used for identification</param>
/// <param name="secret">The api secret used for signing</param>
/// <param name="key">The api key / label used for identification</param>
/// <param name="secret">The api secret or private key used for signing</param>
/// <param name="credentialsType">The type of credentials</param>
public ApiCredentials(string key, string secret, ApiCredentialsType credentialsType)
{
+26 -1
View File
@@ -12,6 +12,28 @@ namespace CryptoExchange.Net.Clients
/// </summary>
public abstract class BaseClient : IDisposable
{
/// <summary>
/// Version of the CryptoExchange.Net base library
/// </summary>
public Version CryptoExchangeLibVersion { get; } = typeof(BaseClient).Assembly.GetName().Version;
/// <summary>
/// Version of the client implementation
/// </summary>
public Version ExchangeLibVersion
{
get
{
lock(_versionLock)
{
if (_exchangeVersion == null)
_exchangeVersion = GetType().Assembly.GetName().Version;
return _exchangeVersion;
}
}
}
/// <summary>
/// The name of the API the client is for
/// </summary>
@@ -27,6 +49,9 @@ namespace CryptoExchange.Net.Clients
/// </summary>
protected internal ILogger _logger;
private object _versionLock = new object();
private Version _exchangeVersion;
/// <summary>
/// Provided client options
/// </summary>
@@ -57,7 +82,7 @@ namespace CryptoExchange.Net.Clients
throw new ArgumentNullException(nameof(options));
ClientOptions = options;
_logger.Log(LogLevel.Trace, $"Client configuration: {options}, CryptoExchange.Net: v{typeof(BaseClient).Assembly.GetName().Version}, {Exchange}.Net: v{GetType().Assembly.GetName().Version}");
_logger.Log(LogLevel.Trace, $"Client configuration: {options}, CryptoExchange.Net: v{CryptoExchangeLibVersion}, {Exchange}.Net: v{ExchangeLibVersion}");
}
/// <summary>
@@ -57,6 +57,7 @@ namespace CryptoExchange.Net.Converters.SystemTextJson
var stringValue = reader.GetString();
if (string.IsNullOrWhiteSpace(stringValue)
|| stringValue == "-1"
|| stringValue == "0001-01-01T00:00:00Z"
|| double.TryParse(stringValue, out var doubleVal) && doubleVal == 0)
{
return default;
+7 -7
View File
@@ -6,9 +6,9 @@
<PackageId>CryptoExchange.Net</PackageId>
<Authors>JKorf</Authors>
<Description>CryptoExchange.Net is a base library which is used to implement different cryptocurrency (exchange) API's. It provides a standardized way of implementing different API's, which results in a very similar experience for users of the API implementations.</Description>
<PackageVersion>8.0.0</PackageVersion>
<AssemblyVersion>8.0.0</AssemblyVersion>
<FileVersion>8.0.0</FileVersion>
<PackageVersion>8.0.2</PackageVersion>
<AssemblyVersion>8.0.2</AssemblyVersion>
<FileVersion>8.0.2</FileVersion>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageTags>OKX;OKX.Net;Mexc;Mexc.Net;Kucoin;Kucoin.Net;Kraken;Kraken.Net;Huobi;Huobi.Net;CoinEx;CoinEx.Net;Bybit;Bybit.Net;Bitget;Bitget.Net;Bitfinex;Bitfinex.Net;Binance;Binance.Net;CryptoCurrency;CryptoCurrency Exchange</PackageTags>
<RepositoryType>git</RepositoryType>
@@ -52,12 +52,12 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.1" />
<PackageReference Include="System.Text.Json" Version="8.0.4" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
</ItemGroup>
</Project>
+10
View File
@@ -189,6 +189,16 @@ namespace CryptoExchange.Net
throw new ArgumentException($"No values provided for parameter {argumentName}", argumentName);
}
/// <summary>
/// Format a string to RFC3339/ISO8601 string
/// </summary>
/// <param name="dateTime"></param>
/// <returns></returns>
public static string ToRfc3339String(this DateTime dateTime)
{
return dateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fffzzz", DateTimeFormatInfo.InvariantInfo);
}
/// <summary>
/// Format an exception and inner exception to a readable string
/// </summary>
@@ -506,8 +506,11 @@ namespace CryptoExchange.Net.Sockets
}
if (processor is Subscription subscriptionProcessor && !subscriptionProcessor.Confirmed)
{
// If this message is for this listener then it is automatically confirmed, even if the subscription is not (yet) confirmed
subscriptionProcessor.Confirmed = true;
// This doesn't trigger a waiting subscribe query, should probably also somehow set the wait event for that
}
// 6. Deserialize the message
object? deserialized = null;
@@ -188,7 +188,7 @@ namespace CryptoExchange.Net.Testing.Comparers
{
if (propertyValue == default && propValue.Type != JTokenType.Null && !string.IsNullOrEmpty(propValue.ToString()))
{
if (propertyType == typeof(DateTime?) && (propValue.ToString() == "" || propValue.ToString() == "0" || propValue.ToString() == "-1"))
if (propertyType == typeof(DateTime?) && (propValue.ToString() == "" || propValue.ToString() == "0" || propValue.ToString() == "-1" || propValue.ToString() == "01/01/0001 00:00:00"))
return;
// Property value not correct
+15 -11
View File
@@ -5,17 +5,21 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Binance.Net" Version="9.7.1" />
<PackageReference Include="Bitfinex.Net" Version="7.2.2" />
<PackageReference Include="Bybit.Net" Version="3.7.1" />
<PackageReference Include="CoinEx.Net" Version="6.2.1" />
<PackageReference Include="Huobi.Net" Version="5.2.1" />
<PackageReference Include="JK.BingX.Net" Version="1.0.0" />
<PackageReference Include="JK.Bitget.Net" Version="1.3.1" />
<PackageReference Include="JK.OKX.Net" Version="1.7.1" />
<PackageReference Include="KrakenExchange.Net" Version="4.4.3" />
<PackageReference Include="Kucoin.Net" Version="5.3.2" />
<PackageReference Include="Serilog.AspNetCore" Version="6.0.0" />
<PackageReference Include="Binance.Net" Version="10.5.0" />
<PackageReference Include="Bitfinex.Net" Version="7.8.0" />
<PackageReference Include="BitMart.Net" Version="1.2.0" />
<PackageReference Include="Bybit.Net" Version="3.14.0" />
<PackageReference Include="CoinEx.Net" Version="7.7.0" />
<PackageReference Include="GateIo.Net" Version="1.6.0" />
<PackageReference Include="JK.BingX.Net" Version="1.11.0" />
<PackageReference Include="JK.Bitget.Net" Version="1.10.0" />
<PackageReference Include="JK.Mexc.Net" Version="1.8.0" />
<PackageReference Include="JK.OKX.Net" Version="2.4.0" />
<PackageReference Include="JKorf.Coinbase.Net" Version="1.0.0" />
<PackageReference Include="JKorf.HTX.Net" Version="6.1.0" />
<PackageReference Include="KrakenExchange.Net" Version="4.12.0" />
<PackageReference Include="Kucoin.Net" Version="5.14.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.2" />
</ItemGroup>
</Project>
+25 -5
View File
@@ -2,12 +2,16 @@
@inject IBinanceRestClient binanceClient
@inject IBingXRestClient bingXClient
@inject IBitfinexRestClient bitfinexClient
@inject IBitMartRestClient bitmartClient
@inject IBitgetRestClient bitgetClient
@inject IBybitRestClient bybitClient
@inject ICoinbaseRestClient coinbaseClient
@inject ICoinExRestClient coinexClient
@inject IHuobiRestClient huobiClient
@inject IGateIoRestClient gateioClient
@inject IHTXRestClient huobiClient
@inject IKrakenRestClient krakenClient
@inject IKucoinRestClient kucoinClient
@inject IMexcRestClient mexcClient
@inject IOKXRestClient okxClient
<h3>BTC-USD prices:</h3>
@@ -25,14 +29,18 @@
var bingXTask = bingXClient.SpotApi.ExchangeData.GetTickersAsync("BTC-USDT");
var bitfinexTask = bitfinexClient.SpotApi.ExchangeData.GetTickerAsync("tBTCUSD");
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 huobiTask = huobiClient.SpotApi.ExchangeData.GetTickerAsync("btcusdt");
var gateioTask = gateioClient.SpotApi.ExchangeData.GetTickersAsync("BTC_USDT");
var htxTask = huobiClient.SpotApi.ExchangeData.GetTickerAsync("btcusdt");
var krakenTask = krakenClient.SpotApi.ExchangeData.GetTickerAsync("XBTUSD");
var kucoinTask = kucoinClient.SpotApi.ExchangeData.GetTickerAsync("BTC-USDT");
var mexcTask = mexcClient.SpotApi.ExchangeData.GetTickerAsync("BTCUSDT");
var okxTask = okxClient.UnifiedApi.ExchangeData.GetTickerAsync("BTCUSDT");
await Task.WhenAll(binanceTask, bingXTask, bitfinexTask, bybitTask, coinexTask, huobiTask, krakenTask, kucoinTask);
await Task.WhenAll(binanceTask, bingXTask, bitfinexTask, bitgetTask, bitmartTask, bybitTask, coinexTask, gateioTask, htxTask, krakenTask, kucoinTask, mexcTask, okxTask);
if (binanceTask.Result.Success)
_prices.Add("Binance", binanceTask.Result.Data.LastPrice);
@@ -46,14 +54,23 @@
if (bitgetTask.Result.Success)
_prices.Add("Bitget", bitgetTask.Result.Data.ClosePrice);
if (bitmartTask.Result.Success)
_prices.Add("BitMart", bitgetTask.Result.Data.ClosePrice);
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);
if (huobiTask.Result.Success)
_prices.Add("Huobi", huobiTask.Result.Data.ClosePrice ?? 0);
if (gateioTask.Result.Success)
_prices.Add("GateIo", gateioTask.Result.Data.First().LastPrice);
if (htxTask.Result.Success)
_prices.Add("HTX", htxTask.Result.Data.ClosePrice ?? 0);
if (krakenTask.Result.Success)
_prices.Add("Kraken", krakenTask.Result.Data.First().Value.LastTrade.Price);
@@ -61,6 +78,9 @@
if (kucoinTask.Result.Success)
_prices.Add("Kucoin", kucoinTask.Result.Data.LastPrice ?? 0);
if (mexcTask.Result.Success)
_prices.Add("Mexc", mexcTask.Result.Data.LastPrice);
if (okxTask.Result.Success)
_prices.Add("OKX", okxTask.Result.Data.LastPrice ?? 0);
}
+10 -2
View File
@@ -3,11 +3,15 @@
@inject IBingXSocketClient bingXSocketClient
@inject IBitfinexSocketClient bitfinexSocketClient
@inject IBitgetSocketClient bitgetSocketClient
@inject IBitMartSocketClient bitmartSocketClient
@inject IBybitSocketClient bybitSocketClient
@inject ICoinbaseSocketClient coinbaseSocketClient
@inject ICoinExSocketClient coinExSocketClient
@inject IHuobiSocketClient huobiSocketClient
@inject IGateIoSocketClient gateioSocketClient
@inject IHTXSocketClient htxSocketClient
@inject IKrakenSocketClient krakenSocketClient
@inject IKucoinSocketClient kucoinSocketClient
@inject IMexcSocketClient mexcSocketClient
@inject IOKXSocketClient okxSocketClient
@using System.Collections.Concurrent
@using CryptoExchange.Net.Objects
@@ -33,11 +37,15 @@
bingXSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH-BTC", data => UpdateData("BingX", data.Data.LastPrice)),
bitfinexSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("tETHBTC", data => UpdateData("Bitfinex", data.Data.LastPrice)),
bitgetSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETHBTC", data => UpdateData("Bitget", data.Data.LastPrice)),
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)),
huobiSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ethbtc", data => UpdateData("Huobi", data.Data.ClosePrice ?? 0)),
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)),
kucoinSocketClient.SpotApi.SubscribeToTickerUpdatesAsync("ETH-BTC", data => UpdateData("Kucoin", data.Data.LastPrice ?? 0)),
mexcSocketClient.SpotApi.SubscribeToMiniTickerUpdatesAsync("ETHBTC", data => UpdateData("Mexc", data.Data.LastPrice)),
okxSocketClient.UnifiedApi.ExchangeData.SubscribeToTickerUpdatesAsync("ETH-BTC", data => UpdateData("OKX", data.Data.LastPrice ?? 0)),
};
+15 -3
View File
@@ -5,23 +5,31 @@
@using BingX.Net.Interfaces
@using Bitfinex.Net.Interfaces
@using Bitget.Net.Interfaces;
@using BitMart.Net.Interfaces;
@using Bybit.Net.Interfaces
@using CoinEx.Net.Interfaces
@using Coinbase.Net.Interfaces
@using CryptoExchange.Net.Interfaces
@using Huobi.Net.Interfaces
@using GateIo.Net.Interfaces
@using HTX.Net.Interfaces
@using Kraken.Net.Interfaces
@using Kucoin.Net.Clients
@using Kucoin.Net.Interfaces
@using Mexc.Net.Interfaces
@using OKX.Net.Interfaces;
@inject IBinanceOrderBookFactory binanceFactory
@inject IBingXOrderBookFactory bingXFactory
@inject IBitfinexOrderBookFactory bitfinexFactory
@inject IBitgetOrderBookFactory bitgetFactory
@inject IBitMartOrderBookFactory bitmartFactory
@inject IBybitOrderBookFactory bybitFactory
@inject ICoinbaseOrderBookFactory coinbaseFactory
@inject ICoinExOrderBookFactory coinExFactory
@inject IHuobiOrderBookFactory huobiFactory
@inject IGateIoOrderBookFactory gateioFactory
@inject IHTXOrderBookFactory htxFactory
@inject IKrakenOrderBookFactory krakenFactory
@inject IKucoinOrderBookFactory kucoinFactory
@inject IMexcOrderBookFactory mexcFactory
@inject IOKXOrderBookFactory okxFactory
@implements IDisposable
@@ -60,11 +68,15 @@
{ "BingX", bingXFactory.CreateSpot("ETH-BTC") },
{ "Bitfinex", bitfinexFactory.Create("tETHBTC") },
{ "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") },
{ "Huobi", huobiFactory.CreateSpot("ethbtc") },
{ "GateIo", gateioFactory.CreateSpot("ETH_BTC") },
{ "HTX", htxFactory.CreateSpot("ethbtc") },
{ "Kraken", krakenFactory.CreateSpot("ETH/XBT") },
{ "Kucoin", kucoinFactory.CreateSpot("ETH-BTC") },
{ "Mexc", mexcFactory.CreateSpot("ETHBTC") },
{ "OKX", okxFactory.Create("ETH-BTC") },
};
+8 -7
View File
@@ -1,5 +1,6 @@
@page "/SpotClient"
@inject ICryptoRestClient restClient
@using CryptoExchange.Net.SharedApis
@inject IEnumerable<ISpotTickerRestClient> restClients
<h3>ETH-BTC prices:</h3>
@foreach(var price in _prices.OrderBy(p => p.Key))
@@ -12,13 +13,13 @@
protected override async Task OnInitializedAsync()
{
var clients = restClient.GetSpotClients();
var tasks = clients.Select(c => (c.ExchangeName, c.GetTickerAsync(c.GetSymbolName("ETH", "BTC"))));
await Task.WhenAll(tasks.Select(t => t.Item2));
foreach(var task in tasks)
var symbol = new SharedSymbol(TradingMode.Spot, "ETH", "BTC");
var tasks = restClients.Select(x => x.GetSpotTickerAsync(new GetTickerRequest(symbol)));
await Task.WhenAll(tasks);
foreach (var ticker in tasks.Select(x => x.Result))
{
if(task.Item2.Result.Success)
_prices.Add(task.Item1, task.Item2.Result.Data.HighPrice);
if (ticker.Success)
_prices.Add(ticker.Exchange, ticker.Data.LastPrice);
}
}
+5 -1
View File
@@ -39,11 +39,15 @@ namespace BlazorClient
services.AddBingX();
services.AddBitfinex();
services.AddBitget();
services.AddBitMart();
services.AddBybit();
services.AddCoinbase();
services.AddCoinEx();
services.AddHuobi();
services.AddGateIo();
services.AddHTX();
services.AddKraken();
services.AddKucoin();
services.AddMexc();
services.AddOKX();
}
+5 -1
View File
@@ -12,10 +12,14 @@
@using BingX.Net.Interfaces.Clients;
@using Bitfinex.Net.Interfaces.Clients;
@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 Huobi.Net.Interfaces.Clients;
@using GateIo.Net.Interfaces.Clients;
@using HTX.Net.Interfaces.Clients;
@using Kraken.Net.Interfaces.Clients;
@using Kucoin.Net.Interfaces.Clients;
@using Mexc.Net.Interfaces.Clients;
@using OKX.Net.Interfaces.Clients;
@using CryptoExchange.Net.Interfaces;
+14 -11
View File
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
@@ -6,16 +6,19 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Binance.Net" Version="9.5.0" />
<PackageReference Include="Bitfinex.Net" Version="7.1.0" />
<PackageReference Include="Bittrex.Net" Version="8.0.3" />
<PackageReference Include="Bybit.Net" Version="3.4.0" />
<PackageReference Include="CoinEx.Net" Version="6.1.0" />
<PackageReference Include="Huobi.Net" Version="5.1.0" />
<PackageReference Include="JK.Bitget.Net" Version="1.1.0" />
<PackageReference Include="JK.OKX.Net" Version="1.6.0" />
<PackageReference Include="KrakenExchange.Net" Version="4.3.0" />
<PackageReference Include="Kucoin.Net" Version="5.2.0" />
<PackageReference Include="Binance.Net" Version="10.5.0" />
<PackageReference Include="Bitfinex.Net" Version="7.8.0" />
<PackageReference Include="BitMart.Net" Version="1.2.0" />
<PackageReference Include="Bybit.Net" Version="3.14.0" />
<PackageReference Include="CoinEx.Net" Version="7.7.0" />
<PackageReference Include="GateIo.Net" Version="1.6.0" />
<PackageReference Include="JK.Bitget.Net" Version="1.10.0" />
<PackageReference Include="JK.Mexc.Net" Version="1.8.0" />
<PackageReference Include="JK.OKX.Net" Version="2.4.0" />
<PackageReference Include="JKorf.Coinbase.Net" Version="1.0.0" />
<PackageReference Include="JKorf.HTX.Net" Version="6.1.0" />
<PackageReference Include="KrakenExchange.Net" Version="4.12.0" />
<PackageReference Include="Kucoin.Net" Version="5.14.0" />
</ItemGroup>
</Project>
-2
View File
@@ -4,12 +4,10 @@ using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Binance.Net.Clients;
using Binance.Net.Objects;
using Bybit.Net.Clients;
using ConsoleClient.Exchanges;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Objects.Sockets;
using CryptoExchange.Net.Sockets;
namespace ConsoleClient
{
+50
View File
@@ -0,0 +1,50 @@
using Binance.Net.Clients;
using BitMart.Net.Clients;
using CryptoExchange.Net.SharedApis;
using OKX.Net.Clients;
var symbol = new SharedSymbol(TradingMode.Spot, "ETH", "USDT");
var binanceSpotRestClient = new BinanceRestClient().SpotApi.SharedClient;
var okxSpotRestClient = new OKXRestClient().UnifiedApi.SharedClient;
var bitmartSpotRestClient = new BitMartRestClient().SpotApi.SharedClient;
var binanceSpotSocketClient = new BinanceSocketClient().SpotApi.SharedClient;
var okxSpotSocketClient = new OKXSocketClient().UnifiedApi.SharedClient;
var bitmartSpotSocketClient = new BitMartSocketClient().SpotApi.SharedClient;
await GetLastTradePriceAsync(binanceSpotRestClient, symbol);
await GetLastTradePriceAsync(okxSpotRestClient, symbol);
await GetLastTradePriceAsync(bitmartSpotRestClient, symbol);
Console.WriteLine();
Console.WriteLine("Press enter to start websocket");
Console.ReadLine();
await SubscribeTickerUpdatesAsync(binanceSpotSocketClient, symbol);
await SubscribeTickerUpdatesAsync(okxSpotSocketClient, symbol);
await SubscribeTickerUpdatesAsync(bitmartSpotSocketClient, symbol);
Console.ReadLine();
async Task GetLastTradePriceAsync(ISpotTickerRestClient client, SharedSymbol symbol)
{
var result = await client.GetSpotTickerAsync(new GetTickerRequest(symbol));
if (!result.Success)
{
Console.WriteLine($"Failed to get ticker: {result.Error}");
return;
}
Console.WriteLine($"{client.Exchange} {result.Data.Symbol}: {result.Data.LastPrice}");
}
async Task SubscribeTickerUpdatesAsync(ITickerSocketClient client, SharedSymbol symbol)
{
var result = await client.SubscribeToTickerUpdatesAsync(new SubscribeTickerRequest(symbol), update =>
{
Console.WriteLine($"{client.Exchange} {update.Data.Symbol} {update.Data.LastPrice}");
});
if (!result.Success)
Console.WriteLine($"Failed to subscribe ticker: {result.Error}");
}
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Binance.Net" Version="10.5.0" />
<PackageReference Include="BitMart.Net" Version="1.2.0" />
<PackageReference Include="JK.OKX.Net" Version="2.4.0" />
</ItemGroup>
</Project>
+11 -2
View File
@@ -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.
@@ -47,8 +48,16 @@ Make a one time donation in a crypto currency of your choice. If you prefer to d
Alternatively, sponsor me on Github using [Github Sponsors](https://github.com/sponsors/JKorf).
## Release notes
* Version 8.0.2 - 09 Oct 2024
* Updated dependency versions, including System.Text.Json from 8.0.4 to 8.0.5 containing a vulnerability fix
* Version 8.0.1 - 07 Oct 2024
* Added cached library version properties on base client
* Added support for derserializing 0001-01-01 as datetime null value
* 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
+212 -4
View File
@@ -151,6 +151,7 @@
<tr><td>Bitget</td><td><a href="https://github.com/JKorf/Bitget.Net">JKorf/Bitget.Net</a></td><td><a href="https://www.nuget.org/packages/JK.Bitget.Net" target="_blank"><img src="https://img.shields.io/nuget/v/JK.Bitget.net.svg?style=flat-square" /></a></td></tr>
<tr><td>BitMart</td><td><a href="https://github.com/JKorf/BitMart.Net">JKorf/BitMart.Net</a></td><td><a href="https://www.nuget.org/packages/BitMart.Net" target="_blank"><img src="https://img.shields.io/nuget/v/BitMart.net.svg?style=flat-square" /></a></td></tr>
<tr><td>Bybit</td><td><a href="https://github.com/JKorf/Bybit.Net">JKorf/Bybit.Net</a></td><td><a href="https://www.nuget.org/packages/Bybit.Net" target="_blank"><img src="https://img.shields.io/nuget/v/Bybit.net.svg?style=flat-square" /></a></td></tr>
<tr><td>Coinbase</td><td><a href="https://github.com/JKorf/Coinbase.Net">JKorf/Coinbase.Net</a></td><td><a href="https://www.nuget.org/packages/JKorf.Coinbase.Net" target="_blank"><img src="https://img.shields.io/nuget/v/JKorf.Coinbase.net.svg?style=flat-square" /></a></td></tr>
<tr><td>CoinEx</td><td><a href="https://github.com/JKorf/CoinEx.Net">JKorf/CoinEx.Net</a></td><td><a href="https://www.nuget.org/packages/CoinEx.Net" target="_blank"><img src="https://img.shields.io/nuget/v/CoinEx.net.svg?style=flat-square" /></a></td></tr>
<tr><td>CoinGecko</td><td><a href="https://github.com/JKorf/CoinGecko.Net">JKorf/CoinGecko.Net</a></td><td><a href="https://www.nuget.org/packages/CoinGecko.Net" target="_blank"><img src="https://img.shields.io/nuget/v/CoinGecko.net.svg?style=flat-square" /></a></td></tr>
<tr><td>Gate.io</td><td><a href="https://github.com/JKorf/GateIo.Net">JKorf/GateIo.Net</a></td><td><a href="https://www.nuget.org/packages/GateIo.Net" target="_blank"><img src="https://img.shields.io/nuget/v/GateIo.net.svg?style=flat-square" /></a></td></tr>
@@ -242,10 +243,13 @@
<a class="nav-link" id="install-bybit-tab" data-toggle="tab" href="#install-bybit" role="tab" aria-controls="install-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="install-coingecko-tab" data-toggle="tab" href="#install-coingecko" role="tab" aria-controls="install-coingecko" aria-selected="false">CoinGecko</a>
<a class="nav-link" id="install-coinbase-tab" data-toggle="tab" href="#install-coinbase" role="tab" aria-controls="install-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="install-coinex-tab" data-toggle="tab" href="#install-coinex" role="tab" aria-controls="install-coinex" aria-selected="false">Coinex</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="install-coingecko-tab" data-toggle="tab" href="#install-coingecko" role="tab" aria-controls="install-coingecko" aria-selected="false">CoinGecko</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="install-gateio-tab" data-toggle="tab" href="#install-gateio" role="tab" aria-controls="install-gateio" aria-selected="false">GateIo</a>
@@ -296,6 +300,9 @@
<pre><code>dotnet add package CoinGecko.Net</code></pre>
<img src="assets/images/CoinGeckoInstall.png" />
</div>
<div class="tab-pane fade" id="install-coinbase" role="tabpanel" aria-labelledby="install-coinbase-tab">
<pre><code>dotnet add package JKorf.Coinbase.Net</code></pre>
</div>
<div class="tab-pane fade" id="install-coinex" role="tabpanel" aria-labelledby="install-coinex-tab">
<pre><code>dotnet add package CoinEx.Net</code></pre>
<img src="assets/images/CoinExInstall.png" />
@@ -357,6 +364,9 @@
<li class="nav-item" role="presentation">
<a class="nav-link" id="di-bybit-tab" data-toggle="tab" href="#di-bybit" role="tab" aria-controls="di-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="di-coinbase-tab" data-toggle="tab" href="#di-coinbase" role="tab" aria-controls="di-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="di-coingecko-tab" data-toggle="tab" href="#di-coingecko" role="tab" aria-controls="di-coingecko" aria-selected="false">CoinGecko</a>
</li>
@@ -403,6 +413,9 @@
</div>
<div class="tab-pane fade" id="di-bybit" role="tabpanel" aria-labelledby="di-bybit-tab">
<pre><code>builder.Services.AddBybit();</code></pre>
</div>
<div class="tab-pane fade" id="di-coinbase" role="tabpanel" aria-labelledby="di-coinbase-tab">
<pre><code>builder.Services.AddCoinbase();</code></pre>
</div>
<div class="tab-pane fade" id="di-coingecko" role="tabpanel" aria-labelledby="di-coingecko-tab">
<pre><code>builder.Services.AddCoinGecko();</code></pre>
@@ -455,6 +468,9 @@
<li class="nav-item" role="presentation">
<a class="nav-link" id="interfaces-bybit-tab" data-toggle="tab" href="#interfaces-bybit" role="tab" aria-controls="interfaces-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="interfaces-coinbase-tab" data-toggle="tab" href="#interfaces-coinbase" role="tab" aria-controls="interfaces-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="interfaces-coingecko-tab" data-toggle="tab" href="#interfaces-coingecko" role="tab" aria-controls="interfaces-coingecko" aria-selected="false">CoinGecko</a>
</li>
@@ -688,6 +704,35 @@
</tr>
</table>
</div>
<div class="tab-pane fade" id="interfaces-coinbase" role="tabpanel" aria-labelledby="interfaces-coinbase-tab">
<table class="table table-bordered">
<tr><th>Interface</th><th>Description</th></tr>
<tr>
<td><code>ICoinbaseRestClient</code></td>
<td>The client for accessing the Coinbase REST API</td>
</tr>
<tr>
<td><code>ICoinbaseSocketClient</code></td>
<td>The client for accessing the Coinbase Websocket API</td>
</tr>
<tr>
<td><code>ICoinbaseOrderBookFactory</code></td>
<td>A factory for creating SymbolOrderBook instances for the Coinbase API</td>
</tr>
<tr>
<td><code>ICryptoRestClient</code></td>
<td>An aggregating client from which multiple different library REST clients can be accessed</td>
</tr>
<tr>
<td><code>ICryptoSocketClient</code></td>
<td>An aggregating client from which multiple different library Websocket clients can be accessed</td>
</tr>
<tr>
<td><code>ISharedClient</code></td>
<td>Various interfaces deriving from ISharedClient which can be used for common functionality</td>
</tr>
</table>
</div>
<div class="tab-pane fade" id="interfaces-coingecko" role="tabpanel" aria-labelledby="interfaces-coingecko-tab">
<table class="table table-bordered">
<tr><th>Interface</th><th>Description</th></tr>
@@ -949,6 +994,9 @@
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="rest-bybit-tab" data-toggle="tab" href="#rest-bybit" role="tab" aria-controls="rest-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="rest-coinbase-tab" data-toggle="tab" href="#rest-coinbase" role="tab" aria-controls="rest-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="rest-coingecko-tab" data-toggle="tab" href="#rest-coingecko" role="tab" aria-controls="rest-coingecko" aria-selected="false">CoinGecko</a>
@@ -1056,6 +1104,18 @@ if (!tickersResult.Success)
// Handle error, tickersResult.Error contains more information
}
else
{
// Handle data, tickersResult.Data will contain the actual data
}</code></pre>
</div>
<div class="tab-pane fade" id="rest-coinbase" role="tabpanel" aria-labelledby="rest-coinbase-tab">
<pre><code>var client = new CoinbaseRestClient();
var tickersResult = await client.AdvancedTradeApi.ExchangeData.GetSymbolsAsync();
if (!tickersResult.Success)
{
// Handle error, tickersResult.Error contains more information
}
else
{
// Handle data, tickersResult.Data will contain the actual data
}</code></pre>
@@ -1251,6 +1311,9 @@ else
<li class="nav-item" role="presentation">
<a class="nav-link" id="socket-bybit-tab" data-toggle="tab" href="#socket-bybit" role="tab" aria-controls="socket-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="socket-coinbase-tab" data-toggle="tab" href="#socket-coinbase" role="tab" aria-controls="socket-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="socket-coinex-tab" data-toggle="tab" href="#socket-coinex" role="tab" aria-controls="socket-coinex" aria-selected="false">Coinex</a>
</li>
@@ -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</code></pre>
</div>
<div class="tab-pane fade" id="socket-coinbase" role="tabpanel" aria-labelledby="socket-coinbase-tab">
<pre><code>var client = new CoinbaseSocketClient();
var subscribeResult = await sclient.AdvancedTradeApi.SubscribeToTickerUpdatesAsync("ETH-USDT", 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</code></pre>
</div>
<div class="tab-pane fade" id="socket-coinex" role="tabpanel" aria-labelledby="socket-coinex-tab">
@@ -1598,6 +1672,9 @@ var binanceTriggered = CheckForTrigger(lastBinanceTicker);</code></pre>
<li class="nav-item" role="presentation">
<a class="nav-link" id="shared-bybit-tab" data-toggle="tab" href="#shared-bybit" role="tab" aria-controls="shared-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="shared-coinbase-tab" data-toggle="tab" href="#shared-coinbase" role="tab" aria-controls="shared-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="shared-coinex-tab" data-toggle="tab" href="#shared-coinex" role="tab" aria-controls="shared-coinex" aria-selected="false">Coinex</a>
</li>
@@ -1702,6 +1779,13 @@ var inverseFuturesspotSharedSocketClient = bybitSocketClient.V5InverseApi.Shared
// Private Futures API common functionality socket client
var privateFuturesSharedSocketClient = bybitSocketClient.V5PrivateApi.SharedClient;</code></pre>
</div>
<div class="tab-pane fade" id="shared-coinbase" role="tabpanel" aria-labelledby="shared-coinbase-tab">
<pre><code>// Advanced Trade API common functionality rest client
var spotSharedRestClients = coinbaseRestClient.AdvancedTradeApi.SharedClient;
// Advanced Trade API common functionality socket client
var spotSharedSocketClient = coinbaseSocketClient.AdvancedTradeApi.SharedClient;</code></pre>
</div>
<div class="tab-pane fade" id="shared-coinex" role="tabpanel" aria-labelledby="shared-coinex-tab">
<pre><code>// Spot API common functionality rest client
var spotSharedRestClients = coinExRestClient.SpotApiV2.SharedClient;
@@ -1859,7 +1943,26 @@ while (true)
<pre><code>await foreach (var pageResult in ExchangeHelpers.ExecutePages(client.GetClosedFuturesOrdersAsync, new GetClosedOrdersRequest(symbol, limit: 2)))
Console.WriteLine($"{pageResult.Data.Count()} items");</code></pre>
<h4 id="shared_parameters">Optional and exchange specific parameters</h4>
<p>Not all exchanges require the same parameters. Some parameters are defined on the request model, but only required for specific exchanges. For example a <code>listenKey</code> parameter when subscribing to a user stream. When not provided for an exchange that needs it an <code>ArgumentError</code> will be returned.</p>
<p>Other parameters are not defined on the request model at all because they're very specific to a single exchange. For example the <code>AccountId</code> parameter for Spot authenticated requests on HTX. To not pollute the request models with every single possible parameter for each single exchange there is an <code>ExchangeParameters</code> structure to provide these values.</p>
<pre><code>// Set as static parameter, automatically used if not overridden
ExchangeParameters.SetStaticParameter("HTX", "AccountId", 123123123);
var balances1 = await restClient.HTX.SpotApi.SharedClient.GetBalancesAsync(new GetBalancesRequest());
// Specify exchange parameters for a request
var exchangeParameters = new ExchangeParameters(new ExchangeParameter("HTX", "AccountId", 456456456));
var balances = await restClient.HTX.SpotApi.SharedClient.GetBalancesAsync(new GetBalancesRequest(exchangeParameters: exchangeParameters));</code></pre>
<p>To determine which parameters are required for an exchange request either inspect the ArgmumentError when the call fails, or output the request info:</p>
<pre><code>Console.WriteLine(restClient.HTX.SpotApi.SharedClient.GetBalancesOptions.ToString(Exchange.HTX));
// Output:
// HTX GetBalancesRequest
// Needs authentication: True
// Required exchange specific parameters: [Int64] AccountId: Account id of the user | example: 123123123</code></pre>
<h4 id="shared_interfaces">Available Interfaces</h4>
<p>Available REST shared interfaces</p>
@@ -2014,6 +2117,9 @@ options.ApiCredentials = new ApiCredentials("YOUR PUBLIC KEY", "YOUR PRIVATE KEY
<li class="nav-item" role="presentation">
<a class="nav-link" id="options-bybit-tab" data-toggle="tab" href="#options-bybit" role="tab" aria-controls="options-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="options-coinbase-tab" data-toggle="tab" href="#options-coinbase" role="tab" aria-controls="options-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="options-coingecko-tab" data-toggle="tab" href="#options-coingecko" role="tab" aria-controls="options-coingecko" aria-selected="false">CoinGecko</a>
</li>
@@ -2096,6 +2202,15 @@ options.ApiCredentials = new ApiCredentials("YOUR PUBLIC KEY", "YOUR PRIVATE KEY
</div>
<div class="tab-pane fade" id="options-bybit" role="tabpanel" aria-labelledby="options-bybit-tab">
<pre><code>builder.Services.AddBybit(
restOptions => {
restOptions.RequestTimeout = TimeSpan.FromSeconds(30);
},
socketOptions => {
socketOptions.RequestTimeout = TimeSpan.FromSeconds(10);
});</code></pre>
</div>
<div class="tab-pane fade" id="options-coinbase" role="tabpanel" aria-labelledby="options-coinbase-tab">
<pre><code>builder.Services.AddCoinbase(
restOptions => {
restOptions.RequestTimeout = TimeSpan.FromSeconds(30);
},
@@ -2200,6 +2315,9 @@ options.ApiCredentials = new ApiCredentials("YOUR PUBLIC KEY", "YOUR PRIVATE KEY
<li class="nav-item" role="presentation">
<a class="nav-link" id="options-bybit-tab" data-toggle="tab" href="#options-constr-bybit" role="tab" aria-controls="options-constr-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="options-coinbase-tab" data-toggle="tab" href="#options-constr-coinbase" role="tab" aria-controls="options-constr-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="options-coingecko-tab" data-toggle="tab" href="#options-constr-coingecko" role="tab" aria-controls="options-constr-coingecko" aria-selected="false">CoinGecko</a>
</li>
@@ -2264,6 +2382,12 @@ options.ApiCredentials = new ApiCredentials("YOUR PUBLIC KEY", "YOUR PRIVATE KEY
</div>
<div class="tab-pane fade" id="options-constr-bybit" role="tabpanel" aria-labelledby="options-bybit-tab">
<pre><code>var client = new BybitRestClient(opts =>
{
opts.RequestTimeout = TimeSpan.FromSeconds(30);
});</code></pre>
</div>
<div class="tab-pane fade" id="options-constr-coinbase" role="tabpanel" aria-labelledby="options-coinbase-tab">
<pre><code>var client = new CoinbaseRestClient(opts =>
{
opts.RequestTimeout = TimeSpan.FromSeconds(30);
});</code></pre>
@@ -2341,6 +2465,9 @@ options.ApiCredentials = new ApiCredentials("YOUR PUBLIC KEY", "YOUR PRIVATE KEY
<li class="nav-item" role="presentation">
<a class="nav-link" id="options-bybit-tab" data-toggle="tab" href="#options-default-bybit" role="tab" aria-controls="options-default-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="options-coinbase-tab" data-toggle="tab" href="#options-default-coinbase" role="tab" aria-controls="options-default-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="options-coingecko-tab" data-toggle="tab" href="#options-default-coingecko" role="tab" aria-controls="options-default-coingecko" aria-selected="false">CoinGecko</a>
</li>
@@ -2408,6 +2535,13 @@ var client = new BitMartRestClient();</code></pre>
options.RequestTimeout = TimeSpan.FromSeconds(30);
});
var client = new BybitRestClient();</code></pre>
</div>
<div class="tab-pane fade" id="options-default-coinbase" role="tabpanel" aria-labelledby="options-coinbase-tab">
<pre><code>CoinbaseClient.SetDefaultOptions(options =>
{
options.RequestTimeout = TimeSpan.FromSeconds(30);
});
var client = new CoinbaseRestClient();</code></pre>
</div>
<div class="tab-pane fade" id="options-default-coingecko" role="tabpanel" aria-labelledby="options-coingecko-tab">
<pre><code>CoinGeckoRestClient.SetDefaultOptions(options =>
@@ -2669,6 +2803,9 @@ var client = new OKXRestClient();</code></pre>
<li class="nav-item" role="presentation">
<a class="nav-link" id="book-bybit-tab" data-toggle="tab" href="#book-bybit" role="tab" aria-controls="book-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="book-coinbase-tab" data-toggle="tab" href="#book-coinbase" role="tab" aria-controls="book-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="book-coinex-tab" data-toggle="tab" href="#book-coinex" role="tab" aria-controls="book-coinex" aria-selected="false">Coinex</a>
</li>
@@ -2780,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();
</code></pre>
</div>
<div class="tab-pane fade" id="book-coinbase" role="tabpanel" aria-labelledby="book-coinbase-tab">
<pre><code>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();
</code></pre>
@@ -3050,6 +3200,9 @@ var binanceClient = new BinanceRestClient(new HttpClient(), logFactory, options
<li class="nav-item" role="presentation">
<a class="nav-link" id="limit-bitmart-tab" data-toggle="tab" href="#limit-bitmart" role="tab" aria-controls="limit-bitmart" aria-selected="false">BitMart</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="limit-coinbase-tab" data-toggle="tab" href="#limit-coinbase" role="tab" aria-controls="limit-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="limit-gateio-tab" data-toggle="tab" href="#limit-gateio" role="tab" aria-controls="limit-gateio" aria-selected="false">GateIo</a>
</li>
@@ -3136,6 +3289,20 @@ var binanceClient = new BinanceRestClient(new HttpClient(), logFactory, options
<p>To be notified of when a rate limit is hit the static <code>BitMartExchange.RateLimiter</code> exposes an event which triggers when a rate limit is reached</p>
<pre><code>BitMartExchange.RateLimiter.RateLimitTriggered += (rateLimitEvent) => Console.WriteLine("Limit triggered: " + rateLimitEvent);
</code></pre>
</div>
<div class="tab-pane fade" id="limit-coinbase" role="tabpanel" aria-labelledby="limit-coinbase-tab">
<pre><code>services.AddCoinbase(x =>
x.RatelimiterEnabled = true;
x.RateLimitingBehaviour = RateLimitingBehaviour.Wait;
}, x =>
{
x.RatelimiterEnabled = true;
x.RateLimitingBehaviour = RateLimitingBehaviour.Wait;
});</code></pre>
<p>To be notified of when a rate limit is hit the static <code>CoinbaseExchange.RateLimiter</code> exposes an event which triggers when a rate limit is reached</p>
<pre><code>CoinbaseExchange.RateLimiter.RateLimitTriggered += (rateLimitEvent) => Console.WriteLine("Limit triggered: " + rateLimitEvent);
</code></pre>
</div>
<div class="tab-pane fade" id="limit-gateio" role="tabpanel" aria-labelledby="limit-gateio-tab">
@@ -3298,6 +3465,9 @@ var responseSource = result.DataSource;</code></pre>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-symbols-bybit-tab" data-toggle="tab" href="#example-symbols-bybit" role="tab" aria-controls="example-symbols-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-symbols-coinbase-tab" data-toggle="tab" href="#example-symbols-coinbase" role="tab" aria-controls="example-symbols-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-symbols-coinex-tab" data-toggle="tab" href="#example-symbols-coinex" role="tab" aria-controls="example-symbols-coinex" aria-selected="false">Coinex</a>
</li>
@@ -3342,6 +3512,9 @@ await exchangeRestClient.Binance.SpotApi.ExchangeData.GetExchangeInfoAsync();</c
</div>
<div class="tab-pane fade" id="example-symbols-bybit" role="tabpanel" aria-labelledby="example-symbols-bybit-tab">
<pre><code>await bybitClient.V5Api.ExchangeData.GetSpotSymbolsAsync();</code></pre>
</div>
<div class="tab-pane fade" id="example-symbols-coinbase" role="tabpanel" aria-labelledby="example-symbols-coinbase-tab">
<pre><code>await coinbaseClient.AdvancedTradeApi.ExchangeData.GetSymbolsAsync();</code></pre>
</div>
<div class="tab-pane fade" id="example-symbols-coinex" role="tabpanel" aria-labelledby="example-symbols-coinex-tab">
<pre><code>await coinExClient.SpotApiV2.ExchangeData.GetSymbolsAsync();</code></pre>
@@ -3403,6 +3576,9 @@ await exchangeRestClient.Binance.SpotApi.ExchangeData.GetExchangeInfoAsync();</c
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-ticker-bybit-tab" data-toggle="tab" href="#example-ticker-bybit" role="tab" aria-controls="example-ticker-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-ticker-coinbase-tab" data-toggle="tab" href="#example-ticker-coinbase" role="tab" aria-controls="example-ticker-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-ticker-coinex-tab" data-toggle="tab" href="#example-ticker-coinex" role="tab" aria-controls="example-ticker-coinex" aria-selected="false">Coinex</a>
</li>
@@ -3447,6 +3623,10 @@ await exchangeRestClient.Binance.SpotApi.ExchangeData.GetTickerAsync(spotClient.
</div>
<div class="tab-pane fade" id="example-ticker-bybit" role="tabpanel" aria-labelledby="example-ticker-bybit-tab">
<pre><code>await bybitClient.V5Api.ExchangeData.GetSpotTickersAsync("BTCUSDT");</code></pre>
</div>
<div class="tab-pane fade" id="example-ticker-coinbase" role="tabpanel" aria-labelledby="example-ticker-coinbase-tab">
<pre><code>// Symbol endpoint and ticker endpoints are combined for Coinbase
await coinbaseClient.AdvancedTradeApi.ExchangeData.GetSymbolAsync("BTC-USDT");</code></pre>
</div>
<div class="tab-pane fade" id="example-ticker-coinex" role="tabpanel" aria-labelledby="example-ticker-coinex-tab">
<pre><code>await coinExClient.SpotApiV2.ExchangeData.GetTickersAsync(new[] { "BTCUSDT" });</code></pre>
@@ -3508,6 +3688,9 @@ await exchangeRestClient.Binance.SpotApi.ExchangeData.GetTickerAsync(spotClient.
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-balances-bybit-tab" data-toggle="tab" href="#example-balances-bybit" role="tab" aria-controls="example-balances-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-balances-coinbase-tab" data-toggle="tab" href="#example-balances-coinbase" role="tab" aria-controls="example-balances-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-balances-coinex-tab" data-toggle="tab" href="#example-balances-coinex" role="tab" aria-controls="example-balances-coinex" aria-selected="false">Coinex</a>
</li>
@@ -3552,6 +3735,9 @@ await exchangeRestClient.Binance.SpotApi.Account.GetBalancesAsync();</code></pre
</div>
<div class="tab-pane fade" id="example-balances-bybit" role="tabpanel" aria-labelledby="example-balances-bybit-tab">
<pre><code>await bybitClient.V5Api.Account.GetBalancesAsync(AccountType.Spot);</code></pre>
</div>
<div class="tab-pane fade" id="example-balances-coinbase" role="tabpanel" aria-labelledby="example-balances-coinbase-tab">
<pre><code>await coinbaseClient.AdvancedTradeApi.Account.GetAccountsAsync();</code></pre>
</div>
<div class="tab-pane fade" id="example-balances-coinex" role="tabpanel" aria-labelledby="example-balances-coinex-tab">
<pre><code>await coinExClient.SpotApiV2.Account.GetBalancesAsync();</code></pre>
@@ -3617,6 +3803,9 @@ var result = await htxClient.SpotApi.Account.GetBalancesAsync();</code></pre>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-place-bybit-tab" data-toggle="tab" href="#example-place-bybit" role="tab" aria-controls="example-place-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-place-coinbase-tab" data-toggle="tab" href="#example-place-coinbase" role="tab" aria-controls="example-place-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-place-coinex-tab" data-toggle="tab" href="#example-place-coinex" role="tab" aria-controls="example-place-coinex" aria-selected="false">Coinex</a>
</li>
@@ -3661,6 +3850,9 @@ await exchangeRestClient.Binance.SpotApi.Trading.PlaceOrderAsync("BTCUSDT", Orde
</div>
<div class="tab-pane fade" id="example-place-bybit" role="tabpanel" aria-labelledby="example-place-bybit-tab">
<pre><code>await bybitClient.V5Api.Trading.PlaceOrderAsync(Category.Spot, "BTCUSDT", OrderSide.Buy, NewOrderType.Limit, 0.1m, price: 50000);</code></pre>
</div>
<div class="tab-pane fade" id="example-place-coinbase" role="tabpanel" aria-labelledby="example-place-coinbase-tab">
<pre><code>await coinbaseClient.AdvancedTradeApi.Trading.PlaceOrderAsync("BTC-USDT", OrderSide.Buy, NewOrderType.Limit, 0.1m, price: 50000);</code></pre>
</div>
<div class="tab-pane fade" id="example-place-coinex" role="tabpanel" aria-labelledby="example-place-coinex-tab">
<pre><code>await coinExClient.SpotApiV2.Trading.PlaceOrderAsync("BTCUSDT", AccountType.Spot, OrderSide.Buy, OrderTypeV2.Limit, 0.1m, 50000);</code></pre>
@@ -3726,6 +3918,9 @@ var result = await htxClient.SpotApi.Trading.PlaceOrderAsync(account.Id, "BTCUSD
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-stream-ticker-bybit-tab" data-toggle="tab" href="#example-stream-ticker-bybit" role="tab" aria-controls="example-stream-ticker-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-stream-ticker-coinbase-tab" data-toggle="tab" href="#example-stream-ticker-coinbase" role="tab" aria-controls="example-stream-ticker-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-stream-ticker-coinex-tab" data-toggle="tab" href="#example-stream-ticker-coinex" role="tab" aria-controls="example-stream-ticker-coinex" aria-selected="false">Coinex</a>
</li>
@@ -3783,6 +3978,11 @@ await exchangeSocketClient.Binance.SpotApi.ExchangeData.SubscribeToTickerUpdates
<div class="tab-pane fade" id="example-stream-ticker-bybit" role="tabpanel" aria-labelledby="example-stream-ticker-bybit-tab">
<pre><code>await bybitSocketClient.V5SpotApi.SubscribeToTickerUpdatesAsync("ETHUSDT", data => {
// Handle update
});</code></pre>
</div>
<div class="tab-pane fade" id="example-stream-ticker-coinbase" role="tabpanel" aria-labelledby="example-stream-ticker-coinbase-tab">
<pre><code>await coinbaseSocketClient.AdvancedTradeApi.SubscribeToTickerUpdatesAsync("ETH-USDT", data => {
// Handle update
});</code></pre>
</div>
<div class="tab-pane fade" id="example-stream-ticker-coinex" role="tabpanel" aria-labelledby="example-stream-ticker-coinex-tab">
@@ -3860,6 +4060,9 @@ await exchangeSocketClient.Binance.SpotApi.ExchangeData.SubscribeToTickerUpdates
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-stream-order-bybit-tab" data-toggle="tab" href="#example-stream-order-bybit" role="tab" aria-controls="example-stream-order-bybit" aria-selected="false">Bybit</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-stream-order-coinbase-tab" data-toggle="tab" href="#example-stream-order-coinbase" role="tab" aria-controls="example-stream-order-coinbase" aria-selected="false">Coinbase</a>
</li>
<li class="nav-item" role="presentation">
<a class="nav-link" id="example-stream-order-coinex-tab" data-toggle="tab" href="#example-stream-order-coinex" role="tab" aria-controls="example-stream-order-coinex" aria-selected="false">Coinex</a>
</li>
@@ -3960,6 +4163,11 @@ _ = Task.Run(async () => {
<div class="tab-pane fade" id="example-stream-order-bybit" role="tabpanel" aria-labelledby="example-stream-order-bybit-tab">
<pre><code>await bybitSocketClient.V5PrivateApi.SubscribeToOrderUpdatesAsync(data => {
// Handle update
});</code></pre>
</div>
<div class="tab-pane fade" id="example-stream-order-coinbase" role="tabpanel" aria-labelledby="example-stream-order-coinbase-tab">
<pre><code>await coinbaseSocketClient.AdvancedTradeApi.SubscribeToUserUpdatesAsync(data => {
// Handle update
});</code></pre>
</div>
<div class="tab-pane fade" id="example-stream-order-coinex" role="tabpanel" aria-labelledby="example-stream-order-coinex-tab">
@@ -4024,7 +4232,7 @@ _ = Task.Run(async () => {
<b id="idocs_example_minimal">Minimal API</b><br />
<p>A minimal API example allowing the caller to retrieve ticker information for a specific exchange and asset pair<br />
<p>A minimal API example allowing the caller to retrieve ticker information for a specific exchange and asset pair. This is using the <code>CryptoClient.Net</code> Nuget package.<br />
<div class="accordion" id="accordionMinimalApi">
<div class="card">
<div class="card-header" id="headingMinimalApi">
@@ -4047,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;
});