"""캔들 봉 마감 판별.""" from __future__ import annotations from datetime import datetime, timedelta from bithumb.api.bithumb import parse_kst_datetime def bar_close_time(bar_open: datetime, interval_min: int) -> datetime: """봉 시작 시각 기준 마감 시각(KST naive)을 반환한다.""" return bar_open + timedelta(minutes=interval_min) def is_closed_candle( bar_open: datetime, interval_min: int, *, now: datetime | None = None, ) -> bool: """해당 봉이 마감되었는지 여부.""" ref = now or datetime.now() return ref >= bar_close_time(bar_open, interval_min) def only_closed_candles( rows: list[tuple], interval_min: int, *, now: datetime | None = None, ) -> list[tuple]: """미마감 봉을 제외한 OHLCV 행만 반환한다. Args: rows: ``(ymdhms, open, high, low, close, volume)`` 튜플 리스트. interval_min: 분 단위 인터벌. now: 기준 시각(KST). None이면 ``datetime.now()``. Returns: 마감된 봉만 포함한 리스트(입력 순서 유지). """ if not rows: return [] ref = now or datetime.now() closed: list[tuple] = [] for row in rows: bar_open = parse_kst_datetime(str(row[0])) if is_closed_candle(bar_open, interval_min, now=ref): closed.append(row) return closed def last_closed_bar_open(now: datetime, interval_min: int) -> datetime: """기준 시각에서 가장 최근 마감된 봉의 시작 시각.""" minute = (now.minute // interval_min) * interval_min current_start = now.replace(minute=minute, second=0, microsecond=0) if is_closed_candle(current_start, interval_min, now=now): return current_start return current_start - timedelta(minutes=interval_min)