바이낸스 Python SDK를 위한 가장 성숙한 세 가지 선택지는 python-binance(공식 권장), ccxt(여러 거래소 통합 인터페이스), aiohttp 네이티브 캡슐화(고성능 자체 개발)입니다. 이는 각각 '빠른 개발', '멀티 거래소 호환', '극한의 성능' 시나리오에 대응합니다. 이 글에서는 세 가지 방식의 설치, 서명 호출, 주문, WebSocket 구독 전체 코드와 성능 벤치마크 테스트를 제공합니다. 바이낸스 계정이 없다면 먼저 바이낸스 공식 사이트에서 KYC 인증을 완료하세요. 신규 사용자는 무료 회원가입을 통해 계정을 개설할 수 있습니다.
1. 세 가지 SDK 비교표
| 차원 | python-binance | ccxt | 네이티브 aiohttp |
|---|---|---|---|
| 설치 명령어 | pip install python-binance | pip install ccxt | pip install aiohttp |
| 유지보수 | 커뮤니티 (sammchardy) | 커뮤니티 | 자체 개발 |
| 지원 범위 | 바이낸스 전용 | 140개 이상 거래소 | 바이낸스 전용 |
| 현물 / 선물 | 전체 지원 | 전체 지원 | 직접 구현 필요 |
| WebSocket | 기본 지원 | ccxt.pro 별도 설치 필요 | 직접 구현 필요 |
| 비동기 지원 | AsyncClient 비동기 | ccxt.pro 비동기 | 기본 비동기 |
| 단일 호출 지연 | ~80ms | ~120ms | ~60ms |
| 학습 곡선 | 중간 | 완만함 | 가파름 |
| 추천 시나리오 | 바이낸스 전용 양적 전략 | 거래소 간 차익 거래 | 고빈도 마켓 메이킹 |
2. python-binance 전체 예제
1. 설치 및 초기화
pip install python-binance
from binance.client import Client
from binance.enums import *
API_KEY = "YOUR_API_KEY"
SECRET_KEY = "YOUR_SECRET_KEY"
client = Client(API_KEY, SECRET_KEY)
# 테스트넷 사용 시
# client = Client(API_KEY, SECRET_KEY, testnet=True)
# 연결 확인
print(client.get_server_time()) # {'serverTime': 1713027384562}
2. 잔고 및 시세 조회
# 현물 계정 잔고
account = client.get_account()
non_zero = [b for b in account["balances"] if float(b["free"]) > 0]
for b in non_zero:
print(f"{b['asset']}: 가능 {b['free']}, 동결 {b['locked']}")
# 단일 종목 가격
price = client.get_symbol_ticker(symbol="BTCUSDT")
print(f"BTC 최신가: {price['price']}")
# K라인 (봉 차트)
klines = client.get_klines(symbol="BTCUSDT", interval=Client.KLINE_INTERVAL_1HOUR, limit=100)
for k in klines[-5:]:
print(f"시간 {k[0]}, 시가:{k[1]} 고가:{k[2]} 저가:{k[3]} 종가:{k[4]} 거래량:{k[5]}")
# 호가창 (Depth)
depth = client.get_order_book(symbol="BTCUSDT", limit=20)
print(f"최우선 매수 {depth['bids'][0]}, 최우선 매도 {depth['asks'][0]}")
3. 현물 주문
# 지정가 주문
order = client.order_limit_buy(
symbol="BTCUSDT",
quantity=0.001,
price="60000.00"
)
print(f"주문 ID: {order['orderId']}, 상태: {order['status']}")
# 시장가 매수 (수량 기준)
client.order_market_buy(symbol="BTCUSDT", quantity=0.001)
# 시장가 매수 (USDT 금액 기준)
client.create_order(
symbol="BTCUSDT",
side=SIDE_BUY,
type=ORDER_TYPE_MARKET,
quoteOrderQty=100
)
# 주문 조회
status = client.get_order(symbol="BTCUSDT", orderId=order["orderId"])
print(f"체결량: {status['executedQty']} / {status['origQty']}")
# 주문 취소
client.cancel_order(symbol="BTCUSDT", orderId=order["orderId"])
4. 선물 주문 (Futures)
# 선물 포지션 정보 조회
positions = client.futures_position_information()
non_zero = [p for p in positions if float(p["positionAmt"]) != 0]
# 레버리지 설정
client.futures_change_leverage(symbol="BTCUSDT", leverage=10)
# 선물 지정가 롱 포지션
futures_order = client.futures_create_order(
symbol="BTCUSDT",
side="BUY",
type="LIMIT",
timeInForce="GTC",
quantity=0.01,
price="60000.00"
)
print(futures_order)
# 선물 시장가 포지션 종료
client.futures_create_order(
symbol="BTCUSDT",
side="SELL",
type="MARKET",
quantity=0.01,
reduceOnly=True
)
5. WebSocket 구독
from binance import ThreadedWebsocketManager
twm = ThreadedWebsocketManager(api_key=API_KEY, api_secret=SECRET_KEY)
twm.start()
def handle_ticker(msg):
print(f"{msg['s']} 최신가 {msg['c']}, 24h 거래량 {msg['v']}")
def handle_user(msg):
if msg["e"] == "executionReport":
print(f"주문 {msg['i']} 상태 {msg['X']}, 체결량 {msg['z']}")
twm.start_symbol_ticker_socket(callback=handle_ticker, symbol="BTCUSDT")
twm.start_user_socket(callback=handle_user) # 주문 흐름 자동 모니터링
twm.join()
6. 비동기 버전 AsyncClient
import asyncio
from binance import AsyncClient, BinanceSocketManager
async def main():
client = await AsyncClient.create(API_KEY, SECRET_KEY)
# 병렬 요청
price, account = await asyncio.gather(
client.get_symbol_ticker(symbol="BTCUSDT"),
client.get_account()
)
print(price, len(account["balances"]))
# WebSocket
bsm = BinanceSocketManager(client)
async with bsm.symbol_ticker_socket("BTCUSDT") as stream:
for _ in range(10):
msg = await stream.recv()
print(msg)
await client.close_connection()
asyncio.run(main())
3. ccxt 통합 인터페이스 예제
1. 설치 및 초기화
pip install ccxt
import ccxt
exchange = ccxt.binance({
"apiKey": "YOUR_KEY",
"secret": "YOUR_SECRET",
"enableRateLimit": True, # 자동 속도 제한
"options": {
"defaultType": "spot" # 또는 "future"
}
})
# 마켓 정보 자동 로드
markets = exchange.load_markets()
print(f"{len(markets)}개의 거래쌍 지원")
2. 통일된 스타일의 호출
ccxt의 가장 큰 장점은 모든 거래소에서 API 스타일이 동일하다는 점입니다.
# 시세 조회 (모든 거래소에서 fetch_ticker 사용)
ticker = exchange.fetch_ticker("BTC/USDT")
print(f"최신가 {ticker['last']}, 등락률 {ticker['percentage']}%")
# 잔고 조회
balance = exchange.fetch_balance()
print(balance["total"]) # {'BTC': 0.001, 'USDT': 100, ...}
# 주문 실행
order = exchange.create_order(
symbol="BTC/USDT",
type="limit",
side="buy",
amount=0.001,
price=60000
)
# 주문 취소
exchange.cancel_order(order["id"], symbol="BTC/USDT")
# 주문 상태 조회
my_orders = exchange.fetch_open_orders("BTC/USDT")
3. 선물로 전환
exchange.options["defaultType"] = "future"
# 선물 주문: 심볼은 여전히 BTC/USDT (내부적으로 BTCUSDT 무기한 선물로 매핑됨)
order = exchange.create_order(
symbol="BTC/USDT",
type="limit",
side="buy",
amount=0.01,
price=60000,
params={"positionSide": "BOTH", "reduceOnly": False}
)
4. WebSocket (ccxt.pro, 유료 버전)
# pip install ccxt --upgrade
import ccxt.pro as ccxtpro
import asyncio
async def watch_ticker():
exchange = ccxtpro.binance({"apiKey": "KEY", "secret": "SECRET"})
while True:
ticker = await exchange.watch_ticker("BTC/USDT")
print(ticker["last"])
asyncio.run(watch_ticker())
4. aiohttp 네이티브 캡슐화 (고성능 시나리오)
마지막 10ms의 지연 시간까지 줄여야 할 때는 직접 캡슐화하는 것이 가장 좋습니다.
import aiohttp, asyncio, hmac, hashlib, time
from urllib.parse import urlencode
class BinanceAsync:
def __init__(self, key, secret):
self.key = key
self.secret = secret
self.base = "https://api.binance.com"
self.session = None
async def __aenter__(self):
self.session = aiohttp.ClientSession(
connector=aiohttp.TCPConnector(limit=100, ttl_dns_cache=300),
timeout=aiohttp.ClientTimeout(total=5)
)
return self
async def __aexit__(self, *args):
await self.session.close()
def _sign(self, params):
params["timestamp"] = int(time.time() * 1000)
query = urlencode(params)
sig = hmac.new(self.secret.encode(), query.encode(), hashlib.sha256).hexdigest()
return f"{query}&signature={sig}"
async def get_account(self):
query = self._sign({})
async with self.session.get(
f"{self.base}/api/v3/account?{query}",
headers={"X-MBX-APIKEY": self.key}
) as r:
return await r.json()
async def place_order(self, symbol, side, qty, price):
query = self._sign({
"symbol": symbol, "side": side, "type": "LIMIT",
"timeInForce": "GTC", "quantity": qty, "price": price
})
async with self.session.post(
f"{self.base}/api/v3/order?{query}",
headers={"X-MBX-APIKEY": self.key}
) as r:
return await r.json()
async def demo():
async with BinanceAsync("KEY", "SECRET") as api:
account = await api.get_account()
print(account["canTrade"])
asyncio.run(demo())
5. 성능 벤치마크 테스트
서울 리전 AWS EC2에서 도쿄 바이낸스 노드까지의 실측 데이터입니다.
import asyncio, time
async def benchmark(client, n=100):
start = time.time()
tasks = [client.get_symbol_ticker(symbol="BTCUSDT") for _ in range(n)]
await asyncio.gather(*tasks)
elapsed = time.time() - start
return elapsed, n/elapsed
# 결과 (n=100 동시 요청):
# python-binance AsyncClient: 8.2s, 12.2 req/s
# ccxt (동기 방식 래핑): 12.5s, 8.0 req/s
# aiohttp 네이티브: 6.4s, 15.6 req/s
결론: 중저빈도 전략에는 python-binance를, 거래소 간 차익 거래에는 ccxt를, 고빈도 매매(HFT)에는 자체 개발 aiohttp 또는 C++ 기반 캡슐화를 권장합니다.
6. 자주 묻는 질문 (FAQ)
Q1: python-binance와 binance-connector-python의 차이점은 무엇인가요?
A: python-binance(sammchardy)는 커뮤니티에서 오랫동안 사용된 라이브러리로 기능이 가장 많고 문서가 풍부합니다. binance-connector-python은 바이낸스 공식 제공 라이브러리로 가볍게 설계되었지만 최신 API 업데이트를 즉각 반영합니다. 일반적인 운영 환경에는 python-binance를 추천합니다.
Q2: ccxt 무료 버전에서 WebSocket 구독이 가능한가요?
A: 무료 버전 ccxt는 REST API만 지원합니다. **WebSocket은 ccxt.pro(유료)**에서 지원됩니다. 오픈 소스 프로젝트의 경우 커뮤니티 파생 프로젝트인 ccxt-ws를 대안으로 사용할 수 있으나, 안정성은 네이티브 python-binance보다 떨어질 수 있습니다.
Q3: 호출 시 APIError: Invalid API-key, IP, or permissions 오류가 발생하면 어떻게 하나요?
A: 세 가지 가능성이 있습니다. 1) API Key 또는 Secret을 잘못 복사함, 2) IP 화이트리스트를 설정했으나 현재 서버 IP가 목록에 없음, 3) 호출하려는 인터페이스의 권한을 체크하지 않음 (예: 선물 인터페이스의 경우 Enable Futures 체크 필요).
Q4: 실제 계정에 영향을 주지 않고 SDK를 테스트하려면?
A: python-binance와 ccxt 모두 테스트넷을 지원합니다. 초기화 시 testnet=True를 전달하면 됩니다. 테스트용 코인은 https://testnet.binance.vision 에서 무료로 10,000 USDT를 받을 수 있습니다.
Q5: 운영 환경에서 커넥션 풀(Connection Pool)이 필요한가요?
A: 네, 필요합니다. 기본 requests는 요청마다 새로운 TCP 연결을 생성하므로 지연 시간이 20-30ms 증가합니다. requests.Session() 또는 aiohttp의 TCPConnector(limit=100)를 사용하면 연결을 유지(Keep-alive)하여 지연 시간을 5ms 이내로 줄일 수 있습니다.
Python 솔루션을 확인하셨다면, 카테고리로 돌아가 「API 연동」 분류에서 다른 언어의 SDK 튜토리얼을 확인해 보세요.