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:
@@ -58,6 +58,8 @@ from typing import Any, Callable, Dict, Iterable, List, Optional, Set
|
||||
|
||||
logger = logging.getLogger("KiwoomWebSocket")
|
||||
|
||||
from .ws_reconnect_backoff import ws_reconnect_delay_for_attempt
|
||||
|
||||
|
||||
# ── 환경변수 헬퍼 (KIS WS 와 동일 패턴, fallback 포함) ────────────────────
|
||||
try:
|
||||
@@ -130,9 +132,7 @@ class KiwoomWebSocketPriceCache:
|
||||
SUB_TYPE_ORDERBOOK = "0D" # 주식호가잔량
|
||||
SUB_TYPE_PROGRAM = "0w" # 종목프로그램매매
|
||||
|
||||
# 재연결 정책
|
||||
RECONNECT_BASE_DELAY_SEC = 5.0
|
||||
RECONNECT_MAX_DELAY_SEC = 300.0
|
||||
# 재연결 sleep — ws_reconnect_backoff (기본 1,3,5,7,10초)
|
||||
MAX_RECONNECTS_PER_HOUR = 6
|
||||
MAX_RECONNECT_ATTEMPTS = 10
|
||||
STABLE_CONN_RESET_SEC = 300.0 # 5분 안정 연결 후 끊기면 카운터 초기화
|
||||
@@ -194,7 +194,6 @@ class KiwoomWebSocketPriceCache:
|
||||
# 재연결 추적
|
||||
self._reconnect_count = 0
|
||||
self._reconnect_times: list = []
|
||||
self._reconnect_delay = self.RECONNECT_BASE_DELAY_SEC
|
||||
self._last_connect_time: float = 0.0
|
||||
|
||||
# REG 레이트리밋 회피: 단건 subscribe 는 디바운스 후 묶어 전송
|
||||
@@ -683,7 +682,6 @@ class KiwoomWebSocketPriceCache:
|
||||
self._authenticated = True
|
||||
# 안정 LOGIN 성공 → 재연결 카운터 리셋 (주말 Bye 후 소모분 복구)
|
||||
self._reconnect_count = 0
|
||||
self._reconnect_delay = self.RECONNECT_BASE_DELAY_SEC
|
||||
logger.info("✅ 키움 WS LOGIN OK")
|
||||
# 디바운스 타이머 취소 — LOGIN 직후 일괄 REG 와 이중 전송 방지
|
||||
with self._reg_timer_lock:
|
||||
@@ -756,7 +754,7 @@ class KiwoomWebSocketPriceCache:
|
||||
elif sub_type == self.SUB_TYPE_ORDERBOOK and self._orderbook_cache:
|
||||
try:
|
||||
snap = self._orderbook_cache.update_from_kiwoom_0d(code, values)
|
||||
if self._trigger_snapshot_recorder is not None:
|
||||
if snap is not None and self._trigger_snapshot_recorder is not None:
|
||||
tt = str(values.get("20") or values.get(self.FID_TICK_TIME) or "").strip()
|
||||
self._trigger_snapshot_recorder.on_orderbook(snap, snap_time=tt or None)
|
||||
except Exception as ex:
|
||||
@@ -1075,7 +1073,6 @@ class KiwoomWebSocketPriceCache:
|
||||
if (self._last_connect_time > 0
|
||||
and now - self._last_connect_time >= self.STABLE_CONN_RESET_SEC):
|
||||
self._reconnect_count = 0
|
||||
self._reconnect_delay = self.RECONNECT_BASE_DELAY_SEC
|
||||
|
||||
# 시간당 한도 초과 → 1시간 대기
|
||||
cutoff = now - 3600
|
||||
@@ -1105,14 +1102,13 @@ class KiwoomWebSocketPriceCache:
|
||||
self._invalidate_token_cache("max reconnect cooldown")
|
||||
time.sleep(cool)
|
||||
self._reconnect_count = 0
|
||||
self._reconnect_delay = self.RECONNECT_BASE_DELAY_SEC
|
||||
self._reconnect_times.clear()
|
||||
return
|
||||
|
||||
delay = min(self._reconnect_delay, self.RECONNECT_MAX_DELAY_SEC)
|
||||
attempt = self._reconnect_count + 1
|
||||
delay = ws_reconnect_delay_for_attempt(attempt)
|
||||
logger.info("⏳ 키움 WS %ds 후 재연결 시도 (#%d)",
|
||||
int(delay), self._reconnect_count + 1)
|
||||
int(delay), attempt)
|
||||
time.sleep(delay)
|
||||
self._reconnect_times.append(time.time())
|
||||
self._reconnect_count += 1
|
||||
self._reconnect_delay = min(self._reconnect_delay * 2, self.RECONNECT_MAX_DELAY_SEC)
|
||||
|
||||
Reference in New Issue
Block a user