CCXT.RateLimiter (ccxt_client v0.6.1)

Copy Markdown View Source

Per-credential weighted rate limiter for exchange API requests.

Tracks request costs per {exchange_id, credential_key} using a sliding window. Costs are summed (not counted) to handle weighted endpoints correctly.

Usage

# Authenticated request (per-API-key tracking)
key = {"binance", api_key}
case CCXT.RateLimiter.check_rate(key, %{requests: 1200, period: 60_000}, 4) do
  :ok -> make_request()
  {:delay, ms} -> Process.sleep(ms); make_request()
end

# Or use wait_for_capacity which blocks until ready:
:ok = CCXT.RateLimiter.wait_for_capacity(key, rate_limit, cost)
make_request()

Credential Keys

The key is a tuple {exchange_id, credential_key} where:

  • exchange_id is the exchange string ID ("binance", "bybit", etc.)
  • credential_key is either:
    • The API key string (for authenticated requests) -- isolates per-user limits
    • :public atom (for public requests) -- shared pool for unauthenticated requests

Summary

Types

Rate limiter key: {exchange_id, api_key | :public}.

Rate limit configuration with max weight and period in milliseconds

Functions

Checks if a request can be made within rate limits.

Returns a child specification for starting the rate limiter under a supervisor.

Gets current total cost for a key within a time window.

Records a request for a key with specified cost.

Resets rate limit tracking for a key.

Starts the rate limiter.

Blocks until rate limit capacity is available, then records the request.

Types

key()

@type key() :: {String.t(), String.t() | :public}

Rate limiter key: {exchange_id, api_key | :public}.

rate_limit()

@type rate_limit() :: %{requests: pos_integer(), period: pos_integer()}

Rate limit configuration with max weight and period in milliseconds

Functions

check_rate(key, rate_limit, cost \\ 1, name \\ __MODULE__)

@spec check_rate(key(), rate_limit() | nil, number(), GenServer.name()) ::
  :ok | {:delay, pos_integer()}

Checks if a request can be made within rate limits.

Returns :ok if within limits (and records the request), or {:delay, milliseconds} if the caller should wait before making the request.

Parameters

  • key -- {exchange_id, api_key} or {exchange_id, :public} tuple
  • rate_limit -- %{requests: max_weight, period: period_ms} or nil (no limiting)
  • cost -- Request weight/cost (default: 1)
  • name -- GenServer name (default: CCXT.RateLimiter)

child_spec(init_arg)

@spec child_spec(keyword()) :: Supervisor.child_spec()

Returns a child specification for starting the rate limiter under a supervisor.

get_cost(key, period, name \\ __MODULE__)

@spec get_cost(key(), pos_integer(), GenServer.name()) :: number()

Gets current total cost for a key within a time window.

Useful for debugging and monitoring.

record_request(key, cost \\ 1, name \\ __MODULE__)

@spec record_request(key(), number(), GenServer.name()) :: :ok

Records a request for a key with specified cost.

Called automatically by check_rate/4 when it returns :ok. Exposed for manual tracking if needed.

reset(key, name \\ __MODULE__)

@spec reset(key(), GenServer.name()) :: :ok

Resets rate limit tracking for a key.

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()

Starts the rate limiter.

wait_for_capacity(key, rate_limit, cost \\ 1, name \\ __MODULE__)

@spec wait_for_capacity(key(), rate_limit() | nil, number(), GenServer.name()) :: :ok

Blocks until rate limit capacity is available, then records the request.

Parameters

  • key -- {exchange_id, api_key} or {exchange_id, :public} tuple
  • rate_limit -- %{requests: max_weight, period: period_ms} or nil
  • cost -- Request weight/cost (default: 1)
  • name -- GenServer name (default: CCXT.RateLimiter)