mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-10-04 02:11:11 +00:00
Added support for order polling where Shared order implementation doesn't support time filtering to UserDataTracker implementations
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
using CryptoExchange.Net.Objects;
|
using CryptoExchange.Net.Objects;
|
||||||
using CryptoExchange.Net.Objects.Sockets;
|
using CryptoExchange.Net.Objects.Sockets;
|
||||||
using CryptoExchange.Net.SharedApis;
|
using CryptoExchange.Net.SharedApis;
|
||||||
using CryptoExchange.Net.Trackers.UserData.Objects;
|
using CryptoExchange.Net.Trackers.UserData.Objects;
|
||||||
@@ -19,6 +19,7 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
private readonly IFuturesOrderSocketClient? _socketClient;
|
private readonly IFuturesOrderSocketClient? _socketClient;
|
||||||
private readonly ExchangeParameters? _exchangeParameters;
|
private readonly ExchangeParameters? _exchangeParameters;
|
||||||
private readonly bool _requiresSymbolParameterOpenOrders;
|
private readonly bool _requiresSymbolParameterOpenOrders;
|
||||||
|
private readonly bool _timeFilterSupportedClosedOrders;
|
||||||
private readonly Dictionary<string, int> _openOrderNotReturnedTimes = new();
|
private readonly Dictionary<string, int> _openOrderNotReturnedTimes = new();
|
||||||
private readonly TimeSpan _pollOverlapPeriod = TimeSpan.FromSeconds(3);
|
private readonly TimeSpan _pollOverlapPeriod = TimeSpan.FromSeconds(3);
|
||||||
|
|
||||||
@@ -46,6 +47,7 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
_exchangeParameters = exchangeParameters;
|
_exchangeParameters = exchangeParameters;
|
||||||
|
|
||||||
_requiresSymbolParameterOpenOrders = restClient.GetOpenFuturesOrdersOptions.RequiredOptionalParameters.Any(x => x.Names.Contains("Symbol"));
|
_requiresSymbolParameterOpenOrders = restClient.GetOpenFuturesOrdersOptions.RequiredOptionalParameters.Any(x => x.Names.Contains("Symbol"));
|
||||||
|
_timeFilterSupportedClosedOrders = restClient.GetClosedFuturesOrdersOptions.TimePeriodFilterSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ClearDataForSymbol(SharedSymbol symbol)
|
internal void ClearDataForSymbol(SharedSymbol symbol)
|
||||||
@@ -290,21 +292,81 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
var updatedPollTime = DateTime.UtcNow;
|
var updatedPollTime = DateTime.UtcNow;
|
||||||
foreach (var symbol in _symbolTracker.GetTrackedSymbols())
|
foreach (var symbol in _symbolTracker.GetTrackedSymbols())
|
||||||
{
|
{
|
||||||
|
var symbolError = false;
|
||||||
DateTime? fromTimeOrders = GetClosedOrdersRequestStartTime(symbol);
|
DateTime? fromTimeOrders = GetClosedOrdersRequestStartTime(symbol);
|
||||||
|
if (_timeFilterSupportedClosedOrders)
|
||||||
|
{
|
||||||
|
// Can filter by start time, so we can just request data from that point
|
||||||
|
|
||||||
var closedOrdersResult = await _restClient.GetClosedFuturesOrdersAsync(new GetClosedOrdersRequest(symbol, startTime: fromTimeOrders, exchangeParameters: _exchangeParameters)).ConfigureAwait(false);
|
var closedOrdersResult = await _restClient.GetClosedFuturesOrdersAsync(new GetClosedOrdersRequest(symbol, startTime: fromTimeOrders, exchangeParameters: _exchangeParameters)).ConfigureAwait(false);
|
||||||
if (!closedOrdersResult.Success)
|
if (!closedOrdersResult.Success)
|
||||||
{
|
{
|
||||||
anyError = true;
|
symbolError = true;
|
||||||
|
|
||||||
_initialPollingError ??= closedOrdersResult.Error;
|
_initialPollingError ??= closedOrdersResult.Error;
|
||||||
if (!_firstPollDone)
|
if (!_firstPollDone)
|
||||||
break;
|
return symbolError;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
await ProcessOrders(symbol, openOrders, closedOrdersResult.Data).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Can't filter by start time, so we'll have to request data until we reach an order with a create time before the start time
|
||||||
|
|
||||||
|
List<SharedFuturesOrder> closedOrders = new List<SharedFuturesOrder>();
|
||||||
|
DateTime lastMinReturn = DateTime.MaxValue;
|
||||||
|
PageRequest? nextPageRequest = null;
|
||||||
|
while (lastMinReturn > fromTimeOrders)
|
||||||
|
{
|
||||||
|
var closedOrdersResult = await _restClient.GetClosedFuturesOrdersAsync(new GetClosedOrdersRequest(symbol, direction: DataDirection.Descending, exchangeParameters: _exchangeParameters), nextPageRequest).ConfigureAwait(false);
|
||||||
|
if (!closedOrdersResult.Success)
|
||||||
|
{
|
||||||
|
symbolError = true;
|
||||||
|
|
||||||
|
_initialPollingError ??= closedOrdersResult.Error;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closedOrdersResult.Data.Length == 0)
|
||||||
|
// If there is no data we can stop requesting more data
|
||||||
|
break;
|
||||||
|
|
||||||
|
nextPageRequest = closedOrdersResult.NextPageRequest;
|
||||||
|
lastMinReturn = closedOrdersResult.Data!.Min(x => x.CreateTime ?? DateTime.MinValue);
|
||||||
|
closedOrders.AddRange(closedOrdersResult.Data);
|
||||||
|
|
||||||
|
if (nextPageRequest == null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbolError && !_firstPollDone)
|
||||||
|
return symbolError;
|
||||||
|
|
||||||
|
if (!symbolError)
|
||||||
|
await ProcessOrders(symbol, openOrders, closedOrders.ToArray()).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
anyError = anyError || symbolError;
|
||||||
|
if (!_firstPollDone && anyError)
|
||||||
|
return anyError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anyError)
|
||||||
|
{
|
||||||
|
_lastPollTime = updatedPollTime;
|
||||||
|
_lastDataTimeBeforeDisconnect = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return anyError;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessOrders(SharedSymbol symbol, List<SharedFuturesOrder> openOrders, SharedFuturesOrder[] closedOrdersResult)
|
||||||
{
|
{
|
||||||
// Filter orders to only include where close time is after the start time
|
// Filter orders to only include where close time is after the start time
|
||||||
var relevantOrders = closedOrdersResult.Data.Where(x =>
|
var relevantOrders = closedOrdersResult!.Where(x =>
|
||||||
(x.UpdateTime != null && x.UpdateTime >= _startTime) // Updated after the tracker start time
|
(x.UpdateTime != null && x.UpdateTime >= _startTime) // Updated after the tracker start time
|
||||||
|| (x.CreateTime != null && x.CreateTime >= _startTime) // Created after the tracker start time
|
|| (x.CreateTime != null && x.CreateTime >= _startTime) // Created after the tracker start time
|
||||||
|| (x.CreateTime == null && x.UpdateTime == null) // Unknown time
|
|| (x.CreateTime == null && x.UpdateTime == null) // Unknown time
|
||||||
@@ -338,16 +400,6 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
if (relevantOrders.Length > 0)
|
if (relevantOrders.Length > 0)
|
||||||
await HandleUpdateAsync(UpdateSource.Poll, relevantOrders).ConfigureAwait(false);
|
await HandleUpdateAsync(UpdateSource.Poll, relevantOrders).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!anyError)
|
|
||||||
{
|
|
||||||
_lastPollTime = updatedPollTime;
|
|
||||||
_lastDataTimeBeforeDisconnect = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return anyError;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DateTime? GetClosedOrdersRequestStartTime(SharedSymbol symbol)
|
private DateTime? GetClosedOrdersRequestStartTime(SharedSymbol symbol)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
private readonly ISpotOrderSocketClient? _socketClient;
|
private readonly ISpotOrderSocketClient? _socketClient;
|
||||||
private readonly ExchangeParameters? _exchangeParameters;
|
private readonly ExchangeParameters? _exchangeParameters;
|
||||||
private readonly bool _requiresSymbolParameterOpenOrders;
|
private readonly bool _requiresSymbolParameterOpenOrders;
|
||||||
|
private readonly bool _timeFilterSupportedClosedOrders;
|
||||||
private readonly Dictionary<string, int> _openOrderNotReturnedTimes = new();
|
private readonly Dictionary<string, int> _openOrderNotReturnedTimes = new();
|
||||||
private readonly TimeSpan _pollOverlapPeriod = TimeSpan.FromSeconds(3);
|
private readonly TimeSpan _pollOverlapPeriod = TimeSpan.FromSeconds(3);
|
||||||
|
|
||||||
@@ -46,6 +47,7 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
_exchangeParameters = exchangeParameters;
|
_exchangeParameters = exchangeParameters;
|
||||||
|
|
||||||
_requiresSymbolParameterOpenOrders = restClient.GetOpenSpotOrdersOptions.RequiredOptionalParameters.Any(x => x.Names.Contains("Symbol"));
|
_requiresSymbolParameterOpenOrders = restClient.GetOpenSpotOrdersOptions.RequiredOptionalParameters.Any(x => x.Names.Contains("Symbol"));
|
||||||
|
_timeFilterSupportedClosedOrders = restClient.GetClosedSpotOrdersOptions.TimePeriodFilterSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ClearDataForSymbol(SharedSymbol symbol)
|
internal void ClearDataForSymbol(SharedSymbol symbol)
|
||||||
@@ -300,22 +302,82 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
var updatedPollTime = DateTime.UtcNow;
|
var updatedPollTime = DateTime.UtcNow;
|
||||||
foreach (var symbol in _symbolTracker.GetTrackedSymbols())
|
foreach (var symbol in _symbolTracker.GetTrackedSymbols())
|
||||||
{
|
{
|
||||||
|
var symbolError = false;
|
||||||
DateTime? fromTimeOrders = GetClosedOrdersRequestStartTime(symbol);
|
DateTime? fromTimeOrders = GetClosedOrdersRequestStartTime(symbol);
|
||||||
|
if (_timeFilterSupportedClosedOrders)
|
||||||
|
{
|
||||||
|
// Can filter by start time, so we can just request data from that point
|
||||||
|
|
||||||
var closedOrdersResult = await _restClient.GetClosedSpotOrdersAsync(new GetClosedOrdersRequest(symbol, startTime: fromTimeOrders, exchangeParameters: _exchangeParameters)).ConfigureAwait(false);
|
var closedOrdersResult = await _restClient.GetClosedSpotOrdersAsync(new GetClosedOrdersRequest(symbol, startTime: fromTimeOrders, exchangeParameters: _exchangeParameters)).ConfigureAwait(false);
|
||||||
if (!closedOrdersResult.Success)
|
if (!closedOrdersResult.Success)
|
||||||
{
|
{
|
||||||
anyError = true;
|
symbolError = true;
|
||||||
|
|
||||||
_initialPollingError ??= closedOrdersResult.Error;
|
_initialPollingError ??= closedOrdersResult.Error;
|
||||||
if (!_firstPollDone)
|
if (!_firstPollDone)
|
||||||
break;
|
return symbolError;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
await ProcessOrders(symbol, openOrders, closedOrdersResult.Data).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Can't filter by start time, so we'll have to request data until we reach an order with a create time before the start time
|
||||||
|
|
||||||
|
List<SharedSpotOrder> closedOrders = new List<SharedSpotOrder>();
|
||||||
|
DateTime lastMinReturn = DateTime.MaxValue;
|
||||||
|
PageRequest? nextPageRequest = null;
|
||||||
|
while (lastMinReturn > fromTimeOrders)
|
||||||
|
{
|
||||||
|
var closedOrdersResult = await _restClient.GetClosedSpotOrdersAsync(new GetClosedOrdersRequest(symbol, direction: DataDirection.Descending, exchangeParameters: _exchangeParameters), nextPageRequest).ConfigureAwait(false);
|
||||||
|
if (!closedOrdersResult.Success)
|
||||||
|
{
|
||||||
|
symbolError = true;
|
||||||
|
|
||||||
|
_initialPollingError ??= closedOrdersResult.Error;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (closedOrdersResult.Data.Length == 0)
|
||||||
|
// If there is no data we can stop requesting more data
|
||||||
|
break;
|
||||||
|
|
||||||
|
nextPageRequest = closedOrdersResult.NextPageRequest;
|
||||||
|
lastMinReturn = closedOrdersResult.Data!.Min(x => x.CreateTime ?? DateTime.MinValue);
|
||||||
|
closedOrders.AddRange(closedOrdersResult.Data);
|
||||||
|
|
||||||
|
if (nextPageRequest == null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbolError && !_firstPollDone)
|
||||||
|
return symbolError;
|
||||||
|
|
||||||
|
if (!symbolError)
|
||||||
|
await ProcessOrders(symbol, openOrders, closedOrders.ToArray()).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
anyError = anyError || symbolError;
|
||||||
|
if (!_firstPollDone && anyError)
|
||||||
|
return anyError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anyError)
|
||||||
|
{
|
||||||
|
_lastDataTimeBeforeDisconnect = null;
|
||||||
|
_lastPollTime = updatedPollTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
return anyError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task ProcessOrders(SharedSymbol symbol, List<SharedSpotOrder> openOrders, SharedSpotOrder[] closedOrdersResult)
|
||||||
{
|
{
|
||||||
// Filter orders to only include where close time is after the start time
|
// Filter orders to only include where close time is after the start time
|
||||||
var relevantOrders = closedOrdersResult.Data.Where(x =>
|
var relevantOrders = closedOrdersResult!.Where(x =>
|
||||||
(x.UpdateTime != null && x.UpdateTime >= _startTime) // Updated after the tracker start time
|
(x.UpdateTime != null && x.UpdateTime >= _startTime) // Updated after the tracker start time
|
||||||
|| (x.CreateTime != null && x.CreateTime >= _startTime) // Created after the tracker start time
|
|| (x.CreateTime != null && x.CreateTime >= _startTime) // Created after the tracker start time
|
||||||
|| (x.CreateTime == null && x.UpdateTime == null) // Unknown time
|
|| (x.CreateTime == null && x.UpdateTime == null) // Unknown time
|
||||||
@@ -349,16 +411,6 @@ namespace CryptoExchange.Net.Trackers.UserData.ItemTrackers
|
|||||||
if (relevantOrders.Length > 0)
|
if (relevantOrders.Length > 0)
|
||||||
await HandleUpdateAsync(UpdateSource.Poll, relevantOrders).ConfigureAwait(false);
|
await HandleUpdateAsync(UpdateSource.Poll, relevantOrders).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!anyError)
|
|
||||||
{
|
|
||||||
_lastDataTimeBeforeDisconnect = null;
|
|
||||||
_lastPollTime = updatedPollTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
return anyError;
|
|
||||||
}
|
|
||||||
|
|
||||||
private DateTime? GetClosedOrdersRequestStartTime(SharedSymbol symbol)
|
private DateTime? GetClosedOrdersRequestStartTime(SharedSymbol symbol)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user