Upbit 암호화폐 거래소를 위한 비공식 Python 클라이언트 라이브러리.
Looking for English documentation? See README.en.md.
Warning
이 라이브러리는 투자 수익을 보장하지 않습니다. 버그, API 변경, 네트워크 장애 등 어떤 원인으로든 발생하는 투자 손실에 대해 일체의 책임을 지지 않습니다. 투자 판단과 결과는 전적으로 사용자 본인에게 있습니다.
손으로 직접 고점에 매수하고 저점에 매도하느라 지치셨나요? 이제 코드로 손실을 자동화하세요!
from upbeat import AsyncUpbeat
async with AsyncUpbeat(access_key="...", secret_key="...") as client:
# 실시간 시세를 감시하다가...
async for tick in client.ws.ticker(["KRW-BTC"]):
change = tick.signed_change_rate # 전일 대비 변동률
if change > 0.05:
# 5% 올랐다! 더 오를 것 같으니 추격 매수 (일명 FOMO)
await client.orders.create(
market="KRW-BTC", side="bid",
ord_type="price", price="100000",
)
elif change < -0.03:
# 3% 빠졌다! 패닉셀!
btc = await client.shortcuts.get_account("BTC")
await client.orders.create(
market="KRW-BTC", side="ask",
ord_type="market", volume=btc.balance,
)
# 이 전략의 기대수익률: -∞(농담입니다. 제발 이렇게 쓰지 마세요.)
- AI 친화적 — OpenAPI 3.1 + AsyncAPI 3.0 스펙이 내장되어 있어서 LLM이나 AI 에이전트가 API 구조를 바로 파악하고 코드를 생성할 수 있습니다.
- Upbit API 전체 커버리지 — 시세 조회 12개, 거래 31개, WebSocket 6개 채널. 업비트가 제공하는 API를 빠짐없이 지원합니다.
- 타입 안전성 — 모든 요청과 응답이 Pydantic v2 모델로 정의되어 있어서 IDE 자동완성이 잘 됩니다. 잘못된 파라미터는 실행 전에 잡힙니다.
Note
이 프로젝트는 Agentic 코딩으로 개발되었습니다. AI 코딩 에이전트(Claude Code)와 함께 설계, 구현, 테스트를 진행했습니다. 프로젝트 루트의 CLAUDE.md와 AGENTS.md에 코드 스타일, 아키텍처, 명령어 등 프로젝트 컨텍스트가 정리되어 있어 AI 에이전트가 바로 기여를 시작할 수 있습니다.
- Sync + Async 동시 지원 (
Upbeat/AsyncUpbeat) - REST API 전체 커버리지 (시세 + 거래)
- WebSocket 실시간 데이터 스트리밍
- Pydantic v2 기반 타입 안전한 모델
- 매수 주문 최소금액 클라이언트 사전 검증 (
validate_min_order) - 지수 백오프 자동 재시도
Remaining-Req헤더 기반 스마트 Rate Limit 관리- JWT 인증 (HS512)
- 컨텍스트 매니저를 통한 리소스 정리
- HTTP 클라이언트, 로깅, 타임아웃 커스터마이징
pip install upbeatpandas 지원 포함:
pip install upbeat[pandas]Tip
시세 조회 등 공개 API는 인증 없이 사용할 수 있지만, 주문·계좌·입출금 등 거래 API를 이용하려면 Upbit에서 발급받은 API 키가 필요합니다.
Upbit Open API 관리 페이지에서 access_key와 secret_key를 발급받으세요.
import upbeat
# 모듈 레벨 편의 함수
ticker = upbeat.get_ticker("KRW-BTC")
candles = upbeat.get_candles("KRW-BTC", interval="1m", count=200)
orderbook = upbeat.get_orderbook("KRW-BTC")
markets = upbeat.get_markets()from upbeat import Upbeat
with Upbeat(access_key="...", secret_key="...") as client:
# 시세 조회 (공개)
tickers = client.quotation.get_tickers("KRW-BTC")
# 거래 (인증 필요)
accounts = client.accounts.list()
order = client.orders.create(
market="KRW-BTC",
side="bid",
ord_type="limit",
volume="0.001",
price="50000000",
)from upbeat import AsyncUpbeat
async with AsyncUpbeat(access_key="...", secret_key="...") as client:
tickers = await client.quotation.get_tickers("KRW-BTC")
accounts = await client.accounts.list()from upbeat import AsyncUpbeat
async with AsyncUpbeat(access_key="...", secret_key="...") as client:
async for msg in client.ws.ticker(["KRW-BTC", "KRW-ETH"]):
print(msg.trade_price)from upbeat import Upbeat, Timeout
client = Upbeat(
access_key="...",
secret_key="...",
timeout=Timeout(connect=10.0, read=30.0),
max_retries=3,
logger=my_custom_logger, # Logger Protocol 구현체
validate_min_order=True, # 매수 주문 최소금액 사전 검증
)
# 퍼-리퀘스트 오버라이드
cautious_client = client.with_options(max_retries=5)import httpx
from upbeat import Upbeat
client = Upbeat(
access_key="...",
secret_key="...",
http_client=httpx.Client(proxy="http://proxy:8080"),
)from upbeat import (
Upbeat,
RateLimitError,
InsufficientFundsError,
NotFoundError,
ValidationError,
)
client = Upbeat(access_key="...", secret_key="...", validate_min_order=True)
try:
order = client.orders.create(
market="KRW-BTC",
side="bid",
ord_type="limit",
volume="0.001",
price="50000000",
)
except ValidationError as e:
print(f"주문금액 미달: {e.total} < 최소 {e.min_total} ({e.market})")
except InsufficientFundsError as e:
print(f"잔고 부족: {e.error_message}")
except RateLimitError as e:
print(f"요청 초과. 잔여 횟수: {e.remaining_request}")
except NotFoundError as e:
print(f"리소스 없음: {e.error_message}")UpbeatError
ValidationError
APIError
APIStatusError
BadRequestError (400)
AuthenticationError (401)
PermissionDeniedError (403)
NotFoundError (404)
UnprocessableEntityError (422)
RateLimitError (418, 429)
InternalServerError (5xx)
InsufficientFundsError (400)
MinimumOrderError (400)
APIConnectionError
APITimeoutError
WebSocketError
WebSocketConnectionError
WebSocketClosedError
사용 가능한 리소스 그룹:
| 리소스 | 설명 | 인증 |
|---|---|---|
client.quotation |
시세 데이터 (현재가, 캔들, 호가, 체결) | 불필요 |
client.markets |
페어(거래쌍) 정보 | 불필요 |
client.accounts |
계정 잔고 | 필요 |
client.orders |
주문 관리 | 필요 |
client.deposits |
입금 관련 | 필요 |
client.withdrawals |
출금 관련 | 필요 |
client.ws |
WebSocket 실시간 스트리밍 | 채널별 상이 |
client.shortcuts |
편의 헬퍼 (계좌 조회, 포트폴리오, 시장가 매수 등) | 필요 |
client.strategies |
매매 전략 (DCA, 리밸런싱, 가격 알림) | 필요 |
엔드포인트 상세 문서는 OpenAPI 스펙을 참고하세요:
- 시세 API (Quotation) -- 12개 엔드포인트 (공개, 인증 불필요)
- 거래 API (Exchange) -- 31개 엔드포인트 (JWT 인증 필요)
- WebSocket 채널 -- 6개 채널 (ticker, trade, orderbook, candle, myOrder, myAsset)
기여는 언제나 환영합니다! PR을 올리기 전에 아래 과정을 따라주세요.
# 1. 포크 후 클론
git clone https://github.com/<your-username>/upbeat.git
cd upbeat
# 2. 의존성 설치
uv sync --group dev
# 3. 브랜치 생성
git checkout -b feat/my-feature
# 4. 코드 작성 후, PR 전에 아래를 모두 통과시켜 주세요
uv run ruff check src/ # 린트
uv run ruff format src/ # 포맷
uv run mypy src/upbeat/ # 타입 체크
uv run pytest # 테스트PR을 올릴 때:
- 브랜치 이름은
feat/,fix/,chore/등 접두사를 사용해 주세요. - 커밋 메시지는 변경의 "왜"를 간결하게 담아주세요.
- 새로운 기능에는 테스트를 함께 추가해 주세요.
- 린트, 포맷, 타입 체크, 테스트가 모두 통과하는지 확인해 주세요.