Files
kis_bot/kis_trader/backtest/bt_rest_warmup_cache.py
2026-08-21 20:18:24 +09:00

126 lines
4.0 KiB
Python

# -*- coding: utf-8 -*-
"""백테 REST 전일봉 웜업 DB 캐시 — 다른 PC/동일 study 재사용.
성공분만 저장. 실패는 저장하지 않아 다른 머신·코드 개선 후 재시도 가능.
"""
from __future__ import annotations
import json
import logging
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
logger = logging.getLogger("kis_trader.bt_rest_warmup_cache")
_TABLE = "bt_rest_warmup_cache"
_ENSURED = False
_DDL = """
CREATE TABLE IF NOT EXISTS bt_rest_warmup_cache (
code VARCHAR(16) NOT NULL,
period_day CHAR(8) NOT NULL COMMENT '백테 구간 시작일 YYYYMMDD',
market VARCHAR(8) NOT NULL DEFAULT 'KR',
n_bars INT NOT NULL DEFAULT 0 COMMENT '확보에 쓴 REST 봉수',
ok TINYINT NOT NULL DEFAULT 0,
prefix_json LONGTEXT NULL COMMENT '[{datetime,open,high,low,close,volume},...]',
updated_at DATETIME NOT NULL,
PRIMARY KEY (code, period_day, market),
KEY idx_bt_rest_warm_day (period_day, market)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
COMMENT='모멘텀 백테 REST 전일봉 웜업 공유 캐시(성공만)'
"""
def ensure_bt_rest_warmup_cache_table() -> None:
global _ENSURED
if _ENSURED:
return
try:
from database import TradeDB
db = TradeDB()
db.conn.execute(_DDL)
_ENSURED = True
except Exception as exc:
logger.warning("⚠️ bt_rest_warmup_cache 테이블 생성 실패: %s", exc)
def _day_key(start_key: str) -> str:
s = str(start_key or "").strip().replace("-", "")[:8]
return s if len(s) == 8 and s.isdigit() else ""
def load_rest_warmup_prefix(
code: str,
*,
period_day: str,
market: str = "KR",
) -> Optional[Tuple[List[Dict[str, Any]], int]]:
"""성공 캐시면 (prefix_rows, n_bars), 없으면 None."""
c = str(code or "").strip()
day = _day_key(period_day)
mkt = str(market or "KR").strip().upper() or "KR"
if not c or not day:
return None
try:
ensure_bt_rest_warmup_cache_table()
from database import TradeDB
cur = TradeDB().conn.execute(
"SELECT ok, n_bars, prefix_json FROM bt_rest_warmup_cache "
"WHERE code=%s AND period_day=%s AND market=%s LIMIT 1",
(c, day, mkt),
)
row = cur.fetchone()
if not row:
return None
if int(row.get("ok") or 0) != 1:
return None
raw = row.get("prefix_json") or "[]"
rows = json.loads(raw) if isinstance(raw, str) else (raw or [])
if not isinstance(rows, list) or not rows:
return None
return rows, int(row.get("n_bars") or 0)
except Exception as exc:
logger.debug("bt_rest_warmup load miss %s: %s", c, exc)
return None
def save_rest_warmup_prefix(
code: str,
*,
period_day: str,
market: str,
n_bars: int,
prefix_rows: List[Dict[str, Any]],
) -> bool:
"""성공 접두만 upsert. 실패는 저장하지 않음."""
c = str(code or "").strip()
day = _day_key(period_day)
mkt = str(market or "KR").strip().upper() or "KR"
if not c or not day or not prefix_rows:
return False
try:
ensure_bt_rest_warmup_cache_table()
from database import TradeDB
payload = json.dumps(prefix_rows, ensure_ascii=False, separators=(",", ":"))
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
TradeDB().conn.execute(
"""
INSERT INTO bt_rest_warmup_cache
(code, period_day, market, n_bars, ok, prefix_json, updated_at)
VALUES (%s, %s, %s, %s, 1, %s, %s)
ON DUPLICATE KEY UPDATE
n_bars=VALUES(n_bars),
ok=1,
prefix_json=VALUES(prefix_json),
updated_at=VALUES(updated_at)
""",
(c, day, mkt, int(n_bars or 0), payload, now),
)
return True
except Exception as exc:
logger.warning("⚠️ bt_rest_warmup 저장 실패 %s: %s", c, exc)
return False