fix(시세): LS spill-only·토큰 파일캐시·호가 snap_time 3초컷

- _feed_fallback 미러 OFF, LS cap/grace/hold RAM을 KIS·키움 spill과 정합
- LS 접근토큰 .ls_token_cache_*.json (재시작 재사용, revoke 루프 없음)
- 호가 RAM을 틱과 동일 LIVE_FEED_FALLBACK(snap_time)로 컷, 필터 max_age=0은 유지
- 익절 지정가 로그에 실제 호가 벤더(kis/kiwoom/ls 1·2·3차) 표기

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Your Name
2026-08-27 15:21:21 +09:00
parent ba2f9f0953
commit 5e44b86f8b
24 changed files with 1923 additions and 203 deletions

View File

@@ -7,7 +7,7 @@ kis_trader.execution.orderbook_sell — 익절(수익) 매도 시 호가 잔량
from __future__ import annotations
import logging
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, Callable, Dict, List, Optional, Tuple
from ..utils.env import get_env_bool, get_env_float, get_env_int
@@ -70,14 +70,30 @@ def resolve_orderbook_raw(
code: str,
*,
ws_get=None,
ob_feed_label: Optional[Callable[[str], str]] = None,
rest_client=None,
max_age_sec: float = 3.0,
) -> Tuple[Optional[Dict[str, Any]], str]:
"""
호가 조회 — 키움 WS 캐시 우선, 없으면 KIS REST.
Returns: (raw_dict, source_tag) source_tag: kiwoom_ws | kis_rest | none
호가 조회 — WSManager.get_orderbook(1·2·3차 체인) 우선, 없으면 KIS REST.
Returns: (raw_dict, source_tag)
- WS 성공: ``ob_feed_label(code)`` — 예 ``kis(1차)``, ``ls(3차,spill)``
- REST: ``kis_rest``
- 실패: ``none``
"""
c = str(code or "").strip()
def _ws_source_tag() -> str:
if ob_feed_label is not None:
try:
lab = (ob_feed_label(c) or "").strip()
if lab:
return lab
except Exception:
pass
return "ws"
if ws_get and c:
try:
raw = ws_get(c, max_age_sec=max_age_sec)
@@ -89,7 +105,7 @@ def resolve_orderbook_raw(
except Exception:
raw = None
if raw:
return raw, "kiwoom_ws"
return raw, _ws_source_tag()
if rest_client and c:
try:
raw = rest_client.get_orderbook(c)