diff --git a/agents/stock/workspace/scripts/behive_web.py b/agents/stock/workspace/scripts/behive_web.py index d405b27..83988af 100644 --- a/agents/stock/workspace/scripts/behive_web.py +++ b/agents/stock/workspace/scripts/behive_web.py @@ -672,9 +672,13 @@ def _fetch_quotes_batch(entries: list[dict]) -> list[dict]: if not miss_codes: return cards + nxt_probe_codes = list(miss_codes) + nxt_probe_indices = list(miss_indices) + # WS 허브 연결 시 — 미스 종목 시세를 허브 메모리(0B 실시간, KRX+NXT 통합)에서 우선 충당. - # 서버가 동일 렌더러로 OHLC·마크를 그대로 그린다 (마크는 허브 exchange 필드로 판정). - # 허브에 없는(아직 미체결) 종목만 ka10095 폴백으로 남긴다. 캐시엔 안 넣음 — 매 페치 라이브 허브 사용. + # 서버가 동일 렌더러로 OHLC를 그린다. 단, NXT 거래가능 초록점은 허브 exchange가 아니라 + # 아래 ka10095 NX 단독 응답 가능 여부로만 판정한다. + # 허브에 없는(아직 미체결) 종목만 ka10095 AL 폴백으로 남긴다. 캐시엔 안 넣음 — 매 페치 라이브 허브 사용. hub = _RT_HUB if hub is not None and hub.is_connected(): hub_q = hub.get_quotes(miss_codes) @@ -694,30 +698,32 @@ def _fetch_quotes_batch(entries: list[dict]) -> list[dict]: out['open'] = q.get('open') or None out['high'] = q.get('high') or None out['low'] = q.get('low') or None - is_nxt = (q.get('exchange') or '').upper() == 'NXT' - out['_krx_price'] = 0 if is_nxt else price - out['_nxt_price'] = price if is_nxt else 0 + out['_krx_price'] = price + out['_nxt_price'] = 0 miss_codes, miss_indices = rest_codes, rest_indices - if not miss_codes: - return cards - try: - batch = kc.get_watchlist_quotes(miss_codes) - except Exception as ex: - sys.stderr.write(f'ka10095 batch 실패, ka10001 fallback: {ex}\n') - for idx in miss_indices: - cards[idx] = _fetch_quote(entries[idx]) - return cards + batch: dict[str, dict] = {} + if miss_codes: + try: + batch = kc.get_watchlist_quotes(miss_codes) + except Exception as ex: + sys.stderr.write(f'ka10095 batch 실패, ka10001 fallback: {ex}\n') + for idx in miss_indices: + cards[idx] = _fetch_quote(entries[idx]) # NXT 비교용 batch — 마크(KRX/NXT) 판정에 사용. 실패해도 fallback X (마크만 KRX로 처리). # get_watchlist_quotes는 NXT 단독 suffix를 'NX'로 받는다. 'NXT'는 suffix 없이 KRX/기본값으로 # 떨어져 NXT 미거래 종목도 거래 가능처럼 보이므로 쓰면 안 된다. nxt_batch: dict[str, dict] = {} try: - nxt_batch = kc.get_watchlist_quotes(miss_codes, exchange='NX') + nxt_batch = kc.get_watchlist_quotes(nxt_probe_codes, exchange='NX') except Exception as ex: sys.stderr.write(f'ka10095 NXT batch 실패 (마크 판정용): {ex}\n') + for idx, code in zip(nxt_probe_indices, nxt_probe_codes): + nxt_q = nxt_batch.get(code) if nxt_batch else None + cards[idx]['_nxt_price'] = (nxt_q or {}).get('price', 0) if nxt_q else 0 + for idx, code in zip(miss_indices, miss_codes): q = batch.get(code) out = cards[idx] @@ -735,8 +741,7 @@ def _fetch_quotes_batch(entries: list[dict]) -> list[dict]: else: out['quote_error'] = '가격 0' # 마크 판정: NXT batch 가격 vs 기본 batch 가격 비교. - nxt_q = nxt_batch.get(code) if nxt_batch else None - nxt_price = (nxt_q or {}).get('price', 0) if nxt_q else 0 + nxt_price = out.get('_nxt_price', 0) or 0 out['_krx_price'] = price out['_nxt_price'] = nxt_price snap = { @@ -6158,7 +6163,7 @@ def _render_watchlist_panel(cards: list[dict]) -> tuple[str, int]: sections.append(f'
보유중{len(held)}
') sections.append('\n'.join(_render_row(c) for c in held)) if watching: - sections.append(f'
매수전{len(watching)}
') + sections.append(f'
감시{len(watching)}
') sections.append('\n'.join(_render_row(c) for c in watching)) if trash: sections.append(f'
삭제예정{len(trash)}
')