Skip to content

Commit

Permalink
Feature/rate limit refactor (#221)
Browse files Browse the repository at this point in the history
  • Loading branch information
JKorf authored Apr 17, 2024
1 parent f87758c commit 7abe0a1
Show file tree
Hide file tree
Showing 22 changed files with 630 additions and 344 deletions.
3 changes: 1 addition & 2 deletions Kucoin.Net.UnitTests/JsonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ public class JsonTests
private JsonToObjectComparer<IKucoinRestClient> _comparerSpot = new JsonToObjectComparer<IKucoinRestClient>((json) => TestHelpers.CreateResponseClient(json, x =>
{
x.ApiCredentials = new KucoinApiCredentials("1234", "1234", "12");
x.SpotOptions.RateLimiters = new List<IRateLimiter>();
x.SpotOptions.OutputOriginalData = false;
x.FuturesOptions.RateLimiters = new List<IRateLimiter>();
x.RateLimiterEnabled = false;
x.FuturesOptions.OutputOriginalData = false;
}));

Expand Down
5 changes: 3 additions & 2 deletions Kucoin.Net.UnitTests/TestImplementations/TestSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public class TestSocket: IWebsocket
#pragma warning disable 0067
public event Func<Task> OnReconnected;
public event Func<Task> OnReconnecting;
public event Func<int, Task> OnRequestRateLimited;
#pragma warning restore 0067
public event Func<int, Task> OnRequestSent;
public event Action<WebSocketMessageType, ReadOnlyMemory<byte>> OnStreamMessage;
Expand Down Expand Up @@ -50,10 +51,10 @@ public class TestSocket: IWebsocket
public TimeSpan KeepAliveInterval { get; set; }
public Func<Task<Uri>> GetReconnectionUrl { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }

public Task<bool> ConnectAsync()
public Task<CallResult> ConnectAsync()
{
Connected = CanConnect;
return Task.FromResult(CanConnect);
return Task.FromResult(CanConnect ? new CallResult(null) : new CallResult(new CantConnectError()));
}

public void Send(int requestId, string data, int weight)
Expand Down
6 changes: 3 additions & 3 deletions Kucoin.Net/Clients/FuturesApi/KucoinRestClientFuturesApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden

internal async Task<WebCallResult> Execute(Uri uri, HttpMethod method, CancellationToken ct, Dictionary<string, object>? parameters = null, bool signed = false, HttpMethodParameterPosition? parameterPosition = null)
{
var result = await SendRequestAsync<KucoinResult<object>>(uri, method, ct, parameters, signed, parameterPosition: parameterPosition).ConfigureAwait(false);
var result = await SendRequestAsync<KucoinResult<object>>(uri, method, ct, parameters, signed, parameterPosition: parameterPosition, requestWeight: 0).ConfigureAwait(false);
if (!result)
return result.AsDatalessError(result.Error!);

Expand All @@ -78,9 +78,9 @@ internal async Task<WebCallResult> Execute(Uri uri, HttpMethod method, Cancellat
return result.AsDataless();
}

internal async Task<WebCallResult<T>> Execute<T>(Uri uri, HttpMethod method, CancellationToken ct, Dictionary<string, object>? parameters = null, bool signed = false, int weight = 1, bool ignoreRatelimit = false, HttpMethodParameterPosition? parameterPosition = null)
internal async Task<WebCallResult<T>> Execute<T>(Uri uri, HttpMethod method, CancellationToken ct, Dictionary<string, object>? parameters = null, bool signed = false, HttpMethodParameterPosition? parameterPosition = null)
{
var result = await SendRequestAsync<KucoinResult<T>>(uri, method, ct, parameters, signed, parameterPosition: parameterPosition, requestWeight: weight, ignoreRatelimit: ignoreRatelimit).ConfigureAwait(false);
var result = await SendRequestAsync<KucoinResult<T>>(uri, method, ct, parameters, signed, parameterPosition: parameterPosition, requestWeight: 0).ConfigureAwait(false);
if (!result)
return result.AsError<T>(result.Error!);

Expand Down
28 changes: 14 additions & 14 deletions Kucoin.Net/Clients/FuturesApi/KucoinRestClientFuturesApiAccount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ internal KucoinRestClientFuturesApiAccount(KucoinRestClientFuturesApi baseClient
/// <inheritdoc />
public async Task<WebCallResult<KucoinAccountOverview>> GetAccountOverviewAsync(string? asset = null, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddOptionalParameter("currency", asset);
return await _baseClient.Execute<KucoinAccountOverview>(_baseClient.GetUri("account-overview"), HttpMethod.Get, ct, parameters, true).ConfigureAwait(false);
}

/// <inheritdoc />
public async Task<WebCallResult<KucoinPaginatedSlider<KucoinAccountTransaction>>> GetTransactionHistoryAsync(string? asset = null, TransactionType? type = null, DateTime? startTime = null, DateTime? endTime = null, int? offset = null, int? pageSize = null, bool? forward = null, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddOptionalParameter("currency", asset);
parameters.AddOptionalParameter("startAt", DateTimeConverter.ConvertToMilliseconds(startTime));
parameters.AddOptionalParameter("endAt", DateTimeConverter.ConvertToMilliseconds(endTime));
Expand All @@ -58,7 +58,7 @@ public async Task<WebCallResult<KucoinTransferResult>> TransferToMainAccountAsyn
if (receiveAccountType != AccountType.Main && receiveAccountType != AccountType.Trade)
throw new ArgumentException("Receiving account type should be Main or Trade");

var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("currency", asset);
parameters.AddParameter("amount", quantity.ToString(CultureInfo.InvariantCulture));
parameters.AddParameter("recAccountType", EnumConverter.GetString(receiveAccountType));
Expand All @@ -71,7 +71,7 @@ public async Task<WebCallResult> TransferToFuturesAccountAsync(string asset, dec
if (payAccountType != AccountType.Main && payAccountType != AccountType.Trade)
throw new ArgumentException("Receiving account type should be Main or Trade");

var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("currency", asset);
parameters.AddParameter("amount", quantity.ToString(CultureInfo.InvariantCulture));
parameters.AddParameter("payAccountType", EnumConverter.GetString(payAccountType));
Expand All @@ -81,7 +81,7 @@ public async Task<WebCallResult> TransferToFuturesAccountAsync(string asset, dec
/// <inheritdoc />
public async Task<WebCallResult<KucoinPaginated<KucoinTransfer>>> GetTransferToMainAccountHistoryAsync(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, DepositStatus? status = null, int? currentPage = null, int? pageSize = null, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddOptionalParameter("currency", asset);
parameters.AddOptionalParameter("startAt", DateTimeConverter.ConvertToMilliseconds(startTime));
parameters.AddOptionalParameter("endAt", DateTimeConverter.ConvertToMilliseconds(endTime));
Expand All @@ -94,7 +94,7 @@ public async Task<WebCallResult<KucoinPaginated<KucoinTransfer>>> GetTransferToM
/// <inheritdoc />
public async Task<WebCallResult> CancelTransferToMainAccountAsync(string applyId, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("applyId", applyId);
return await _baseClient.Execute(_baseClient.GetUri("cancel/transfer-out", 1), HttpMethod.Delete, ct, parameters, true).ConfigureAwait(false);
}
Expand All @@ -105,23 +105,23 @@ public async Task<WebCallResult> CancelTransferToMainAccountAsync(string applyId
/// <inheritdoc />
public async Task<WebCallResult<KucoinPosition>> GetPositionAsync(string symbol, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
return await _baseClient.Execute<KucoinPosition>(_baseClient.GetUri("position"), HttpMethod.Get, ct, parameters, true).ConfigureAwait(false);
}

/// <inheritdoc />
public async Task<WebCallResult<IEnumerable<KucoinPosition>>> GetPositionsAsync(string? asset = null, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddOptionalParameter("currency", asset);
return await _baseClient.Execute<IEnumerable<KucoinPosition>>(_baseClient.GetUri("positions"), HttpMethod.Get, ct, parameters, signed: true).ConfigureAwait(false);
}

/// <inheritdoc />
public async Task<WebCallResult> ToggleAutoDepositMarginAsync(string symbol, bool enabled, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
parameters.AddParameter("status", enabled.ToString());
return await _baseClient.Execute(_baseClient.GetUri("position/margin/auto-deposit-status"), HttpMethod.Post, ct, parameters, true).ConfigureAwait(false);
Expand All @@ -130,7 +130,7 @@ public async Task<WebCallResult> ToggleAutoDepositMarginAsync(string symbol, boo
/// <inheritdoc />
public async Task<WebCallResult> AddMarginAsync(string symbol, decimal quantity, string? clientId = null, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
parameters.AddParameter("bizNo", clientId ?? Convert.ToBase64String(Guid.NewGuid().ToByteArray()));
parameters.AddParameter("margin", quantity.ToString(CultureInfo.InvariantCulture));
Expand All @@ -144,7 +144,7 @@ public async Task<WebCallResult> AddMarginAsync(string symbol, decimal quantity,
/// <inheritdoc />
public async Task<WebCallResult<KucoinPaginatedSlider<KucoinFundingItem>>> GetFundingHistoryAsync(string symbol, DateTime? startTime = null, DateTime? endTime = null, int? offset = null, int? pageSize = null, bool? forward = null, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddOptionalParameter("symbol", symbol);
parameters.AddOptionalParameter("startAt", DateTimeConverter.ConvertToMilliseconds(startTime));
parameters.AddOptionalParameter("endAt", DateTimeConverter.ConvertToMilliseconds(endTime));
Expand All @@ -160,7 +160,7 @@ public async Task<WebCallResult<KucoinPaginatedSlider<KucoinFundingItem>>> GetFu
/// <inheritdoc />
public async Task<WebCallResult<KucoinOrderValuation>> GetOpenOrderValueAsync(string symbol, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
return await _baseClient.Execute<KucoinOrderValuation>(_baseClient.GetUri("openOrderStatistics"), HttpMethod.Get, ct, parameters, true).ConfigureAwait(false);
}
Expand All @@ -171,7 +171,7 @@ public async Task<WebCallResult<KucoinOrderValuation>> GetOpenOrderValueAsync(st
/// <inheritdoc />
public async Task<WebCallResult<IEnumerable<Objects.Models.Futures.KucoinRiskLimit>>> GetRiskLimitLevelAsync(string symbol, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
return await _baseClient.Execute<IEnumerable<Objects.Models.Futures.KucoinRiskLimit>>(_baseClient.GetUri("contracts/risk-limit/" + symbol), HttpMethod.Get, ct, parameters, true).ConfigureAwait(false);
}
Expand All @@ -182,7 +182,7 @@ public async Task<WebCallResult<KucoinOrderValuation>> GetOpenOrderValueAsync(st
/// <inheritdoc />
public async Task<WebCallResult<bool>> SetRiskLimitLevelAsync(string symbol, int level, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
parameters.AddParameter("level", level);
return await _baseClient.Execute<bool>(_baseClient.GetUri("position/risk-limit-level/change"), HttpMethod.Post, ct, parameters, true).ConfigureAwait(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public async Task<WebCallResult<KucoinContract>> GetContractAsync(string symbol,
/// <inheritdoc />
public async Task<WebCallResult<KucoinFuturesTick>> GetTickerAsync(string symbol, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
return await _baseClient.Execute<KucoinFuturesTick>(_baseClient.GetUri("ticker"), HttpMethod.Get, ct, parameters).ConfigureAwait(false);
}
Expand All @@ -59,7 +59,7 @@ public async Task<WebCallResult<KucoinFuturesTick>> GetTickerAsync(string symbol
/// <inheritdoc />
public async Task<WebCallResult<KucoinOrderBook>> GetAggregatedFullOrderBookAsync(string symbol, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
return await _baseClient.Execute<KucoinOrderBook>(_baseClient.GetUri("level2/snapshot"), HttpMethod.Get, ct, parameters).ConfigureAwait(false);
}
Expand All @@ -69,7 +69,7 @@ public async Task<WebCallResult<KucoinOrderBook>> GetAggregatedPartialOrderBookA
{
depth.ValidateIntValues(nameof(depth), 20, 100);

var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
return await _baseClient.Execute<KucoinOrderBook>(_baseClient.GetUri("level2/depth" + depth), HttpMethod.Get, ct, parameters).ConfigureAwait(false);
}
Expand All @@ -81,7 +81,7 @@ public async Task<WebCallResult<KucoinOrderBook>> GetAggregatedPartialOrderBookA
/// <inheritdoc />
public async Task<WebCallResult<IEnumerable<KucoinFuturesTrade>>> GetTradeHistoryAsync(string symbol, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
return await _baseClient.Execute<IEnumerable<KucoinFuturesTrade>>(_baseClient.GetUri("trade/history"), HttpMethod.Get, ct, parameters).ConfigureAwait(false);
}
Expand All @@ -93,7 +93,7 @@ public async Task<WebCallResult<IEnumerable<KucoinFuturesTrade>>> GetTradeHistor
/// <inheritdoc />
public async Task<WebCallResult<KucoinPaginatedSlider<KucoinFuturesInterest>>> GetInterestRatesAsync(string symbol, DateTime? startTime = null, DateTime? endTime = null, int? offset = null, int? pageSize = null, bool? forward = null, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddOptionalParameter("symbol", symbol);
parameters.AddOptionalParameter("startAt", DateTimeConverter.ConvertToMilliseconds(startTime));
parameters.AddOptionalParameter("endAt", DateTimeConverter.ConvertToMilliseconds(endTime));
Expand All @@ -106,7 +106,7 @@ public async Task<WebCallResult<KucoinPaginatedSlider<KucoinFuturesInterest>>> G
/// <inheritdoc />
public async Task<WebCallResult<KucoinPaginatedSlider<KucoinIndex>>> GetIndexListAsync(string symbol, DateTime? startTime = null, DateTime? endTime = null, int? offset = null, int? pageSize = null, bool? forward = null, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddOptionalParameter("symbol", symbol);
parameters.AddOptionalParameter("startAt", DateTimeConverter.ConvertToMilliseconds(startTime));
parameters.AddOptionalParameter("endAt", DateTimeConverter.ConvertToMilliseconds(endTime));
Expand All @@ -125,7 +125,7 @@ public async Task<WebCallResult<KucoinMarkPrice>> GetCurrentMarkPriceAsync(strin
/// <inheritdoc />
public async Task<WebCallResult<KucoinPaginatedSlider<KucoinPremiumIndex>>> GetPremiumIndexAsync(string symbol, DateTime? startTime = null, DateTime? endTime = null, int? offset = null, int? pageSize = null, bool? forward = null, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddOptionalParameter("symbol", symbol);
parameters.AddOptionalParameter("startAt", DateTimeConverter.ConvertToMilliseconds(startTime));
parameters.AddOptionalParameter("endAt", DateTimeConverter.ConvertToMilliseconds(endTime));
Expand All @@ -148,7 +148,7 @@ public async Task<WebCallResult<KucoinFundingRate>> GetCurrentFundingRateAsync(s
/// <inheritdoc />
public async Task<WebCallResult<DateTime>> GetServerTimeAsync(CancellationToken ct = default)
{
var result = await _baseClient.Execute<long>(_baseClient.GetUri("timestamp"), HttpMethod.Get, ct, ignoreRatelimit: true).ConfigureAwait(false);
var result = await _baseClient.Execute<long>(_baseClient.GetUri("timestamp"), HttpMethod.Get, ct).ConfigureAwait(false);
return result.As(result ? new DateTime(1970, 1, 1).AddMilliseconds(result.Data) : default);
}

Expand All @@ -169,7 +169,7 @@ public async Task<WebCallResult<KucoinFuturesServiceStatus>> GetServiceStatusAsy
/// <inheritdoc />
public async Task<WebCallResult<IEnumerable<KucoinFuturesKline>>> GetKlinesAsync(string symbol, FuturesKlineInterval interval, DateTime? startTime = null, DateTime? endTime = null, CancellationToken ct = default)
{
var parameters = new Dictionary<string, object>();
var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
parameters.AddParameter("granularity", JsonConvert.SerializeObject(interval, new FuturesKlineIntervalConverter(false)));
parameters.AddOptionalParameter("from", DateTimeConverter.ConvertToMilliseconds(startTime));
Expand Down
Loading

0 comments on commit 7abe0a1

Please sign in to comment.