10000 rolling window rate limiter by caoilainnl · Pull Request #25423 · ccxt/ccxt · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

rolling window rate limiter #25423

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 48 commits into
base: master
Choose a base branch
from

Conversation

caoilainnl
Copy link
@caoilainnl caoilainnl commented Mar 7, 2025

A rolling window rate limiter is more efficient because it reduces wait times when part of your rate limit is still available. It also allows an initial burst of requests.

Some exchanges, such as Bitget, use a window size of 1000 ms. This means 20 requests should be sent immediately in the first second, another 20 in the second, and so on. To ensure this rate limiter works with all exchanges, the rollingWindowSize property will need to be configured individually for each exchange.
It is also likely a good idea to keep the leakyBucket rate limiter available, since some exchanges track usage with a leaky bucket model, using only a rolling window limiter could otherwise result in going over their limits.

I’m using the following programs to test this: https://github.com/caoilainnl/test-rate-limiter

The results show significant time improvements. All tests were run on Binance.

Typescript

Requests Leaky Bucket Rolling Window
1 1187 ms 817 ms
10 1517 ms 1143 ms
100 3135 ms 1430 ms
1000 21951 ms 5048 ms
5000 101246 ms 68715 ms.

Python

Requests Leaky Bucket Rolling Window
1 1649.91 ms 1242.52 ms
10 2020.80 ms 1676.62 ms
100 3726.29 ms 1906.12 ms
1000 21816.88 ms 3818.78 ms
5000 101736.17 ms 65126.31 ms.

PHP

Requests Leaky Bucket Rolling Window
1 2925.61 ms 2258.99 ms
100 4164.62 ms 3032.44 ms
1000 22228.53 ms 8375.37 ms
4000 82587.13 ms 67923.34 ms.

C#

Requests Leaky Bucket Rolling Window
1 211 ms 152 ms
10 451 ms 273 ms
100 2364 ms 784 ms
1000 20357 ms 4297 ms
5000 100171 ms 70685 ms.

GO

Requests Leaky Bucket Rolling Window
1 184 ms 141 ms
10 726 ms 150 ms
100 2316 ms 552 ms
1000 20166 ms 2544 ms
5000 100319 ms 60612 ms

@caoilainnl caoilainnl force-pushed the rolling-window-rate-limiter branch from 04c051d to e044217 Compare March 9, 2025 11:28
@caoilainnl caoilainnl force-pushed the rolling-window-rate-limiter branch from e044217 to 21a8113 Compare April 8, 2025 02:53
@ttodua
Copy link
Member
ttodua commented Apr 8, 2025

Hi @caoilainnl
I'll be looking into this

@caoilainnl caoilainnl force-pushed the rolling-window-rate-limiter branch from 21a8113 to d08ed7a Compare June 2, 2025 10:48
@caoilainnl caoilainnl force-pushed the rolling-window-rate-limiter branch from 021ac92 to aad1d09 Compare June 11, 2025 03:18
@caoilainnl caoilainnl changed the title added rolling window rate limiter rolling window rate limiter Jun 11, 2025
@carlosmiei
Copy link
Collaborator

@caoilainnl impressive work 👏


private bool running = false;
private List<(long timestamp, double cost)> timestamps = new List<(long, double)>();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@carlosmiei what about having ConcurrentList here instead of the regular list? or SlimList even?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might have to look into this more, I've read a little bit about it and it looks like right now, timestamps is single-threaded, so a plain List is fine (and slightly faster). Switching to a concurrent collection should only happen if the list is to run outside rollingWindowLoop() as well (which I don't think it ever would)

8000

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@carlosmiei what about having ConcurrentList here instead of the regular list? or SlimList even?

I think it's better to use a regular list. I haven't run into concurrency issues using it yet, and it looks like a plain List is slightly faster

Copy link
Author
@caoilainnl caoilainnl Jun 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is needed, I created thread safe timestamps on caoilainnl@d1feae0 , I don't think it is though because theres only 1 iteration of the rollingWindowLoop executing at a time, and the timestamp list isn't accessed anywhere else (other than NewThrottler, which is only called once)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@carlosmiei do you think a thread safe timestamp list would be useful?

@ccxt ccxt deleted a comment from caoilainnl Jun 16, 2025
@ccxt ccxt deleted a comment from caoilainnl Jun 16, 2025
ttodua and others added 16 commits June 16, 2025 19:37
-
Merge branch 'master' of github.com:ccxt/ccxt into rolling-window-rate-limiter

# Conflicts:
#	go/v4/exchange.go
-
Merge branch 'rolling-window-rate-limiter' of github.com:caoilainnl/ccxt into rolling-window-rate-limiter

# Conflicts:
#	go/v4/exchange.go
Co-authored-by: T. Todua <7117978+ttodua@users.noreply.github.com>
Co-authored-by: T. Todua <7117978+ttodua@users.noreply.github.com>
Co-authored-by: T. Todua <7117978+ttodua@users.noreply.github.com>
Co-authored-by: T. Todua <7117978+ttodua@users.noreply.github.com>
@@ -1619,6 +1619,7 @@ export default class bitget extends Exchange {
// fiat currencies on deposit page
'fiatCurrencies': [ 'EUR', 'VND', 'PLN', 'CZK', 'HUF', 'DKK', 'AUD', 'CAD', 'NOK', 'SEK', 'CHF', 'MXN', 'COP', 'ARS', 'GBP', 'BRL', 'UAH', 'ZAR' ],
},
'rollingWindowSize': 1000,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'rollingWindowSize': 1000,
'rateLimiterAlogrithm': 'leakyBucket', // `leakyBucket` or `rollingWindow`
'rollingWindowSize': 1000,

I meant this

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any benefit to this. The only reason it should be added to an exchange would be if rollingWindow caused the rateLimiter to go over (because the exchange tracked requests using leakyBucket or something).

I included rollingWindowSize on Bitget here because bitget can only consume a maximum per second, but with Binance it was a maximum weight per minute

Copy link
Member
@ttodua ttodua Jun 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@caoilainnl,
last nuance - even if you set that, how do you tell exchange to use rollingWindow algorithm? I mean, some extra check is needed in base. telling users to do new bitget({'rateLimiterAlgorithm':'rollingWindow'}) does not seem a good way.

@carlosmiei wdyt?

This comment was marked as outdated.

Copy link
Author
@caoilainnl caoilainnl Jun 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@caoilainnl, last nuance - even if you set that, how do you tell exchange to use rollingWindow algorithm? I mean, some extra check is needed in base. telling users to do new bitget({'rateLimiterAlgorigthm':'rollingWindow'}) does not seem a good way.

@carlosmiei wdyt?

You're saying enable it by default if rollingWindowSize has been assigned? That could probably be done, unless there's a reason not to

@carlosmiei can you think of a reason not to do this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0