diff --git a/CryptoExchange.Net.UnitTests/RestClientTests.cs b/CryptoExchange.Net.UnitTests/RestClientTests.cs
index 555cf70d..d17a4560 100644
--- a/CryptoExchange.Net.UnitTests/RestClientTests.cs
+++ b/CryptoExchange.Net.UnitTests/RestClientTests.cs
@@ -96,7 +96,7 @@ namespace CryptoExchange.Net.UnitTests
// assert
ClassicAssert.IsFalse(result.Success);
Assert.That(result.Error != null);
- Assert.That(result.Error is ServerError);
+ Assert.That(result.Error is DeserializeError);
Assert.That(result.Error.Message.Contains(response));
}
diff --git a/CryptoExchange.Net/ExchangeHelpers.cs b/CryptoExchange.Net/ExchangeHelpers.cs
index 9cd859b4..1e200a49 100644
--- a/CryptoExchange.Net/ExchangeHelpers.cs
+++ b/CryptoExchange.Net/ExchangeHelpers.cs
@@ -4,6 +4,7 @@ using CryptoExchange.Net.SharedApis;
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Threading;
@@ -310,11 +311,11 @@ namespace CryptoExchange.Net
/// The request parameters
/// Cancellation token
///
- public static async IAsyncEnumerable> ExecutePages(Func>> paginatedFunc, U request, [EnumeratorCancellation]CancellationToken ct = default)
+ public static async IAsyncEnumerable> ExecutePages(Func>> paginatedFunc, U request, [EnumeratorCancellation]CancellationToken ct = default)
{
var result = new List();
ExchangeWebResult batch;
- INextPageToken? nextPageToken = null;
+ PageRequest? nextPageToken = null;
while (true)
{
batch = await paginatedFunc(request, nextPageToken, ct).ConfigureAwait(false);
@@ -323,12 +324,42 @@ namespace CryptoExchange.Net
break;
result.AddRange(batch.Data);
- nextPageToken = batch.NextPageToken;
+ nextPageToken = batch.NextPageRequest;
if (nextPageToken == null)
break;
}
}
+ ///
+ /// Apply filters to the data set
+ ///
+ /// Type
+ /// Data set
+ /// Time selector for the data
+ /// Start time filter
+ /// End time filter
+ /// Data direction
+ public static IEnumerable ApplyFilter(
+ IEnumerable data,
+ Func timeSelector,
+ DateTime? startTime,
+ DateTime? endTime,
+ DataDirection direction)
+ {
+ if (direction == DataDirection.Ascending)
+ data = data.OrderBy(timeSelector);
+ else
+ data = data.OrderByDescending(timeSelector);
+
+ if (startTime != null)
+ data = data.Where(x => timeSelector(x) >= startTime.Value);
+
+ if (endTime != null)
+ data = data.Where(x => timeSelector(x) < endTime.Value);
+
+ return data;
+ }
+
///
/// Apply the rules (price and quantity step size and decimals precision, min/max quantity) from the symbol to the quantity and price
///
diff --git a/CryptoExchange.Net/Objects/CallResult.cs b/CryptoExchange.Net/Objects/CallResult.cs
index 74f79ac6..a4a02e13 100644
--- a/CryptoExchange.Net/Objects/CallResult.cs
+++ b/CryptoExchange.Net/Objects/CallResult.cs
@@ -531,11 +531,11 @@ namespace CryptoExchange.Net.Objects
/// The exchange
/// Trade mode the result applies to
/// Data
- /// Next page token
+ /// Next page request
///
- public ExchangeWebResult AsExchangeResult(string exchange, TradingMode tradeMode, [AllowNull] K data, INextPageToken? nextPageToken = null)
+ public ExchangeWebResult AsExchangeResult(string exchange, TradingMode tradeMode, [AllowNull] K data, PageRequest? nextPageRequest = null)
{
- return new ExchangeWebResult(exchange, tradeMode, As(data), nextPageToken);
+ return new ExchangeWebResult(exchange, tradeMode, As(data), nextPageRequest);
}
///
@@ -545,11 +545,11 @@ namespace CryptoExchange.Net.Objects
/// The exchange
/// Trade modes the result applies to
/// Data
- /// Next page token
+ /// Next page token
///
- public ExchangeWebResult AsExchangeResult(string exchange, TradingMode[]? tradeModes, [AllowNull] K data, INextPageToken? nextPageToken = null)
+ public ExchangeWebResult AsExchangeResult(string exchange, TradingMode[]? tradeModes, [AllowNull] K data, PageRequest? nextPageRequest = null)
{
- return new ExchangeWebResult(exchange, tradeModes, As(data), nextPageToken);
+ return new ExchangeWebResult(exchange, tradeModes, As(data), nextPageRequest);
}
///
diff --git a/CryptoExchange.Net/RateLimiting/Filters/PathStartFilter.cs b/CryptoExchange.Net/RateLimiting/Filters/PathStartFilter.cs
index ba68b8b6..1001b663 100644
--- a/CryptoExchange.Net/RateLimiting/Filters/PathStartFilter.cs
+++ b/CryptoExchange.Net/RateLimiting/Filters/PathStartFilter.cs
@@ -17,11 +17,11 @@ namespace CryptoExchange.Net.RateLimiting.Filters
///
public PathStartFilter(string path)
{
- _path = path;
+ _path = path.TrimStart('/');
}
///
public bool Passes(RateLimitItemType type, RequestDefinition definition, string host, string? apiKey)
- => definition.Path.StartsWith(_path, StringComparison.OrdinalIgnoreCase);
+ => definition.Path.TrimStart('/').StartsWith(_path, StringComparison.OrdinalIgnoreCase);
}
}
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/INextPageToken.cs b/CryptoExchange.Net/SharedApis/Interfaces/INextPageToken.cs
deleted file mode 100644
index ceb1e73d..00000000
--- a/CryptoExchange.Net/SharedApis/Interfaces/INextPageToken.cs
+++ /dev/null
@@ -1,111 +0,0 @@
-using System;
-
-namespace CryptoExchange.Net.SharedApis
-{
- ///
- /// A token which a request can use to retrieve the next page if there are more pages in the result set
- ///
- public interface INextPageToken
- {
- }
-
- ///
- /// A datetime offset token
- ///
- public record DateTimeToken: INextPageToken
- {
- ///
- /// Last result time
- ///
- public DateTime LastTime { get; set; }
-
- ///
- /// ctor
- ///
- public DateTimeToken(DateTime timestamp)
- {
- LastTime = timestamp;
- }
- }
-
- ///
- /// A current page index token
- ///
- public record PageToken: INextPageToken
- {
- ///
- /// The next page index
- ///
- public int Page { get; set; }
- ///
- /// Page size
- ///
- public int PageSize { get; set; }
-
- ///
- /// ctor
- ///
- public PageToken(int page, int pageSize)
- {
- Page = page;
- PageSize = pageSize;
- }
- }
-
- ///
- /// A id offset token
- ///
- public record FromIdToken : INextPageToken
- {
- ///
- /// The last id from previous result
- ///
- public string FromToken { get; set; }
-
- ///
- /// ctor
- ///
- public FromIdToken(string fromToken)
- {
- FromToken = fromToken;
- }
- }
-
- ///
- /// A cursor token
- ///
- public record CursorToken : INextPageToken
- {
- ///
- /// The next page cursor
- ///
- public string Cursor { get; set; }
-
- ///
- /// ctor
- ///
- public CursorToken(string cursor)
- {
- Cursor = cursor;
- }
- }
-
- ///
- /// A result offset token
- ///
- public record OffsetToken : INextPageToken
- {
- ///
- /// Offset in the result set
- ///
- public int Offset { get; set; }
-
- ///
- /// ctor
- ///
- public OffsetToken(int offset)
- {
- Offset = offset;
- }
- }
-}
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFundingRateRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFundingRateRestClient.cs
index 057cb367..0798554b 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFundingRateRestClient.cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFundingRateRestClient.cs
@@ -16,8 +16,8 @@ namespace CryptoExchange.Net.SharedApis
/// Get funding rate records
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
- Task> GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetFundingRateHistoryAsync(GetFundingRateHistoryRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
}
}
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFuturesOrderRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFuturesOrderRestClient.cs
index 5c3af62b..39632ddd 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFuturesOrderRestClient.cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IFuturesOrderRestClient.cs
@@ -73,14 +73,14 @@ namespace CryptoExchange.Net.SharedApis
///
/// Spot get closed orders request options
///
- PaginatedEndpointOptions GetClosedFuturesOrdersOptions { get; }
+ GetClosedOrdersOptions GetClosedFuturesOrdersOptions { get; }
///
/// Get info on closed futures orders
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
- Task> GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetClosedFuturesOrdersAsync(GetClosedOrdersRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
///
/// Futures get order trades request options
@@ -96,14 +96,14 @@ namespace CryptoExchange.Net.SharedApis
///
/// Futures user trades request options
///
- PaginatedEndpointOptions GetFuturesUserTradesOptions { get; }
+ GetUserTradesOptions GetFuturesUserTradesOptions { get; }
///
/// Get futures user trade records
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
- Task> GetFuturesUserTradesAsync(GetUserTradesRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetFuturesUserTradesAsync(GetUserTradesRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
///
/// Futures cancel order request options
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IIndexPriceKlineRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IIndexPriceKlineRestClient.cs
index 4c2299f2..85b78a27 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IIndexPriceKlineRestClient.cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IIndexPriceKlineRestClient.cs
@@ -16,8 +16,8 @@ namespace CryptoExchange.Net.SharedApis
/// Get index price kline/candlestick data
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
- Task> GetIndexPriceKlinesAsync(GetKlinesRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetIndexPriceKlinesAsync(GetKlinesRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
}
}
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IMarkPriceKlineRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IMarkPriceKlineRestClient.cs
index 0b025280..a749c166 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IMarkPriceKlineRestClient.cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IMarkPriceKlineRestClient.cs
@@ -16,8 +16,8 @@ namespace CryptoExchange.Net.SharedApis
/// Get mark price kline/candlestick data
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
- Task> GetMarkPriceKlinesAsync(GetKlinesRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetMarkPriceKlinesAsync(GetKlinesRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
}
}
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IPositionHistoryRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IPositionHistoryRestClient.cs
index 59059275..d51b8c2a 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IPositionHistoryRestClient.cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Futures/IPositionHistoryRestClient.cs
@@ -16,8 +16,8 @@ namespace CryptoExchange.Net.SharedApis
/// Get position history
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
- Task> GetPositionHistoryAsync(GetPositionHistoryRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetPositionHistoryAsync(GetPositionHistoryRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
}
}
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/IDepositRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/IDepositRestClient.cs
index c50758e1..9e1af83f 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/IDepositRestClient.cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/IDepositRestClient.cs
@@ -30,9 +30,9 @@ namespace CryptoExchange.Net.SharedApis
/// Get deposit records
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
///
- Task> GetDepositsAsync(GetDepositsRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetDepositsAsync(GetDepositsRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
}
}
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/IKlineRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/IKlineRestClient.cs
index a71ac1ea..81e1c515 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/IKlineRestClient.cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/IKlineRestClient.cs
@@ -17,9 +17,9 @@ namespace CryptoExchange.Net.SharedApis
/// Get kline/candlestick data
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
///
- Task> GetKlinesAsync(GetKlinesRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetKlinesAsync(GetKlinesRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
}
}
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/ITradeHistoryRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/ITradeHistoryRestClient.cs
index c20d9ce4..327db6e3 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/ITradeHistoryRestClient.cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/ITradeHistoryRestClient.cs
@@ -17,9 +17,9 @@ namespace CryptoExchange.Net.SharedApis
/// Get public trade history
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
///
- Task> GetTradeHistoryAsync(GetTradeHistoryRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetTradeHistoryAsync(GetTradeHistoryRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
}
}
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/IWithdrawalRestClient .cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/IWithdrawalRestClient .cs
index c2f36000..fd21b0b2 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/IWithdrawalRestClient .cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/IWithdrawalRestClient .cs
@@ -17,9 +17,9 @@ namespace CryptoExchange.Net.SharedApis
/// Get withdrawal records
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
///
- Task> GetWithdrawalsAsync(GetWithdrawalsRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetWithdrawalsAsync(GetWithdrawalsRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
}
}
diff --git a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotOrderRestClient.cs b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotOrderRestClient.cs
index c4d1a321..6a1bd1ba 100644
--- a/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotOrderRestClient.cs
+++ b/CryptoExchange.Net/SharedApis/Interfaces/Rest/Spot/ISpotOrderRestClient.cs
@@ -72,14 +72,14 @@ namespace CryptoExchange.Net.SharedApis
///
/// Spot get closed orders request options
///
- PaginatedEndpointOptions GetClosedSpotOrdersOptions { get; }
+ GetClosedOrdersOptions GetClosedSpotOrdersOptions { get; }
///
/// Get info on closed spot orders
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
- Task> GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetClosedSpotOrdersAsync(GetClosedOrdersRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
///
/// Spot get order trades request options
@@ -95,14 +95,14 @@ namespace CryptoExchange.Net.SharedApis
///
/// Spot user trades request options
///
- PaginatedEndpointOptions GetSpotUserTradesOptions { get; }
+ GetUserTradesOptions GetSpotUserTradesOptions { get; }
///
/// Get spot user trade records
///
/// Request info
- /// The pagination token from the previous request to continue pagination
+ /// The pagination request from the previous request result `NextPageRequest` property to continue pagination
/// Cancellation token
- Task> GetSpotUserTradesAsync(GetUserTradesRequest request, INextPageToken? nextPageToken = null, CancellationToken ct = default);
+ Task> GetSpotUserTradesAsync(GetUserTradesRequest request, PageRequest? nextPageToken = null, CancellationToken ct = default);
///
/// Spot cancel order request options
diff --git a/CryptoExchange.Net/SharedApis/Models/ExchangeWebResult.cs b/CryptoExchange.Net/SharedApis/Models/ExchangeWebResult.cs
index 7861d212..6819f79a 100644
--- a/CryptoExchange.Net/SharedApis/Models/ExchangeWebResult.cs
+++ b/CryptoExchange.Net/SharedApis/Models/ExchangeWebResult.cs
@@ -24,9 +24,9 @@ namespace CryptoExchange.Net.SharedApis
public TradingMode[]? DataTradeMode { get; }
///
- /// 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
///
- public INextPageToken? NextPageToken { get; }
+ public PageRequest? NextPageRequest { get; }
///
/// ctor
@@ -46,7 +46,7 @@ namespace CryptoExchange.Net.SharedApis
string exchange,
TradingMode dataTradeMode,
WebCallResult 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;
}
///
@@ -74,7 +74,7 @@ namespace CryptoExchange.Net.SharedApis
string exchange,
TradingMode[]? dataTradeModes,
WebCallResult 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;
}
///
@@ -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;
}
///
@@ -144,7 +144,7 @@ namespace CryptoExchange.Net.SharedApis
///
public new ExchangeWebResult As([AllowNull] K data)
{
- return new ExchangeWebResult(Exchange, DataTradeMode, ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, Error, NextPageToken);
+ return new ExchangeWebResult(Exchange, DataTradeMode, ResponseStatusCode, HttpVersion, ResponseHeaders, ResponseTime, ResponseLength, OriginalData, RequestId, RequestUrl, RequestBody, RequestMethod, RequestHeaders, DataSource, data, Error, NextPageRequest);
}
///
diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetClosedOrdersOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetClosedOrdersOptions.cs
index 1727806e..12f2f942 100644
--- a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetClosedOrdersOptions.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetClosedOrdersOptions.cs
@@ -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
///
public class GetClosedOrdersOptions : PaginatedEndpointOptions
{
- ///
- /// Whether the start/end time filter is supported
- ///
- public bool TimeFilterSupported { get; set; }
-
///
/// ctor
///
- 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;
}
///
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();
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetDepositsOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetDepositsOptions.cs
index fee678b2..88e39052 100644
--- a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetDepositsOptions.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetDepositsOptions.cs
@@ -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
///
public class GetDepositsOptions : PaginatedEndpointOptions
{
- ///
- /// Whether the start/end time filter is supported
- ///
- public bool TimeFilterSupported { get; set; }
-
///
/// ctor
///
- 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;
}
///
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();
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetFundingRateHistoryOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetFundingRateHistoryOptions.cs
index be857c25..114b6456 100644
--- a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetFundingRateHistoryOptions.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetFundingRateHistoryOptions.cs
@@ -1,4 +1,8 @@
-namespace CryptoExchange.Net.SharedApis
+using CryptoExchange.Net.Objects;
+using System;
+using System.Text;
+
+namespace CryptoExchange.Net.SharedApis
{
///
/// Options for requesting funding rate history
@@ -8,8 +12,43 @@
///
/// ctor
///
- 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)
{
}
+
+ ///
+ 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);
+ }
+
+ ///
+ public override string ToString(string exchange)
+ {
+ var sb = new StringBuilder(base.ToString(exchange));
+ sb.AppendLine($"Time filter supported: {TimePeriodFilterSupport}");
+ return sb.ToString();
+ }
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetKlinesOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetKlinesOptions.cs
index c1712591..3cf3e5d9 100644
--- a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetKlinesOptions.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetKlinesOptions.cs
@@ -18,15 +18,12 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of data points which can be requested
///
public int? MaxTotalDataPoints { get; set; }
- ///
- /// The max age of the data that can be requested
- ///
- public TimeSpan? MaxAge { get; set; }
///
/// ctor
///
- 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
///
/// ctor
///
- 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}");
diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetPositionHistoryOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetPositionHistoryOptions.cs
index ffb01585..59f82f00 100644
--- a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetPositionHistoryOptions.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetPositionHistoryOptions.cs
@@ -1,4 +1,8 @@
-namespace CryptoExchange.Net.SharedApis
+using CryptoExchange.Net.Objects;
+using System;
+using System.Text;
+
+namespace CryptoExchange.Net.SharedApis
{
///
/// Options for requesting position history
@@ -8,8 +12,43 @@
///
/// ctor
///
- 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)
{
}
+
+ ///
+ 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);
+ }
+
+ ///
+ public override string ToString(string exchange)
+ {
+ var sb = new StringBuilder(base.ToString(exchange));
+ sb.AppendLine($"Time filter supported: {TimePeriodFilterSupport}");
+ return sb.ToString();
+ }
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetTradeHistoryOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetTradeHistoryOptions.cs
index d07972fd..6c174dc7 100644
--- a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetTradeHistoryOptions.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetTradeHistoryOptions.cs
@@ -9,34 +9,27 @@ namespace CryptoExchange.Net.SharedApis
///
public class GetTradeHistoryOptions : PaginatedEndpointOptions
{
- ///
- /// The max age of data that can be requested
- ///
- public TimeSpan? MaxAge { get; set; }
-
///
/// ctor
///
- 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)
{
}
///
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);
}
-
- ///
- 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();
- }
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetUserTradesOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetUserTradesOptions.cs
new file mode 100644
index 00000000..f59d4480
--- /dev/null
+++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetUserTradesOptions.cs
@@ -0,0 +1,54 @@
+using CryptoExchange.Net.Objects;
+using System;
+using System.Text;
+
+namespace CryptoExchange.Net.SharedApis
+{
+ ///
+ /// Options for requesting user trades
+ ///
+ public class GetUserTradesOptions : PaginatedEndpointOptions
+ {
+ ///
+ /// ctor
+ ///
+ public GetUserTradesOptions(bool supportsAscending, bool supportsDescending, bool timeFilterSupported, int maxLimit)
+ : base(supportsAscending, supportsDescending, timeFilterSupported, maxLimit, true)
+ {
+ }
+
+ ///
+ 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);
+ }
+
+ ///
+ public override string ToString(string exchange)
+ {
+ var sb = new StringBuilder(base.ToString(exchange));
+ sb.AppendLine($"Time filter supported: {TimePeriodFilterSupport}");
+ return sb.ToString();
+ }
+ }
+}
diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetWithdrawalsOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetWithdrawalsOptions.cs
index 01572378..fa8a2bcd 100644
--- a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetWithdrawalsOptions.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/GetWithdrawalsOptions.cs
@@ -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
///
public class GetWithdrawalsOptions : PaginatedEndpointOptions
{
- ///
- /// Whether the start/end time filter is supported
- ///
- public bool TimeFilterSupported { get; set; }
-
///
/// ctor
///
- 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;
}
///
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();
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/PaginatedEndpointOptions.cs b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/PaginatedEndpointOptions.cs
index ed0e4960..e61cf11a 100644
--- a/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/PaginatedEndpointOptions.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Options/Endpoints/PaginatedEndpointOptions.cs
@@ -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
{
///
- /// Type of pagination supported
+ /// Whether ascending data retrieval and pagination is available
///
- public SharedPaginationSupport PaginationSupport { get; }
+ public bool SupportsAscending { get; set; }
+ ///
+ /// Whether ascending data retrieval and pagination is available
+ ///
+ public bool SupportsDescending { get; set; }
///
/// Whether filtering based on start/end time is supported
@@ -28,12 +33,23 @@ namespace CryptoExchange.Net.SharedApis
///
public int MaxLimit { get; set; }
+ ///
+ /// Max age of data that can be requested
+ ///
+ public TimeSpan? MaxAge { get; set; }
+
///
/// ctor
///
- 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();
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Pagination/DataDirection.cs b/CryptoExchange.Net/SharedApis/Models/Pagination/DataDirection.cs
new file mode 100644
index 00000000..30f541b7
--- /dev/null
+++ b/CryptoExchange.Net/SharedApis/Models/Pagination/DataDirection.cs
@@ -0,0 +1,17 @@
+namespace CryptoExchange.Net.SharedApis
+{
+ ///
+ /// Data direction
+ ///
+ public enum DataDirection
+ {
+ ///
+ /// Old to new order
+ ///
+ Ascending,
+ ///
+ /// New to old order
+ ///
+ Descending
+ }
+}
diff --git a/CryptoExchange.Net/SharedApis/Models/Pagination/PageRequest.cs b/CryptoExchange.Net/SharedApis/Models/Pagination/PageRequest.cs
new file mode 100644
index 00000000..f77acea2
--- /dev/null
+++ b/CryptoExchange.Net/SharedApis/Models/Pagination/PageRequest.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace CryptoExchange.Net.SharedApis
+{
+ ///
+ /// Next page request info
+ ///
+ public class PageRequest
+ {
+ ///
+ /// Pagination cursor
+ ///
+ public string? Cursor { get; set; }
+ ///
+ /// Page number
+ ///
+ public int? Page { get; set; }
+ ///
+ /// Result offset
+ ///
+ public int? Offset { get; set; }
+ ///
+ /// From id filter
+ ///
+ public string? FromId { get; set; }
+ ///
+ /// Start time filter
+ ///
+ public DateTime? StartTime { get; set; }
+ ///
+ /// End time filter
+ ///
+ public DateTime? EndTime { get; set; }
+ }
+}
diff --git a/CryptoExchange.Net/SharedApis/Models/Pagination/Pagination.cs b/CryptoExchange.Net/SharedApis/Models/Pagination/Pagination.cs
new file mode 100644
index 00000000..81042ef9
--- /dev/null
+++ b/CryptoExchange.Net/SharedApis/Models/Pagination/Pagination.cs
@@ -0,0 +1,405 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace CryptoExchange.Net.SharedApis
+{
+ ///
+ /// Pagination methods
+ ///
+ public static class Pagination
+ {
+ ///
+ /// Get pagination parameters
+ ///
+ /// The data direction
+ /// Result limit
+ /// User request start time
+ /// User request end time
+ /// Provided page request
+ /// Whether to set start time if direction is descending, or end time if direction is ascending
+ /// Max period the time filters can span
+ ///
+ 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
+ };
+ }
+
+ ///
+ /// Get the next page request parameters from result kline data
+ ///
+ /// Callback for returning the next page request
+ /// Number of results in data
+ /// Timestamps of the result data
+ /// User request start time
+ /// User request end time
+ /// The last used pagination data
+ /// Kline interval
+ ///
+ public static PageRequest? GetNextPageRequestKlines(
+ Func nextPageRequest,
+ int resultCount,
+ IEnumerable 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;
+ }
+
+ ///
+ /// Get the next page request parameters from result data
+ ///
+ /// Callback for returning the next page request
+ /// Number of results in data
+ /// Timestamps of the result data
+ /// User request start time
+ /// User request end time
+ /// The last used pagination data
+ /// Max period the time filters can span
+ /// Max age of the data
+ ///
+ public static PageRequest? GetNextPageRequest(
+ Func nextPageRequest,
+ int resultCount,
+ IEnumerable 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;
+ }
+
+ ///
+ /// Check whether there is (potentially) another page available
+ ///
+ /// Number of result entries
+ /// Timestamps
+ /// User request start time
+ /// User request end time
+ /// Max number of results requested
+ /// Data direction
+ /// Kline interval
+ ///
+ public static bool HasNextPageKlines(
+ int resultCount,
+ IEnumerable 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;
+ }
+ }
+
+ ///
+ /// Check whether there is (potentially) another page available
+ ///
+ /// Number of result entries
+ /// Timestamps
+ /// User request start time
+ /// User request end time
+ /// Max number of results requested
+ /// Data direction
+ ///
+ public static bool HasNextPage(
+ int resultCount,
+ IEnumerable 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;
+ }
+ }
+
+ ///
+ /// Get the next page PageRequest
+ ///
+ public static PageRequest NextPageFromPage(PaginationParameters lastPaginationData)
+ {
+ return new PageRequest { Page = (lastPaginationData.Page ?? 1) + 1 };
+ }
+ ///
+ /// Get the next offset PageRequest
+ ///
+ public static PageRequest NextPageFromOffset(PaginationParameters lastPaginationData, int resultCount)
+ {
+ return new PageRequest { Offset = (lastPaginationData.Offset ?? 0) + resultCount };
+ }
+ ///
+ /// Get the next page cursor PageRequest
+ ///
+ public static PageRequest NextPageFromCursor(string nextCursor)
+ {
+ return new PageRequest { Cursor = nextCursor };
+ }
+ ///
+ /// Get the next id PageRequest
+ ///
+ public static PageRequest NextPageFromId(long nextFromId)
+ {
+ return new PageRequest { FromId = nextFromId.ToString() };
+ }
+ ///
+ /// Get the next id PageRequest
+ ///
+ public static PageRequest NextPageFromId(string nextFromId)
+ {
+ return new PageRequest { FromId = nextFromId };
+ }
+ ///
+ /// Get the next start/end time PageRequest
+ ///
+ 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 };
+ }
+
+ ///
+ /// Get the next start/end time klines PageRequest
+ ///
+ 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 };
+ }
+ }
+
+ ///
+ /// Whether another time period is to be requested
+ ///
+ /// User request start time
+ /// User request end time
+ /// Data direction
+ /// Pagination parameters used
+ /// Max time period a request can span
+ /// Max age of data that can be requested
+ 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;
+ }
+ }
+ }
+
+ ///
+ /// Get the start/end time for the next data period
+ ///
+ /// User request start time
+ /// User request end time
+ /// Data direction
+ /// Pagination parameters used
+ /// Max time period a request can span
+ /// Max age of data that can be requested
+ 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);
+ }
+ }
+}
diff --git a/CryptoExchange.Net/SharedApis/Models/Pagination/PaginationParameters.cs b/CryptoExchange.Net/SharedApis/Models/Pagination/PaginationParameters.cs
new file mode 100644
index 00000000..cf8e35d4
--- /dev/null
+++ b/CryptoExchange.Net/SharedApis/Models/Pagination/PaginationParameters.cs
@@ -0,0 +1,43 @@
+using System;
+
+namespace CryptoExchange.Net.SharedApis
+{
+ ///
+ /// Pagination parameters
+ ///
+ public record PaginationParameters
+ {
+ ///
+ /// Data direction
+ ///
+ public DataDirection Direction { get; set; }
+ ///
+ /// Start time filter
+ ///
+ public DateTime? StartTime { get; set; }
+ ///
+ /// End time filter
+ ///
+ public DateTime? EndTime { get; set; }
+ ///
+ /// Id filter
+ ///
+ public string? FromId { get; set; }
+ ///
+ /// Result offset
+ ///
+ public int? Offset { get; set; }
+ ///
+ /// Page number
+ ///
+ public int? Page { get; set; }
+ ///
+ /// Pagination cursor
+ ///
+ public string? Cursor { get; set; }
+ ///
+ /// Max number of results
+ ///
+ public int Limit { get; set; }
+ }
+}
diff --git a/CryptoExchange.Net/SharedApis/Models/Rest/GetClosedOrdersRequest.cs b/CryptoExchange.Net/SharedApis/Models/Rest/GetClosedOrdersRequest.cs
index 4920d8e3..5e1808ea 100644
--- a/CryptoExchange.Net/SharedApis/Models/Rest/GetClosedOrdersRequest.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Rest/GetClosedOrdersRequest.cs
@@ -19,6 +19,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
///
public int? Limit { get; }
+ ///
+ /// Data direction
+ ///
+ public DataDirection? Direction { get; set; }
///
/// ctor
@@ -27,12 +31,14 @@ namespace CryptoExchange.Net.SharedApis
/// Filter by start time
/// Filter by end time
/// Max number of results
+ /// Data direction
/// Exchange specific parameters
- 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;
}
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Rest/GetDepositsRequest.cs b/CryptoExchange.Net/SharedApis/Models/Rest/GetDepositsRequest.cs
index 5f53be22..78fc887f 100644
--- a/CryptoExchange.Net/SharedApis/Models/Rest/GetDepositsRequest.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Rest/GetDepositsRequest.cs
@@ -23,6 +23,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
///
public int? Limit { get; }
+ ///
+ /// Data direction
+ ///
+ public DataDirection? Direction { get; set; }
///
/// ctor
@@ -31,13 +35,15 @@ namespace CryptoExchange.Net.SharedApis
/// Filter by start time
/// Filter by end time
/// Max number of results
+ /// Data direction
/// Exchange specific parameters
- 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;
}
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Rest/GetFundingRateHistoryRequest.cs b/CryptoExchange.Net/SharedApis/Models/Rest/GetFundingRateHistoryRequest.cs
index 213657fe..6f9ad50f 100644
--- a/CryptoExchange.Net/SharedApis/Models/Rest/GetFundingRateHistoryRequest.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Rest/GetFundingRateHistoryRequest.cs
@@ -19,6 +19,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
///
public int? Limit { get; set; }
+ ///
+ /// Data direction
+ ///
+ public DataDirection? Direction { get; set; }
///
/// ctor
@@ -27,12 +31,14 @@ namespace CryptoExchange.Net.SharedApis
/// Filter by start time
/// Filter by end time
/// Max number of results
+ /// Data direction
/// Exchange specific parameters
- 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;
}
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Rest/GetKlinesRequest.cs b/CryptoExchange.Net/SharedApis/Models/Rest/GetKlinesRequest.cs
index 6eef5a22..54b1013a 100644
--- a/CryptoExchange.Net/SharedApis/Models/Rest/GetKlinesRequest.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Rest/GetKlinesRequest.cs
@@ -23,6 +23,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
///
public int? Limit { get; set; }
+ ///
+ /// Data direction
+ ///
+ public DataDirection? Direction { get; set; }
///
/// ctor
@@ -32,13 +36,15 @@ namespace CryptoExchange.Net.SharedApis
/// Filter by start time
/// Filter by end time
/// Max number of results
+ /// Data direction
/// Exchange specific parameters
- 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;
}
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Rest/GetPositionHistoryRequest.cs b/CryptoExchange.Net/SharedApis/Models/Rest/GetPositionHistoryRequest.cs
index 7bbb209a..db62b2fa 100644
--- a/CryptoExchange.Net/SharedApis/Models/Rest/GetPositionHistoryRequest.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Rest/GetPositionHistoryRequest.cs
@@ -27,6 +27,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
///
public int? Limit { get; set; }
+ ///
+ /// Data direction
+ ///
+ public DataDirection? Direction { get; set; }
///
/// ctor
@@ -35,13 +39,15 @@ namespace CryptoExchange.Net.SharedApis
/// Filter by start time
/// Filter by end time
/// Max number of results
+ /// Data direction
/// Exchange specific parameters
- 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;
}
///
@@ -51,13 +57,15 @@ namespace CryptoExchange.Net.SharedApis
/// Filter by start time
/// Filter by end time
/// Max number of results
+ /// Data direction
/// Exchange specific parameters
- 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;
}
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Rest/GetTradeHistoryRequest.cs b/CryptoExchange.Net/SharedApis/Models/Rest/GetTradeHistoryRequest.cs
index 8664f747..2eaea31c 100644
--- a/CryptoExchange.Net/SharedApis/Models/Rest/GetTradeHistoryRequest.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Rest/GetTradeHistoryRequest.cs
@@ -10,15 +10,19 @@ namespace CryptoExchange.Net.SharedApis
///
/// Filter by start time
///
- public DateTime StartTime { get; }
+ public DateTime StartTime { get; set; }
///
/// Filter by end time
///
- public DateTime EndTime { get; }
+ public DateTime? EndTime { get; set; }
///
/// Max number of results
///
- public int? Limit { get; }
+ public int? Limit { get; set; }
+ ///
+ /// Data direction
+ ///
+ public DataDirection? Direction { get; set; }
///
/// ctor
@@ -27,12 +31,14 @@ namespace CryptoExchange.Net.SharedApis
/// Filter by start time
/// Filter by end time
/// Max number of results
+ /// Data direction
/// Exchange specific parameters
- 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;
}
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Rest/GetUserTradesRequest.cs b/CryptoExchange.Net/SharedApis/Models/Rest/GetUserTradesRequest.cs
index 8fd84078..0cf88b0f 100644
--- a/CryptoExchange.Net/SharedApis/Models/Rest/GetUserTradesRequest.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Rest/GetUserTradesRequest.cs
@@ -19,6 +19,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
///
public int? Limit { get; }
+ ///
+ /// Data direction
+ ///
+ public DataDirection? Direction { get; set; }
///
/// ctor
@@ -27,12 +31,14 @@ namespace CryptoExchange.Net.SharedApis
/// Filter by start time
/// Filter by end time
/// Max number of results
+ /// Data direction
/// Exchange specific parameters
- 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;
}
}
}
diff --git a/CryptoExchange.Net/SharedApis/Models/Rest/GetWithdrawalsRequest.cs b/CryptoExchange.Net/SharedApis/Models/Rest/GetWithdrawalsRequest.cs
index 5130079d..0438b701 100644
--- a/CryptoExchange.Net/SharedApis/Models/Rest/GetWithdrawalsRequest.cs
+++ b/CryptoExchange.Net/SharedApis/Models/Rest/GetWithdrawalsRequest.cs
@@ -23,6 +23,10 @@ namespace CryptoExchange.Net.SharedApis
/// Max number of results
///
public int? Limit { get; }
+ ///
+ /// Data direction
+ ///
+ public DataDirection? Direction { get; set; }
///
/// ctor
@@ -31,13 +35,15 @@ namespace CryptoExchange.Net.SharedApis
/// Filter by start time
/// Filter by end time
/// Max number of results
+ /// Data direction
/// Exchange specific parameters
- 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;
}
}
}
diff --git a/CryptoExchange.Net/Trackers/Klines/KlineTracker.cs b/CryptoExchange.Net/Trackers/Klines/KlineTracker.cs
index 50834749..f6be4867 100644
--- a/CryptoExchange.Net/Trackers/Klines/KlineTracker.cs
+++ b/CryptoExchange.Net/Trackers/Klines/KlineTracker.cs
@@ -332,7 +332,8 @@ namespace CryptoExchange.Net.Trackers.Klines
_data.Add(item.OpenTime, item);
}
- _firstTimestamp = _data.Min(v => v.Key);
+ _firstTimestamp = _data.Count == 0 ? null : _data.Min(v => v.Key);
+
ApplyWindow(false);
_logger.KlineTrackerInitialDataSet(SymbolName, _data.Last().Key);
}
@@ -375,7 +376,7 @@ namespace CryptoExchange.Net.Trackers.Klines
}
}
- _firstTimestamp = _data.Min(x => x.Key);
+ _firstTimestamp = _data.Count == 0 ? null : _data.Min(x => x.Key);
_changed = true;
SetSyncStatus();
diff --git a/CryptoExchange.Net/Trackers/Trades/TradeTracker.cs b/CryptoExchange.Net/Trackers/Trades/TradeTracker.cs
index 76c17324..6a7e0095 100644
--- a/CryptoExchange.Net/Trackers/Trades/TradeTracker.cs
+++ b/CryptoExchange.Net/Trackers/Trades/TradeTracker.cs
@@ -259,11 +259,11 @@ namespace CryptoExchange.Net.Trackers.Trades
var startTime = Period == null ? DateTime.UtcNow.AddMinutes(-5) : DateTime.UtcNow.Add(-Period.Value);
var request = new GetTradeHistoryRequest(Symbol, startTime, DateTime.UtcNow);
var data = new List();
- await foreach(var result in ExchangeHelpers.ExecutePages(_historyRestClient.GetTradeHistoryAsync, request).ConfigureAwait(false))
+ await foreach (var result in ExchangeHelpers.ExecutePages(_historyRestClient.GetTradeHistoryAsync, request).ConfigureAwait(false))
{
if (!result)
return result;
-
+
if (Limit != null && data.Count > Limit)
break;