WebSocket을 통해 주식 체결, 호가, 주문체결 등 실시간 데이터를 수신하는 방법을 안내합니다.
실시간 기능은 asyncio 기반 비동기 API입니다. KiwoomRealtime을 async with로 사용하면 연결과 종료가 자동으로 처리됩니다.
import asyncio
from kiwoompy import KiwoomClient
from kiwoompy.realtime import KiwoomRealtime
from kiwoompy.models import RealtimeEvent
async def main():
client = KiwoomClient(env="demo", appkey="...", secretkey="...")
async with KiwoomRealtime(client.api, env="demo") as rt:
# 구독 등록
await rt.subscribe(
type="0B", # 주식체결
items=["005930", "000660"], # 삼성전자, SK하이닉스
callback=on_trade,
)
await asyncio.sleep(60) # 60초간 수신
asyncio.run(main())
콜백은 async def로 정의하고 RealtimeEvent를 인자로 받습니다.
from kiwoompy.models import RealtimeEvent
async def on_trade(event: RealtimeEvent) -> None:
print(f"TR: {event.type} / 종목: {event.item}")
print(f" 현재가: {event.values.get('10', '')}원")
print(f" 등락률: {event.values.get('12', '')}%")
print(f" 거래량: {event.values.get('15', '')}주")
event.values는 dict[str, str]이며 키는 키움 실시간 필드 번호입니다.
| TR 타입 | 이름 | items |
|---|---|---|
"00" |
주문체결 | [""] (계좌 기반, 종목코드 불필요) |
"04" |
잔고 | [""] (계좌 기반) |
"0A" |
주식기세 | 종목코드 목록 |
"0B" |
주식체결 | 종목코드 목록 |
"0C" |
주식우선호가 | 종목코드 목록 |
"0D" |
주식호가잔량 | 종목코드 목록 |
"0E" |
주식시간외호가 | 종목코드 목록 |
"0H" |
주식예상체결 | 종목코드 목록 |
"0J" |
업종지수 | 업종코드 목록 |
"1h" |
VI발동/해제 | 종목코드 목록 |
0B) 주요 필드| 필드 번호 | 설명 |
|---|---|
"10" |
현재가 |
"11" |
전일대비 |
"12" |
등락률 |
"13" |
누적거래량 |
"14" |
누적거래대금 |
"15" |
체결량 |
"20" |
시가 |
"21" |
고가 |
"22" |
저가 |
"27" |
최우선매도호가 |
"28" |
최우선매수호가 |
00) 주요 필드| 필드 번호 | 설명 |
|---|---|
"9203" |
주문번호 |
"913" |
주문상태 (접수/체결/취소/거부) |
"302" |
종목명 |
"900" |
주문수량 |
"901" |
주문가격 |
"902" |
미체결수량 |
"905" |
주문구분 (매수/매도/정정/취소) |
"910" |
체결가 |
"911" |
체결량 |
async def on_trade(event: RealtimeEvent) -> None:
price = event.values.get("10", "")
print(f"[체결] {event.item}: {price}원")
async def on_orderbook(event: RealtimeEvent) -> None:
ask = event.values.get("27", "")
bid = event.values.get("28", "")
print(f"[호가] {event.item}: 매도 {ask} / 매수 {bid}")
async def on_my_order(event: RealtimeEvent) -> None:
status = event.values.get("913", "")
name = event.values.get("302", "")
print(f"[내 주문] {name}: {status}")
async def main():
client = KiwoomClient(env="demo", appkey="...", secretkey="...")
async with KiwoomRealtime(client.api, env="demo") as rt:
# 주식체결 구독
await rt.subscribe("0B", items=["005930", "000660"], callback=on_trade)
# 호가잔량 구독
await rt.subscribe("0D", items=["005930"], callback=on_orderbook)
# 내 주문체결 구독 (계좌 기반 — items에 빈 문자열)
await rt.subscribe("00", items=[""], callback=on_my_order)
await asyncio.sleep(300) # 5분간 수신
async with KiwoomRealtime(client.api, env="demo") as rt:
await rt.subscribe("0B", items=["005930", "000660"], callback=on_trade)
await asyncio.sleep(30)
# 특정 종목만 해제
await rt.unsubscribe("0B", items=["000660"])
# 해당 TR 전체 해제
await rt.unsubscribe("0B")
await asyncio.sleep(30)
연결이 끊기면 지수 백오프(1초 → 최대 30초)로 자동 재연결하고 기존 구독을 복원합니다. 별도 처리 없이 동작합니다.
재연결을 비활성화하려면:
rt = KiwoomRealtime(client.api, env="demo", reconnect=False)
키움 공식 정책에 따라 최대 100건까지 구독할 수 있습니다. 초과 시 KiwoomApiError가 발생합니다.
from kiwoompy import KiwoomApiError
try:
await rt.subscribe("0B", items=["005930"], callback=on_trade)
except KiwoomApiError as e:
print(f"구독 실패: {e}")