거래소 API란?
자동매매의 첫 단계는 거래소 API 연동입니다. API(Application Programming Interface)를 통해 프로그램이 직접 주문을 넣고, 잔고를 조회하고, 실시간 시세를 받아올 수 있습니다. 수동으로 차트를 보며 클릭하는 대신, 코드가 24시간 자동으로 매매를 실행합니다.
하지만 API 연동은 단순히 키를 발급받는 것 이상의 보안, 에러 처리, 속도 최적화 문제를 포함합니다. 이 글에서는 실전에서 반드시 알아야 할 핵심 사항을 정리합니다.
API 키 발급과 보안 설정
거래소에서 API 키를 발급받을 때 반드시 지켜야 할 보안 원칙이 있습니다.
권한 최소화 원칙
| 권한 | 자동매매에 필요 여부 | 권장 |
|---|---|---|
| 시세 조회(Read) | ✅ 필수 | 활성화 |
| 주문(Trade) | ✅ 필수 | 활성화 |
| 출금(Withdraw) | ❌ 불필요 | 반드시 비활성화 |
| 내부 이체(Transfer) | ❌ 불필요 | 비활성화 |
출금 권한은 절대 활성화하지 마십시오. API 키가 유출되면 자산 전액이 탈취될 수 있습니다.
IP 화이트리스트
봇 서버의 고정 IP만 허용하도록 설정합니다. 클라우드 서버(AWS, GCP 등)를 사용한다면 Elastic IP를 할당하여 고정 IP를 확보하세요.
# .env 파일 — API 키를 코드에 직접 넣지 마세요
BINANCE_API_KEY=your_api_key_here
BINANCE_SECRET_KEY=your_secret_key_here
# 절대 금지: 코드에 하드코딩
# api_key = "abc123..." ← 이러면 Git에 올라감
CCXT로 멀티 거래소 연동
CCXT는 100개 이상의 거래소를 통일된 인터페이스로 연동할 수 있는 파이썬 라이브러리입니다. 거래소별로 다른 API 규격을 추상화하여, 코드 변경 없이 거래소를 교체할 수 있습니다.
import ccxt
import os
# 거래소 초기화
exchange = ccxt.binance({
'apiKey': os.environ['BINANCE_API_KEY'],
'secret': os.environ['BINANCE_SECRET_KEY'],
'options': {'defaultType': 'future'}, # 선물 거래
'enableRateLimit': True, # Rate Limit 자동 관리
})
# 잔고 조회
balance = exchange.fetch_balance()
usdt = balance['USDT']['free']
print(f"가용 잔고: {usdt:.2f} USDT")
# 시장가 매수
order = exchange.create_market_buy_order('BTC/USDT', 0.001)
print(f"체결가: {order['average']}, 수량: {order['filled']}")
# 지정가 매수
limit_order = exchange.create_limit_buy_order(
'BTC/USDT', 0.001, price=60000
)
print(f"주문 ID: {limit_order['id']}, 상태: {limit_order['status']}")
enableRateLimit: True를 반드시 설정하세요. 이를 빠뜨리면 요청이 너무 빨라 거래소에서 IP를 차단당할 수 있습니다.
Rate Limit 관리
모든 거래소는 API 요청 횟수 제한(Rate Limit)을 두고 있습니다. 이를 초과하면 일시적 또는 영구적으로 차단됩니다.
| 거래소 | 요청 제한 | 주의사항 |
|---|---|---|
| 바이낸스 | 1200 req/min (가중치 기반) | 주문 관련 API는 가중치가 높음 |
| 업비트 | 초당 10회 / 분당 600회 | 주문 API는 초당 8회 |
| 바이비트 | 120 req/5sec | 연속 위반 시 영구 차단 가능 |
WebSocket으로 실시간 데이터 수신
REST API는 요청할 때마다 데이터를 받아오는 폴링 방식입니다. 반면 WebSocket은 연결을 유지하면서 실시간으로 데이터를 받아옵니다.
import asyncio
import ccxt.pro as ccxtpro
async def watch_orderbook():
exchange = ccxtpro.binance({'options': {'defaultType': 'future'}})
try:
while True:
ob = await exchange.watch_order_book('BTC/USDT')
best_bid = ob['bids'][0][0]
best_ask = ob['asks'][0][0]
spread = (best_ask - best_bid) / best_bid * 100
print(f"매수: {best_bid} | 매도: {best_ask} | 스프레드: {spread:.4f}%")
finally:
await exchange.close()
asyncio.run(watch_orderbook())
WebSocket을 사용하면 Rate Limit 소모 없이 실시간 호가, 체결, 캔들 데이터를 받을 수 있습니다. 자동매매 봇에서는 시세 수신은 WebSocket, 주문 실행은 REST API로 분리하는 것이 일반적입니다.
에러 처리와 재시도 패턴
실전 자동매매에서 API 호출은 다양한 이유로 실패합니다. 견고한 에러 처리가 없으면 봇이 멈추거나 잘못된 포지션을 잡게 됩니다.
import time
import ccxt
def safe_order(exchange, symbol, side, amount, max_retries=3):
"""재시도 로직이 포함된 안전한 주문 함수"""
for attempt in range(max_retries):
try:
if side == 'buy':
return exchange.create_market_buy_order(symbol, amount)
else:
return exchange.create_market_sell_order(symbol, amount)
except ccxt.RateLimitExceeded:
wait = 2 ** attempt # 지수 백오프
print(f"Rate Limit 초과, {wait}초 대기...")
time.sleep(wait)
except ccxt.NetworkError as e:
print(f"네트워크 에러: {e}, 재시도 {attempt+1}/{max_retries}")
time.sleep(1)
except ccxt.InsufficientFunds:
print("잔고 부족! 주문 취소")
return None
except ccxt.ExchangeError as e:
print(f"거래소 에러: {e}")
return None
print("최대 재시도 횟수 초과")
return None
핵심 원칙: 일시적 에러(네트워크, Rate Limit)는 재시도하고, 영구적 에러(잔고 부족, 최소 주문량 미달)는 즉시 중단합니다.
실전 API 연동 체크리스트
- ☑️ 출금 권한 비활성화 확인
- ☑️ IP 화이트리스트 설정
- ☑️ API 키 환경변수 저장 (.env 파일)
- ☑️ Rate Limit 자동 관리 활성화
- ☑️ WebSocket 실시간 데이터 수신 구현
- ☑️ 에러별 재시도/중단 로직 구현
- ☑️ 주문 체결 로그 기록 (추후 분석용)
- ☑️ 테스트넷에서 충분한 검증 후 실전 전환
관련 글 더 보기
마무리
거래소 API 연동은 자동매매의 인프라 기반입니다. 보안 설정을 소홀히 하면 자산을 잃고, 에러 처리를 소홀히 하면 봇이 멈춥니다. API 키 보안, Rate Limit 관리, WebSocket 활용, 견고한 에러 처리까지 모두 갖춘 뒤에야 전략 로직에 집중할 수 있습니다.
기반이 튼튼한 봇만이 24시간 시장에서 안정적으로 살아남습니다.