""" 05 연동: 최신 봉에서 matched 규칙 평가. """ from __future__ import annotations import time from typing import Any import pandas as pd from config import CHART_LOOKBACK_DAYS, MATCH_LIVE_CACHE_SEC, MATCH_LIVE_LOOKBACK_DAYS, SYMBOL from deepcoin.data.mtf_bb import load_frames_from_db from deepcoin.matching.load_rules import load_monitor_rules from deepcoin.matching.rule_eval import ( build_mtf_scan_frame, conditions_columns, eval_conditions, ) from deepcoin.ops.monitor import Monitor _cache: dict[str, Any] = {"ts": 0.0, "frame": None, "rules_key": ""} def evaluate_live_rules( rules: list[dict[str, Any]] | None = None, *, lookback_days: int | None = None, force_refresh: bool = False, ) -> list[dict[str, Any]]: """ 최신 완성 3분봉에서 활성 규칙 발화 여부를 검사합니다. Args: rules: 규칙 목록. None이면 matched_rules에서 로드. lookback_days: DB 조회 일수(기본 MATCH_LIVE_LOOKBACK_DAYS). force_refresh: 캐시 무시. Returns: 발화한 규칙 정보 리스트 (rule_id, side, dt, close). """ active = rules if rules is not None else load_monitor_rules() if not active: return [] lb = lookback_days if lookback_days is not None else MATCH_LIVE_LOOKBACK_DAYS rules_key = ",".join(r["rule_id"] for r in active) now = time.time() global _cache if ( not force_refresh and _cache.get("frame") is not None and now - float(_cache.get("ts", 0)) < MATCH_LIVE_CACHE_SEC and _cache.get("rules_key") == rules_key ): frame = _cache["frame"] else: mon = Monitor(cooldown_file=None) days = min(lb, CHART_LOOKBACK_DAYS) frames = load_frames_from_db(mon, SYMBOL, lookback_days=days) needed = conditions_columns(active) frame = build_mtf_scan_frame(frames, needed) _cache["ts"] = now _cache["frame"] = frame _cache["rules_key"] = rules_key if frame.empty: return [] ts = frame.index[-1] row_frame = frame.iloc[[-1]] fired: list[dict[str, Any]] = [] close_col = "close" for rule in active: if not eval_conditions(row_frame, rule["conditions"]).iloc[0]: continue fired.append( { "rule_id": rule["rule_id"], "side": rule["side"], "kind": rule.get("kind", ""), "dt": ts.strftime("%Y-%m-%d %H:%M:%S"), "close": float(row_frame[close_col].iloc[0]), } ) return fired