3분~일봉 GT 타점 분석(03c), leg 체결 순서 수정, 총자산 90% 검증 루프, walk-forward Go/No-Go 시뮬, monitor·live_trader 및 reference 문서를 포함한다. Co-authored-by: Cursor <cursoragent@cursor.com>
87 lines
2.6 KiB
Python
87 lines
2.6 KiB
Python
"""
|
|
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
|