diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml
index 53dfbca3..53d08e4e 100644
--- a/.github/workflows/dotnet.yml
+++ b/.github/workflows/dotnet.yml
@@ -16,7 +16,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
- dotnet-version: 8.0.x
+ dotnet-version: 9.0.x
- name: Set GitHub package source
run: dotnet nuget add source --username JKorf --password ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text --name github "https://nuget.pkg.github.com/JKorf/index.json"
- name: Restore dependencies
diff --git a/ByBit.Net/Bybit.Net.csproj b/ByBit.Net/Bybit.Net.csproj
index 8f0e2038..ea43aeef 100644
--- a/ByBit.Net/Bybit.Net.csproj
+++ b/ByBit.Net/Bybit.Net.csproj
@@ -48,7 +48,7 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/ByBit.Net/Clients/BybitRestClient.cs b/ByBit.Net/Clients/BybitRestClient.cs
index ef95bd7f..4b735a48 100644
--- a/ByBit.Net/Clients/BybitRestClient.cs
+++ b/ByBit.Net/Clients/BybitRestClient.cs
@@ -12,6 +12,7 @@
using Microsoft.Extensions.Logging;
using CryptoExchange.Net.Clients;
using Microsoft.Extensions.Options;
+using CryptoExchange.Net.Objects.Options;
namespace Bybit.Net.Clients
{
@@ -56,6 +57,15 @@ public BybitRestClient(HttpClient? httpClient, ILoggerFactory? loggerFactory, IO
#endregion
+ ///
+ public void SetOptions(UpdateOptions options)
+ {
+ SpotApiV3.SetOptions(options);
+ CopyTradingApi.SetOptions(options);
+ DerivativesApi.SetOptions(options);
+ V5Api.SetOptions(options);
+ }
+
///
/// Set the default options to be used when creating new clients
///
diff --git a/ByBit.Net/Clients/BybitSocketClient.cs b/ByBit.Net/Clients/BybitSocketClient.cs
index 35fc312e..d62103f2 100644
--- a/ByBit.Net/Clients/BybitSocketClient.cs
+++ b/ByBit.Net/Clients/BybitSocketClient.cs
@@ -15,6 +15,7 @@
using Bybit.Net.Clients.SpotApi.v3;
using CryptoExchange.Net.Clients;
using Microsoft.Extensions.Options;
+using CryptoExchange.Net.Objects.Options;
namespace Bybit.Net.Clients
{
@@ -71,6 +72,20 @@ public BybitSocketClient(IOptions options, ILoggerFactory? l
V5PrivateApi = AddApiClient(new BybitSocketClientPrivateApi(_logger, options.Value));
}
+ ///
+ public void SetOptions(UpdateOptions options)
+ {
+ SpotV3Api.SetOptions(options);
+ DerivativesApi.SetOptions(options);
+ UnifiedMarginApi.SetOptions(options);
+ ContractApi.SetOptions(options);
+ V5SpotApi.SetOptions(options);
+ V5InverseApi.SetOptions(options);
+ V5LinearApi.SetOptions(options);
+ V5OptionsApi.SetOptions(options);
+ V5PrivateApi.SetOptions(options);
+ }
+
///
/// Set the default options to be used when creating new clients
///
diff --git a/ByBit.Net/Clients/DerivativesApi/BybitSocketClientDerivativesPublicApi.cs b/ByBit.Net/Clients/DerivativesApi/BybitSocketClientDerivativesPublicApi.cs
index 47f80b99..0bb05dfc 100644
--- a/ByBit.Net/Clients/DerivativesApi/BybitSocketClientDerivativesPublicApi.cs
+++ b/ByBit.Net/Clients/DerivativesApi/BybitSocketClientDerivativesPublicApi.cs
@@ -40,7 +40,19 @@ internal BybitSocketClientDerivativesPublicApi(ILogger log, BybitSocketOptions o
UnhandledMessageExpected = true;
KeepAliveInterval = TimeSpan.Zero;
- RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { });
+ RegisterPeriodicQuery(
+ "Heartbeat",
+ TimeSpan.FromSeconds(20),
+ x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) },
+ (connection, result) =>
+ {
+ if (result.Error?.Message.Equals("Query timeout") == true)
+ {
+ // Ping timeout, reconnect
+ _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId);
+ _ = connection.TriggerReconnectAsync();
+ }
+ });
}
///
diff --git a/ByBit.Net/Clients/DerivativesApi/ContractApi/BybitSocketClientContractApi.cs b/ByBit.Net/Clients/DerivativesApi/ContractApi/BybitSocketClientContractApi.cs
index 67e6c231..ab73c55b 100644
--- a/ByBit.Net/Clients/DerivativesApi/ContractApi/BybitSocketClientContractApi.cs
+++ b/ByBit.Net/Clients/DerivativesApi/ContractApi/BybitSocketClientContractApi.cs
@@ -36,7 +36,19 @@ internal BybitSocketClientContractApi(ILogger log, BybitSocketOptions options)
UnhandledMessageExpected = true;
KeepAliveInterval = TimeSpan.Zero;
- RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { });
+ RegisterPeriodicQuery(
+ "Heartbeat",
+ TimeSpan.FromSeconds(20),
+ x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) },
+ (connection, result) =>
+ {
+ if (result.Error?.Message.Equals("Query timeout") == true)
+ {
+ // Ping timeout, reconnect
+ _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId);
+ _ = connection.TriggerReconnectAsync();
+ }
+ });
}
///
diff --git a/ByBit.Net/Clients/DerivativesApi/UnifiedMarginApi/BybitSocketClientUnifiedMarginApi.cs b/ByBit.Net/Clients/DerivativesApi/UnifiedMarginApi/BybitSocketClientUnifiedMarginApi.cs
index 5fa9d9be..118a3dae 100644
--- a/ByBit.Net/Clients/DerivativesApi/UnifiedMarginApi/BybitSocketClientUnifiedMarginApi.cs
+++ b/ByBit.Net/Clients/DerivativesApi/UnifiedMarginApi/BybitSocketClientUnifiedMarginApi.cs
@@ -38,7 +38,19 @@ internal BybitSocketClientUnifiedMarginApi(ILogger log, BybitSocketOptions optio
{
KeepAliveInterval = TimeSpan.Zero;
- RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitPingQuery(), x => { });
+ RegisterPeriodicQuery(
+ "Heartbeat",
+ TimeSpan.FromSeconds(20),
+ x => new BybitPingQuery(),
+ (connection, result) =>
+ {
+ if (result.Error?.Message.Equals("Query timeout") == true)
+ {
+ // Ping timeout, reconnect
+ _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId);
+ _ = connection.TriggerReconnectAsync();
+ }
+ });
}
///
diff --git a/ByBit.Net/Clients/SpotApi/v3/BybitSocketClientSpotApiV3.cs b/ByBit.Net/Clients/SpotApi/v3/BybitSocketClientSpotApiV3.cs
index 7dd9822b..e0f98310 100644
--- a/ByBit.Net/Clients/SpotApi/v3/BybitSocketClientSpotApiV3.cs
+++ b/ByBit.Net/Clients/SpotApi/v3/BybitSocketClientSpotApiV3.cs
@@ -34,7 +34,19 @@ internal BybitSocketClientSpotApiV3(ILogger logger, BybitSocketOptions options)
{
KeepAliveInterval = TimeSpan.Zero;
- RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { });
+ RegisterPeriodicQuery(
+ "Heartbeat",
+ TimeSpan.FromSeconds(20),
+ x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) },
+ (connection, result) =>
+ {
+ if (result.Error?.Message.Equals("Query timeout") == true)
+ {
+ // Ping timeout, reconnect
+ _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId);
+ _ = connection.TriggerReconnectAsync();
+ }
+ });
}
///
diff --git a/ByBit.Net/Clients/V5/BybitSocketClientInverseApi.cs b/ByBit.Net/Clients/V5/BybitSocketClientInverseApi.cs
index e34d3ce0..ab4582bd 100644
--- a/ByBit.Net/Clients/V5/BybitSocketClientInverseApi.cs
+++ b/ByBit.Net/Clients/V5/BybitSocketClientInverseApi.cs
@@ -26,7 +26,19 @@ internal partial class BybitSocketClientInverseApi : BybitSocketClientBaseApi, I
internal BybitSocketClientInverseApi(ILogger log, BybitSocketOptions options)
: base(log, options, "/v5/public/inverse")
{
- RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { });
+ RegisterPeriodicQuery(
+ "Heartbeat",
+ TimeSpan.FromSeconds(20),
+ x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) },
+ (connection, result) =>
+ {
+ if (result.Error?.Message.Equals("Query timeout") == true)
+ {
+ // Ping timeout, reconnect
+ _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId);
+ _ = connection.TriggerReconnectAsync();
+ }
+ });
}
public IBybitSocketClientInverseApiShared SharedClient => this;
diff --git a/ByBit.Net/Clients/V5/BybitSocketClientLinearApi.cs b/ByBit.Net/Clients/V5/BybitSocketClientLinearApi.cs
index cc3a7a8d..f4f2f232 100644
--- a/ByBit.Net/Clients/V5/BybitSocketClientLinearApi.cs
+++ b/ByBit.Net/Clients/V5/BybitSocketClientLinearApi.cs
@@ -26,7 +26,19 @@ internal partial class BybitSocketClientLinearApi : BybitSocketClientBaseApi, IB
internal BybitSocketClientLinearApi(ILogger log, BybitSocketOptions options)
: base(log, options, "/v5/public/linear")
{
- RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { });
+ RegisterPeriodicQuery(
+ "Heartbeat",
+ TimeSpan.FromSeconds(20),
+ x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) },
+ (connection, result) =>
+ {
+ if (result.Error?.Message.Equals("Query timeout") == true)
+ {
+ // Ping timeout, reconnect
+ _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId);
+ _ = connection.TriggerReconnectAsync();
+ }
+ });
}
public IBybitSocketClientLinearApiShared SharedClient => this;
diff --git a/ByBit.Net/Clients/V5/BybitSocketClientOptionApi.cs b/ByBit.Net/Clients/V5/BybitSocketClientOptionApi.cs
index c5e5b021..33ca15b3 100644
--- a/ByBit.Net/Clients/V5/BybitSocketClientOptionApi.cs
+++ b/ByBit.Net/Clients/V5/BybitSocketClientOptionApi.cs
@@ -30,7 +30,19 @@ internal class BybitSocketClientOptionApi : BybitSocketClientBaseApi, IBybitSock
internal BybitSocketClientOptionApi(ILogger log, BybitSocketOptions options)
: base(log, options, "/v5/public/option")
{
- RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitPingQuery(), x => { });
+ RegisterPeriodicQuery(
+ "Heartbeat",
+ TimeSpan.FromSeconds(20),
+ x => new BybitPingQuery(),
+ (connection, result) =>
+ {
+ if (result.Error?.Message.Equals("Query timeout") == true)
+ {
+ // Ping timeout, reconnect
+ _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId);
+ _ = connection.TriggerReconnectAsync();
+ }
+ });
}
///
diff --git a/ByBit.Net/Clients/V5/BybitSocketClientPrivateApi.cs b/ByBit.Net/Clients/V5/BybitSocketClientPrivateApi.cs
index e192a544..8707f2b8 100644
--- a/ByBit.Net/Clients/V5/BybitSocketClientPrivateApi.cs
+++ b/ByBit.Net/Clients/V5/BybitSocketClientPrivateApi.cs
@@ -40,7 +40,19 @@ internal BybitSocketClientPrivateApi(ILogger logger, BybitSocketOptions options)
_referer = !string.IsNullOrEmpty(options.Referer) ? options.Referer! : "Zx000356";
- RegisterPeriodicQuery("Heartbeat", options.V5Options.PingInterval, GetPingQuery, x => { });
+ RegisterPeriodicQuery(
+ "Heartbeat",
+ options.V5Options.PingInterval,
+ GetPingQuery,
+ (connection, result) =>
+ {
+ if (result.Error?.Message.Equals("Query timeout") == true)
+ {
+ // Ping timeout, reconnect
+ _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId);
+ _ = connection.TriggerReconnectAsync();
+ }
+ });
SetDedicatedConnection(BaseAddress.AppendPath("/v5/trade"), true);
}
@@ -49,7 +61,7 @@ private Query GetPingQuery(SocketConnection connection)
{
if (connection.ConnectionUri.AbsolutePath.EndsWith("private"))
{
- return new BybitQuery("ping", null);
+ return new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) };
}
else
{
diff --git a/ByBit.Net/Clients/V5/BybitSocketClientSpotApi.cs b/ByBit.Net/Clients/V5/BybitSocketClientSpotApi.cs
index 81671567..7e0b5e72 100644
--- a/ByBit.Net/Clients/V5/BybitSocketClientSpotApi.cs
+++ b/ByBit.Net/Clients/V5/BybitSocketClientSpotApi.cs
@@ -27,7 +27,19 @@ internal partial class BybitSocketClientSpotApi : BybitSocketClientBaseApi, IByb
internal BybitSocketClientSpotApi(ILogger logger, BybitSocketOptions options)
: base(logger, options, "/v5/public/spot")
{
- RegisterPeriodicQuery("Heartbeat", TimeSpan.FromSeconds(20), x => new BybitQuery("ping", null), x => { });
+ RegisterPeriodicQuery(
+ "Heartbeat",
+ TimeSpan.FromSeconds(20),
+ x => new BybitQuery("ping", null) { RequestTimeout = TimeSpan.FromSeconds(5) },
+ (connection, result) =>
+ {
+ if (result.Error?.Message.Equals("Query timeout") == true)
+ {
+ // Ping timeout, reconnect
+ _logger.LogWarning("[Sckt {SocketId}] Ping response timeout, reconnecting", connection.SocketId);
+ _ = connection.TriggerReconnectAsync();
+ }
+ });
}
///
diff --git a/ByBit.Net/ExtensionMethods/ServiceCollectionExtensions.cs b/ByBit.Net/ExtensionMethods/ServiceCollectionExtensions.cs
index cb2a93d1..870e32a1 100644
--- a/ByBit.Net/ExtensionMethods/ServiceCollectionExtensions.cs
+++ b/ByBit.Net/ExtensionMethods/ServiceCollectionExtensions.cs
@@ -112,6 +112,7 @@ private static IServiceCollection AddBybitCore(
try
{
handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
+ handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials;
}
catch (PlatformNotSupportedException)
{ }
diff --git a/ByBit.Net/Interfaces/Clients/IBybitRestClient.cs b/ByBit.Net/Interfaces/Clients/IBybitRestClient.cs
index e1cf8b19..3451cafc 100644
--- a/ByBit.Net/Interfaces/Clients/IBybitRestClient.cs
+++ b/ByBit.Net/Interfaces/Clients/IBybitRestClient.cs
@@ -3,6 +3,7 @@
using Bybit.Net.Interfaces.Clients.SpotApi.v3;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Interfaces;
+using CryptoExchange.Net.Objects.Options;
namespace Bybit.Net.Interfaces.Clients
{
@@ -30,6 +31,12 @@ public interface IBybitRestClient: IRestClient
///
V5.IBybitRestClientApi V5Api { get; }
+ ///
+ /// Update specific options
+ ///
+ /// Options to update. Only specific options are changable after the client has been created
+ void SetOptions(UpdateOptions options);
+
///
/// Set the API credentials for this client. All Api clients in this client will use the new credentials, regardless of earlier set options.
///
diff --git a/ByBit.Net/Interfaces/Clients/IBybitSocketClient.cs b/ByBit.Net/Interfaces/Clients/IBybitSocketClient.cs
index 8c81e754..3f6aa2b2 100644
--- a/ByBit.Net/Interfaces/Clients/IBybitSocketClient.cs
+++ b/ByBit.Net/Interfaces/Clients/IBybitSocketClient.cs
@@ -5,6 +5,7 @@
using Bybit.Net.Interfaces.Clients.V5;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Interfaces;
+using CryptoExchange.Net.Objects.Options;
namespace Bybit.Net.Interfaces.Clients
{
@@ -50,6 +51,12 @@ public interface IBybitSocketClient : ISocketClient
///
public IBybitSocketClientPrivateApi V5PrivateApi { get; }
+ ///
+ /// Update specific options
+ ///
+ /// Options to update. Only specific options are changable after the client has been created
+ void SetOptions(UpdateOptions options);
+
///
/// Set the API credentials for this client. All Api clients in this client will use the new credentials, regardless of earlier set options.
///
diff --git a/ByBit.Net/Objects/Sockets/Queries/BybitPingQuery.cs b/ByBit.Net/Objects/Sockets/Queries/BybitPingQuery.cs
index 3898cce9..911c5714 100644
--- a/ByBit.Net/Objects/Sockets/Queries/BybitPingQuery.cs
+++ b/ByBit.Net/Objects/Sockets/Queries/BybitPingQuery.cs
@@ -1,5 +1,6 @@
using CryptoExchange.Net;
using CryptoExchange.Net.Sockets;
+using System;
using System.Collections.Generic;
namespace Bybit.Net.Objects.Sockets.Queries
@@ -10,6 +11,7 @@ internal class BybitPingQuery : Query
public BybitPingQuery() : base(new BybitRequestMessage { RequestId = ExchangeHelpers.NextId().ToString(), Operation = "ping", Args = null }, false, 1)
{
+ RequestTimeout = TimeSpan.FromSeconds(5);
ListenerIdentifiers = new HashSet() { "pong" };
}
}
diff --git a/Bybit.UnitTests/Bybit.UnitTests.csproj b/Bybit.UnitTests/Bybit.UnitTests.csproj
index 691d866a..9ebbb812 100644
--- a/Bybit.UnitTests/Bybit.UnitTests.csproj
+++ b/Bybit.UnitTests/Bybit.UnitTests.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net9.0
false