feat: config.yaml 기반 설정 마이그레이션 및 대시보드/종목조회 기능 추가
- config.yaml에서 직접 KIS 설정 관리 (BaseSettings 제거)
- 대시보드 KIS 계좌 잔고 실시간 연동, 로컬 DB 폴백
- 종목 조회 페이지: 시세/호가/일봉차트 (canvas) 구현
- 호가 REST API 엔드포인트 (/api/stocks/{code}/orderbook) 추가
- 토큰 캐시(.auth_cache.json) 저장/복원, 1분 재시도 제한
- KIS WebSocket 자동 연결 + 재연결 로직
- httpx 타임아웃 10초→30초, 라우터 타임아웃 핸들링 (504)
- rate limit: requests_per_second 2.0 (모의투자 초당 2건)
- 사이드바 3메뉴: 실거래 / 과거기록 / 종목조회
This commit is contained in:
@@ -19,7 +19,7 @@ _FID_COND_MRKT_DIV_CODE = "FID_COND_MRKT_DIV_CODE"
|
||||
|
||||
class MarketDataService:
|
||||
def __init__(self) -> None:
|
||||
self._client = httpx.AsyncClient(timeout=10.0)
|
||||
self._client = httpx.AsyncClient(timeout=30.0)
|
||||
self._rate_limiter = RateLimiter(settings.rate_limit.requests_per_second)
|
||||
|
||||
def _check_auth(self) -> bool:
|
||||
|
||||
@@ -30,6 +30,10 @@ class RealtimeService:
|
||||
self._heartbeat_task: asyncio.Task | None = None
|
||||
self._receive_task: asyncio.Task | None = None
|
||||
|
||||
@property
|
||||
def is_connected(self) -> bool:
|
||||
return self._ws is not None and self._running
|
||||
|
||||
def on(self, event: str, callback: Callable) -> None:
|
||||
self._callbacks.setdefault(event, []).append(callback)
|
||||
|
||||
@@ -40,7 +44,7 @@ class RealtimeService:
|
||||
try:
|
||||
self._ws = await websockets.connect(
|
||||
url,
|
||||
extra_headers={"approval_key": approval_key, "type": "Y"},
|
||||
additional_headers={"approval_key": approval_key, "type": "Y"},
|
||||
)
|
||||
self._running = True
|
||||
self._receive_task = asyncio.create_task(self._receive_loop())
|
||||
@@ -106,11 +110,14 @@ class RealtimeService:
|
||||
await self._handle_message(raw_msg)
|
||||
except websockets.ConnectionClosed:
|
||||
logger.warning("WebSocket 연결 끊김. 5초 후 재연결...")
|
||||
if self._running:
|
||||
await asyncio.sleep(5)
|
||||
await self.connect()
|
||||
except Exception as e:
|
||||
logger.error("WebSocket 수신 오류: %s", e)
|
||||
if self._running:
|
||||
await asyncio.sleep(5)
|
||||
try:
|
||||
await self.connect()
|
||||
except Exception:
|
||||
logger.error("WebSocket 재연결 실패")
|
||||
|
||||
async def _handle_message(self, raw_msg: str) -> None:
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user