fix(ws): KIS/키움 WS·조건검색 안정화 및 매도시세 폴백
WS 매니저 spill·조건검색 CNSR 회복·kiwoom_ws_diag 진단 경로를 보강한다. live_sell_price stale RAM/REST 폴백 정합을 유지한다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
85
kis_trader/ws/kiwoom_ws_diag.py
Normal file
85
kis_trader/ws/kiwoom_ws_diag.py
Normal file
@@ -0,0 +1,85 @@
|
||||
"""키움 WS 진단 로그 — return_code/return_msg·스레드·trnm 추적."""
|
||||
from __future__ import annotations
|
||||
|
||||
import threading
|
||||
from typing import Any, Mapping, Optional
|
||||
|
||||
from kis_trader.utils.env import get_env_bool
|
||||
|
||||
|
||||
def kiwoom_ws_diag_enabled() -> bool:
|
||||
try:
|
||||
return bool(get_env_bool("KIWOOM_WS_DIAG_ENABLED", True))
|
||||
except Exception:
|
||||
return True
|
||||
|
||||
|
||||
def _thread_tag() -> str:
|
||||
t = threading.current_thread()
|
||||
return f"{t.name}#{getattr(t, 'ident', 0) or 0}"
|
||||
|
||||
|
||||
def format_kiwoom_return(msg: Mapping[str, Any]) -> str:
|
||||
rc = msg.get("return_code")
|
||||
rm = msg.get("return_msg")
|
||||
if rc is None and rm in (None, ""):
|
||||
return ""
|
||||
return f"rc={rc} msg={rm}"
|
||||
|
||||
|
||||
def log_kiwoom_ws(
|
||||
logger: Any,
|
||||
event: str,
|
||||
*,
|
||||
level: str = "info",
|
||||
rc: Any = None,
|
||||
msg: Any = None,
|
||||
trnm: Optional[str] = None,
|
||||
extra: Optional[str] = None,
|
||||
force: bool = False,
|
||||
) -> None:
|
||||
"""KIWOOM_WS_DIAG_ENABLED 또는 force=True 일 때 INFO/WARNING 로그."""
|
||||
if not force and not kiwoom_ws_diag_enabled():
|
||||
return
|
||||
parts = [f"🔎 [키움WS/{event}]", f"thr={_thread_tag()}"]
|
||||
if trnm:
|
||||
parts.append(f"trnm={trnm}")
|
||||
if rc is not None or (msg not in (None, "")):
|
||||
parts.append(f"rc={rc} msg={msg}")
|
||||
if extra:
|
||||
parts.append(str(extra))
|
||||
line = " ".join(parts)
|
||||
try:
|
||||
getattr(logger, level, logger.info)(line)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def log_kiwoom_api_msg(
|
||||
logger: Any,
|
||||
trnm: str,
|
||||
data: Mapping[str, Any],
|
||||
*,
|
||||
level: str = "warning",
|
||||
prefix: str = "",
|
||||
) -> None:
|
||||
"""수신 JSON에 return_code 가 있고 0이 아니면 항상 로그 (진단 OFF여도)."""
|
||||
rc_raw = data.get("return_code")
|
||||
if rc_raw is None:
|
||||
return
|
||||
rc = str(rc_raw).strip()
|
||||
if rc in ("0", "0.0", ""):
|
||||
return
|
||||
rm = str(data.get("return_msg") or "").strip()
|
||||
seq = data.get("seq") or data.get("data")
|
||||
extra = f"seq={seq}" if seq not in (None, "", []) else ""
|
||||
head = f"{prefix} " if prefix else ""
|
||||
line = f"{head}키움 {trnm} rc={rc} msg={rm}"
|
||||
if extra:
|
||||
line = f"{line} {extra}"
|
||||
if kiwoom_ws_diag_enabled():
|
||||
line = f"🔎 {line} thr={_thread_tag()}"
|
||||
try:
|
||||
getattr(logger, level, logger.warning)(line)
|
||||
except Exception:
|
||||
pass
|
||||
Reference in New Issue
Block a user