1
0
mirror of https://github.com/JKorf/CryptoExchange.Net.git synced 2026-10-16 08:01:06 +00:00

Shared interfaces pagination update (#274)

Updated INextPageToken parameter on Shared interfaces to PageRequest type, functionality unchanged
Added SupportsAscending and SupportsDescending properties to PaginatedEndpointOptions to expose supported data directions
Added MaxAge property to PaginatedEndpointOptions to expose the max age of data that can be requested
Added Direction property to Shared interfaces paginated requests to configure pagination data direction 
Removed PaginationSupport property from PaginatedEndpointOptions, replaced by above new properties
Updated Shared GetTradeHistoryRequest EndTime property to be optional
Updated I(Futures/Spot)OrderRestClient.GetClosed(Futures/Spot)OrdersOptions from PaginatedEndpointOptions<GetClosedOrdersRequest> to GetClosedOrdersOptions 
Updated I(Futures/Spot)OrderRestClient.Get(Futures/Spot)UserTradesOptions from PaginatedEndpointOptions<GetUserTradesRequest> to GetUserTradesOptions
Updated rate limiting PathStartFilter to ignore added or missing slash before the path
Fixed KlineTracker throwing exception if there is no data in the initial snapshot
This commit is contained in:
Jan Korf
2026-02-23 14:53:38 +01:00
committed by GitHub
parent 0ce2e778f4
commit b29cdc41f3
39 changed files with 909 additions and 238 deletions
@@ -24,9 +24,9 @@ namespace CryptoExchange.Net.SharedApis
public TradingMode[]? DataTradeMode { get; }
/// <summary>
/// Token to retrieve the next page with
/// Next page request, can be passed to the next request on the same endpoint to get the next page
/// </summary>
public INextPageToken? NextPageToken { get; }
public PageRequest? NextPageRequest { get; }
/// <summary>
/// ctor
@@ -46,7 +46,7 @@ namespace CryptoExchange.Net.SharedApis
string exchange,
TradingMode dataTradeMode,
WebCallResult<T> result,
INextPageToken? nextPageToken = null) :
PageRequest? nextPageToken = null) :
base(result.ResponseStatusCode,
result.HttpVersion,
result.ResponseHeaders,
@@ -64,7 +64,7 @@ namespace CryptoExchange.Net.SharedApis
{
DataTradeMode = new[] { dataTradeMode };
Exchange = exchange;
NextPageToken = nextPageToken;
NextPageRequest = nextPageToken;
}
/// <summary>
@@ -74,7 +74,7 @@ namespace CryptoExchange.Net.SharedApis
string exchange,
TradingMode[]? dataTradeModes,
WebCallResult<T> result,
INextPageToken? nextPageToken = null) :
PageRequest? nextPageRequest = null) :
base(result.ResponseStatusCode,
result.HttpVersion,
result.ResponseHeaders,
@@ -92,7 +92,7 @@ namespace CryptoExchange.Net.SharedApis
{
DataTradeMode = dataTradeModes;
Exchange = exchange;
NextPageToken = nextPageToken;
NextPageRequest = nextPageRequest;
}
/// <summary>
@@ -115,7 +115,7 @@ namespace CryptoExchange.Net.SharedApis
ResultDataSource dataSource,
[AllowNull] T data,
Error? error,
INextPageToken? nextPageToken = null) : base(
PageRequest? nextPageToken = null) : base(
code,
httpVersion,
responseHeaders,
@@ -133,7 +133,7 @@ namespace CryptoExchange.Net.SharedApis
{
DataTradeMode = dataTradeModes;
Exchange = exchange;
NextPageToken = nextPageToken;
NextPageRequest = nextPageToken;
}
/// <summary>
@@ -144,7 +144,7 @@ namespace CryptoExchange.Net.SharedApis
/// <returns></returns>
public new ExchangeWebResult<K> As<K>([AllowNull] K data)
{
return new ExchangeWebResult<K>(Exchange, DataTradeMode, ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, Error, NextPageToken);
return new ExchangeWebResult<K>(Exchange, DataTradeMode, ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, Error, NextPageRequest);
}
/// <inheritdoc />
@@ -1,4 +1,5 @@
using CryptoExchange.Net.Objects;
using System;
using System.Text;
namespace CryptoExchange.Net.SharedApis
@@ -8,24 +9,36 @@ namespace CryptoExchange.Net.SharedApis
/// </summary>
public class GetClosedOrdersOptions : PaginatedEndpointOptions<GetClosedOrdersRequest>
{
/// <summary>
/// Whether the start/end time filter is supported
/// </summary>
public bool TimeFilterSupported { get; set; }
/// <summary>
/// ctor
/// </summary>
public GetClosedOrdersOptions(SharedPaginationSupport paginationType, bool timeFilterSupported, int maxLimit) : base(paginationType, timeFilterSupported, maxLimit, true)
public GetClosedOrdersOptions(bool supportsAscending, bool supportsDescending, bool timeFilterSupported, int maxLimit)
: base(supportsAscending, supportsDescending, timeFilterSupported, maxLimit, true)
{
TimeFilterSupported = timeFilterSupported;
}
/// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetClosedOrdersRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{
if (!TimeFilterSupported && request.StartTime != null)
return ArgumentError.Invalid(nameof(GetClosedOrdersRequest.StartTime), $"Time filter is not supported");
if (!SupportsAscending && request.Direction == DataDirection.Ascending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Ascending direction is not supported");
if (!SupportsDescending && request.Direction == DataDirection.Descending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Descending direction is not supported");
if (MaxAge.HasValue && request.StartTime < DateTime.UtcNow.Add(-MaxAge.Value))
return ArgumentError.Invalid(nameof(GetKlinesRequest.StartTime), $"Only the most recent {MaxAge} period data is available");
if (!TimePeriodFilterSupport)
{
// When going descending we can still allow startTime filter to limit the results
var now = DateTime.UtcNow;
if ((request.Direction != DataDirection.Descending && request.StartTime != null)
|| (request.EndTime != null && now - request.EndTime > TimeSpan.FromSeconds(5)))
{
return ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
}
}
return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
}
@@ -34,7 +47,7 @@ namespace CryptoExchange.Net.SharedApis
public override string ToString(string exchange)
{
var sb = new StringBuilder(base.ToString(exchange));
sb.AppendLine($"Time filter supported: {TimeFilterSupported}");
sb.AppendLine($"Time filter supported: {TimePeriodFilterSupport}");
return sb.ToString();
}
}
@@ -1,4 +1,5 @@
using CryptoExchange.Net.Objects;
using System;
using System.Text;
namespace CryptoExchange.Net.SharedApis
@@ -8,24 +9,36 @@ namespace CryptoExchange.Net.SharedApis
/// </summary>
public class GetDepositsOptions : PaginatedEndpointOptions<GetDepositsRequest>
{
/// <summary>
/// Whether the start/end time filter is supported
/// </summary>
public bool TimeFilterSupported { get; set; }
/// <summary>
/// ctor
/// </summary>
public GetDepositsOptions(SharedPaginationSupport paginationType, bool timeFilterSupported, int maxLimit) : base(paginationType, timeFilterSupported, maxLimit, true)
public GetDepositsOptions(bool supportsAscending, bool supportsDescending, bool timeFilterSupported, int maxLimit)
: base(supportsAscending, supportsDescending, timeFilterSupported, maxLimit, true)
{
TimeFilterSupported = timeFilterSupported;
}
/// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetDepositsRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{
if (!TimeFilterSupported && request.StartTime != null)
return ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
if (!SupportsAscending && request.Direction == DataDirection.Ascending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Ascending direction is not supported");
if (!SupportsDescending && request.Direction == DataDirection.Descending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Descending direction is not supported");
if (MaxAge.HasValue && request.StartTime < DateTime.UtcNow.Add(-MaxAge.Value))
return ArgumentError.Invalid(nameof(GetKlinesRequest.StartTime), $"Only the most recent {MaxAge} period data is available");
if (!TimePeriodFilterSupport)
{
// When going descending we can still allow startTime filter to limit the results
var now = DateTime.UtcNow;
if ((request.Direction != DataDirection.Descending && request.StartTime != null)
|| (request.EndTime != null && now - request.EndTime > TimeSpan.FromSeconds(5)))
{
return ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
}
}
return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
}
@@ -34,7 +47,7 @@ namespace CryptoExchange.Net.SharedApis
public override string ToString(string exchange)
{
var sb = new StringBuilder(base.ToString(exchange));
sb.AppendLine($"Time filter supported: {TimeFilterSupported}");
sb.AppendLine($"Time filter supported: {TimePeriodFilterSupport}");
return sb.ToString();
}
}
@@ -1,4 +1,8 @@
namespace CryptoExchange.Net.SharedApis
using CryptoExchange.Net.Objects;
using System;
using System.Text;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Options for requesting funding rate history
@@ -8,8 +12,43 @@
/// <summary>
/// ctor
/// </summary>
public GetFundingRateHistoryOptions(SharedPaginationSupport paginationType, bool timeFilterSupported, int maxLimit, bool needsAuthentication) : base(paginationType, timeFilterSupported, maxLimit, needsAuthentication)
public GetFundingRateHistoryOptions(bool supportsAscending, bool supportsDescending, bool timeFilterSupported, int maxLimit, bool needsAuthentication)
: base(supportsAscending, supportsDescending, timeFilterSupported, maxLimit, needsAuthentication)
{
}
/// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetFundingRateHistoryRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{
if (!SupportsAscending && request.Direction == DataDirection.Ascending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Ascending direction is not supported");
if (!SupportsDescending && request.Direction == DataDirection.Descending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Descending direction is not supported");
if (MaxAge.HasValue && request.StartTime < DateTime.UtcNow.Add(-MaxAge.Value))
return ArgumentError.Invalid(nameof(GetKlinesRequest.StartTime), $"Only the most recent {MaxAge} period data is available");
if (!TimePeriodFilterSupport)
{
// When going descending we can still allow startTime filter to limit the results
var now = DateTime.UtcNow;
if ((request.Direction != DataDirection.Descending && request.StartTime != null)
|| (request.EndTime != null && now - request.EndTime > TimeSpan.FromSeconds(5)))
{
return ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
}
}
return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
}
/// <inheritdoc />
public override string ToString(string exchange)
{
var sb = new StringBuilder(base.ToString(exchange));
sb.AppendLine($"Time filter supported: {TimePeriodFilterSupport}");
return sb.ToString();
}
}
}
@@ -18,15 +18,12 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of data points which can be requested
/// </summary>
public int? MaxTotalDataPoints { get; set; }
/// <summary>
/// The max age of the data that can be requested
/// </summary>
public TimeSpan? MaxAge { get; set; }
/// <summary>
/// ctor
/// </summary>
public GetKlinesOptions(SharedPaginationSupport paginationType, bool timeFilterSupported, int maxLimit, bool needsAuthentication) : base(paginationType, timeFilterSupported, maxLimit, needsAuthentication)
public GetKlinesOptions(bool supportsAscending, bool supportsDescending, bool timeFilterSupported, int maxLimit, bool needsAuthentication)
: base(supportsAscending, supportsDescending, timeFilterSupported, maxLimit, needsAuthentication)
{
SupportIntervals = new[]
{
@@ -50,7 +47,8 @@ namespace CryptoExchange.Net.SharedApis
/// <summary>
/// ctor
/// </summary>
public GetKlinesOptions(SharedPaginationSupport paginationType, bool timeFilterSupported, int maxLimit, bool needsAuthentication, params SharedKlineInterval[] intervals) : base(paginationType, timeFilterSupported, maxLimit, needsAuthentication)
public GetKlinesOptions(bool supportsAscending, bool supportsDescending, bool timeFilterSupported, int maxLimit, bool needsAuthentication, params SharedKlineInterval[] intervals)
: base(supportsAscending, supportsDescending, timeFilterSupported, maxLimit, needsAuthentication)
{
SupportIntervals = intervals;
}
@@ -68,12 +66,29 @@ namespace CryptoExchange.Net.SharedApis
if (!IsSupported(request.Interval))
return ArgumentError.Invalid(nameof(GetKlinesRequest.Interval), "Interval not supported");
if (!SupportsAscending && request.Direction == DataDirection.Ascending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Ascending direction is not supported");
if (!SupportsDescending && request.Direction == DataDirection.Descending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Descending direction is not supported");
if (MaxAge.HasValue && request.StartTime < DateTime.UtcNow.Add(-MaxAge.Value))
return ArgumentError.Invalid(nameof(GetKlinesRequest.StartTime), $"Only the most recent {MaxAge} klines are available");
if (request.Limit > MaxLimit)
return ArgumentError.Invalid(nameof(GetKlinesRequest.Limit), $"Only {MaxLimit} klines can be retrieved per request");
if (!TimePeriodFilterSupport)
{
// When going descending we can still allow startTime filter to limit the results
var now = DateTime.UtcNow;
if ((request.Direction == DataDirection.Ascending && request.StartTime != null)
|| (request.EndTime != null && now - request.EndTime > TimeSpan.FromSeconds(5)))
{
return ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
}
}
if (MaxTotalDataPoints.HasValue)
{
if (request.Limit > MaxTotalDataPoints.Value)
@@ -93,6 +108,7 @@ namespace CryptoExchange.Net.SharedApis
public override string ToString(string exchange)
{
var sb = new StringBuilder(base.ToString(exchange));
sb.AppendLine($"Time filter supported: {TimePeriodFilterSupport}");
sb.AppendLine($"Supported SharedKlineInterval values: {string.Join(", ", SupportIntervals)}");
if (MaxAge != null)
sb.AppendLine($"Max age of data: {MaxAge}");
@@ -1,4 +1,8 @@
namespace CryptoExchange.Net.SharedApis
using CryptoExchange.Net.Objects;
using System;
using System.Text;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Options for requesting position history
@@ -8,8 +12,43 @@
/// <summary>
/// ctor
/// </summary>
public GetPositionHistoryOptions(SharedPaginationSupport paginationType, bool timeFilterSupported, int maxLimit) : base(paginationType, timeFilterSupported, maxLimit, true)
public GetPositionHistoryOptions(bool supportsAscending, bool supportsDescending, bool timeFilterSupported, int maxLimit)
: base(supportsAscending, supportsDescending, timeFilterSupported, maxLimit, true)
{
}
/// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetPositionHistoryRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{
if (!SupportsAscending && request.Direction == DataDirection.Ascending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Ascending direction is not supported");
if (!SupportsDescending && request.Direction == DataDirection.Descending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Descending direction is not supported");
if (MaxAge.HasValue && request.StartTime < DateTime.UtcNow.Add(-MaxAge.Value))
return ArgumentError.Invalid(nameof(GetKlinesRequest.StartTime), $"Only the most recent {MaxAge} period data is available");
if (!TimePeriodFilterSupport)
{
// When going descending we can still allow startTime filter to limit the results
var now = DateTime.UtcNow;
if ((request.Direction != DataDirection.Descending && request.StartTime != null)
|| (request.EndTime != null && now - request.EndTime > TimeSpan.FromSeconds(5)))
{
return ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
}
}
return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
}
/// <inheritdoc />
public override string ToString(string exchange)
{
var sb = new StringBuilder(base.ToString(exchange));
sb.AppendLine($"Time filter supported: {TimePeriodFilterSupport}");
return sb.ToString();
}
}
}
@@ -9,34 +9,27 @@ namespace CryptoExchange.Net.SharedApis
/// </summary>
public class GetTradeHistoryOptions : PaginatedEndpointOptions<GetTradeHistoryRequest>
{
/// <summary>
/// The max age of data that can be requested
/// </summary>
public TimeSpan? MaxAge { get; set; }
/// <summary>
/// ctor
/// </summary>
public GetTradeHistoryOptions(SharedPaginationSupport paginationType, bool timeFilterSupported, int maxLimit, bool needsAuthentication) : base(paginationType, timeFilterSupported, maxLimit, needsAuthentication)
public GetTradeHistoryOptions(bool supportsAscending, bool supportsDescending, bool timeFilterSupported, int maxLimit, bool needsAuthentication)
: base(supportsAscending, supportsDescending, timeFilterSupported, maxLimit, needsAuthentication)
{
}
/// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetTradeHistoryRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{
if (!SupportsAscending && request.Direction == DataDirection.Ascending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Ascending direction is not supported");
if (!SupportsDescending && request.Direction == DataDirection.Descending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Descending direction is not supported");
if (MaxAge.HasValue && request.StartTime < DateTime.UtcNow.Add(-MaxAge.Value))
return ArgumentError.Invalid(nameof(GetTradeHistoryRequest.StartTime), $"Only the most recent {MaxAge} trades are available");
return ArgumentError.Invalid(nameof(GetKlinesRequest.StartTime), $"Only the most recent {MaxAge} period data is available");
return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
}
/// <inheritdoc />
public override string ToString(string exchange)
{
var sb = new StringBuilder(base.ToString(exchange));
if (MaxAge != null)
sb.AppendLine($"Max age of data: {MaxAge}");
return sb.ToString();
}
}
}
@@ -0,0 +1,54 @@
using CryptoExchange.Net.Objects;
using System;
using System.Text;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Options for requesting user trades
/// </summary>
public class GetUserTradesOptions : PaginatedEndpointOptions<GetUserTradesRequest>
{
/// <summary>
/// ctor
/// </summary>
public GetUserTradesOptions(bool supportsAscending, bool supportsDescending, bool timeFilterSupported, int maxLimit)
: base(supportsAscending, supportsDescending, timeFilterSupported, maxLimit, true)
{
}
/// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetUserTradesRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{
if (!SupportsAscending && request.Direction == DataDirection.Ascending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Ascending direction is not supported");
if (!SupportsDescending && request.Direction == DataDirection.Descending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Descending direction is not supported");
if (MaxAge.HasValue && request.StartTime < DateTime.UtcNow.Add(-MaxAge.Value))
return ArgumentError.Invalid(nameof(GetKlinesRequest.StartTime), $"Only the most recent {MaxAge} period data is available");
if (!TimePeriodFilterSupport)
{
// When going descending we can still allow startTime filter to limit the results
var now = DateTime.UtcNow;
if ((request.Direction != DataDirection.Descending && request.StartTime != null)
|| (request.EndTime != null && now - request.EndTime > TimeSpan.FromSeconds(5)))
{
return ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
}
}
return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
}
/// <inheritdoc />
public override string ToString(string exchange)
{
var sb = new StringBuilder(base.ToString(exchange));
sb.AppendLine($"Time filter supported: {TimePeriodFilterSupport}");
return sb.ToString();
}
}
}
@@ -1,4 +1,5 @@
using CryptoExchange.Net.Objects;
using System;
using System.Text;
namespace CryptoExchange.Net.SharedApis
@@ -8,24 +9,36 @@ namespace CryptoExchange.Net.SharedApis
/// </summary>
public class GetWithdrawalsOptions : PaginatedEndpointOptions<GetWithdrawalsRequest>
{
/// <summary>
/// Whether the start/end time filter is supported
/// </summary>
public bool TimeFilterSupported { get; set; }
/// <summary>
/// ctor
/// </summary>
public GetWithdrawalsOptions(SharedPaginationSupport paginationType, bool timeFilterSupported, int maxLimit) : base(paginationType, timeFilterSupported, maxLimit, true)
public GetWithdrawalsOptions(bool supportsAscending, bool supportsDescending, bool timeFilterSupported, int maxLimit)
: base(supportsAscending, supportsDescending, timeFilterSupported, maxLimit, true)
{
TimeFilterSupported = timeFilterSupported;
}
/// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetWithdrawalsRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{
if (!TimeFilterSupported && request.StartTime != null)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.StartTime), $"Time filter is not supported");
if (!SupportsAscending && request.Direction == DataDirection.Ascending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Ascending direction is not supported");
if (!SupportsDescending && request.Direction == DataDirection.Descending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.Direction), $"Descending direction is not supported");
if (MaxAge.HasValue && request.StartTime < DateTime.UtcNow.Add(-MaxAge.Value))
return ArgumentError.Invalid(nameof(GetKlinesRequest.StartTime), $"Only the most recent {MaxAge} period data is available");
if (!TimePeriodFilterSupport)
{
// When going descending we can still allow startTime filter to limit the results
var now = DateTime.UtcNow;
if ((request.Direction != DataDirection.Descending && request.StartTime != null)
|| (request.EndTime != null && now - request.EndTime > TimeSpan.FromSeconds(5)))
{
return ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
}
}
return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
}
@@ -34,7 +47,7 @@ namespace CryptoExchange.Net.SharedApis
public override string ToString(string exchange)
{
var sb = new StringBuilder(base.ToString(exchange));
sb.AppendLine($"Time filter supported: {TimeFilterSupported}");
sb.AppendLine($"Time filter supported: {TimePeriodFilterSupport}");
return sb.ToString();
}
}
@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text;
namespace CryptoExchange.Net.SharedApis
@@ -14,9 +15,13 @@ namespace CryptoExchange.Net.SharedApis
#endif
{
/// <summary>
/// Type of pagination supported
/// Whether ascending data retrieval and pagination is available
/// </summary>
public SharedPaginationSupport PaginationSupport { get; }
public bool SupportsAscending { get; set; }
/// <summary>
/// Whether ascending data retrieval and pagination is available
/// </summary>
public bool SupportsDescending { get; set; }
/// <summary>
/// Whether filtering based on start/end time is supported
@@ -28,12 +33,23 @@ namespace CryptoExchange.Net.SharedApis
/// </summary>
public int MaxLimit { get; set; }
/// <summary>
/// Max age of data that can be requested
/// </summary>
public TimeSpan? MaxAge { get; set; }
/// <summary>
/// ctor
/// </summary>
public PaginatedEndpointOptions(SharedPaginationSupport paginationType, bool timePeriodSupport, int maxLimit, bool needsAuthentication) : base(needsAuthentication)
public PaginatedEndpointOptions(
bool supportsAscending,
bool supportsDescending,
bool timePeriodSupport,
int maxLimit,
bool needsAuthentication) : base(needsAuthentication)
{
PaginationSupport = paginationType;
SupportsAscending = supportsAscending;
SupportsDescending = supportsDescending;
TimePeriodFilterSupport = timePeriodSupport;
MaxLimit = maxLimit;
}
@@ -42,9 +58,11 @@ namespace CryptoExchange.Net.SharedApis
public override string ToString(string exchange)
{
var sb = new StringBuilder(base.ToString(exchange));
sb.AppendLine($"Pagination type: {PaginationSupport}");
sb.AppendLine($"Ascending retrieval supported: {SupportsAscending}");
sb.AppendLine($"Descending retrieval supported: {SupportsDescending}");
sb.AppendLine($"Time period filter support: {TimePeriodFilterSupport}");
sb.AppendLine($"Max limit: {MaxLimit}");
sb.AppendLine($"Max age: {MaxAge}");
return sb.ToString();
}
}
@@ -0,0 +1,17 @@
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Data direction
/// </summary>
public enum DataDirection
{
/// <summary>
/// Old to new order
/// </summary>
Ascending,
/// <summary>
/// New to old order
/// </summary>
Descending
}
}
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Next page request info
/// </summary>
public class PageRequest
{
/// <summary>
/// Pagination cursor
/// </summary>
public string? Cursor { get; set; }
/// <summary>
/// Page number
/// </summary>
public int? Page { get; set; }
/// <summary>
/// Result offset
/// </summary>
public int? Offset { get; set; }
/// <summary>
/// From id filter
/// </summary>
public string? FromId { get; set; }
/// <summary>
/// Start time filter
/// </summary>
public DateTime? StartTime { get; set; }
/// <summary>
/// End time filter
/// </summary>
public DateTime? EndTime { get; set; }
}
}
@@ -0,0 +1,405 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Pagination methods
/// </summary>
public static class Pagination
{
/// <summary>
/// Get pagination parameters
/// </summary>
/// <param name="direction">The data direction</param>
/// <param name="limit">Result limit</param>
/// <param name="requestStartTime">User request start time</param>
/// <param name="requestEndTime">User request end time</param>
/// <param name="paginationRequest">Provided page request</param>
/// <param name="setOtherTimeLimiter">Whether to set start time if direction is descending, or end time if direction is ascending</param>
/// <param name="maxPeriod">Max period the time filters can span</param>
/// <returns></returns>
public static PaginationParameters GetPaginationParameters(
DataDirection direction,
int limit,
DateTime? requestStartTime,
DateTime requestEndTime,
PageRequest? paginationRequest,
bool setOtherTimeLimiter = true,
TimeSpan? maxPeriod = null
)
{
var startTime = paginationRequest?.StartTime ?? requestStartTime;
var endTime = paginationRequest?.EndTime ?? requestEndTime;
if (maxPeriod != null)
{
if (direction == DataDirection.Ascending)
{
if (startTime == null)
{
startTime = endTime.Add(-maxPeriod.Value);
}
else
{
endTime = startTime.Value.Add(maxPeriod.Value);
if (endTime > DateTime.UtcNow)
endTime = DateTime.UtcNow;
}
}
else
{
startTime = endTime.Add(-maxPeriod.Value);
}
}
return new PaginationParameters
{
Limit = limit,
StartTime = direction == DataDirection.Ascending || setOtherTimeLimiter ? startTime : null,
EndTime = direction == DataDirection.Descending || setOtherTimeLimiter ? endTime : null,
Direction = direction,
FromId = paginationRequest?.FromId,
Offset = paginationRequest?.Offset,
Page = paginationRequest?.Page,
Cursor = paginationRequest?.Cursor
};
}
/// <summary>
/// Get the next page request parameters from result kline data
/// </summary>
/// <param name="nextPageRequest">Callback for returning the next page request</param>
/// <param name="resultCount">Number of results in data</param>
/// <param name="timestamps">Timestamps of the result data</param>
/// <param name="requestStartTime">User request start time</param>
/// <param name="requestEndTime">User request end time</param>
/// <param name="lastPaginationData">The last used pagination data</param>
/// <param name="interval">Kline interval</param>
/// <returns></returns>
public static PageRequest? GetNextPageRequestKlines(
Func<PageRequest?> nextPageRequest,
int resultCount,
IEnumerable<DateTime> timestamps,
DateTime? requestStartTime,
DateTime requestEndTime,
PaginationParameters lastPaginationData,
SharedKlineInterval interval
)
{
if (HasNextPageKlines(resultCount, timestamps, requestStartTime, requestEndTime, lastPaginationData.Limit, lastPaginationData.Direction, interval))
{
var result = nextPageRequest();
if (result != null)
{
result.StartTime ??= lastPaginationData.StartTime;
result.EndTime ??= lastPaginationData.EndTime;
return result;
}
}
return null;
}
/// <summary>
/// Get the next page request parameters from result data
/// </summary>
/// <param name="nextPageRequest">Callback for returning the next page request</param>
/// <param name="resultCount">Number of results in data</param>
/// <param name="timestamps">Timestamps of the result data</param>
/// <param name="requestStartTime">User request start time</param>
/// <param name="requestEndTime">User request end time</param>
/// <param name="lastPaginationData">The last used pagination data</param>
/// <param name="maxPeriod">Max period the time filters can span</param>
/// <param name="maxAge">Max age of the data</param>
/// <returns></returns>
public static PageRequest? GetNextPageRequest(
Func<PageRequest?> nextPageRequest,
int resultCount,
IEnumerable<DateTime> timestamps,
DateTime? requestStartTime,
DateTime requestEndTime,
PaginationParameters lastPaginationData,
TimeSpan? maxPeriod = null,
TimeSpan? maxAge = null
)
{
if (HasNextPage(resultCount, timestamps, requestStartTime, requestEndTime, lastPaginationData.Limit, lastPaginationData.Direction))
{
var result = nextPageRequest();
if (result != null)
{
result.StartTime ??= lastPaginationData.StartTime;
result.EndTime ??= lastPaginationData.EndTime;
return result;
}
}
if (maxPeriod != null)
{
if (HasNextPeriod(requestStartTime, requestEndTime, lastPaginationData.Direction, lastPaginationData, maxPeriod.Value, maxAge))
{
var (startTime, endTime) = GetNextPeriod(requestStartTime, requestEndTime, lastPaginationData.Direction, lastPaginationData, maxPeriod.Value, maxAge);
return new PageRequest
{
StartTime = startTime,
EndTime = endTime
};
}
}
return null;
}
/// <summary>
/// Check whether there is (potentially) another page available
/// </summary>
/// <param name="resultCount">Number of result entries</param>
/// <param name="timestamps">Timestamps</param>
/// <param name="requestStartTime">User request start time</param>
/// <param name="requestEndTime">User request end time</param>
/// <param name="limit">Max number of results requested</param>
/// <param name="direction">Data direction</param>
/// <param name="interval">Kline interval</param>
/// <returns></returns>
public static bool HasNextPageKlines(
int resultCount,
IEnumerable<DateTime> timestamps,
DateTime? requestStartTime,
DateTime requestEndTime,
int limit,
DataDirection direction,
SharedKlineInterval interval
)
{
if (resultCount < limit)
return false;
if (direction == DataDirection.Ascending)
{
if (timestamps.Max().AddSeconds((int)interval) >= requestEndTime)
return false;
return true;
}
else
{
if (timestamps.Min().AddSeconds((int)interval) < requestStartTime)
return false;
return true;
}
}
/// <summary>
/// Check whether there is (potentially) another page available
/// </summary>
/// <param name="resultCount">Number of result entries</param>
/// <param name="timestamps">Timestamps</param>
/// <param name="requestStartTime">User request start time</param>
/// <param name="requestEndTime">User request end time</param>
/// <param name="limit">Max number of results requested</param>
/// <param name="direction">Data direction</param>
/// <returns></returns>
public static bool HasNextPage(
int resultCount,
IEnumerable<DateTime> timestamps,
DateTime? requestStartTime,
DateTime requestEndTime,
int limit,
DataDirection direction)
{
if (resultCount < limit)
return false;
if (!timestamps.Any())
return false;
if (direction == DataDirection.Ascending)
{
if (timestamps.Max() >= requestEndTime)
return false;
return true;
}
else
{
if (timestamps.Min() < requestStartTime)
return false;
return true;
}
}
/// <summary>
/// Get the next page PageRequest
/// </summary>
public static PageRequest NextPageFromPage(PaginationParameters lastPaginationData)
{
return new PageRequest { Page = (lastPaginationData.Page ?? 1) + 1 };
}
/// <summary>
/// Get the next offset PageRequest
/// </summary>
public static PageRequest NextPageFromOffset(PaginationParameters lastPaginationData, int resultCount)
{
return new PageRequest { Offset = (lastPaginationData.Offset ?? 0) + resultCount };
}
/// <summary>
/// Get the next page cursor PageRequest
/// </summary>
public static PageRequest NextPageFromCursor(string nextCursor)
{
return new PageRequest { Cursor = nextCursor };
}
/// <summary>
/// Get the next id PageRequest
/// </summary>
public static PageRequest NextPageFromId(long nextFromId)
{
return new PageRequest { FromId = nextFromId.ToString() };
}
/// <summary>
/// Get the next id PageRequest
/// </summary>
public static PageRequest NextPageFromId(string nextFromId)
{
return new PageRequest { FromId = nextFromId };
}
/// <summary>
/// Get the next start/end time PageRequest
/// </summary>
public static PageRequest NextPageFromTime(PaginationParameters lastPaginationData, DateTime lastTimestamp, bool setOtherTimeLimiter = true)
{
if (lastPaginationData.Direction == DataDirection.Ascending)
return new PageRequest { StartTime = lastTimestamp.AddMilliseconds(1), EndTime = setOtherTimeLimiter ? lastPaginationData.EndTime : null };
else
return new PageRequest { EndTime = lastTimestamp.AddMilliseconds(-1), StartTime = setOtherTimeLimiter ? lastPaginationData.StartTime : null };
}
/// <summary>
/// Get the next start/end time klines PageRequest
/// </summary>
public static PageRequest NextPageFromTimeKlines(DataDirection direction, GetKlinesRequest request, DateTime lastTimestamp, int limit)
{
if (direction == DataDirection.Ascending)
{
var nextStartTime = lastTimestamp.AddSeconds((int)request.Interval);
var endTime = nextStartTime.AddSeconds(limit * (int)request.Interval);
var requestEndTime = request.EndTime ?? DateTime.UtcNow;
if (endTime > requestEndTime)
endTime = requestEndTime;
return new PageRequest { StartTime = nextStartTime, EndTime = endTime };
}
else
{
var nextEndTime = lastTimestamp.AddSeconds(-(int)request.Interval);
var startTime = nextEndTime.AddSeconds(-(limit * (int)request.Interval));
var requestStartTime = request.StartTime ?? DateTime.UtcNow;
if (startTime < requestStartTime)
startTime = requestStartTime;
return new PageRequest { StartTime = startTime, EndTime = nextEndTime };
}
}
/// <summary>
/// Whether another time period is to be requested
/// </summary>
/// <param name="requestStartTime">User request start time</param>
/// <param name="requestEndTime">User request end time</param>
/// <param name="direction">Data direction</param>
/// <param name="lastPaginationParameters">Pagination parameters used</param>
/// <param name="period">Max time period a request can span</param>
/// <param name="maxAge">Max age of data that can be requested</param>
public static bool HasNextPeriod(
DateTime? requestStartTime,
DateTime requestEndTime,
DataDirection direction,
PaginationParameters lastPaginationParameters,
TimeSpan period,
TimeSpan? maxAge)
{
if (direction == DataDirection.Ascending && lastPaginationParameters.StartTime == null)
throw new InvalidOperationException("Invalid pagination data; no start time for ascending pagination");
if (direction == DataDirection.Ascending)
{
return (requestEndTime - lastPaginationParameters.EndTime!.Value).TotalSeconds > 1;
}
else
{
var lastPageStartTime = lastPaginationParameters.StartTime ?? lastPaginationParameters.EndTime!.Value.Add(-period);
if (requestStartTime != null)
{
var nextPeriodDuration = lastPageStartTime - requestStartTime.Value;
return nextPeriodDuration.TotalSeconds > 1;
}
else
{
var nextStartTime = lastPageStartTime - period;
if (maxAge != null)
{
var minStartTime = DateTime.UtcNow - maxAge.Value;
if ((nextStartTime.Add(period) - minStartTime).TotalSeconds < 1)
return false;
}
var nextPeriodDuration = lastPageStartTime - nextStartTime;
return (nextPeriodDuration).TotalSeconds > 1;
}
}
}
/// <summary>
/// Get the start/end time for the next data period
/// </summary>
/// <param name="requestStartTime">User request start time</param>
/// <param name="requestEndTime">User request end time</param>
/// <param name="direction">Data direction</param>
/// <param name="lastPaginationParameters">Pagination parameters used</param>
/// <param name="period">Max time period a request can span</param>
/// <param name="maxAge">Max age of data that can be requested</param>
public static (DateTime? startTime, DateTime? endTime) GetNextPeriod(
DateTime? requestStartTime,
DateTime requestEndTime,
DataDirection direction,
PaginationParameters lastPaginationParameters,
TimeSpan period,
TimeSpan? maxAge
)
{
DateTime? nextStartTime = null;
DateTime? nextEndTime = null;
if (direction == DataDirection.Ascending)
{
if (lastPaginationParameters.StartTime != null)
nextStartTime = lastPaginationParameters.StartTime.Value.Add(period);
if (lastPaginationParameters.EndTime != null)
nextEndTime = lastPaginationParameters.EndTime.Value.Add(period);
}
else
{
if (lastPaginationParameters.StartTime != null)
nextStartTime = lastPaginationParameters.StartTime.Value.Add(-period);
if (lastPaginationParameters.EndTime != null)
nextEndTime = lastPaginationParameters.EndTime.Value.Add(-period);
}
if (nextStartTime != null && nextStartTime < requestStartTime)
nextStartTime = requestStartTime;
if (nextStartTime != null && maxAge != null && nextStartTime < DateTime.UtcNow - maxAge)
{
nextStartTime = DateTime.UtcNow.Add(-maxAge.Value);
// Add 30 seconds to max sure the client/server time offset and latency doesn't push the timestamp over the limit
nextStartTime = nextStartTime.Value.Add(TimeSpan.FromSeconds(30));
}
if (nextEndTime != null && nextEndTime > requestEndTime)
nextEndTime = requestEndTime;
return (nextStartTime, nextEndTime);
}
}
}
@@ -0,0 +1,43 @@
using System;
namespace CryptoExchange.Net.SharedApis
{
/// <summary>
/// Pagination parameters
/// </summary>
public record PaginationParameters
{
/// <summary>
/// Data direction
/// </summary>
public DataDirection Direction { get; set; }
/// <summary>
/// Start time filter
/// </summary>
public DateTime? StartTime { get; set; }
/// <summary>
/// End time filter
/// </summary>
public DateTime? EndTime { get; set; }
/// <summary>
/// Id filter
/// </summary>
public string? FromId { get; set; }
/// <summary>
/// Result offset
/// </summary>
public int? Offset { get; set; }
/// <summary>
/// Page number
/// </summary>
public int? Page { get; set; }
/// <summary>
/// Pagination cursor
/// </summary>
public string? Cursor { get; set; }
/// <summary>
/// Max number of results
/// </summary>
public int Limit { get; set; }
}
}
@@ -19,6 +19,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
/// </summary>
public int? Limit { get; }
/// <summary>
/// Data direction
/// </summary>
public DataDirection? Direction { get; set; }
/// <summary>
/// ctor
@@ -27,12 +31,14 @@ namespace CryptoExchange.Net.SharedApis
/// <param name="startTime">Filter by start time</param>
/// <param name="endTime">Filter by end time</param>
/// <param name="limit">Max number of results</param>
/// <param name="direction">Data direction</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public GetClosedOrdersRequest(SharedSymbol symbol, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, ExchangeParameters? exchangeParameters = null) : base(symbol, exchangeParameters)
public GetClosedOrdersRequest(SharedSymbol symbol, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, DataDirection? direction = null, ExchangeParameters? exchangeParameters = null) : base(symbol, exchangeParameters)
{
StartTime = startTime;
EndTime = endTime;
Limit = limit;
Direction = direction;
}
}
}
@@ -23,6 +23,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
/// </summary>
public int? Limit { get; }
/// <summary>
/// Data direction
/// </summary>
public DataDirection? Direction { get; set; }
/// <summary>
/// ctor
@@ -31,13 +35,15 @@ namespace CryptoExchange.Net.SharedApis
/// <param name="startTime">Filter by start time</param>
/// <param name="endTime">Filter by end time</param>
/// <param name="limit">Max number of results</param>
/// <param name="direction">Data direction</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public GetDepositsRequest(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, ExchangeParameters? exchangeParameters = null) : base(exchangeParameters)
public GetDepositsRequest(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, DataDirection? direction = null, ExchangeParameters? exchangeParameters = null) : base(exchangeParameters)
{
Asset = asset;
StartTime = startTime;
EndTime = endTime;
Limit = limit;
Direction = direction;
}
}
}
@@ -19,6 +19,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
/// </summary>
public int? Limit { get; set; }
/// <summary>
/// Data direction
/// </summary>
public DataDirection? Direction { get; set; }
/// <summary>
/// ctor
@@ -27,12 +31,14 @@ namespace CryptoExchange.Net.SharedApis
/// <param name="startTime">Filter by start time</param>
/// <param name="endTime">Filter by end time</param>
/// <param name="limit">Max number of results</param>
/// <param name="direction">Data direction</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public GetFundingRateHistoryRequest(SharedSymbol symbol, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, ExchangeParameters? exchangeParameters = null) : base(symbol, exchangeParameters)
public GetFundingRateHistoryRequest(SharedSymbol symbol, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, DataDirection? direction = null, ExchangeParameters? exchangeParameters = null) : base(symbol, exchangeParameters)
{
StartTime = startTime;
EndTime = endTime;
Limit = limit;
Direction = direction;
}
}
}
@@ -23,6 +23,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
/// </summary>
public int? Limit { get; set; }
/// <summary>
/// Data direction
/// </summary>
public DataDirection? Direction { get; set; }
/// <summary>
/// ctor
@@ -32,13 +36,15 @@ namespace CryptoExchange.Net.SharedApis
/// <param name="startTime">Filter by start time</param>
/// <param name="endTime">Filter by end time</param>
/// <param name="limit">Max number of results</param>
/// <param name="direction">Data direction</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public GetKlinesRequest(SharedSymbol symbol, SharedKlineInterval interval, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, ExchangeParameters? exchangeParameters = null) : base(symbol, exchangeParameters)
public GetKlinesRequest(SharedSymbol symbol, SharedKlineInterval interval, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, DataDirection? direction = null, ExchangeParameters? exchangeParameters = null) : base(symbol, exchangeParameters)
{
Interval = interval;
StartTime = startTime;
EndTime = endTime;
Limit = limit;
Direction = direction;
}
}
}
@@ -27,6 +27,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
/// </summary>
public int? Limit { get; set; }
/// <summary>
/// Data direction
/// </summary>
public DataDirection? Direction { get; set; }
/// <summary>
/// ctor
@@ -35,13 +39,15 @@ namespace CryptoExchange.Net.SharedApis
/// <param name="startTime">Filter by start time</param>
/// <param name="endTime">Filter by end time</param>
/// <param name="limit">Max number of results</param>
/// <param name="direction">Data direction</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public GetPositionHistoryRequest(SharedSymbol symbol, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, ExchangeParameters? exchangeParameters = null) : base(exchangeParameters)
public GetPositionHistoryRequest(SharedSymbol symbol, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, DataDirection? direction = null, ExchangeParameters? exchangeParameters = null) : base(exchangeParameters)
{
Symbol = symbol;
StartTime = startTime;
EndTime = endTime;
Limit = limit;
Direction = direction;
}
/// <summary>
@@ -51,13 +57,15 @@ namespace CryptoExchange.Net.SharedApis
/// <param name="startTime">Filter by start time</param>
/// <param name="endTime">Filter by end time</param>
/// <param name="limit">Max number of results</param>
/// <param name="direction">Data direction</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public GetPositionHistoryRequest(TradingMode? tradeMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, ExchangeParameters? exchangeParameters = null) : base(exchangeParameters)
public GetPositionHistoryRequest(TradingMode? tradeMode = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, DataDirection? direction = null, ExchangeParameters? exchangeParameters = null) : base(exchangeParameters)
{
TradingMode = tradeMode;
StartTime = startTime;
EndTime = endTime;
Limit = limit;
Direction = direction;
}
}
}
@@ -10,15 +10,19 @@ namespace CryptoExchange.Net.SharedApis
/// <summary>
/// Filter by start time
/// </summary>
public DateTime StartTime { get; }
public DateTime StartTime { get; set; }
/// <summary>
/// Filter by end time
/// </summary>
public DateTime EndTime { get; }
public DateTime? EndTime { get; set; }
/// <summary>
/// Max number of results
/// </summary>
public int? Limit { get; }
public int? Limit { get; set; }
/// <summary>
/// Data direction
/// </summary>
public DataDirection? Direction { get; set; }
/// <summary>
/// ctor
@@ -27,12 +31,14 @@ namespace CryptoExchange.Net.SharedApis
/// <param name="startTime">Filter by start time</param>
/// <param name="endTime">Filter by end time</param>
/// <param name="limit">Max number of results</param>
/// <param name="direction">Data direction</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public GetTradeHistoryRequest(SharedSymbol symbol, DateTime startTime, DateTime endTime, int? limit = null, ExchangeParameters? exchangeParameters = null) : base(symbol, exchangeParameters)
public GetTradeHistoryRequest(SharedSymbol symbol, DateTime startTime, DateTime? endTime = null, int? limit = null, DataDirection? direction = null, ExchangeParameters? exchangeParameters = null) : base(symbol, exchangeParameters)
{
StartTime = startTime;
EndTime = endTime;
Limit = limit;
Direction = direction;
}
}
}
@@ -19,6 +19,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
/// </summary>
public int? Limit { get; }
/// <summary>
/// Data direction
/// </summary>
public DataDirection? Direction { get; set; }
/// <summary>
/// ctor
@@ -27,12 +31,14 @@ namespace CryptoExchange.Net.SharedApis
/// <param name="startTime">Filter by start time</param>
/// <param name="endTime">Filter by end time</param>
/// <param name="limit">Max number of results</param>
/// <param name="direction">Data direction</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public GetUserTradesRequest(SharedSymbol symbol, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, ExchangeParameters? exchangeParameters = null) : base(symbol, exchangeParameters)
public GetUserTradesRequest(SharedSymbol symbol, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, DataDirection? direction = null, ExchangeParameters? exchangeParameters = null) : base(symbol, exchangeParameters)
{
StartTime = startTime;
EndTime = endTime;
Limit = limit;
Direction = direction;
}
}
}
@@ -23,6 +23,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
/// </summary>
public int? Limit { get; }
/// <summary>
/// Data direction
/// </summary>
public DataDirection? Direction { get; set; }
/// <summary>
/// ctor
@@ -31,13 +35,15 @@ namespace CryptoExchange.Net.SharedApis
/// <param name="startTime">Filter by start time</param>
/// <param name="endTime">Filter by end time</param>
/// <param name="limit">Max number of results</param>
/// <param name="direction">Data direction</param>
/// <param name="exchangeParameters">Exchange specific parameters</param>
public GetWithdrawalsRequest(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, ExchangeParameters? exchangeParameters = null) : base(exchangeParameters)
public GetWithdrawalsRequest(string? asset = null, DateTime? startTime = null, DateTime? endTime = null, int? limit = null, DataDirection? direction = null, ExchangeParameters? exchangeParameters = null) : base(exchangeParameters)
{
Asset = asset;
StartTime = startTime;
EndTime = endTime;
Limit = limit;
Direction = direction;
}
}
}