1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2026-04-13 00:22:22 +00:00

Compare commits

...

3 Commits

Author SHA1 Message Date
Jkorf
777a0466a0 wip 2026-02-18 16:16:53 +01:00
Jkorf
f225f6ffb8 wip 2026-02-18 11:23:10 +01:00
Jkorf
5651813ed0 wip 2026-02-17 14:33:34 +01:00
12 changed files with 190 additions and 26 deletions

View File

@ -73,7 +73,7 @@ namespace CryptoExchange.Net.SharedApis
/// <summary> /// <summary>
/// Spot get closed orders request options /// Spot get closed orders request options
/// </summary> /// </summary>
PaginatedEndpointOptions<GetClosedOrdersRequest> GetClosedFuturesOrdersOptions { get; } GetClosedOrdersOptions GetClosedFuturesOrdersOptions { get; }
/// <summary> /// <summary>
/// Get info on closed futures orders /// Get info on closed futures orders
/// </summary> /// </summary>
@ -96,7 +96,7 @@ namespace CryptoExchange.Net.SharedApis
/// <summary> /// <summary>
/// Futures user trades request options /// Futures user trades request options
/// </summary> /// </summary>
PaginatedEndpointOptions<GetUserTradesRequest> GetFuturesUserTradesOptions { get; } GetUserTradesOptions GetFuturesUserTradesOptions { get; }
/// <summary> /// <summary>
/// Get futures user trade records /// Get futures user trade records
/// </summary> /// </summary>

View File

@ -72,7 +72,7 @@ namespace CryptoExchange.Net.SharedApis
/// <summary> /// <summary>
/// Spot get closed orders request options /// Spot get closed orders request options
/// </summary> /// </summary>
PaginatedEndpointOptions<GetClosedOrdersRequest> GetClosedSpotOrdersOptions { get; } GetClosedOrdersOptions GetClosedSpotOrdersOptions { get; }
/// <summary> /// <summary>
/// Get info on closed spot orders /// Get info on closed spot orders
/// </summary> /// </summary>
@ -95,7 +95,7 @@ namespace CryptoExchange.Net.SharedApis
/// <summary> /// <summary>
/// Spot user trades request options /// Spot user trades request options
/// </summary> /// </summary>
PaginatedEndpointOptions<GetUserTradesRequest> GetSpotUserTradesOptions { get; } GetUserTradesOptions GetSpotUserTradesOptions { get; }
/// <summary> /// <summary>
/// Get spot user trade records /// Get spot user trade records
/// </summary> /// </summary>

View File

@ -1,4 +1,5 @@
using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects;
using System;
using System.Text; using System.Text;
namespace CryptoExchange.Net.SharedApis namespace CryptoExchange.Net.SharedApis
@ -19,8 +20,22 @@ namespace CryptoExchange.Net.SharedApis
/// <inheritdoc /> /// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetClosedOrdersRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes) public override Error? ValidateRequest(string exchange, GetClosedOrdersRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{ {
if (!TimePeriodFilterSupport && request.StartTime != null) if (!SupportsAscending && request.Direction == DataDirection.Ascending)
return ArgumentError.Invalid(nameof(GetClosedOrdersRequest.StartTime), $"Time filter is not supported"); 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 (!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); return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
} }

View File

@ -1,4 +1,5 @@
using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects;
using System;
using System.Text; using System.Text;
namespace CryptoExchange.Net.SharedApis namespace CryptoExchange.Net.SharedApis
@ -19,8 +20,22 @@ namespace CryptoExchange.Net.SharedApis
/// <inheritdoc /> /// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetDepositsRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes) public override Error? ValidateRequest(string exchange, GetDepositsRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{ {
if (!TimePeriodFilterSupport && request.StartTime != null) 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 (!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 ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
}
}
return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes); return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
} }

View File

@ -1,4 +1,5 @@
using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects;
using System;
using System.Text; using System.Text;
namespace CryptoExchange.Net.SharedApis namespace CryptoExchange.Net.SharedApis
@ -19,8 +20,22 @@ namespace CryptoExchange.Net.SharedApis
/// <inheritdoc /> /// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetFundingRateHistoryRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes) public override Error? ValidateRequest(string exchange, GetFundingRateHistoryRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{ {
if (!TimePeriodFilterSupport && request.StartTime != null) 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 (!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 ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
}
}
return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes); return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
} }

View File

