auto: 일일 백업 2026-06-11 02:00

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hyowons
2026-06-11 02:00:01 +09:00
parent af058cf36d
commit 81e8847a8e
14 changed files with 1064 additions and 342 deletions
+34 -7
View File
@@ -88,14 +88,19 @@ def _flow_cache_path(code: str):
def investor_flow(code: str, days: int = config.FLOW_DAYS) -> list[dict]:
"""최근 days 일 외국인·기관·개인 순매수 (최신순). 60분 TTL 캐시."""
"""최근 days 일 외국인·기관·개인 순매수 (최신순). 60분 TTL 캐시 + 스캔 내 메모."""
mk = (code, days)
if mk in _FLOW_MEMO_SCAN:
return _FLOW_MEMO_SCAN[mk]
path = _flow_cache_path(code)
now = time.time()
if path.exists():
try:
cached = json.loads(path.read_text())
if now - cached.get('ts', 0) < FLOW_TTL_SEC:
return cached.get('rows', [])[:days]
rows = cached.get('rows', [])[:days]
_FLOW_MEMO_SCAN[mk] = rows
return rows
except Exception:
pass
try:
@@ -105,6 +110,7 @@ def investor_flow(code: str, days: int = config.FLOW_DAYS) -> list[dict]:
return []
FLOW_CACHE_DIR.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps({'ts': now, 'rows': rows}, ensure_ascii=False))
_FLOW_MEMO_SCAN[mk] = rows[:days]
return rows[:days]
@@ -116,11 +122,15 @@ def flow_net(rows: list[dict]) -> dict:
def analyst(code: str, price: int) -> dict | None:
"""애널 게이트/가점용. 캐시 미스(네트워크 발생) 시에만 페이싱 — 연속 크롤링 차단 회피."""
"""애널 게이트/가점용. 캐시 미스(네트워크 발생) 시에만 페이싱 + 스캔 내 메모."""
if code in _ANL_MEMO_SCAN:
return _ANL_MEMO_SCAN[code]
fresh = (_cache_fresh(FNGUIDE_CACHE_DIR / f'{code}.json')
and _cache_fresh(WISEREPORT_CACHE_DIR / f'{code}.json'))
try:
return _analyst_query(code, price)
out = _analyst_query(code, price)
_ANL_MEMO_SCAN[code] = out
return out
finally:
if not fresh:
time.sleep(ANALYST_PACING_SEC)
@@ -168,10 +178,27 @@ def _analyst_query(code: str, price: int) -> dict | None:
}
# 스캔 1회 동안 호가 공유 — 같은 스캔에서 같은 종목은 같은 체결가 (선수 간 체결 공정성 + API 절감).
# engine._gather 가 스캔 시작마다 reset.
_BOOK_MEMO: dict = {}
_FLOW_MEMO_SCAN: dict = {} # 스캔 1회 동안 종목별 수급 공유 (파라미터 무관)
_ANL_MEMO_SCAN: dict = {} # 스캔 1회 동안 종목별 애널 공유 (파라미터 무관)
def reset_book_memo():
_BOOK_MEMO.clear()
_FLOW_MEMO_SCAN.clear()
_ANL_MEMO_SCAN.clear()
def quote_book(code: str) -> dict | None:
"""체결가용 호가 (매도1/매수1). 실패 시 None."""
"""체결가용 호가 (매도1/매수1). 스캔 내 종목당 1회 조회 후 공유. 실패 시 None."""
if code in _BOOK_MEMO:
return _BOOK_MEMO[code]
try:
return kc.get_quote_book(code)
book = kc.get_quote_book(code)
except Exception as e:
sys.stderr.write(f'[data] quote_book {code} 실패: {e}\n')
return None
book = None
_BOOK_MEMO[code] = book
return book