""" param_search_dates.py — 파라미터 탐색 기본 시작/종료일 (거래일 보정 + 조건식 컷오프) """ from __future__ import annotations from typing import Optional, Tuple from kis_trader.utils.env import get_env_from_db, get_env_int from kis_trader.utils.kr_trading_day import ( clamp_to_prev_kr_trading_day, default_kr_trading_end, default_kr_trading_start, resolve_kr_backtest_date_defaults, ) def _normalize_ymd(raw: str) -> str: s = (raw or "").strip() if not s: return "" if "-" in s and len(s) >= 10: return s[:10] digits = s.replace("-", "").replace("/", "")[:8] if len(digits) == 8 and digits.isdigit(): return f"{digits[:4]}-{digits[4:6]}-{digits[6:8]}" return s[:10] def resolve_param_search_end() -> str: """CLI/웹 기본 --end: 오늘이 주말·휴장이면 이전 장운영일.""" return default_kr_trading_end() def resolve_param_search_start( strategy: str = "TAIL", *, lookback_days: int = 7, min_start_env_key: Optional[str] = None, ) -> str: """ 파라미터 탐색 CLI 기본 --start. - lookback_days 전(거래일 보정)과 env 최소시작일 중 **늦은 날** 사용 - 조건식 변경 후 ``TAIL_PARAM_SEARCH_MIN_START=2026-07-07`` 처럼 설정 """ lb = max(1, int(lookback_days)) week_ago = default_kr_trading_start(lb) sid = (strategy or "TAIL").strip().upper() env_key = min_start_env_key or f"{sid}_PARAM_SEARCH_MIN_START" if sid == "SHORT": env_key = "TAIL_PARAM_SEARCH_MIN_START" min_start = _normalize_ymd(str(get_env_from_db(env_key, "") or "")) if min_start: # 최소시작일도 휴장이면 다음이 아니라 **이전** 거래일로 맞추면 컷오프가 # 당겨질 수 있어, 컷오프는 그대로 두고 week_ago 와 max 만 한다. return max(week_ago, min_start) return week_ago def resolve_param_search_range( strategy: str = "TAIL", *, lookback_days: Optional[int] = None, ) -> Tuple[str, str]: """(start, end) — 주말/휴장 보정된 기본 구간.""" lb = int( lookback_days if lookback_days is not None else get_env_int("PARAM_SEARCH_DEFAULT_LOOKBACK_DAYS", 7) ) end = resolve_param_search_end() start = resolve_param_search_start(strategy, lookback_days=lb) if start > end: start = end return start, end def clamp_date_input(raw: str, *, fallback: Optional[str] = None) -> str: """인풋 날짜 문자열 → 거래일 보정. 빈 값이면 fallback 또는 기본 end.""" s = _normalize_ymd(raw) if not s: return fallback if fallback is not None else resolve_param_search_end() return clamp_to_prev_kr_trading_day(s) # 하위 호환 re-export __all__ = [ "resolve_param_search_start", "resolve_param_search_end", "resolve_param_search_range", "clamp_date_input", "resolve_kr_backtest_date_defaults", "clamp_to_prev_kr_trading_day", ]