#!/usr/bin/env python3 """ env_config → env_config(공통) + config_{전략} 분리 마이그레이션. 1) config_scalp / config_short / config_momentum / config_breakout / config_updow 테이블 생성·컬럼 보강 2) 기존 env_config 최신 행 + env_config_ext 값을 테이블별로 INSERT 3) 공통 키만 env_config 에 새 스냅샷 INSERT 실행: cd ~/kis_bot && python3 -m kis_trader.scripts.migrate_split_env_config """ from __future__ import annotations import sys from pathlib import Path _ROOT = Path(__file__).resolve().parents[2] if str(_ROOT) not in sys.path: sys.path.insert(0, str(_ROOT)) from config_schema import CONFIG_TABLE_NAMES, classify_config_key # noqa: E402 from database import ( # noqa: E402 CONFIG_TABLE_KEYS, ENV_CONFIG_KEYS, TradeDB, ) def _load_legacy_flat(db: TradeDB) -> dict: """기존 fat env_config 1행 + env_config_ext.""" flat = {} try: row = db.conn.execute( "SELECT * FROM env_config ORDER BY id DESC LIMIT 1" ).fetchone() if row: rk = row.keys() if hasattr(row, "keys") else [] for k in ENV_CONFIG_KEYS: if k in rk and row[k] is not None and str(row[k]).strip() != "": flat[k] = str(row[k]) except Exception as e: print(f"legacy env_config 읽기 실패: {e}") try: ext = db.conn.execute( "SELECT env_key, env_value FROM env_config_ext" ).fetchall() for er in ext or []: ek = er["env_key"] if isinstance(er, dict) else er[0] ev = er["env_value"] if isinstance(er, dict) else er[1] if ek: flat[str(ek)] = "" if ev is None else str(ev) except Exception: pass return flat def main() -> int: db = TradeDB() db._migrate_config_table_columns() flat = _load_legacy_flat(db) if not flat: merged = db.get_merged_env_snapshot() if merged: flat = dict(merged) if not flat: print("❌ 마이그레이션할 env 데이터 없음") db.close() return 1 print(f"소스 키 {len(flat)}개 → 테이블별 INSERT") eid = db.insert_env_snapshot(flat) if not eid: print("❌ insert_env_snapshot 실패") db.close() return 1 snap = db.get_merged_env_snapshot() print(f"\n✅ 완료 env_config id={eid}") print(f"병합 snapshot 키 수: {len(snap)}") for tbl in CONFIG_TABLE_NAMES: n = len(CONFIG_TABLE_KEYS.get(tbl, ())) filled = sum(1 for k in CONFIG_TABLE_KEYS.get(tbl, ()) if snap.get(k)) print(f" {tbl}: 컬럼 {n} / 값 있음 {filled}") checks = [ "KIS_APP_KEY_REAL", "SCALP_STOP_LOSS_PCT", "TAIL_ATR_TP_MAX_PCT", "SHOULDER_MIN_HIGH_PCT", "MOMENTUM_SLOT_MONEY", "UPDOW_MAX_BUY_AMOUNT", "SELL_USE_ORDERBOOK_ON_PROFIT", ] print("\n검증:") for k in checks: tbl = classify_config_key(k) print(f" {k} [{tbl}] = {snap.get(k, '(없음)')}") db.close() return 0 if __name__ == "__main__": raise SystemExit(main())