@ -70,8 +70,22 @@ namespace CryptoExchange.Net.SharedApis
if (!IsSupported(request.Interval)) if (!IsSupported(request.Interval))
return ArgumentError.Invalid(nameof(GetKlinesRequest.Interval), "Interval not supported"); return ArgumentError.Invalid(nameof(GetKlinesRequest.Interval), "Interval not supported");
if (!TimePeriodFilterSupport && request.StartTime != null) 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 (!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 ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
}
}
if (MaxAge.HasValue && request.StartTime < DateTime.UtcNow.Add(-MaxAge.Value)) if (MaxAge.HasValue && request.StartTime < DateTime.UtcNow.Add(-MaxAge.Value))
return ArgumentError.Invalid(nameof(GetKlinesRequest.StartTime), $"Only the most recent {MaxAge} klines are available"); return ArgumentError.Invalid(nameof(GetKlinesRequest.StartTime), $"Only the most recent {MaxAge} klines are available");

View File

@ -1,4 +1,5 @@
using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects;
using System;
using System.Text; using System.Text;
namespace CryptoExchange.Net.SharedApis namespace CryptoExchange.Net.SharedApis
@ -19,8 +20,22 @@ namespace CryptoExchange.Net.SharedApis
/// <inheritdoc /> /// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetPositionHistoryRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes) public override Error? ValidateRequest(string exchange, GetPositionHistoryRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{ {
if (!TimePeriodFilterSupport && request.StartTime != null) 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 (!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 ArgumentError.Invalid(nameof(GetDepositsRequest.StartTime), $"Time filter is not supported");
}
}
return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes); return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
} }

View File

@ -25,6 +25,12 @@ namespace CryptoExchange.Net.SharedApis
/// <inheritdoc /> /// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetTradeHistoryRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes) 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)) 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(GetTradeHistoryRequest.StartTime), $"Only the most recent {MaxAge} trades are available");

View File

@ -0,0 +1,51 @@
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 (!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();
}
}
}

View File

@ -1,4 +1,5 @@
using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects;
using System;
using System.Text; using System.Text;
namespace CryptoExchange.Net.SharedApis namespace CryptoExchange.Net.SharedApis
@ -19,8 +20,22 @@ namespace CryptoExchange.Net.SharedApis
/// <inheritdoc /> /// <inheritdoc />
public override Error? ValidateRequest(string exchange, GetWithdrawalsRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes) public override Error? ValidateRequest(string exchange, GetWithdrawalsRequest request, TradingMode? tradingMode, TradingMode[] supportedApiTypes)
{ {
if (!TimePeriodFilterSupport && request.StartTime != null) if (!SupportsAscending && request.Direction == DataDirection.Ascending)
return ArgumentError.Invalid(nameof(GetWithdrawalsRequest.StartTime), $"Time filter is not supported"); 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 (!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); return base.ValidateRequest(exchange, request, tradingMode, supportedApiTypes);
} }

View File

