126 lines
4.0 KiB
Python
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
|