backend:
- fetch/kis.py: fetch_orderbook(code) — KIS FHKST01010200 (inquire-asking-price-exp-ccn)
호출. output1 의 askp1~10/bidp1~10 + 잔량 + 합계, output2 의 현재가/전일대비 파싱.
- api/orderbook.py: GET /api/orderbook/{code}. symbols 매칭 안 되면 404, KIS 키 없으면
skipped_missing_key 상태로 빈 호가 반환 (502 와 구분).
- main.py: orderbook_router 등록.
frontend:
- lib/api.ts: OrderbookResponse 타입 + api.orderbook(code).
- components/OrderbookPanel.tsx: 매도 10단계(위→아래 가격 내림차순) / 현재가(굵게, 전일대비)
/ 매수 10단계. 잔량 막대는 사이드별 max 정규화로 셀 안에서 자라남. ask=파랑, bid=빨강
(한국 거래소 관행). 10초 폴링.
- app/[code]/page.tsx: 사이드바에 SymbolSidebar 다음으로 OrderbookPanel 마운트.
실시간 ws 가 아니라 HTTP 폴링이라 KIS rate-limit 친화적. 표시 전용 — 주문/체결 endpoint 는
일절 import 하지 않음 (kis.py 문서 정책).
61 lines
1.8 KiB
Python
61 lines
1.8 KiB
Python
"""호가(orderbook) API — KIS 10단계 호가 스냅샷.
|
|
|
|
장중에 호출하면 호가 + 잔량 + 현재가가 한 번의 KIS 호출로 따라온다. 실시간 ws 가
|
|
아니라 폴링 친화 (프론트가 5~10s 주기로 재호출) 설계 — 표시 전용.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from fastapi import APIRouter, HTTPException
|
|
from sqlalchemy import text
|
|
|
|
from app.db.connection import get_engine
|
|
from app.fetch.kis import SkippedMissingKey, fetch_orderbook
|
|
|
|
router = APIRouter(prefix="/api/orderbook", tags=["orderbook"])
|
|
|
|
|
|
@router.get("/{code}")
|
|
def get_orderbook(code: str) -> dict:
|
|
"""code 의 10단계 호가 스냅샷.
|
|
|
|
- symbols 에 없는 코드는 404.
|
|
- KIS 키 미설정이면 status="skipped_missing_key" + 빈 호가 (프론트에서 안내).
|
|
- KIS 호출 실패는 502.
|
|
"""
|
|
eng = get_engine()
|
|
with eng.connect() as conn:
|
|
sym = conn.execute(
|
|
text("SELECT code, name, market FROM symbols WHERE code = :c"),
|
|
{"c": code},
|
|
).first()
|
|
if not sym:
|
|
raise HTTPException(status_code=404, detail=f"unknown code: {code}")
|
|
|
|
try:
|
|
snap = fetch_orderbook(code)
|
|
except SkippedMissingKey:
|
|
return {
|
|
"code": sym[0],
|
|
"name": sym[1],
|
|
"market": sym[2],
|
|
"status": "skipped_missing_key",
|
|
"ts": None,
|
|
"current": None,
|
|
"prev_close_diff": None,
|
|
"prev_close_pct": None,
|
|
"asks": [],
|
|
"bids": [],
|
|
"ask_total": 0,
|
|
"bid_total": 0,
|
|
}
|
|
except Exception as exc: # noqa: BLE001
|
|
raise HTTPException(status_code=502, detail=f"kis orderbook failed: {exc}") from exc
|
|
|
|
return {
|
|
"code": sym[0],
|
|
"name": sym[1],
|
|
"market": sym[2],
|
|
"status": "ok",
|
|
**snap,
|
|
}
|