DigitalRuby / ExchangeSharp

ExchangeSharp is a powerful, fast and easy to use .NET/C# API for interfacing with many crypto currency exchanges. REST and web sockets are supported.
https://www.digitalruby.com
MIT License
737 stars 374 forks source link

Binance GetTickersAsync Slow response on every few calls #830

Closed BZ-CO closed 4 months ago

BZ-CO commented 4 months ago

I've noticed that there is a big delay on every 3rd or 4th GetTickersAsync call. I've wrote a simple app to measure the response times with Stopwatch.

using System.Diagnostics;
using ExchangeSharp;

var binanceApi = await ExchangeAPI.GetExchangeAPIAsync<ExchangeBinanceAPI>();
var sw = new Stopwatch();
var retriesCount = 1;

while (true)
{
    sw.Start();
    var tickerData = await binanceApi.GetTickersAsync();
    sw.Stop();
    Console.WriteLine($"Retry #: {retriesCount} | Ticker data retrieved for {sw.Elapsed.TotalMilliseconds} ms");
    sw.Reset();
    retriesCount++;
    await Task.Delay(5000);
}

Output:

Retry #: 1 | Ticker data retrieved for 18014.2488 ms Retry #: 2 | Ticker data retrieved for 0.0376 ms Retry #: 3 | Ticker data retrieved for 0.0165 ms Retry #: 4 | Ticker data retrieved for 8706.018 ms Retry #: 5 | Ticker data retrieved for 0.0205 ms Retry #: 6 | Ticker data retrieved for 0.0165 ms Retry #: 7 | Ticker data retrieved for 0.0158 ms Retry #: 8 | Ticker data retrieved for 19169.7104 ms Retry #: 9 | Ticker data retrieved for 0.0233 ms Retry #: 10 | Ticker data retrieved for 0.0302 ms Retry #: 11 | Ticker data retrieved for 0.0229 ms Retry #: 12 | Ticker data retrieved for 9606.9587 ms Retry #: 13 | Ticker data retrieved for 0.0466 ms Retry #: 14 | Ticker data retrieved for 0.021 ms Retry #: 15 | Ticker data retrieved for 0.0193 ms Retry #: 16 | Ticker data retrieved for 13773.2705 ms Retry #: 17 | Ticker data retrieved for 0.0142 ms Retry #: 18 | Ticker data retrieved for 0.014 ms Retry #: 19 | Ticker data retrieved for 0.018 ms Retry #: 20 | Ticker data retrieved for 15893.759 ms Retry #: 21 | Ticker data retrieved for 0.0189 ms Retry #: 22 | Ticker data retrieved for 0.0135 ms Retry #: 23 | Ticker data retrieved for 0.0212 ms Retry #: 24 | Ticker data retrieved for 12843.4538 ms Retry #: 25 | Ticker data retrieved for 0.0338 ms Retry #: 26 | Ticker data retrieved for 0.019 ms Retry #: 27 | Ticker data retrieved for 0.0141 ms Retry #: 28 | Ticker data retrieved for 11724.1011 ms Retry #: 29 | Ticker data retrieved for 0.0183 ms Retry #: 30 | Ticker data retrieved for 0.018 ms Retry #: 31 | Ticker data retrieved for 0.0145 ms Retry #: 32 | Ticker data retrieved for 14661.0153 ms Retry #: 33 | Ticker data retrieved for 0.0227 ms Retry #: 34 | Ticker data retrieved for 0.0292 ms Retry #: 35 | Ticker data retrieved for 15086.7355 ms Retry #: 36 | Ticker data retrieved for 0.0146 ms Retry #: 37 | Ticker data retrieved for 0.0321 ms Retry #: 38 | Ticker data retrieved for 11840.5882 ms Retry #: 39 | Ticker data retrieved for 0.0119 ms Retry #: 40 | Ticker data retrieved for 0.0119 ms Retry #: 41 | Ticker data retrieved for 18851.1393 ms Retry #: 42 | Ticker data retrieved for 0.0155 ms Retry #: 43 | Ticker data retrieved for 0.0225 ms Retry #: 44 | Ticker data retrieved for 0.0204 ms Retry #: 45 | Ticker data retrieved for 11742.3238 ms

I am excluding rate limiting, because we are calling the method every 5 seconds. Any ideas?

