""" 백테/Optuna 유니버스 이력 테이블 소스 해석 ======================================== - ``kiwoom`` / ``target`` → ``target_candidates_history`` (실매 키움·KIS 조건식) - ``ls`` → ``ls_candidates_history`` (LS AFR 수집) 기본값 ``kiwoom``. CLI / 웹 body / env ``BACKTEST_UNIVERSE_HISTORY_SOURCE`` 우선순위. """ from __future__ import annotations from typing import Any, Optional from kis_trader.utils.env import get_env_bool, get_env_from_db VALID_HISTORY_SOURCES = frozenset({"kiwoom", "target", "ls"}) def normalize_universe_history_source(raw: Any) -> str: s = str(raw or "").strip().lower() if s in ("", "kiwoom", "target", "kis", "condition"): return "kiwoom" if s in ("ls", "ls_condition", "ls_afr"): return "ls" return "kiwoom" def resolve_backtest_universe_history_source( override: Any = None, *, default: str = "kiwoom", ) -> str: """override(CLI/웹) > env BACKTEST_UNIVERSE_HISTORY_SOURCE > default.""" if override is not None and str(override).strip() != "": return normalize_universe_history_source(override) env_v = get_env_from_db("BACKTEST_UNIVERSE_HISTORY_SOURCE", default) return normalize_universe_history_source(env_v or default) def history_table_for_source(source: str) -> str: src = normalize_universe_history_source(source) if src == "ls": return "ls_candidates_history" return "target_candidates_history" def history_source_label(source: str, *, strict: bool = False) -> str: src = normalize_universe_history_source(source) if src == "ls": return "history_ls_strict" if strict else "history_ls" return "history_strict" if strict else "history" def ls_universe_session_only_enabled() -> bool: """LS sticky(장전 00시 스냅) 제외 — 기본 ON.""" return bool(get_env_bool("BACKTEST_LS_UNIVERSE_SESSION_ONLY", True)) def apply_ls_session_filter_to_start( start_time: str, *, source: str, session_only: Optional[bool] = None, ) -> str: """ LS + session_only 이면 당일 09:00:00 이전 스냅을 조회 시작에서 잘라낸다. start_time 형식: 'YYYY-MM-DD HH:MM:SS' """ src = normalize_universe_history_source(source) if src != "ls": return start_time if session_only is None: session_only = ls_universe_session_only_enabled() if not session_only: return start_time # start_time 날짜의 09:00:00 과 max try: day = str(start_time)[:10] floor = f"{day} 09:00:00" return floor if floor > str(start_time) else str(start_time) except Exception: return start_time