@ -20,6 +20,7 @@ namespace CryptoExchange.Net.SharedApis
public string? FromId { get; set; } public string? FromId { get; set; }
public int? Offset { get; set; } public int? Offset { get; set; }
public int? Page { get; set; } public int? Page { get; set; }
public string? Cursor { get; set; }
} }
public class PageRequest public class PageRequest
{ {
@ -59,9 +60,15 @@ namespace CryptoExchange.Net.SharedApis
if (direction == DataDirection.Ascending) if (direction == DataDirection.Ascending)
{ {
if (startTime == null) if (startTime == null)
{
startTime = endTime.Add(-maxPeriod.Value); startTime = endTime.Add(-maxPeriod.Value);
}
else else
{
endTime = startTime.Value.Add(maxPeriod.Value); endTime = startTime.Value.Add(maxPeriod.Value);
if (endTime > DateTime.UtcNow)
endTime = DateTime.UtcNow;
}
} }
else else
{ {
@ -76,12 +83,13 @@ namespace CryptoExchange.Net.SharedApis
Direction = direction, Direction = direction,
FromId = paginationRequest?.FromId, FromId = paginationRequest?.FromId,
Offset = paginationRequest?.Offset, Offset = paginationRequest?.Offset,
Page = paginationRequest?.Page Page = paginationRequest?.Page,
Cursor = paginationRequest?.Cursor
}; };
} }
public static PageRequest? GetNextPageRequest( public static PageRequest? GetNextPageRequest(
Func<PageRequest> nextPageRequest, Func<PageRequest?> nextPageRequest,
int resultCount, int resultCount,
IEnumerable<DateTime> timestamps, IEnumerable<DateTime> timestamps,
DateTime? requestStartTime, DateTime? requestStartTime,
@ -93,7 +101,16 @@ namespace CryptoExchange.Net.SharedApis
) )
{ {
if (HasNextPage(resultCount, timestamps, requestStartTime, requestEndTime, limit, direction)) if (HasNextPage(resultCount, timestamps, requestStartTime, requestEndTime, limit, direction))
return nextPageRequest(); {
var result = nextPageRequest();
if (result != null)
{
#warning correct?
result.StartTime ??= lastPaginationData.StartTime;
result.EndTime ??= lastPaginationData.EndTime;
return result;
}
}
if (maxTimespan != null) if (maxTimespan != null)
{ {
@ -143,11 +160,11 @@ namespace CryptoExchange.Net.SharedApis
public static PageRequest NextPageFromPage(PaginationParameters lastPaginationData) public static PageRequest NextPageFromPage(PaginationParameters lastPaginationData)
{ {
return new PageRequest { Page = lastPaginationData.Page + 1 }; return new PageRequest { Page = (lastPaginationData.Page ?? 1) + 1 };
} }
public static PageRequest NextPageFromOffset(PaginationParameters lastPaginationData, int resultCount) public static PageRequest NextPageFromOffset(PaginationParameters lastPaginationData, int resultCount)
{ {
return new PageRequest { Offset = lastPaginationData.Offset + resultCount }; return new PageRequest { Offset = (lastPaginationData.Offset ?? 0) + resultCount };
} }
public static PageRequest NextPageFromCursor(string nextCursor) public static PageRequest NextPageFromCursor(string nextCursor)
{ {
@ -161,7 +178,7 @@ namespace CryptoExchange.Net.SharedApis
{ {
return new PageRequest { FromId = nextFromId }; return new PageRequest { FromId = nextFromId };
} }
public static PageRequest NextPageFromTime(PaginationParameters lastPaginationData, DateTime lastTimestamp, bool setOtherTimeLimiter) public static PageRequest NextPageFromTime(PaginationParameters lastPaginationData, DateTime lastTimestamp, bool setOtherTimeLimiter = true)
{ {
if (lastPaginationData.Direction == DataDirection.Ascending) if (lastPaginationData.Direction == DataDirection.Ascending)
return new PageRequest { StartTime = lastTimestamp.AddMilliseconds(1), EndTime = setOtherTimeLimiter ? lastPaginationData.EndTime : null }; return new PageRequest { StartTime = lastTimestamp.AddMilliseconds(1), EndTime = setOtherTimeLimiter ? lastPaginationData.EndTime : null };
@ -185,10 +202,11 @@ namespace CryptoExchange.Net.SharedApis
} }
else else
{ {
var lastPageStartTime = lastPaginationParameters.StartTime ?? lastPaginationParameters.EndTime!.Value.Add(-period);
if (requestStartTime != null) if (requestStartTime != null)
return (lastPaginationParameters.StartTime!.Value - requestStartTime.Value).TotalSeconds > 1; return (lastPageStartTime - requestStartTime.Value).TotalSeconds > 1;
else else
return (lastPaginationParameters.StartTime!.Value - (lastPaginationParameters.EndTime!.Value - period)).TotalSeconds > 1; return (lastPageStartTime - (lastPaginationParameters.EndTime!.Value - period)).TotalSeconds > 1;
} }
} }

View File

@ -14,7 +14,7 @@ namespace CryptoExchange.Net.SharedApis
/// <summary> /// <summary>
/// Filter by end time /// Filter by end time
/// </summary> /// </summary>
public DateTime EndTime { get; set; } public DateTime? EndTime { get; set; }
/// <summary> /// <summary>
/// Max number of results /// Max number of results
/// </summary> /// </summary>
@ -33,7 +33,7 @@ namespace CryptoExchange.Net.SharedApis
/// <param name="limit">Max number of results</param> /// <param name="limit">Max number of results</param>
/// <param name="direction">Data direction</param> /// <param name="direction">Data direction</param>
/// <param name="exchangeParameters">Exchange specific parameters</param> /// <param name="exchangeParameters">Exchange specific parameters</param>
public GetTradeHistoryRequest(SharedSymbol symbol, DateTime startTime, DateTime endTime, int? limit = null, DataDirection? direction = 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; StartTime = startTime;
EndTime = endTime; EndTime = endTime;