바이낸스 테스트넷 API 발급 — 선물은 Demo Mode
https://testnet.binance.vision/api(GitHub 계정으로 로그인해 키 발급),
선물은 2026-08-30 기준 testnet.binancefuture.com으로 접속하면
demo.binance.com으로 넘어가고 Demo Mode의 REST 주소는
https://demo-api.binance.com/api입니다.
두 환경은 계정도 키도 서로 호환되지 않습니다.
주소와 키를 잘못 짝지으면 인증 실패가 아니라 -2015로 키 자체가 거절됩니다.
바이낸스 API 키 발급 가이드에서 실전 키를 만드는 절차를 다뤘습니다.
이 글은 그 앞 단계, "돈을 걸기 전에 어디서 연습하나"에 해당하는 모의 환경만 떼어 정리한 것입니다.
한국어 자료 대부분이 testnet.binancefuture.com에서 가입하라고 안내하는데,
지금은 그 주소가 그대로 남아 있지 않습니다. 여기서부터 막히는 사람이 많습니다.
모의 환경이 두 개다 — 주소부터 정리
바이낸스 공식 문서 기준으로 현물 테스트넷과 Demo Mode는 별개의 시스템입니다. 이름이 비슷해서 하나로 착각하기 쉬운데, 도메인 계열이 아예 다릅니다.
| 용도 | 현물 테스트넷 | Demo Mode |
|---|---|---|
| REST | https://testnet.binance.vision/api | https://demo-api.binance.com/api |
| WebSocket API | wss://ws-api.testnet.binance.vision | wss://demo-ws-api.binance.com |
| 실시간 스트림 | wss://stream.testnet.binance.vision | wss://demo-stream.binance.com/ws |
| SBE 스트림 | — | wss://demo-stream-sbe.binance.com |
| FIX | — | tcp+tls://demo-fix-oe.binance.com |
| 키 발급 | GitHub 계정으로 로그인 | demo.binance.com의 API 관리 페이지 |
선물 테스트넷 주소가 바뀌었습니다.
2026-08-30에 확인한 결과 testnet.binancefuture.com으로 접속하면
demo.binance.com/en/futures/BTCUSDT로 넘어갑니다.
기존 튜토리얼을 따라 가입 페이지를 찾다가 헤매는 원인이 이것입니다.
주소는 공지 없이 또 바뀔 수 있으니 코드에 하드코딩하지 말고 환경변수로 빼 두십시오.
키 발급 — HMAC 말고 Ed25519
현물 테스트넷은 GitHub 계정으로 로그인해 키를 만듭니다.
바이낸스 실전 계정과 무관하고, 별도 회원가입 절차도 없습니다.
Demo Mode는 바이낸스 계정으로 로그인한 뒤 demo.binance.com의 API 관리 페이지에서 만듭니다.
여기서 대부분의 한국어 자료가 낡았습니다. 지원되는 키 종류는 세 가지인데, 바이낸스 공식 문서는 Ed25519를 권장하고 HMAC은 deprecated 되었다고 명시하고 있습니다.
| 키 종류 | 방식 | 공식 문서 입장 |
|---|---|---|
| Ed25519 | 비대칭 — 개인키는 내가 보관 | 권장 (성능·보안 모두 최선) |
| RSA | 비대칭 | 지원 |
| HMAC | 대칭 — 공유 비밀키 | deprecated, 이전 권고 |
공식 문서는 Ed25519가 3072비트 RSA에 준하는 보안을 제공하면서 키와 서명이 더 작고 서명 계산이 빠르다고 설명합니다. 새로 만드는 봇이라면 처음부터 Ed25519로 가는 편이 낫습니다. 다만 쓰려는 라이브러리가 Ed25519 서명을 지원하는지 먼저 확인해야 합니다. 키 자체를 어떻게 보관할지는 API 키 보안과 계좌 보호에 정리해 두었습니다.
코드에서는 BASE 주소 한 줄만 바뀐다
구조를 제대로 잡아 두면 실전과 모의를 오가는 데 코드 수정이 필요 없습니다. 주소와 키를 한 쌍으로 묶어 환경변수에서 읽는 것이 핵심입니다.
import os, time, hmac, hashlib, requests
from urllib.parse import urlencode
ENV = os.getenv("BINANCE_ENV", "testnet") # testnet | live
CONF = {
"testnet": {
"base": "https://testnet.binance.vision",
"key": os.getenv("TESTNET_KEY"),
"sec": os.getenv("TESTNET_SECRET"),
},
"live": {
"base": "https://api.binance.com",
"key": os.getenv("LIVE_KEY"),
"sec": os.getenv("LIVE_SECRET"),
},
}[ENV]
def signed(path, params, method="GET"):
params["timestamp"] = int(time.time() * 1000)
params["recvWindow"] = 5000
qs = urlencode(params)
sig = hmac.new(CONF["sec"].encode(), qs.encode(), hashlib.sha256).hexdigest()
url = f'{CONF["base"]}{path}?{qs}&signature={sig}'
r = requests.request(method, url,
headers={"X-MBX-APIKEY": CONF["key"]}, timeout=10)
return r
X-MBX-APIKEY 헤더 이름과 signature 파라미터는 실전과 테스트넷이 동일합니다.
바뀌는 것은 base와 키뿐입니다.
ENV를 live로 바꾸는 순간 진짜 돈이 나간다는 사실만 잊지 마십시오.
실전 전환에서 무엇이 달라지는지는
모의투자에서 실전 전환에 국내 증권사 사례로 정리해 두었습니다.
실전 키와 테스트넷 키를 같은 .env 파일에 두지 마십시오.
변수명 한 글자를 잘못 읽어 실전 키가 로드되는 사고가 실제로 일어납니다.
파일을 아예 분리하고, 봇이 시작할 때 어느 환경으로 붙었는지 로그 첫 줄에 찍게 하는 것이
가장 값싼 안전장치입니다.
여기서 나는 에러 네 가지
테스트넷을 붙일 때 나오는 에러는 사실상 정해져 있습니다. 공식 에러 문서의 정의는 다음과 같습니다.
| 코드 | 이름 | 실제 원인 |
|---|---|---|
-2015 | REJECTED_MBX_KEY | 주소와 키가 짝이 안 맞음 · IP 화이트리스트 · 권한 미부여 |
-2014 | BAD_API_KEY_FMT | 키 문자열에 줄바꿈·공백이 섞임 |
-1022 | INVALID_SIGNATURE | 서명 대상 문자열이 실제 전송 쿼리와 다름 |
-1021 | INVALID_TIMESTAMP | 시계 어긋남 · recvWindow 초과 |
-1121 | BAD_SYMBOL | 테스트넷에 없는 심볼 요청 |
실패 응답은 이렇게 옵니다.
{
"code": -2015,
"msg": "Invalid API-key, IP, or permissions for action."
}
-2015가 압도적으로 많습니다. 그리고 원인의 대부분은 권한이 아니라
실전 키를 테스트넷 주소에 보냈거나 그 반대입니다.
메시지에 IP와 permissions가 같이 적혀 있어서 화이트리스트를 뒤지느라 시간을 버리기 쉬운데,
주소와 키의 짝부터 확인하십시오.
-1022는 서명 순서 문제입니다. 서명은 실제로 전송할 쿼리 문자열 그대로에 대해
계산해야 합니다. 서명한 뒤 파라미터를 하나 더 붙이거나 순서를 바꾸면 바로 깨집니다.
-1021은 시계입니다. 공식 문서는 timestamp가 recvWindow 밖이거나
서버 시간보다 1000ms 앞선 경우로 정의합니다. VPS를 새로 띄웠을 때 자주 납니다.
24시간 운영 환경 구성은
VPS 24시간 봇 운영에 정리해 두었습니다.
테스트넷도 호출 제한이 있다
"모의니까 마음껏 때려도 되겠지"가 아닙니다. 테스트넷 문서에도 실전과 같은 제한 구조가 그대로 있습니다.
- 응답 헤더
X-MBX-USED-WEIGHT-(intervalNum)(intervalLetter)에 현재 사용량이 담깁니다. - 주문 응답에는
X-MBX-ORDER-COUNT-헤더가 붙습니다. - 제한은 API 키가 아니라 IP 기준입니다.
- 초과하면
429, 계속 때리면418로 IP가 자동 차단됩니다. - IP 차단은 반복 위반 시 2분에서 3일까지 늘어납니다.
Retry-After헤더에 대기 초가 옵니다.
재시도 루프가 가장 위험합니다. 429를 받고도 즉시 재시도하는 코드는
테스트 단계에서 418을 부르고, 그 IP는 실전 호출에도 그대로 묶입니다.
백오프를 테스트넷 단계에서 이미 넣어 두십시오.
weight 계산과 밴 회피는
바이낸스 API 제한 — weight와 418 IP 밴에 자세히 정리했습니다.
참고로 HTTP 403은 방화벽(WAF) 차단이고, -1007 TIMEOUT은
실행 상태를 알 수 없는 응답입니다. 공식 문서는 이 경우 요청이 실패했다는 뜻이 아니라고 못 박습니다.
타임아웃을 실패로 간주해 같은 주문을 다시 보내면 중복 주문이 됩니다.
반드시 주문 상태를 조회해 확인한 뒤 재전송하십시오.
테스트넷으로 검증되는 것과 안 되는 것
가장 많이 하는 오해는 "테스트넷에서 수익이 났으니 실전에서도 날 것"입니다. 테스트넷은 전략 검증 도구가 아니라 배관 검증 도구입니다.
| 검증된다 | 검증되지 않는다 |
|---|---|
| 서명·인증이 통과하는가 | 실제 체결 가격 (호가가 얇음) |
| 주문 파라미터가 유효한가 | 슬리피지·시장충격 |
| 에러 코드별 분기가 도는가 | 수수료 반영 후 손익 |
| 웹소켓 재접속이 복구되는가 | 유동성 부족 시 미체결 |
| 재시도·백오프가 동작하는가 | 실계좌 잔고·증거금 반응 |
테스트넷은 잔고와 주문 데이터가 주기적으로 초기화될 수 있습니다. 어제까지 쌓인 포지션이 오늘 사라져 있어도 버그가 아닙니다. 그래서 며칠에 걸친 누적 성과를 여기서 측정하는 것은 의미가 없습니다. 백테스트와 실거래가 왜 벌어지는지는 백테스트와 실거래의 괴리에서 다뤘습니다.
실전 전환 전 체크리스트
- BASE 주소와 키가 환경변수 한 쌍으로 묶여 있는가. 코드에 주소가 하드코딩돼 있으면 사고가 납니다.
- 봇 시작 로그에 현재 환경이 찍히는가.
ENV=live를 눈으로 확인할 수 있어야 합니다. 429·418백오프가 실제로 동작하는가. 일부러 한도를 넘겨 확인하십시오.-1007타임아웃에서 재주문 대신 상태 조회를 하는가. 중복 주문 방지의 핵심입니다.- 최소 수량으로 실계좌 1회를 통과했는가. 테스트넷 통과는 실전 통과가 아닙니다.
- 일일 손실 한도와 킬 스위치가 붙어 있는가. 전략보다 먼저 있어야 합니다.
바이낸스 봇을 실제로 붙일 때 자주 밟는 다른 지뢰들은 바이낸스 봇 개발 함정에, 엔드포인트 전반은 바이낸스 API 사용법과 엔드포인트에 정리해 두었습니다.
2026-08-30 기준으로 바이낸스 공식 저장소
binance/binance-spot-api-docs의 testnet/rest-api.md,
testnet/web-socket-api.md, testnet/web-socket-streams.md,
demo-mode/general-info.md, faqs/api_key_types.md, errors.md에 적힌
주소·키 종류·에러 정의와, 같은 날 직접 접속해 확인한 리다이렉트 동작을 기준으로 작성했습니다.
본문의 코드는 구조를 보여주기 위한 예시이며 그대로 실전에 쓰라는 뜻이 아닙니다.
도메인·키 정책·호출 한도는 거래소 공지로 예고 없이 바뀝니다.
운영 전 공식 문서에서 현재 값을 대조하십시오.
이 글은 수익이나 시장 방향을 예측하지 않으며 투자 권유가 아닙니다.
테스트넷 검증까지 포함해 만들어 드립니다
바이낸스 현물·선물 봇을 만들 때 테스트넷 단계에서 인증·재시도·백오프·중복주문 방지를 먼저 통과시키고, 그다음 실전으로 넘깁니다. 24시간 빠른 답변 가능합니다.
무료 상담 시작하기