feat(param-search): Add new evaluation functions for breakout, momentum, and tail parameter combinations
Changes: - Added `apply_params_to_db` function to streamline parameter application to the database. - Introduced `evaluate_breakout_param_combo`, `evaluate_momentum_param_combo`, and `evaluate_tail_param_combo` functions to enhance the evaluation of parameter combinations for respective strategies. - Updated `requirements.txt` to include `optuna==4.2.1` for improved optimization capabilities. Impact: - These additions improve the modularity and efficiency of parameter evaluations across different trading strategies, facilitating better optimization and backtesting processes.
This commit is contained in:
148
kis_trader/backtest/optuna_common.py
Normal file
148
kis_trader/backtest/optuna_common.py
Normal file
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
kis_trader/backtest/optuna_common.py — Optuna storage·DB 공통 (MariaDB 141)
|
||||
=========================================================================
|
||||
TradeDB(database.py) 와 동일 호스트·계정, 전용 DB kis_optuna 에 study 저장.
|
||||
Win11·VM 양쪽에서 같은 storage 로 trial 공유·재개 가능.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
from typing import Optional
|
||||
from urllib.parse import quote_plus
|
||||
|
||||
from kis_trader.utils.env import get_env_from_db
|
||||
|
||||
logger = logging.getLogger("optuna_common")
|
||||
|
||||
# Optuna 전용 MariaDB (매매 DB kis_quant_db 와 분리)
|
||||
DEFAULT_OPTUNA_DB_NAME = "kis_optuna"
|
||||
OPTUNA_STRATEGIES = ("tail", "momentum", "breakout")
|
||||
|
||||
|
||||
def mariadb_creds() -> dict:
|
||||
"""TradeDB(database.py) 와 동일 우선순위 — env > 기본 141."""
|
||||
return {
|
||||
"host": os.environ.get("DB_HOST", "192.168.0.141"),
|
||||
"port": int(os.environ.get("DB_PORT", "3306")),
|
||||
"user": os.environ.get("DB_USER", "jae"),
|
||||
"password": os.environ.get("DB_PASS", "1234"),
|
||||
}
|
||||
|
||||
|
||||
def resolve_optuna_db_name() -> str:
|
||||
"""
|
||||
Optuna storage DB — 기본 kis_optuna (매매 kis_quant_db 와 분리).
|
||||
env OPTUNA_DB_NAME 로 오버라이드 가능.
|
||||
"""
|
||||
raw = get_env_from_db("OPTUNA_DB_NAME", "")
|
||||
if raw and str(raw).strip() not in ("", "None"):
|
||||
return str(raw).strip()
|
||||
env = os.environ.get("OPTUNA_DB_NAME", "")
|
||||
if env and str(env).strip():
|
||||
return str(env).strip()
|
||||
return DEFAULT_OPTUNA_DB_NAME
|
||||
|
||||
|
||||
def build_mariadb_storage_url(db_name: Optional[str] = None) -> str:
|
||||
"""mysql+pymysql://…@141/optuna 형식 storage URL."""
|
||||
creds = mariadb_creds()
|
||||
name = (db_name or resolve_optuna_db_name()).strip()
|
||||
user = quote_plus(creds["user"])
|
||||
passwd = quote_plus(creds["password"])
|
||||
return (
|
||||
f"mysql+pymysql://{user}:{passwd}@{creds['host']}:{creds['port']}/{name}"
|
||||
f"?charset=utf8mb4"
|
||||
)
|
||||
|
||||
|
||||
def ensure_optuna_database(db_name: Optional[str] = None) -> str:
|
||||
"""
|
||||
MariaDB 141 — kis_optuna 존재 확인 (없으면 CREATE 시도).
|
||||
"""
|
||||
name = (db_name or resolve_optuna_db_name()).strip()
|
||||
creds = mariadb_creds()
|
||||
|
||||
try:
|
||||
import pymysql
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Optuna MariaDB storage 는 pymysql 필요: pip install PyMySQL"
|
||||
) from exc
|
||||
|
||||
# DB 존재 여부만 확인 (이미 있으면 CREATE 생략)
|
||||
conn = pymysql.connect(
|
||||
host=creds["host"],
|
||||
port=creds["port"],
|
||||
user=creds["user"],
|
||||
password=creds["password"],
|
||||
charset="utf8mb4",
|
||||
autocommit=True,
|
||||
connect_timeout=10,
|
||||
)
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("SHOW DATABASES LIKE %s", (name,))
|
||||
exists = cur.fetchone() is not None
|
||||
if not exists:
|
||||
cur.execute(
|
||||
f"CREATE DATABASE IF NOT EXISTS `{name}` "
|
||||
"DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"
|
||||
)
|
||||
logger.info(
|
||||
"📦 Optuna DB 생성: %s@%s:%s/%s",
|
||||
creds["user"], creds["host"], creds["port"], name,
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
"📦 Optuna storage DB: %s@%s:%s/%s",
|
||||
creds["user"], creds["host"], creds["port"], name,
|
||||
)
|
||||
except Exception as exc:
|
||||
logger.error("❌ Optuna DB '%s' 접속/확인 실패: %s", name, exc)
|
||||
raise
|
||||
finally:
|
||||
conn.close()
|
||||
return name
|
||||
|
||||
|
||||
def resolve_optuna_storage_url(cli_override: Optional[str] = None) -> str:
|
||||
"""
|
||||
Storage URL 우선순위:
|
||||
1) CLI --storage
|
||||
2) OPTUNA_STORAGE_URL (DB/env)
|
||||
3) MariaDB 141 / kis_optuna (TradeDB 동일 계정)
|
||||
"""
|
||||
if cli_override and str(cli_override).strip():
|
||||
return str(cli_override).strip()
|
||||
from_db = get_env_from_db("OPTUNA_STORAGE_URL", "")
|
||||
if from_db and str(from_db).strip() not in ("", "None"):
|
||||
return str(from_db).strip()
|
||||
db_name = ensure_optuna_database()
|
||||
return build_mariadb_storage_url(db_name)
|
||||
|
||||
|
||||
def resolve_study_name(
|
||||
*,
|
||||
strategy: str,
|
||||
mode: str,
|
||||
start: str,
|
||||
end: str,
|
||||
cli_override: Optional[str] = None,
|
||||
) -> str:
|
||||
"""Study 이름 — 전략·기간·모드 포함."""
|
||||
if cli_override and str(cli_override).strip():
|
||||
return str(cli_override).strip()
|
||||
env_key = f"OPTUNA_{strategy.upper()}_STUDY_NAME"
|
||||
from_db = get_env_from_db(env_key, "")
|
||||
if from_db and str(from_db).strip() not in ("", "None"):
|
||||
return str(from_db).strip()
|
||||
legacy = get_env_from_db("OPTUNA_TAIL_STUDY_NAME", "")
|
||||
if strategy == "tail" and legacy and str(legacy).strip() not in ("", "None"):
|
||||
return str(legacy).strip()
|
||||
return f"{strategy}_{mode}_{start}_{end}"
|
||||
|
||||
|
||||
def optuna_run_lock_name(strategy: str) -> str:
|
||||
return f"{strategy}_param_search_optuna"
|
||||
Reference in New Issue
Block a user