> For the complete documentation index, see [llms.txt](https://docs.nexus.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nexus.xyz/api-reference/ko/guides/rate-limits.md).

# 요청 한도

요청 비용, 요청 한도 헤더의 의미, 서로 독립된 예산의 구분, 그리고 각 한도를 초과했을 때 일어나는 일을 설명합니다.

거래소는 트래픽 예산을 초당 요청 수로 산정하지 않습니다. **초당 가중치**로 산정합니다. 모든 요청에는 비용이 부과되며, 대부분의 요청은 1단위이고 일부는 그보다 많습니다. 요청 횟수를 세어 속도를 조절하는 클라이언트는 자체 카운터가 아직 여유 있어 보이는 상태에서 거부됩니다. 이 API와 통합할 때 가장 흔히 겪는 의외의 상황입니다.

이 페이지는 모델을 설명합니다. 무엇에 얼마의 비용이 드는지, 어떤 예산이 분리되어 있는지, 헤더를 어떻게 읽는지입니다. **규범적인** 정의는 [`nexus-xyz/nexus-exchange-api`](https://github.com/nexus-xyz/nexus-exchange-api)에 게시되고 `/openapi.json`에서 제공되는 OpenAPI 계약입니다. API 설명의 "Rate limits" 섹션이 헤더의 의미를 정의하며, 각 작업은 기계가 읽을 수 있는 자체 비용을 담고 있습니다. 이 페이지와 계약이 다를 경우 계약이 옳습니다.

### 요청 비용

예산은 **등급별 초당 비율로 연속해서 다시 채워지는 토큰 버킷**이며, 용량은 정확히 1초 분량의 토큰입니다. 이 용량에서 두 가지 결과가 나옵니다. 지속 비율과 버스트 허용량이 같은 숫자이므로, 유휴 상태로 여러 초 분량을 비축해 둘 수 없습니다. 그리고 `remaining`은 `limit`을 결코 초과할 수 없습니다.

대부분의 요청 비용은 **1**입니다. 예외는 다음과 같습니다.

| 비용                                | 적용 대상                                                                                                                                                                                                         | 이유                                                                                                              |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| **5**                             | `GET /account/summary`, `GET /fills`, `GET /orders/history`, `GET /account/portfolio-history`, `GET /positions/pnl`, `GET /account/activity`, `GET /stats/referrals`, 그리고 마지막 항목을 제외한 모든 항목의 `/api/v1` 쌍둥이 경로 | 각각 계정별 대용량 버퍼(체결, 주문 내역, 포트폴리오 시계열, 병합된 활동 피드)를 집계하거나 스캔하거나, 미결제 포지션 전체로 분산 처리하거나, 계정 백엔드에서 거래소 전체의 추천 수를 집계합니다 |
| **`1 + floor(order_count / 40)`** | `POST /orders/batch`                                                                                                                                                                                          | 최대 40건의 주문은 1건과 같은 비용이며, 40건이 추가될 때마다 1단위가 늘어납니다                                                                |
| **1**                             | 계약에 문서화된 그 밖의 모든 작업                                                                                                                                                                                           | 기본값                                                                                                             |

따라서 `limit: 20`인 Pro 호출자는 같은 등급의 같은 예산에서 초당 티커 조회 20회, **또는 `/fills` 조회 4회**를 할 수 있습니다. 요청 횟수가 아니라 가중치를 기준으로 속도를 조절하십시오.

두 가지 안전 속성이 최악의 경우를 제한합니다. 단일 요청의 부과량은 1초 분량의 토큰으로 제한되므로, 지나치게 큰 배치가 영원히 처리 불가능한 상태가 되지는 않습니다. 버킷이 다시 채워지면 그 1초 분량을 모두 소모하고 처리되며, 결코 감당할 수 없는 재시도를 끝없이 반복하지 않습니다. 또한 서버가 파싱할 수 없는 배치 본문은 가중치 때문에 거부되지 않고 기본 1단위가 부과됩니다.

위 표를 하드코딩하기보다 계약에서 비용을 읽으십시오. 1단위보다 비용이 큰 작업에는 **`x-nexus-rate-limit-weight`가** 붙고, 본문에 따라 비용이 달라지는 작업에는 **`x-nexus-rate-limit-weight-formula`도** 붙습니다. **계약에 문서화된 작업의 경우, 표시가 없으면 가중치는 1입니다.** 클라이언트 측 리미터는 이 형태를 기준으로 구축하십시오.

이 조건이 중요합니다. 계약은 지원되는 작업을 나열하며 이 규칙은 그 작업 전반에 적용되지만, 우연히 응답하는 다른 경로에 대해서는 아무것도 말하지 않습니다. 계약에 나열되지 않은 경로에는 표시가 없고, 규칙의 적용을 받지 않으며, 표시가 없다는 사실이 암시하는 것과 다르게 부과될 수 있습니다. 탐색으로 찾아낸 경로가 아니라 계약에 문서화된 작업을 기준으로 구축하십시오. 가중치와 이 페이지가 설명하는 것은 그 작업들입니다.

### 예산은 하나가 아니라 넷입니다

서로 독립된 리소스 클래스가 네 개 있습니다. 하나를 소모해도 나머지는 소모되지 않으며, 각각 고유한 방식으로 거부합니다.

| 클래스                 | 대상                                                                        | 부과 대상                                               |
| ------------------- | ------------------------------------------------------------------------- | --------------------------------------------------- |
| **요청**              | 주문 쓰기가 아닌 모든 REST 작업                                                      | 키별 및 소유자별 요청 버킷                                     |
| **거래 작업**           | `/orders` 아래의 `POST` 및 `PATCH`, `x-nexus-rate-limit-class: trading`으로 표시됨 | 요청 버킷과 초당 크기가 같은 전용 주문 버킷                           |
| **취소**              | `/orders` 아래의 `DELETE`, 마찬가지로 `x-nexus-rate-limit-class: trading`으로 표시됨   | 역시 초당 크기가 같은 **별도의** 취소 버킷                          |
| **WebSocket 제어 평면** | 연결, 구독, 클라이언트에서 들어오는 프레임                                                  | 등급별 상한. [WebSocket 상한](#websocket-ceilings)을 참조하십시오 |

주문 쓰기는 요청 버킷에 더해서가 아니라 요청 버킷 **대신** 거래 버킷에 부과됩니다. 이렇게 분리되어 있으므로 폴링이 몰려도 주문 제출이 고갈되지 않고, 주문 흐름이 조회를 고갈시키지도 않습니다. 따라서 **마지막 조회의 `x-ratelimit-remaining`이 여유 있다고 해서 주문 제출 여유분에 대해 알 수 있는 것은 없습니다.** 서로 다른 풀이므로, 곧 소모할 풀을 읽으십시오. `GET /account/rate-limit`은 `buckets`에서 각 예산을 따로 보고하며, 주문을 넣을 수 있는지는 `buckets.order`가 알려 줍니다.

#### 취소는 제출과 토큰을 공유하지 않습니다

취소는 거래 작업에서 분리되어 자체 예산을 갖는 유일한 작업입니다. 주문 엔드포인트에 대한 `DELETE`(단건 취소, 전체 취소, 시장별 취소)는 주문 버킷 대신 취소 버킷에 부과되므로, **주문을 넣느라 제출 허용량을 모두 소진한 키라도 주문을 거둬들이는 데 쓸 허용량은 온전히 그대로 남아 있습니다.**

이것이 이 모델에서 유일하게 의도된 비대칭입니다. 제출은 기다릴 수 있지만 리스크 축소는 기다릴 수 없습니다. 포지션이 불리하게 움직이는 동안 취소를 거부하는 리미터는 공정성 통제를 손실로 바꿔 버립니다. 그래서 이 규칙은 무조건적입니다. 제출을 소진해도 취소는 결코 거부될 수 없습니다. 둘은 같은 토큰을 절대 사용하지 않기 때문입니다.

클라이언트에게 이는 다음을 의미합니다.

* **제출 `429`로부터 취소 여유분을 추론하지 마십시오.** 빈 `order` 버킷은 `cancel` 버킷에 대해 아무것도 알려 주지 않습니다. 주문 제출이 한 번 거부된 뒤 모든 주문 호출을 줄이는 클라이언트는 여전히 해야 할 바로 그 호출을 스스로 막은 것입니다.
* **별도 버킷이 우회로는 아닙니다.** 취소도 다른 모든 것과 같은 등급별 초당 비율로 계량되므로, 취소 루프도 `429`를 받을 수 있습니다. 이 응답에는 `bucket: cancel`이 담기며, 취소 채널이 포화되었음을 뜻하는 유일한 거부입니다. 이 경우에는 `retry-after`를 준수하십시오.

주문 수정은 취소가 아니라 제출로 부과됩니다. `PATCH`는 수정이 익스포저를 줄이는지 늘리는지 알려 주지 않으며, 수량을 늘리는 수정은 어떻게 보더라도 제출입니다. 따라서 위의 보장은 항상 리스크를 줄이는 메서드에만 적용됩니다. 보장이 필요하다면 취소하십시오.

`POST /orders/preview`도 거래 작업이라는 점은 놓치기 쉽습니다. 이는 `/orders` 아래의 쓰기이며, 주문 제출과 마찬가지로 거래 클래스 1단위가 듭니다. 따라서 매 주문 전에 미리보기를 하면 실효 주문 제출 비율이 절반이 됩니다. 그런 방식으로 제출하는 주문마다 거래 클래스 부과 2회를 예산에 잡거나, 수량을 이미 알고 있다면 미리보기를 생략하십시오.

HMAC 키를 제시하는 호출자는 **키별** 버킷을 통과한 다음 해당 등급의 **소유자별** 버킷을 통과하며, 실효 상한은 둘 중 먼저 걸리는 쪽입니다. `GET /account/rate-limit`은 그 최솟값을 보고하며, 이를 폴링하는 데는 비용이 들지 않습니다. 토큰을 소모하지 않는 유일한 작업이므로, 속도를 조절하려고 이를 호출해도 한도에 걸리지 않습니다.

막 등급이 올라갔다면, 키 자체의 상한은 키가 생성될 때 기록되며(기본값 20/s) 등급이 바뀌어도 다시 쓰이지 않는다는 점에 유의하십시오. 따라서 기본값으로 발급된 키를 여전히 사용하는 Market Maker 계정은 등급의 수치가 아니라 키의 수치로 제한될 수 있습니다. 승급 후에는 등급 수치를 가정하지 말고 `/account/rate-limit`을 읽으십시오. 보고된 최솟값이 예상과 다르다면 새 키를 발급하십시오.

### 헤더 읽기

* **모든** 인증된 응답에: `x-ratelimit-limit`와 `x-ratelimit-remaining`.
* **`429`에만** 추가로: `x-ratelimit-reset`(unix 초)와 `retry-after`(초, 1 미만이 되지 않음).

성공 응답에서는 뒤의 두 헤더를 기대하지 마십시오. 2xx에서 `x-ratelimit-reset`을 읽는 클라이언트는 아무것도 읽지 못합니다.

**`remaining`과 `retry-after`는 의도적으로 서로 다른 단위를 사용합니다.** `remaining`은 1단위 비용 요청의 개수를 세므로, `x-ratelimit-remaining: 10`은 가중치 1인 요청 10건 *또는* 무거운 요청 2건을 뜻합니다. `retry-after`는 거부된 요청의 가중 비용에서 도출됩니다. `remaining`을 "지금 보내려는 종류의 요청 수"로 읽는 리미터는 무거운 엔드포인트에서 과도하게 전송하여 스스로 429를 유발합니다.

거부는 다음 본문을 가진 `HTTP 429`입니다.

```json
{
  "code": "RATE_LIMIT_EXCEEDED",
  "message": "Order placement rate limit exceeded",
  "bucket": "order",
  "tier": "Pro"
}
```

`code`로 분기한 다음 **`bucket`으로** 분기하십시오. 값은 `key`, `owner`, `order`, `cancel`, `ip`, `login` 중 하나이며, 앞의 네 가지는 `GET /account/rate-limit`의 `buckets`에서 조회할 키입니다. `ip`와 `login`은 그곳에 나타나지 않습니다. 둘 다 계정이 아닌 연결을 계량하며, `login`은 계정이 확정되기도 전에 거부됩니다. 같은 값이 `x-ratelimit-bucket` 헤더로도 전송되므로, 프록시나 재시도 래퍼가 본문을 파싱하지 않고도 읽을 수 있습니다. `message`는 어떤 풀이 소진되었는지 알려 줍니다(`Rate limit exceeded`, `API key rate limit exceeded`, `Order placement rate limit exceeded`, `IP rate limit exceeded`). 이는 **진단용**입니다. 문구가 안정적이지 않으므로 프로그램에서 이 값으로 매칭하지 마십시오.

`403` 관할 지역 거부와 달리 `429`는 재시도할 수 **있습니다**. `retry-after`를 준수하고 백오프하십시오. 상한에 부딪혀 알아내기보다 `x-ratelimit-remaining`을 기준으로 속도를 조절하는 편이 낫습니다.

무료인 `GET /account/rate-limit`은 토큰을 소모하지 않고 같은 상태를 보고합니다. 최상위 필드는 요청 클래스를 다루고, `buckets`는 모든 예산을 다룹니다.

```json
{
  "tier": "pro",
  "limit": 20,
  "remaining": 17,
  "reset_at_ms": 1750000000123,
  "buckets": {
    "key":    { "limit": 20, "remaining": 17, "reset_at_ms": 1750000000123 },
    "owner":  { "limit": 20, "remaining": 19, "reset_at_ms": 1750000000051 },
    "order":  { "limit": 20, "remaining": 20, "reset_at_ms": 0 },
    "cancel": { "limit": 20, "remaining": 20, "reset_at_ms": 0 }
  }
}
```

**`buckets`의 키는 `429`가 사용하는 것과 같은 레이블입니다.** `bucket` 필드와 `x-ratelimit-bucket` 헤더 모두 같습니다. 따라서 거부는 그 원인이 된 상태에 바로 대응합니다: `buckets[error.bucket]`. 리미터를 이 조회를 중심으로 구축하십시오. `key`는 키별 버킷이 사용자를 제한할 때만 나타나며, `ip`와 `login`은 둘 다 계정이 아닌 연결을 계량하므로 결코 나타나지 않습니다.

최상위의 `limit`, `remaining`, `reset_at_ms`는 변함없이 **요청** 클래스이므로, 이 값을 읽는 코드는 바꿀 필요가 없습니다. 이 값들은 "주문을 넣을 수 있는가"에 답하지 않습니다. 그 답은 `buckets.order`가 줍니다. 호가 제출로 막 제출 상한에 도달한 키에서는 두 값이 완전히 어긋납니다: `remaining: 20`이면서 `buckets.order.remaining: 0`입니다.

이 엔드포인트와 헤더를 모두 사용할 때 처리해야 할 세부 사항이 두 가지 있습니다. `reset_at_ms`는 **밀리초**이고, `x-ratelimit-reset` 헤더는 unix **초**입니다. 그리고 등급 이름은 여기서는 소문자(`pro`)이지만 `429` 본문에서는 그렇지 않으므로(`Pro`), 리터럴과 비교하지 말고 대소문자를 구분하지 않고 비교하십시오.

`Unlimited` 호출자의 경우 세 숫자 필드는 모두 `null`이며, 이 호출자는 계정별이 아니라 IP별로 버킷이 적용됩니다. 계정 범위의 예산이 이 호출자를 전혀 계량하지 않으므로 `buckets`는 `{}`로 반환됩니다.

### 등급과 현재 상한

등급은 서로 다른 모델이 아니라 하나의 모델에 곱해지는 배수입니다. **Pro**는 모든 계정의 기본값입니다. **MarketMaker**는 관리자가 부여합니다. Nexus 담당자를 통해 요청하고, [시장 조성자 가이드](https://docs.nexus.xyz/exchange/apis-and-rates/market-maker-guide)를 참조하십시오. **Unlimited**는 여러 사용자를 다중화하는 게이트웨이 키를 위해 존재하며, 거래 계정에는 결코 부여되지 않습니다.

| 등급            | 요청        | 거래 작업                | WS 연결 | WS 구독 | WS 수신 프레임 |
| ------------- | --------- | -------------------- | ----- | ----- | --------- |
| `Pro`         | 20/s      | 20/s                 | 5     | 50    | 10/s      |
| `MarketMaker` | 2,000/s   | 2,000/s              | 100   | 1,000 | 50/s      |
| `Unlimited`   | IP별, 50/s | IP별, 50/s, 조회와 같은 버킷 | 면제    | 면제    | 면제        |

등급과 관계없이 적용되는 한도가 세 가지 있으며, 모두 자격 증명을 보유하기 전에 적용됩니다. 인증되지 않은 시장 데이터 조회는 **클라이언트 IP당 50/s**로 버킷이 적용됩니다. `POST /auth/login`은 별도로, 훨씬 더 엄격하게 계량되며 자체 풀에서 **클라이언트 IP당 5/s**입니다. 로그인 시도 한 번에는 EIP-191 서명에 대한 ecrecover 비용이 들며, 엔드포인트에 접근할 수 있는 누구나 서버가 그 비용을 치르게 할 수 있습니다. 서명된 메시지는 고정된 상수이고 무차별 대입할 대상이 없으므로, 이 한도는 비밀 추측을 막는 방어가 아닙니다. 비용 방어입니다. 클라이언트 IP를 전혀 확인할 수 없는 트래픽도 제한 없이 허용되지 않습니다. 조회는 하나의 엄격한 5/s 버킷을 공유하고 로그인은 **두 번째, 별도의** 버킷을 공유하므로, `x-forwarded-for`를 제거한 대량 요청이 확인 불가능한 나머지 트래픽이 의존하는 풀을 고갈시킬 수 없습니다. 출처를 확인할 수 없는 요청에는 상한이 없는 것이 아니라 낮은 상한이 적용됩니다.

로그인 거부에는 `bucket: login`이 담기며, 이는 로그인 관문 자체가 포화되었음을 뜻하는 유일한 거부입니다. 이는 IP별 상한이므로 같은 NAT 또는 송신 프록시 뒤에 있는 모든 사용자와 공유되며, 사용자의 계정에 대해서는 아무것도 알려 주지 않습니다. 아직 계정이 없기 때문입니다.

취소에는 거래 작업 비율과 같은 자체 예산이 주어집니다(`Pro`는 추가 20/s, `MarketMaker`는 2,000/s). 두 숫자가 구조상 같기 때문에 표에서 취소에 별도 열을 두지 않았습니다.

`Unlimited`의 면제 범위는 이름이 암시하는 것보다 좁습니다. 이 등급의 주문 쓰기**와 취소는** 요청 한도에서 면제되지 **않습니다**. 이들은 전용 거래 버킷과 취소 버킷을 모두 건너뛰고, 조회와 같은 IP별 버킷에 부과됩니다. 따라서 위의 클래스 독립성도, 취소 보장도 이 등급에서는 성립하지 않으며, 트래픽 구성을 가장 예측하기 어려운 이 등급에서 게이트웨이 자체의 폴링이 주문 흐름을 밀어낼 수 있습니다. 이 등급이 면제되는 WS 상한은 *계정별* 상한입니다. 아래의 IP별 연결 상한은 여전히 적용됩니다.

**이 수치는 계약이 아니라 현재 기본값입니다.** 배포 설정(일부는 아직 코드 상수)이며, 등급 체계가 확정됨에 따라 바뀔 것입니다. 하드코딩하지 말고 `/account/rate-limit`을 읽으십시오.

### WebSocket 상한

WebSocket 상한은 REST 요청 예산 및 거래 작업 예산과 독립된 별도의 리소스 클래스입니다. 하나를 소진해도 다른 것에는 영향을 주지 않습니다.

**연결**은 등급에 따라 계정별로 제한됩니다(Pro 5, MarketMaker 100). 별도의 **IP별 상한(기본값 5)이** 업그레이드 시점에 먼저 적용되며, `Unlimited`를 포함한 모든 등급에 적용되므로 하나의 출발지 주소만으로는 계정별 수치에 도달할 수 없습니다. 여기서 거부된 연결은 close 프레임이 아니라 업그레이드 요청에 대한 `HTTP 429`(`ws_conn_limit_exceeded`)를 받습니다. 어느 경우든 일회용 스트림 토큰은 소모되므로, 다시 연결하기 전에 새 토큰을 발급하십시오.

**구독**은 같은 숫자로 두 번 제한됩니다. 연결별로, *그리고* 계정의 모든 연결 전체에 걸쳐 제한됩니다. 따라서 소켓을 더 열어도 구독을 더 얻을 수 없습니다. 이미 보유한 `(channel, market)` 키를 다시 구독하면 제자리에서 교체되며 비용이 들지 않습니다. 상한을 초과하면 상태 코드가 아니라 `error` 프레임(`subscription_limit_exceeded`)이 반환됩니다. 소켓이 열린 뒤에는 HTTP 응답이 없기 때문입니다.

**수신 프레임**(사용자가 보내는 subscribe, unsubscribe, ping)은 등급별 지속 비율로 제한되며, 그 위로 **2배 버스트**가 허용되므로 재연결 후 재구독이 몰려도 불이익을 받지 않습니다. 그 이상이면 서버는 한도를 초과한 프레임을 **폐기**하고, 프레임마다가 아니라 집계 구간마다 `error` 알림을 한 번 보내므로, 수신 폭주가 송신 폭주로 이어지지 않습니다. 지속적인 폭주, 즉 한 구간 안에서 충분히 많은 프레임이 폐기되면 코드 **`1008`**(정책 위반)로 연결이 종료됩니다. 서버는 폐기된 프레임을 적용하지 않으며 이를 알려 주지도 않습니다. `subscribed` 확인 응답을 받지 못했다면, 적용되었다고 가정하지 말고 백오프한 뒤 subscribe를 다시 보내십시오.

### 예산은 네트워크별입니다

각 네트워크는 별도의 배포이므로 **네트워크마다 자체 버킷이 있습니다**. 메인넷이 출시되더라도 테스트넷에서의 소모가 메인넷 여유분을 줄이지 않으며, 그 반대도 마찬가지입니다. 자격 증명도 네트워크를 넘나들지 않습니다. 키는 그 키를 발급한 네트워크에 바인딩됩니다. [네트워크](/api-reference/ko/guides/networks.md)를 참조하십시오.

### 현재 한도 적용 위치

외부에서 보이는 현재의 제약이 하나 있으며, 이는 사용자에게 불리하지 않고 오히려 유리하게 작용합니다.

게이트웨이 프로세스는 리미터 상태를 공유 저장소가 아니라 **메모리**에 보관합니다. 여기서 두 가지가 따라옵니다. 첫째, 영속적이지 않습니다. 재배포하면 버킷이 초기화되며, 등급 승급은 다시 적용될 때까지 잠시 기본 등급으로 되돌아갈 수 있습니다. 둘째, 네트워크의 게이트웨이가 둘 이상의 복제본으로 실행되면 각 복제본이 자체 버킷을 보유하므로, 연결이 어디에 배치되는지에 따라 클라이언트가 관찰하는 *총* 상한이 게시된 초당 수치보다 높을 수 있습니다.

이 여유분을 기준으로 설계하지 마십시오. 게시된 수치를 자신에게 허용된 상한으로 간주하고 그에 맞춰 속도를 조절하십시오. 추가 여유분은 현재 한도가 적용되는 위치에서 생기는 것으로, 고르게 분배되지 않으며, 카운터가 공유 저장소로 옮겨지면 사라집니다. 게시된 수치에 맞춰 구축한 클라이언트는 그 변경이 적용되어도 계속 작동합니다. 관찰된 총량에 맞춰 조정한 클라이언트는 429를 받기 시작할 것입니다.

### 서명자가 따라갈 수 있습니까?

클라이언트는 모든 인증된 요청을 보내기 전에 서명하므로, 서명자는 위 예산과 별개로 자체 상한을 만듭니다. SDK를 선택하기 전에 그 상한을 확인하십시오. 상한은 언어보다 서명 방식과 암호화 라이브러리에 훨씬 더 크게 좌우됩니다.

거래소는 두 가지 요청 서명 방식을 허용합니다([인증](/api-reference/ko/guides/authentication.md#signing-a-request-with-the-key) 및 [에이전트](/api-reference/ko/guides/agent-keys.md) 참조).

* **HMAC**(`hmacAuth`). 16진수 디코딩한 API 시크릿을 키로 하여 다섯 필드 정규 문자열에 대해 계산하는 HMAC-SHA256입니다. 대칭 MAC은 어떤 언어에서든 마이크로초 단위로 처리됩니다.
* **에이전트 키**(`agentAuth`). 여섯 필드 정규 문자열의 `keccak256`에 대한 secp256k1 ECDSA이며, low-S로 65바이트 `r||s||v`로 전송됩니다. 타원 곡선 서명이므로, 그 비용은 하부 라이브러리가 네이티브 코드인지 순수 인터프리터 코드인지에 따라 달라집니다.

각 SDK 자체의 서명 경로를 통해, 하나의 고정된 `POST /api/v1/orders` 본문으로, 단일 스레드에서 측정했습니다. 이는 클라이언트가 모든 요청에서 수행하는 호출과 같으며, 정규 문자열 구성, 본문 해싱, 결과의 16진수 인코딩을 포함하지만 네트워크 I/O는 포함하지 않습니다.

| SDK                              | 방식     | 하부 암호화 라이브러리                 |    p50 |    p95 |     초당 서명 수 | 5회 실행의 p50 범위 |
| -------------------------------- | ------ | ---------------------------- | -----: | -----: | ----------: | ------------- |
| Rust (`nexus-exchange-rs`)       | HMAC   | `hmac` + `sha2`              | 0.9 µs | 0.9 µs | \~1,080,000 | 0.88–0.96 µs  |
| Rust (`nexus-exchange-rs`)       | 에이전트 키 | `k256`                       |  79 µs |  91 µs |    \~12,500 | 74–79 µs      |
| TypeScript (`nexus-exchange-ts`) | HMAC   | Web Crypto (비동기)             |  27 µs |  43 µs |    \~29,000 | 24–35 µs      |
| TypeScript (`nexus-exchange-ts`) | 에이전트 키 | `@noble/curves`              | 319 µs | 470 µs |     \~2,900 | 293–645 µs    |
| Python (`nexus-exchange-py`)     | HMAC   | 표준 라이브러리 `hmac`              | 2.1 µs | 2.2 µs |   \~460,000 | 1.96–2.25 µs  |
| Python, 기본 설치                    | 에이전트 키 | `eth-keys` 순수 Python 백엔드     | 3.5 ms | 4.2 ms |       \~280 | 3.43–4.11 ms  |
| Python + `coincurve`             | 에이전트 키 | `coincurve`를 통한 libsecp256k1 |  97 µs | 110 µs |    \~10,000 | 96–116 µs     |

CLI는 Rust 크레이트를 통해 서명하므로, 자체 수치 없이 Rust 행의 수치를 그대로 따릅니다.

**`Pro` 등급에서는 어떤 SDK와 어떤 방식도 서명자가 병목이 되지 않습니다.** 초당 20건의 요청이면 서명당 50 ms가 남습니다. 가장 느린 행인 기본 Python 설치의 에이전트 키 서명은 그중 3.5 ms를 사용하므로, 코어 하나로 Pro 비율의 약 14배를 서명할 수 있습니다. 세 가지 Pro 버킷(요청, 거래 작업, 취소, 초당 서명 요청 60건)을 동시에 모두 포화시키는 호출자라도 서명에 코어 하나의 약 5분의 1을 사용합니다. TypeScript의 에이전트 키 서명자는 100배 넘는 여유가 있으며, HMAC은 모든 SDK에서 사실상 비용이 없습니다.

**`MarketMaker` 등급에서는 서명 방식과 라이브러리가 중요해지기 시작합니다.** 초당 2,000건의 거래 작업과 별도의 2,000건 취소를 더하면, 단일 스레드에서 서명당 0.25–0.5 ms가 남습니다.

* **에이전트 키를 사용하는 Python:** 기본 설치는 초당 약 280건을 서명하며, 이는 거래 상한의 약 7분의 1입니다. 같은 환경에 `coincurve`를 설치하면(`pip install coincurve`) 코드 변경 없이 `AgentSigner`가 libsecp256k1에서 실행되어 초당 약 10,000건을 처리합니다. SDK가 곡선 백엔드를 직접 선택하지는 않습니다. `ECC_BACKEND_CLASS` 환경 변수가 다른 백엔드를 지정하지 않는 한, `eth-keys`는 `coincurve`를 가져올 수 있으면 언제든 이를 사용합니다. Python 벤치마크는 측정한 백엔드를 출력하므로, 전환이 제대로 되었는지 확인하는 가장 빠른 방법입니다. 또는 결코 제약이 되지 않는 HMAC으로 서명하십시오.
* **에이전트 키를 사용하는 TypeScript:** 초당 약 2,900건으로 코어 하나에서 거래 상한은 넘지만, 거래와 취소를 합친 수치는 넘지 못합니다. 둘 다 최대 비율로 실행하는 클라이언트는 HMAC으로 서명하거나 서명을 워커 스레드에 분산하십시오.
* **Rust 및 CLI:** 어느 방식이든 여유가 있습니다.

요청당 서명은 TypeScript에서 0.3 ms, 기본 Python 에이전트 키 설치에서 3.5 ms를 더합니다. 수십 밀리초 단위로 측정되는 클라이언트 왕복 시간에 비하면 작은 비중이지만, Python 경로에서는 체감될 수 있습니다. 에이전트 키로 Python에서 거래한다면 이것도 `coincurve`를 설치할 또 하나의 이유입니다.

#### Paradex 공개 수치와의 비교

Paradex는 비슷한 표를 공개합니다. Rust에서 초당 약 5,000건, Go에서 1,430건, TypeScript에서 50건, Python 또는 Java에서 8건입니다. 액면 그대로 읽으면 TypeScript의 서명당 20 ms는 스레드 하나를 초당 50건으로 제한합니다. 이는 20/s 예산 하나는 감당하지만 서명만으로 코어의 40%를 사용하며, Pro 호출자가 요청, 거래 작업, 취소를 합쳐 쓸 수 있는 60/s에는 미치지 못합니다. 이 수치는 그대로 적용되지 않습니다. Paradex는 StarkNet 키로 주문에 서명하는데, 이는 여기의 두 방식과 곡선도 해시도 다르며, 그 수치는 아래의 하드웨어에서 측정되지 않았으므로 두 표 사이의 비율은 기껏해야 방향성만 보여 줍니다. 그러나 패턴은 그대로 적용됩니다. 순수 인터프리터 코드로 된 타원 곡선 서명자가 느린 경우이며, 네이티브 바인딩이 그 격차의 대부분을 메웁니다. 여기서 다른 점은 느린 경우(순수 Python 대체 경로의 Python, 초당 약 280건)조차 Pro 등급에 필요한 속도보다 10배 넘게 빠르다는 것입니다.

#### 측정 방법

* **하드웨어.** Apple M2, 8코어(성능 코어 4개, 효율 코어 4개), 8 GB, macOS 26.5(빌드 25F84), AC 전원, 저전력 모드 꺼짐. macOS는 프로세스를 코어에 고정할 수 없고, 측정 중 시스템이 완전히 유휴 상태가 아니었으므로(실행 중 부하 평균 4–14), p95 열과 범위는 상한으로 읽으십시오.
* **런타임.** Rust 1.97(릴리스 프로필), Node.js 22.23, 그리고 HMAC 및 기본 에이전트 키 행에는 Python 3.14를 사용했습니다. `coincurve` 행은 `coincurve`가 아직 Python 3.14 휠을 제공하지 않으므로 Python 3.13에서 실행됩니다. 기본 에이전트 키 행은 3.13에서도 같게 측정되므로(3.5 ms), 인터프리터가 차이의 원인은 아닙니다.
* **고정 입력.** 세 SDK 모두 동일합니다: `POST`, 경로 `/api/v1/orders`, 빈 쿼리, 155바이트 지정가 주문 본문, 고정 타임스탬프. 에이전트 서명자는 실제 쓰기에서와 마찬가지로 반복마다 새 논스를 발급합니다. 이 입력에 대해 두 방식 모두 SDK 간에 바이트 단위로 동일한 서명을 생성합니다.
* **절차.** 2초 동안 워밍업한 뒤 각 서명의 시간을 개별 측정하고(Rust 20,000회, TypeScript 5,000회, Python 3,000회 또는 5,000회), 샘플에서 p50과 p95를 구했습니다. 초당 서명 수는 샘플 수를 측정 루프의 경과 시간으로 나눈 값입니다. 각 벤치마크는 서로 번갈아 가며 5회 실행했습니다. 표에는 중앙값 실행과 5회 전체의 p50 범위가 표시됩니다. Rust 벤치마크는 criterion도 실행하며, 그 평균 추정치는 측정 루프와 일치했습니다(에이전트 키의 경우 76–85 µs).
* **다시 실행하기.** 각 SDK에 벤치마크가 포함되어 있습니다: `nexus-exchange-rs`의 `cargo bench --bench signing`, `nexus-exchange-ts`의 `pnpm bench`, `nexus-exchange-py`의 `python bench/signing_bench.py`. Python 벤치마크는 측정한 `eth-keys` 백엔드를 출력합니다.

### 한도를 고려한 설계

* **반복 대신 배치를 사용하십시오.** `POST /orders/batch`는 `1 + floor(n / 40)`을 부과하므로, 한 요청에 담은 40건의 주문은 단건 제출 40회 비용의 40분의 1입니다.
* **폴링 대신 스트림을 사용하십시오.** WebSocket을 통한 오더북 및 체결 데이터는 요청 예산에 비용이 들지 않으며 더 빨리 도착합니다. subscribe 프레임은 수신 프레임 하나이며, 이후 이어지는 스트림은 무료입니다.
* **무거운 조회는 실제 비용으로 예산을 잡으십시오.** `/fills`, `/orders/history`, `/account/summary`, `/account/portfolio-history`는 각각 5의 비용이 듭니다. 네 가지를 매초 폴링하면 20/s가 들며, 이는 Pro 호출자의 전체 예산입니다.
* **하나의 일관된 조회를 우선하십시오.** `GET /account/state`는 요약과 모든 미결제 포지션을 함께 반환합니다. 두 번 호출하는 것보다 저렴하며, 두 호출 사이의 경합도 없습니다([포트폴리오 및 계정 상태](/api-reference/ko/guides/portfolio.md) 참조).
* **바뀌지 않는 것은 캐시하십시오.** `GET /markets`의 시장 메타데이터는 매 주기마다 다시 가져올 필요가 없습니다.
* **헤더와 `/account/rate-limit`을 기준으로 속도를 조절하십시오.** 이 엔드포인트를 폴링하는 데는 비용이 들지 않습니다. `429` 후에 무작정 재시도하는 데는 비용이 듭니다.

### 관련 문서

* [OpenAPI 사양](https://github.com/nexus-xyz/nexus-exchange-api): 규범적인 작업별 가중치, 클래스, 헤더 의미
* [네트워크](/api-reference/ko/guides/networks.md): 네트워크를 선택하는 방법과 키를 네트워크에 바인딩하는 요소
* [포트폴리오 및 계정 상태](/api-reference/ko/guides/portfolio.md): 무거운 조회 엔드포인트와 이를 한 번의 호출로 읽는 방법
* [요청 및 연결 한도](https://docs.nexus.xyz/exchange/apis-and-rates/rate-limits): HMAC 시간 창, 토큰 수명, 포셋 허용량
* [시장 조성자 가이드](https://docs.nexus.xyz/exchange/apis-and-rates/market-maker-guide): MarketMaker 등급 요청
* [인터페이스 개요](/api-reference/ko/readme.md)

> **상태:** 테스트넷의 개발 프리뷰입니다. 메인넷은 아직 출시되지 않았습니다. 이 페이지의 모든 상한은 고정된 계약이 아니라 현재 설정입니다. 프로덕션에서는 숫자를 하드코딩하지 말고 `/account/rate-limit`을 읽으십시오. 또한 기준으로 삼는 작업별 가중치가 고정되도록 릴리스된 사양 버전에 고정하십시오. 리미터 상태는 아직 게이트웨이 재시작 후에도 유지되지 않습니다. 테스트넷 자격 증명과 잔액에는 실제 가치가 없습니다.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.nexus.xyz/api-reference/ko/guides/rate-limits.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