I've just noticed that the same thing applies for all other exchanges as well, but not with such high response times, so I guess it is something inherited.

vslee commented 4 months ago

Since the delay is so long (10+ secs), can you pause the debugger to see what internal method it is waiting on?

BZ-CO commented 4 months ago

Are we caching the tickers?

vslee commented 4 months ago

I think so, not sure.

BZ-CO commented 4 months ago

Calling GetTickersAsync on BinanceCOM also invokes GetMarketSymbolsMetadataAsync multiple times. GetMarketSymbolsMetadataAsync is used for getting base and quote currencies when parsing ExchangeVolume, not sure why the symbols are not cached after the first request.

Calling GetTickersAsync on BinanceUS also invokes GetMarketSymbolsMetadataAsync, but just a single time.

That seems odd, because they both share the same OnGetTickersAsync from BinanceGroupCommon class.

Here is the output:


# BinanceCom

2024-02-16 19:31:31.0701|INFO|ExchangeSharp.Logger|Executing OnGetTickerAsync
2024-02-16 19:31:31.1081|INFO|ExchangeSharp.Logger|Executing MakeRequestAsync | URL: https://api.binance.com/api/v3/ticker/24hr
2024-02-16 19:31:31.6712|INFO|ExchangeSharp.Logger|Executing CacheMethod | Args: GetMarketSymbolsMetadataAsync
2024-02-16 19:31:31.6712|INFO|ExchangeSharp.Logger|Executing MakeRequestAsync | URL: https://api.binance.com/api/v3/exchangeInfo
2024-02-16 19:31:33.8141|INFO|ExchangeSharp.Logger|Executing CacheMethod | Args: GetMarketSymbolsMetadataAsync
2024-02-16 19:31:33.8141|INFO|ExchangeSharp.Logger|Executing MakeRequestAsync | URL: https://api.binance.com/api/v3/exchangeInfo
2024-02-16 19:31:36.6626|INFO|ExchangeSharp.Logger|Executing CacheMethod | Args: GetMarketSymbolsMetadataAsync
2024-02-16 19:31:36.6626|INFO|ExchangeSharp.Logger|Executing MakeRequestAsync | URL: https://api.binance.com/api/v3/exchangeInfo
2024-02-16 19:31:39.5941|INFO|ExchangeSharp.Logger|Executing CacheMethod | Args: GetMarketSymbolsMetadataAsync
2024-02-16 19:31:39.5941|INFO|ExchangeSharp.Logger|Executing MakeRequestAsync | URL: https://api.binance.com/api/v3/exchangeInfo
Retry #: 1 | Ticker data retrieved for 11200.0951 ms

----------------------------

# BinanceUS

2024-02-16 19:32:16.6104|INFO|ExchangeSharp.Logger|Executing OnGetTickerAsync
2024-02-16 19:32:16.6453|INFO|ExchangeSharp.Logger|Executing MakeRequestAsync | URL: https://api.binance.us/api/v3/ticker/24hr
2024-02-16 19:32:17.6935|INFO|ExchangeSharp.Logger|Executing CacheMethod | Args: GetMarketSymbolsMetadataAsync
2024-02-16 19:32:17.6981|INFO|ExchangeSharp.Logger|Executing MakeRequestAsync | URL: https://api.binance.us/api/v3/exchangeInfo
Retry #: 1 | Ticker data retrieved for 2350.1533 ms
BZ-CO commented 4 months ago

The issue comes from here: https://github.com/DigitalRuby/ExchangeSharp/blob/9486d777ca4c529fc92890244780df3267ff2654/src/ExchangeSharp/API/Exchanges/_Base/ExchangeAPI.cs#L1021

BinanceCOM ticker data has some delisted pairs, which are not available in GetMarketSymbolsMetadataAsync response.

Do we really need to retry GetMarketSymbolsMetadataAsync request if there is missing pair?

I think we have two options: 1) To remove the retry from GetExchangeMarketFromCacheAsync and if there is new pair listed, it will be available in 4 hours after the current cache expires. 2) To add some logic that will track the inconsistency between ticker and symbols responses.

Let me know what you guys think.

vslee commented 4 months ago

First option sounds like the simplest. 4 hour delay is nothing in the grand scheme of things. For ppl who can't wait the 4 hours, they can always override.