GT MTF 프로필·캘리브레이션과 04 매칭/시뮬/실거래 파이프라인을 추가한다.

3분~일봉 GT 타점 분석(03c), leg 체결 순서 수정, 총자산 90% 검증 루프,
walk-forward Go/No-Go 시뮬, monitor·live_trader 및 reference 문서를 포함한다.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-05-31 11:27:50 +09:00
parent b52d61b777
commit 2cb67c42b3
47 changed files with 5956 additions and 209 deletions

View File

@@ -0,0 +1,86 @@
"""
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