바이낸스 API 제한 — weight 6000과 418 IP 밴
api.binance.com의 /api/v3/exchangeInfo를 직접 호출해 받은 값은
REQUEST_WEIGHT 1분당 6,000 ·
ORDERS 10초당 100, 1일당 200,000 ·
RAW_REQUESTS 5분당 300,000입니다.
한국어 자료에 아직 많이 남아 있는 “분당 1200”은 과거 값입니다.
현재 소모량은 모든 응답에 붙는 X-MBX-USED-WEIGHT-1m 헤더로 확인하고,
한도를 넘기면 429(경고 · Retry-After 동봉)가,
거기서 멈추지 않으면 418(자동 IP 차단)이 돌아옵니다.
차단 기간은 2분에서 3일까지 늘어나고,
제한은 API 키가 아니라 IP 기준이라 키를 더 만들어도 늘지 않습니다.
1. “분당 1200”이 왜 아직도 돌아다니나
바이낸스 자동매매를 시작하면 거의 반드시 “바이낸스는 분당 weight 1200”이라는 문장을 만납니다.
한국어 블로그·유튜브에 널리 퍼져 있고 오래된 라이브러리 코드에도 상수로 박혀 있습니다.
문제는 지금의 값이 아니라는 것입니다. 바이낸스는 현물 REST API의
REQUEST_WEIGHT를 과거 1분당 1,200에서 1분당 6,000으로 올렸고,
한국어 자료가 갱신되지 않은 채 남았습니다.
실무에서 문제가 되는 이유는 양쪽으로 다 틀리기 때문입니다.
1,200으로 알고 설계하면 필요 없는 sleep을 넣어 봇을 5배 느리게 만들고,
반대로 6000을 코드에 박아 두면 바이낸스가 한도를 조정했을 때
봇이 그 사실을 영영 모른 채 어느 날 418을 맞습니다.
결론은 “숫자를 외우지 말라”입니다. 바이낸스는 현재 한도를 API로 직접 알려 줍니다. 봇이 시작할 때 그 값을 읽어 쓰면 이 논쟁 자체가 사라집니다.
2. 내 계정의 진짜 한도를 확인하는 한 줄
/api/v3/exchangeInfo 응답의 rateLimits 배열에 현재 한도가 들어 있습니다.
API 키도, 로그인도 필요 없습니다. 지금 터미널에 그대로 붙여 넣어 보십시오.
curl -s "https://api.binance.com/api/v3/exchangeInfo?symbol=BTCUSDT" \
| python -c "import sys,json; print(json.dumps(json.load(sys.stdin)['rateLimits'], indent=1))"
2026-08-22에 실행해 받은 실제 응답입니다.
[
{
"rateLimitType": "REQUEST_WEIGHT",
"interval": "MINUTE",
"intervalNum": 1,
"limit": 6000
},
{
"rateLimitType": "ORDERS",
"interval": "SECOND",
"intervalNum": 10,
"limit": 100
},
{
"rateLimitType": "ORDERS",
"interval": "DAY",
"intervalNum": 1,
"limit": 200000
},
{
"rateLimitType": "RAW_REQUESTS",
"interval": "MINUTE",
"intervalNum": 5,
"limit": 300000
}
]
세 종류의 한도가 동시에 걸려 있다는 점이 핵심입니다.
| rateLimitType | 무엇을 세나 | 2026-08-22 확인값 | 어디서 터지나 |
|---|---|---|---|
REQUEST_WEIGHT |
엔드포인트별 가중치 합계 | 1분당 6,000 | 시세·잔고 폴링이 많은 봇 |
ORDERS |
주문 제출 건수 | 10초당 100 1일당 200,000 |
호가 추종·마켓메이킹 봇 |
RAW_REQUESTS |
weight 무관 순수 요청 수 | 5분당 300,000 | 가벼운 요청을 미친 듯이 반복할 때 |
RAW_REQUESTS가 따로 있는 이유가 여기 있습니다.
weight 1짜리 가벼운 엔드포인트만 골라 부르면 REQUEST_WEIGHT는 여유가 있어도
순수 호출 수 상한에 먼저 걸릴 수 있습니다.
“가벼운 API니까 마음껏 불러도 된다”가 성립하지 않는다는 뜻입니다.
실무 권장 — 하드코딩 대신 부팅 시 1회 조회.
봇이 뜰 때 exchangeInfo를 한 번 불러 rateLimits를 읽고,
그 값의 70~80%를 자체 상한으로 삼으십시오.
한도가 바뀌어도 코드를 고칠 필요가 없고, 여유분이 재시도·재접속 비용을 흡수합니다.
3. weight는 호출 1번 = 1이 아니다
여기서 대부분의 계산이 틀어집니다. 엔드포인트마다 weight가 다르고, 같은 엔드포인트라도 파라미터에 따라 달라집니다. 바이낸스 공식 문서는 여러 심볼을 한꺼번에 다루는 요청과 무거운 엔드포인트에 더 큰 weight를 매긴다고 설명합니다.
말로 하면 와닿지 않으니 직접 재는 방법을 쓰겠습니다. 응답 헤더에 그 순간까지의 누적 소모량이 찍히므로, 요청 전후 차이가 곧 그 요청의 weight입니다.
curl -s -D - -o /dev/null \
"https://api.binance.com/api/v3/exchangeInfo?symbol=BTCUSDT" \
| grep -i "x-mbx"
실행 결과(2026-08-22, 새 IP에서 첫 호출):
x-mbx-uuid: 96486c7f-121e-4fe4-b096-085fdd3d28d1
x-mbx-used-weight: 20
x-mbx-used-weight-1m: 20
심볼 하나를 지정한 exchangeInfo 한 번이 weight 20을 먹었습니다.
호출 1회 = weight 1이라고 가정했다면 이미 20배 어긋난 것입니다.
그리고 symbol 파라미터를 빼고 전체 심볼 정보를 받으면 이보다 훨씬 무겁습니다.
같은 URL인데 파라미터 하나로 비용이 달라진다는 것이 이 시스템의 성격입니다.
가장 흔한 사고 — 전체 조회 폴링. 심볼을 지정하지 않은 전체 시세·전체 심볼 정보 조회를 루프 안에서 반복하는 코드는 weight 예산을 몇 초 만에 태웁니다. 실제로 쓰는 심볼이 3개라면 3개만 지정해 부르십시오. “어차피 한 번에 받는 게 효율적”이라는 직관이 여기서는 정확히 반대로 작동합니다.
내 봇의 소모량을 실제로 재는 코드
추측하지 말고 봇의 1주기를 그대로 재현해 실측하십시오.
import requests
BASE = "https://api.binance.com"
def call(path, **params):
r = requests.get(BASE + path, params=params, timeout=10)
print(f"{path:28s} used_1m={r.headers.get('X-MBX-USED-WEIGHT-1m')}")
# 봇이 1주기에 실제로 부르는 순서 그대로 재현한다
call("/api/v3/ticker/bookTicker", symbol="BTCUSDT")
call("/api/v3/klines", symbol="BTCUSDT", interval="1m", limit=100)
call("/api/v3/depth", symbol="BTCUSDT", limit=100)
used_1m 증가폭이 1주기 비용입니다. 여기에 분당 주기 수를 곱한 값이
exchangeInfo가 알려 준 6,000의 70%를 넘으면 설계를 바꿔야 합니다.
거래소별 비교는 API 호출 제한 설계 — 바이낸스·업비트·KIS·키움 한도에 있습니다.
4. 응답 헤더로 잔량 읽기
바이낸스는 모든 응답에 현재 소모량을 실어 보냅니다. 이름 규칙은 다음과 같습니다.
| 헤더 | 의미 | 예시 |
|---|---|---|
X-MBX-USED-WEIGHT-(intervalNum)(intervalLetter) |
해당 구간 동안 이 IP가 쓴 weight | X-MBX-USED-WEIGHT-1m: 20 |
X-MBX-ORDER-COUNT-(intervalNum)(intervalLetter) |
해당 구간 동안 낸 주문 수 | X-MBX-ORDER-COUNT-10sX-MBX-ORDER-COUNT-1d |
Retry-After |
429·418일 때 몇 초 뒤에 오라 | Retry-After: 27 |
intervalNum과 intervalLetter가 붙는 형식이라
헤더 이름을 문자열로 고정해 두면 안 됩니다.
바이낸스가 집계 구간을 바꾸면 X-MBX-USED-WEIGHT-1m이 아닌 이름으로 올 수 있습니다.
접두어로 찾는 방식이 안전합니다.
def read_usage(resp):
"""헤더 이름을 하드코딩하지 않고 접두어로 훑는다."""
weight, orders = {}, {}
for k, v in resp.headers.items():
kl = k.lower()
if kl.startswith("x-mbx-used-weight-"):
weight[kl.split("-")[-1]] = int(v) # {'1m': 20}
elif kl.startswith("x-mbx-order-count-"):
orders[kl.split("-")[-1]] = int(v) # {'10s': 3, '1d': 412}
return weight, orders
모니터링에 반드시 남기십시오.
used_weight_1m을 로그·대시보드에 초 단위로 찍어 두면
418을 맞기 전에 그래프가 올라가는 것이 보입니다.
사후에 “왜 밴됐지”를 추적하는 것보다 훨씬 쌉니다.
텔레그램으로 임계치 알림을 받는 구성은
텔레그램 봇 모니터링·원격 제어에 정리해 두었습니다.
5. 429와 418 — 경고와 처형
이 둘을 같은 것으로 다루는 코드가 정말 많습니다. 완전히 다릅니다.
429 — 아직 되돌릴 수 있다
한도를 넘겼을 때 돌아옵니다. Retry-After 헤더가 함께 오고
그 초만큼 쉬었다가 재개하면 아무 일도 일어나지 않습니다.
본문에는 바이낸스 자체 에러코드 -1003 TOO_MANY_REQUESTS가 담깁니다.
HTTP/1.1 429 Too Many Requests
Retry-After: 27
Content-Type: application/json
{
"code": -1003,
"msg": "Too much request weight used; current limit is 6000 request weight per 1 MINUTE. Please use WebSocket Streams for live updates to avoid polling the API."
}
메시지 안에 현재 한도가 그대로 적혀 옵니다. 그리고 바이낸스가 직접 “폴링 대신 WebSocket 스트림을 쓰라”고 안내하고 있습니다. 9장에서 다룹니다.
418 — 이미 차단됐다
429를 받고도 계속 요청을 보내면 바이낸스가 해당 IP를 자동으로 차단합니다.
이때부터 HTTP 418이 돌아오고, 공식 문서는 차단 기간이
반복 위반자에게 점점 길어져 2분에서 3일 사이라고 명시합니다.
에러 본문은 보통 -1003의 세 번째 변형입니다.
HTTP/1.1 418 I'm a teapot
Retry-After: 172800
{
"code": -1003,
"msg": "Way too much request weight used; IP banned until 1787000000000. Please use WebSocket Streams for live updates to avoid bans."
}
재시도 로직이 범인인 경우가 압도적입니다.
try/except 안에서 continue로 무한 재시도하는 코드는
429를 받은 순간부터 초당 수백 번 요청을 던집니다.
백오프 없는 재시도는 봇을 살리는 코드가 아니라 봇을 3일간 죽이는 코드입니다.
올바른 대응 — Retry-After를 존중하는 백오프
import time, requests
def safe_get(path, params=None, max_retry=5):
url = "https://api.binance.com" + path
for attempt in range(max_retry):
r = requests.get(url, params=params, timeout=10)
if r.status_code == 418:
# 이미 밴이다. 재시도로 풀 수 있는 상태가 아니다.
wait = int(r.headers.get("Retry-After", 120))
raise SystemExit(f"[FATAL] IP banned. {wait}s. 봇을 멈추고 원인부터 고칠 것")
if r.status_code == 429:
wait = int(r.headers.get("Retry-After", 2 ** attempt))
print(f"[WARN] 429 → {wait}s 대기 (attempt {attempt + 1})")
time.sleep(wait + 1) # 서버 시계와 어긋날 수 있으니 +1
continue
if r.status_code >= 500:
time.sleep(2 ** attempt) # 서버 오류는 지수 백오프
continue
return r
raise RuntimeError("재시도 한도 초과 — 호출 빈도 설계를 다시 볼 것")
핵심은 세 가지입니다.
418은 재시도하지 않고 즉시 중단,
429는 Retry-After를 그대로 따르기,
재시도 횟수에 상한 두기.
이 셋이 없으면 어떤 라이브러리를 써도 결국 밴을 맞습니다.
6. 주문 카운터는 완전히 별개다
REQUEST_WEIGHT가 여유로워도 주문 한도에 먼저 걸릴 수 있습니다.
앞의 exchangeInfo 응답이 알려 준 값은 10초당 100건, 1일당 200,000건이었습니다.
초과하면 -1015 TOO_MANY_ORDERS가 돌아옵니다.
{
"code": -1015,
"msg": "Too many new orders; current limit is 100 orders per 10 SECONDS."
}
10초당 100건이면 넉넉해 보이지만 호가 추종 봇(1틱마다 취소·재주문 = 2건), 분할 매수 봇(20분할이면 진입 한 번에 20건), 재시작 루프(미체결 전량 취소·재등록)에서는 순식간에 찹니다.
대응은 “주문을 덜 내는 설계”입니다. 호가 1틱마다 옮기지 말고 최소 이동폭(예: 3틱 이상 벌어질 때만 정정)을 두고, 재시작 시 미체결을 전량 지우지 말고 기존 주문을 조회해 살릴 것은 살리십시오. 분할 개수 설계는 포지션 사이징 4가지와 같이 보시면 됩니다.
7. IP 기준이라는 함정
바이낸스 공식 문서는 “제한은 API 키가 아니라 IP 기준”이라고 못 박습니다. 이 한 문장이 실무에서 만드는 사고가 셋 있습니다.
함정 1 — 키를 여러 개 만들면 늘어난다는 착각
같은 서버에서 API 키만 다르게 봇을 두 개 돌리면 한도가 두 배가 되는 게 아니라 하나의 예산을 둘이 나눠 씁니다. 한쪽에 버그가 나면 멀쩡한 다른 봇까지 같이 418을 맞습니다. 전략이 여러 개면 호출을 한 모듈로 모아 한 곳에서 예산을 배분하십시오.
함정 2 — 공유 IP와 백테스트
일부 저가 VPS·컨테이너는 출구 IP를 여러 고객이 공유합니다.
내가 잘못하지 않아도 같은 IP를 쓰는 남 때문에 밴을 맞을 수 있으니 고정 IP 서버를 고르십시오.
같은 맥락에서 과거 데이터 대량 수집과 실매매 봇을 한 IP에 두지 마십시오.
수집이 weight를 다 먹고 정작 주문이 429를 맞습니다.
바이낸스 API 키 설정의 Restrict access to trusted IPs only 등록은
바이낸스 API 발급 가이드에 화면 기준으로 정리해 두었습니다.
8. ccxt를 쓸 때 반드시 켜야 하는 옵션
라이브러리가 알아서 해 주겠지가 가장 위험한 가정입니다. 옵션을 켜야 동작합니다.
import ccxt
ex = ccxt.binance({
"apiKey": "...",
"secret": "...",
"enableRateLimit": True, # ← 켜야 ccxt가 호출 간격을 스스로 벌린다
"options": {"adjustForTimeDifference": True},
})
enableRateLimit은 기본값에 의존하지 말고 명시적으로 켜십시오.
다만 ccxt 내부 한도 테이블도 거래소 변경을 따라가지 못할 수 있으므로
2장의 exchangeInfo 실측과 4장의 헤더 로깅은 그대로 유지하는 편이 안전합니다.
python-binance를 쓴다면 BinanceAPIException의
status_code(418)와 code(-1003·-1015)를 나눠서 분기해야 합니다.
선물(USDT-M)은 한도 체계가 또 다릅니다.
이 글의 숫자는 현물 api.binance.com 기준이고,
선물은 도메인부터 fapi.binance.com으로 다르며 주문 한도 구조가 별개입니다.
선물 봇이라면 해당 도메인의 exchangeInfo를 따로 조회하십시오.
전반적인 함정은 바이낸스 자동매매 봇 놓치기 쉬운 5가지에 모아 두었습니다.
9. WebSocket으로 옮기면 weight가 사라진다
바이낸스가 429 에러 메시지 안에서까지 권하는 방법입니다. 시세는 REST로 물어보지 말고 스트림으로 받으십시오. 구독은 접속할 때만 비용이 들고, 이후 흘러 들어오는 시세는 REST weight를 소모하지 않습니다.
import json, websockets, asyncio
URL = "wss://stream.binance.com:9443/stream?streams=btcusdt@bookTicker/ethusdt@bookTicker"
async def run():
async with websockets.connect(URL, ping_interval=20) as ws:
while True:
msg = json.loads(await ws.recv())
d = msg["data"]
print(d["s"], d["b"], d["a"]) # 심볼, 최우선 매수호가, 최우선 매도호가
asyncio.run(run())
1초마다 bookTicker를 REST로 폴링하던 봇이 이 구조로 바뀌면
시세 쪽 weight 소모가 사실상 0이 됩니다.
남는 예산은 주문·잔고 확인처럼 정말 REST로만 되는 일에 쓰면 됩니다.
단, 스트림에도 함정이 있습니다.
연결이 끊겼는데 재접속 로직이 없으면 봇은 “가격이 안 변한다”고 착각한 채 계속 돕니다.
ping_interval로 살아 있음을 확인하고, 마지막 수신 시각이 일정 초를 넘으면
스스로 재접속하도록 만드십시오.
그리고 재접속 폭주가 다시 429를 부르지 않도록 재접속에도 백오프를 거십시오.
업비트 쪽 동일 패턴은 업비트 REST·WebSocket 정리에 있습니다.
10. 배포 전 체크리스트 7가지
- 한도를 코드에 박지 않았다. 부팅 시
exchangeInfo의rateLimits를 읽는다. - 자체 상한을 한도의 70~80%로 잡았다. 여유분이 재시도·재접속 비용을 흡수한다.
X-MBX-USED-WEIGHT-*를 로그에 남긴다. 헤더 이름은 접두어로 찾는다.- 418에서는 재시도하지 않고 즉시 중단한다. 재시도로 풀리는 상태가 아니다.
- 429에서는
Retry-After를 그대로 따른다. 임의의sleep(1)로 덮지 않는다. - 시세는 WebSocket, 주문·잔고만 REST. 전체 조회 폴링을 루프에서 제거했다.
- 같은 IP에서 도는 다른 프로세스를 확인했다. 데이터 수집기·백테스터를 분리했다.
일곱 가지 모두 “고급 최적화”가 아니라 봇을 며칠씩 멈추지 않게 하는 최소 조건입니다. 알고랩에 들어오는 바이낸스 문의 중 상당수가 전략이 아니라 호출 설계 문제였습니다.
자주 묻는 질문
바이낸스 API 분당 호출 한도는 몇인가요?
요청 개수가 아니라 weight로 셉니다. 2026-08-22 기준 /api/v3/exchangeInfo로 확인한 값은
REQUEST_WEIGHT 1분당 6,000, ORDERS 10초당 100·1일당 200,000,
RAW_REQUESTS 5분당 300,000입니다. “분당 1200”은 과거 값이며,
6000도 코드에 박지 마십시오.
429와 418은 무엇이 다른가요?
429는 경고, 418은 이미 차단입니다. 429에는 Retry-After가 함께 오고 그만큼 쉬면 정상 복귀합니다.
무시하고 재시도하면 IP가 자동 차단되어 418이 돌아오고, 공식 문서 기준 차단 기간은
반복 위반에 따라 2분에서 3일까지 길어집니다.
API 키를 여러 개 만들면 한도가 늘어나나요?
늘어나지 않습니다. 공식 문서가 제한은 API 키가 아니라 IP 기준이라고 명시합니다.
한 봇의 폭주가 같은 IP의 나머지 봇까지 죽입니다. 반면 주문 카운터는 계정 단위로 집계되며
X-MBX-ORDER-COUNT-10s·X-MBX-ORDER-COUNT-1d로 확인합니다.
weight를 줄이려면 어떻게 해야 하나요?
시세 조회를 WebSocket 스트림으로 옮기고, 심볼을 지정해 부르고, 폴링 주기를 전략이 실제로 요구하는 값까지만 줄입니다.
이미 418을 맞았으면 어떻게 풀리나요?
기다리는 것 외에 즉시 푸는 방법은 없습니다. 봇을 완전히 멈추고,
Retry-After와 에러 본문의 banned until로 해제 시점을 확인한 뒤
그사이에 폭주 원인을 고치십시오. 고치지 않고 재개하면 다음 차단은 더 깁니다.
이 숫자들을 그대로 믿어도 되나요?
이 글의 한도 값은 2026-08-22에 https://api.binance.com/api/v3/exchangeInfo를 직접 호출해 받은 응답과
같은 시점 바이낸스 공식 API 문서(Rate Limits · Error Codes)에서 확인한 것입니다.
거래소 정책은 공지 없이 바뀔 수 있으므로 운영 전 현재 응답으로 대조하시고,
한도·도메인 값은 상수로 박지 말고 설정 또는 런타임 조회로 빼 두시기 바랍니다.
이 글은 개발 실무 안내이며 투자 권유나 수익 보장이 아닙니다.
밴 안 맞는 바이낸스 봇이 필요하다면
호출 예산 관리·백오프·WebSocket 전환까지 포함해 운영에 견디는 구조로 만들어 드립니다. 24시간 빠른 답변 가능합니다.
무료 상담 시작하기