mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-08-15 02:13:01 +00:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d06bd5f176 | |||
| d55fc8da65 | |||
| 01184f2c5d | |||
| cadc93c2f0 | |||
| 2600a51461 | |||
| 9e6a86ba8b | |||
| c4430d63fa | |||
| f3e1cfef33 | |||
| cc3053719c | |||
| cd6907e601 | |||
| 8fe00693bd | |||
| fb90d1e015 | |||
| 4b44861e43 | |||
| e42ca4ab5a | |||
| 5b97f6dd67 | |||
| a9813ecb0a |
@@ -6,10 +6,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<packagereference Include="Microsoft.NET.Test.Sdk" Version="17.1.0-preview-20211130-02"></packagereference>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0-preview-20211130-02"></PackageReference>
|
||||||
<PackageReference Include="Moq" Version="4.16.1" />
|
<PackageReference Include="Moq" Version="4.16.1" />
|
||||||
<packagereference Include="NUnit" Version="3.13.2"></packagereference>
|
<PackageReference Include="NUnit" Version="3.13.2"></PackageReference>
|
||||||
<packagereference Include="NUnit3TestAdapter" Version="4.2.0"></packagereference>
|
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0"></PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ namespace CryptoExchange.Net
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected int MaxSocketConnections { get; set; } = 9999;
|
protected int MaxSocketConnections { get; set; } = 9999;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// Keep alive interval for websocket connection
|
||||||
|
/// </summary>
|
||||||
|
protected TimeSpan KeepAliveInterval { get; set; } = TimeSpan.FromSeconds(10);
|
||||||
|
/// <summary>
|
||||||
/// Delegate used for processing byte data received from socket connections before it is processed by handlers
|
/// Delegate used for processing byte data received from socket connections before it is processed by handlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Func<byte[], string>? dataInterpreterBytes;
|
protected Func<byte[], string>? dataInterpreterBytes;
|
||||||
@@ -574,6 +578,7 @@ namespace CryptoExchange.Net
|
|||||||
if (ClientOptions.Proxy != null)
|
if (ClientOptions.Proxy != null)
|
||||||
socket.SetProxy(ClientOptions.Proxy);
|
socket.SetProxy(ClientOptions.Proxy);
|
||||||
|
|
||||||
|
socket.KeepAliveInterval = KeepAliveInterval;
|
||||||
socket.Timeout = ClientOptions.SocketNoDataTimeout;
|
socket.Timeout = ClientOptions.SocketNoDataTimeout;
|
||||||
socket.DataInterpreterBytes = dataInterpreterBytes;
|
socket.DataInterpreterBytes = dataInterpreterBytes;
|
||||||
socket.DataInterpreterString = dataInterpreterString;
|
socket.DataInterpreterString = dataInterpreterString;
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace CryptoExchange.Net.Converters
|
|||||||
if(reader.TokenType is JsonToken.Integer)
|
if(reader.TokenType is JsonToken.Integer)
|
||||||
{
|
{
|
||||||
var longValue = (long)reader.Value;
|
var longValue = (long)reader.Value;
|
||||||
if (longValue == 0)
|
if (longValue == 0 || longValue == -1)
|
||||||
return objectType == typeof(DateTime) ? default(DateTime): null;
|
return objectType == typeof(DateTime) ? default(DateTime): null;
|
||||||
if (longValue < 19999999999)
|
if (longValue < 19999999999)
|
||||||
return ConvertFromSeconds(longValue);
|
return ConvertFromSeconds(longValue);
|
||||||
@@ -45,6 +45,9 @@ namespace CryptoExchange.Net.Converters
|
|||||||
else if (reader.TokenType is JsonToken.Float)
|
else if (reader.TokenType is JsonToken.Float)
|
||||||
{
|
{
|
||||||
var doubleValue = (double)reader.Value;
|
var doubleValue = (double)reader.Value;
|
||||||
|
if (doubleValue == 0 || doubleValue == -1)
|
||||||
|
return objectType == typeof(DateTime) ? default(DateTime) : null;
|
||||||
|
|
||||||
if (doubleValue < 19999999999)
|
if (doubleValue < 19999999999)
|
||||||
return ConvertFromSeconds(doubleValue);
|
return ConvertFromSeconds(doubleValue);
|
||||||
|
|
||||||
@@ -56,6 +59,9 @@ namespace CryptoExchange.Net.Converters
|
|||||||
if (string.IsNullOrWhiteSpace(stringValue))
|
if (string.IsNullOrWhiteSpace(stringValue))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(stringValue) || stringValue == "0" || stringValue == "-1")
|
||||||
|
return objectType == typeof(DateTime) ? default(DateTime) : null;
|
||||||
|
|
||||||
if (stringValue.Length == 8)
|
if (stringValue.Length == 8)
|
||||||
{
|
{
|
||||||
// Parse 20211103 format
|
// Parse 20211103 format
|
||||||
|
|||||||
@@ -6,16 +6,16 @@
|
|||||||
<PackageId>CryptoExchange.Net</PackageId>
|
<PackageId>CryptoExchange.Net</PackageId>
|
||||||
<Authors>JKorf</Authors>
|
<Authors>JKorf</Authors>
|
||||||
<Description>A base package for implementing cryptocurrency API's</Description>
|
<Description>A base package for implementing cryptocurrency API's</Description>
|
||||||
<PackageVersion>5.1.9</PackageVersion>
|
<PackageVersion>5.1.11</PackageVersion>
|
||||||
<AssemblyVersion>5.1.9</AssemblyVersion>
|
<AssemblyVersion>5.1.11</AssemblyVersion>
|
||||||
<FileVersion>5.1.9</FileVersion>
|
<FileVersion>5.1.11</FileVersion>
|
||||||
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
|
||||||
<RepositoryType>git</RepositoryType>
|
<RepositoryType>git</RepositoryType>
|
||||||
<RepositoryUrl>https://github.com/JKorf/CryptoExchange.Net.git</RepositoryUrl>
|
<RepositoryUrl>https://github.com/JKorf/CryptoExchange.Net.git</RepositoryUrl>
|
||||||
<PackageProjectUrl>https://github.com/JKorf/CryptoExchange.Net</PackageProjectUrl>
|
<PackageProjectUrl>https://github.com/JKorf/CryptoExchange.Net</PackageProjectUrl>
|
||||||
<NeutralLanguage>en</NeutralLanguage>
|
<NeutralLanguage>en</NeutralLanguage>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<PackageReleaseNotes>5.1.9 - Added latency to the timesync calculation, Small fix for exception in socket close handling</PackageReleaseNotes>
|
<PackageReleaseNotes>5.1.11 - Added KeepAliveInterval setting, Fixed port not being copied when setting parameters on request, Fixed inconsistent PackageReference casing in csproj</PackageReleaseNotes>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<LangVersion>9.0</LangVersion>
|
<LangVersion>9.0</LangVersion>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
|||||||
@@ -426,6 +426,7 @@ namespace CryptoExchange.Net
|
|||||||
var uriBuilder = new UriBuilder();
|
var uriBuilder = new UriBuilder();
|
||||||
uriBuilder.Scheme = baseUri.Scheme;
|
uriBuilder.Scheme = baseUri.Scheme;
|
||||||
uriBuilder.Host = baseUri.Host;
|
uriBuilder.Host = baseUri.Host;
|
||||||
|
uriBuilder.Port = baseUri.Port;
|
||||||
uriBuilder.Path = baseUri.AbsolutePath;
|
uriBuilder.Path = baseUri.AbsolutePath;
|
||||||
var httpValueCollection = HttpUtility.ParseQueryString(string.Empty);
|
var httpValueCollection = HttpUtility.ParseQueryString(string.Empty);
|
||||||
foreach (var parameter in parameters)
|
foreach (var parameter in parameters)
|
||||||
@@ -454,6 +455,7 @@ namespace CryptoExchange.Net
|
|||||||
var uriBuilder = new UriBuilder();
|
var uriBuilder = new UriBuilder();
|
||||||
uriBuilder.Scheme = baseUri.Scheme;
|
uriBuilder.Scheme = baseUri.Scheme;
|
||||||
uriBuilder.Host = baseUri.Host;
|
uriBuilder.Host = baseUri.Host;
|
||||||
|
uriBuilder.Port = baseUri.Port;
|
||||||
uriBuilder.Path = baseUri.AbsolutePath;
|
uriBuilder.Path = baseUri.AbsolutePath;
|
||||||
var httpValueCollection = HttpUtility.ParseQueryString(string.Empty);
|
var httpValueCollection = HttpUtility.ParseQueryString(string.Empty);
|
||||||
foreach (var parameter in parameters)
|
foreach (var parameter in parameters)
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ namespace CryptoExchange.Net.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
TimeSpan Timeout { get; set; }
|
TimeSpan Timeout { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// The interval at which to send a ping frame to the server
|
||||||
|
/// </summary>
|
||||||
|
TimeSpan KeepAliveInterval { get; set; }
|
||||||
|
/// <summary>
|
||||||
/// Set a proxy to use when connecting
|
/// Set a proxy to use when connecting
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="proxy"></param>
|
/// <param name="proxy"></param>
|
||||||
|
|||||||
@@ -258,24 +258,32 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
}
|
}
|
||||||
|
|
||||||
_subscription = startResult.Data;
|
_subscription = startResult.Data;
|
||||||
_subscription.ConnectionLost += () =>
|
_subscription.ConnectionLost += HandleConnectionLost;
|
||||||
{
|
_subscription.ConnectionClosed += HandleConnectionClosed;
|
||||||
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} connection lost");
|
_subscription.ConnectionRestored += HandleConnectionRestored;
|
||||||
Status = OrderBookStatus.Reconnecting;
|
|
||||||
Reset();
|
|
||||||
};
|
|
||||||
_subscription.ConnectionClosed += () =>
|
|
||||||
{
|
|
||||||
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} disconnected");
|
|
||||||
Status = OrderBookStatus.Disconnected;
|
|
||||||
_ = StopAsync();
|
|
||||||
};
|
|
||||||
|
|
||||||
_subscription.ConnectionRestored += async time => await ResyncAsync().ConfigureAwait(false);
|
|
||||||
Status = OrderBookStatus.Synced;
|
Status = OrderBookStatus.Synced;
|
||||||
return new CallResult<bool>(true);
|
return new CallResult<bool>(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleConnectionLost() {
|
||||||
|
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} connection lost");
|
||||||
|
if (Status != OrderBookStatus.Disposed) {
|
||||||
|
Status = OrderBookStatus.Reconnecting;
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleConnectionClosed() {
|
||||||
|
log.Write(LogLevel.Warning, $"{Id} order book {Symbol} disconnected");
|
||||||
|
Status = OrderBookStatus.Disconnected;
|
||||||
|
_ = StopAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void HandleConnectionRestored(TimeSpan _) {
|
||||||
|
await ResyncAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public async Task StopAsync()
|
public async Task StopAsync()
|
||||||
{
|
{
|
||||||
@@ -286,8 +294,12 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
if (_processTask != null)
|
if (_processTask != null)
|
||||||
await _processTask.ConfigureAwait(false);
|
await _processTask.ConfigureAwait(false);
|
||||||
|
|
||||||
if (_subscription != null)
|
if (_subscription != null) {
|
||||||
await _subscription.CloseAsync().ConfigureAwait(false);
|
await _subscription.CloseAsync().ConfigureAwait(false);
|
||||||
|
_subscription.ConnectionLost -= HandleConnectionLost;
|
||||||
|
_subscription.ConnectionClosed -= HandleConnectionClosed;
|
||||||
|
_subscription.ConnectionRestored -= HandleConnectionRestored;
|
||||||
|
}
|
||||||
log.Write(LogLevel.Trace, $"{Id} order book {Symbol} stopped");
|
log.Write(LogLevel.Trace, $"{Id} order book {Symbol} stopped");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -601,13 +613,13 @@ namespace CryptoExchange.Net.OrderBook
|
|||||||
|
|
||||||
private async Task ProcessQueue()
|
private async Task ProcessQueue()
|
||||||
{
|
{
|
||||||
while (Status != OrderBookStatus.Disconnected)
|
while (Status != OrderBookStatus.Disconnected && Status != OrderBookStatus.Disposed)
|
||||||
{
|
{
|
||||||
await _queueEvent.WaitAsync().ConfigureAwait(false);
|
await _queueEvent.WaitAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
while (_processQueue.TryDequeue(out var item))
|
while (_processQueue.TryDequeue(out var item))
|
||||||
{
|
{
|
||||||
if (Status == OrderBookStatus.Disconnected)
|
if (Status == OrderBookStatus.Disconnected || Status == OrderBookStatus.Disposed)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (_stopProcessing)
|
if (_stopProcessing)
|
||||||
|
|||||||
@@ -122,6 +122,9 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public TimeSpan Timeout { get; set; }
|
public TimeSpan Timeout { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public TimeSpan KeepAliveInterval { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public double IncomingKbps
|
public double IncomingKbps
|
||||||
{
|
{
|
||||||
@@ -332,7 +335,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
socket.Options.Cookies = cookieContainer;
|
socket.Options.Cookies = cookieContainer;
|
||||||
foreach (var header in headers)
|
foreach (var header in headers)
|
||||||
socket.Options.SetRequestHeader(header.Key, header.Value);
|
socket.Options.SetRequestHeader(header.Key, header.Value);
|
||||||
socket.Options.KeepAliveInterval = TimeSpan.FromSeconds(10);
|
socket.Options.KeepAliveInterval = KeepAliveInterval;
|
||||||
socket.Options.SetBuffer(65536, 65536); // Setting it to anything bigger than 65536 throws an exception in .net framework
|
socket.Options.SetBuffer(65536, 65536); // Setting it to anything bigger than 65536 throws an exception in .net framework
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,6 +141,8 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
private readonly List<PendingRequest> pendingRequests;
|
private readonly List<PendingRequest> pendingRequests;
|
||||||
private Task? _socketProcessReconnectTask;
|
private Task? _socketProcessReconnectTask;
|
||||||
|
|
||||||
|
private SocketStatus _status;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The underlying websocket
|
/// The underlying websocket
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -217,10 +219,24 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
subscription.CancellationTokenRegistration.Value.Dispose();
|
subscription.CancellationTokenRegistration.Value.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await _socket.CloseAsync().ConfigureAwait(false);
|
|
||||||
|
|
||||||
if (_socketProcessReconnectTask != null)
|
if (_status == SocketStatus.Reconnecting)
|
||||||
await _socketProcessReconnectTask.ConfigureAwait(false);
|
{
|
||||||
|
// Wait for reconnect task to finish
|
||||||
|
log.Write(LogLevel.Trace, "In reconnecting state, waiting for reconnecting to end");
|
||||||
|
if (_socketProcessReconnectTask != null)
|
||||||
|
await _socketProcessReconnectTask.ConfigureAwait(false);
|
||||||
|
|
||||||
|
await _socket.CloseAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Close before waiting for process task to finish
|
||||||
|
await _socket.CloseAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (_socketProcessReconnectTask != null)
|
||||||
|
await _socketProcessReconnectTask.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
_socket.Dispose();
|
_socket.Dispose();
|
||||||
}
|
}
|
||||||
@@ -232,7 +248,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task CloseAsync(SocketSubscription subscription)
|
public async Task CloseAsync(SocketSubscription subscription)
|
||||||
{
|
{
|
||||||
if (!_socket.IsOpen)
|
if (!_socket.IsOpen || _status == SocketStatus.Disposed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (subscription.CancellationTokenRegistration.HasValue)
|
if (subscription.CancellationTokenRegistration.HasValue)
|
||||||
@@ -255,9 +271,11 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
private void StartProcessingTask()
|
private void StartProcessingTask()
|
||||||
{
|
{
|
||||||
log.Write(LogLevel.Trace, $"Starting {SocketId} process/reconnect task");
|
log.Write(LogLevel.Trace, $"Starting {SocketId} process/reconnect task");
|
||||||
|
_status = SocketStatus.Processing;
|
||||||
_socketProcessReconnectTask = Task.Run(async () =>
|
_socketProcessReconnectTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await _socket.ProcessAsync().ConfigureAwait(false);
|
await _socket.ProcessAsync().ConfigureAwait(false);
|
||||||
|
_status = SocketStatus.Reconnecting;
|
||||||
await ReconnectAsync().ConfigureAwait(false);
|
await ReconnectAsync().ConfigureAwait(false);
|
||||||
log.Write(LogLevel.Trace, $"Process/reconnect {SocketId} task finished");
|
log.Write(LogLevel.Trace, $"Process/reconnect {SocketId} task finished");
|
||||||
});
|
});
|
||||||
@@ -283,7 +301,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (!lostTriggered)
|
if (!lostTriggered)
|
||||||
{
|
{
|
||||||
lostTriggered = true;
|
lostTriggered = true;
|
||||||
ConnectionLost?.Invoke();
|
_ = Task.Run(() => ConnectionLost?.Invoke());
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ShouldReconnect)
|
while (ShouldReconnect)
|
||||||
@@ -372,7 +390,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
if (lostTriggered)
|
if (lostTriggered)
|
||||||
{
|
{
|
||||||
lostTriggered = false;
|
lostTriggered = false;
|
||||||
_ = Task.Run(() => ConnectionRestored?.Invoke(time.HasValue ? DateTime.UtcNow - time.Value : TimeSpan.FromSeconds(0))).ConfigureAwait(false);
|
_ = Task.Run(() => ConnectionRestored?.Invoke(time.HasValue ? DateTime.UtcNow - time.Value : TimeSpan.FromSeconds(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -396,6 +414,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
_status = SocketStatus.Disposed;
|
||||||
_socket.Dispose();
|
_socket.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,7 +477,7 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
var total = DateTime.UtcNow - timestamp;
|
var total = DateTime.UtcNow - timestamp;
|
||||||
if (userProcessTime.TotalMilliseconds > 500)
|
if (userProcessTime.TotalMilliseconds > 500)
|
||||||
log.Write(LogLevel.Debug, $"Socket {SocketId} message processing slow ({(int)total.TotalMilliseconds}ms), consider offloading data handling to another thread. " +
|
log.Write(LogLevel.Debug, $"Socket {SocketId} message processing slow ({(int)total.TotalMilliseconds}ms, {(int)userProcessTime.TotalMilliseconds}ms user code), consider offloading data handling to another thread. " +
|
||||||
"Data from this socket may arrive late or not at all if message processing is continuously slow.");
|
"Data from this socket may arrive late or not at all if message processing is continuously slow.");
|
||||||
|
|
||||||
log.Write(LogLevel.Trace, $"Socket {SocketId} message processed in {(int)total.TotalMilliseconds}ms, ({(int)userProcessTime.TotalMilliseconds}ms user code)");
|
log.Write(LogLevel.Trace, $"Socket {SocketId} message processed in {(int)total.TotalMilliseconds}ms, ({(int)userProcessTime.TotalMilliseconds}ms user code)");
|
||||||
@@ -671,5 +690,13 @@ namespace CryptoExchange.Net.Sockets
|
|||||||
|
|
||||||
return await socketClient.SubscribeAndWaitAsync(this, socketSubscription.Request!, socketSubscription).ConfigureAwait(false);
|
return await socketClient.SubscribeAndWaitAsync(this, socketSubscription.Request!, socketSubscription).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum SocketStatus
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Processing,
|
||||||
|
Reconnecting,
|
||||||
|
Disposed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,17 @@ I develop and maintain this package on my own for free in my spare time. Donatio
|
|||||||
Alternatively, sponsor me on Github using [Github Sponsors](https://github.com/sponsors/JKorf)
|
Alternatively, sponsor me on Github using [Github Sponsors](https://github.com/sponsors/JKorf)
|
||||||
|
|
||||||
## Release notes
|
## Release notes
|
||||||
|
* Version 5.1.11 - 24 May 2022
|
||||||
|
* Added KeepAliveInterval setting
|
||||||
|
* Fixed port not being copied when setting parameters on request
|
||||||
|
* Fixed inconsistent PackageReference casing in csproj
|
||||||
|
|
||||||
|
* Version 5.1.10 - 22 May 2022
|
||||||
|
* Fixed order book reconnecting while Diposed
|
||||||
|
* Fixed exception when disposing socket client while reconnecting
|
||||||
|
* Added additional null/default checking in DateTimeConverter
|
||||||
|
* Changed ConnectionLost subscription event to run in seperate task to prevent exception/longer operations from intervering with reconnecting
|
||||||
|
|
||||||
* Version 5.1.9 - 08 May 2022
|
* Version 5.1.9 - 08 May 2022
|
||||||
* Added latency to the timesync calculation
|
* Added latency to the timesync calculation
|
||||||
* Small fix for exception in socket close handling
|
* Small fix for exception in socket close handling
|
||||||
|
|||||||
+4
-1
@@ -61,4 +61,7 @@ var client = new BinanceClient(new BinanceClientOptions
|
|||||||
BaseAddress = BinanceApiAddresses.TestNet.UsdFuturesRestClientAddress
|
BaseAddress = BinanceApiAddresses.TestNet.UsdFuturesRestClientAddress
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### How are timezones handled / Timestamps are off by xx
|
||||||
|
Exchange API's treat all timestamps as UTC, both incoming and outgoing. The client libraries do no conversion so be sure to use UTC as well.
|
||||||
Reference in New Issue
Block a user