바이낸스 자동매매 봇 만들 때 놓치기 쉬운 5가지
바이낸스 자동매매 봇은 REST + WebSocket 조합이라 문서만 보면 깔끔해 보이지만, 3년간 알고랩에서 80건+ 제작하며 나온 장애 로그를 분석해보면 전체 장애의 약 80%가 이 5가지 함정에서 발생합니다. 처음 봇 만드시는 분은 이 5개만 피해도 절반은 간 거예요.
함정 1. 서버시간 동기화 실패 → -1021 Timestamp
바이낸스 API 는 모든 요청에 timestamp 를 서명 페이로드로 넣어야 합니다.
그런데 클라이언트 시계가 바이낸스 서버 시계보다 ±1초 이상 벗어나면 요청 거부 (code: -1021 "Timestamp for this request is outside of the recvWindow").
Windows PC 는 NTP 동기화가 기본 꺼져 있거나 간격이 너무 길어서 이 문제를 자주 만납니다. 특히 VPS 환경에서 자주 발생.
해결: 요청 전 바이낸스 서버시간을 받아서 로컬과의 차이(offset)를 계산하고, 모든 요청 timestamp 를 이 offset 으로 보정.
import time, requests
# 1. 서버시간 받기
server_time = requests.get("https://fapi.binance.com/fapi/v1/time").json()["serverTime"]
local_time = int(time.time() * 1000)
TIME_OFFSET = server_time - local_time # 보정값
# 2. 주문 시
timestamp = int(time.time() * 1000) + TIME_OFFSET
# → 이 timestamp 를 서명에 사용
추가로 NTP 서비스도 반드시 켜두세요. Windows 기본 NTP 는 time.windows.com, 한국은 kr.pool.ntp.org 권장.
함정 2. IP 화이트리스트 없이 키 발급 → 탈취 리스크
바이낸스 API 키는 생성 시 "Restrict access to trusted IPs only" 옵션이 있습니다. 이걸 끄면 어디서든 그 키로 주문 가능. 키가 유출되면 자금 도난 직결.
반드시 아래 3가지 원칙을 지키세요.
- IP 화이트리스트 ON — 실제 봇 돌리는 서버 IP만 허용
- Withdraw 권한 OFF — 자동매매에 출금 권한 불필요
- 키를 절대 코드 저장소에 커밋 금지 — 환경변수·시크릿 매니저 사용
실제 사례: 과거 알고랩 고객 중 한 분이 GitHub 에 API 키를 잘못 커밋했다가 10분 만에 자동 스캔 봇에 털려 포지션이 반대로 털린 사례가 있습니다. 다행히 Withdraw 권한은 꺼져 있어 출금은 막혔지만, 강제 청산으로 손실이 났습니다.
함정 3. WebSocket 재연결 로직 누락 → 장 시간 데이터 끊김
바이낸스 WebSocket 연결은 24시간마다 자동 끊김. 또한 네트워크 순간 단절도 흔합니다. 재연결 로직이 없으면 봇은 "수신 중" 인 줄 알고 매매 안 함 → 기회 놓침 또는 청산 신호 놓쳐서 손실 커짐.
해결: 지수 백오프 재연결 + ping/pong heartbeat.
async def websocket_loop():
backoff = 1
while True:
try:
async with websockets.connect(WS_URL) as ws:
backoff = 1 # 성공하면 reset
# ping 3분마다 (바이낸스 권장)
async for msg in ws:
handle_message(msg)
except Exception as e:
logger.warning(f"WS disconnected: {e}, retry in {backoff}s")
await asyncio.sleep(backoff)
backoff = min(backoff * 2, 60) # 최대 1분
함정 4. 레버리지 기본값 혼동 — 선물 주문 시 의도치 않은 청산
바이낸스 선물은 심볼당 레버리지 설정이 개별 저장됩니다. 코드에서 명시하지 않으면 계정이 기억하는 마지막 설정값이 그대로 적용됩니다. 봇 개발 중 10배로 테스트해뒀다가, 실계좌에 배포하고 "왜 이렇게 청산이 자주 나지" 헤매는 경우가 흔합니다.
해결: 주문 전 반드시 레버리지 명시적으로 설정.
client.futures_change_leverage(symbol="BTCUSDT", leverage=3) # 3배로 고정
# → 이 후 주문부터 3배 적용
마진 모드(Isolated vs Cross) 도 동일하게 명시적으로 설정하세요: futures_change_margin_type(symbol, marginType="ISOLATED").
함정 5. listenKey 만료 → 체결 이벤트 수신 중단
User Data Stream (개인 체결·잔고·주문 실시간 이벤트) 는 listenKey 로 인증합니다.
이 키는 60분 후 자동 만료. 명시적 PUT /listenKey 요청으로 갱신 안 하면 만료 후 체결 이벤트가 안 옵니다.
증상: 봇이 "주문은 접수됐는데 체결 감지 못해서 중복 주문 넣음" 같은 이상 동작. 거래대금 많을 때 치명적.
해결: 30분마다 자동 갱신 스케줄러.
import asyncio
async def keepalive_listenkey():
while True:
await asyncio.sleep(30 * 60) # 30분
try:
client.futures_stream_keepalive(listen_key)
logger.info("listenKey 갱신")
except Exception as e:
logger.error(f"listenKey 갱신 실패: {e} — WS 재연결 필요")
정리
이 5가지를 예방적으로 넣는 것만으로 프로덕션 장애의 80%가 사라집니다. 초기 개발 시간은 +2~3시간 정도 들지만, 나중에 장애 대응하는 시간·돈(놓친 기회비용)에 비하면 훨씬 쌉니다.
알고랩에서 제작하는 모든 바이낸스 봇은 이 5가지가 기본 포함됩니다.