feat: Enhance Optuna integration and logging for backtesting framework
Changes: - Added new API endpoints for continuing and confirming Optuna jobs, allowing for better management of ongoing studies. - Introduced detailed logging for tick feed tracking and order book processing, improving traceability of vendor performance during backtests. - Updated database schema to include new fields for managing Optuna study results, enhancing the ability to track study progress and outcomes. - Refactored existing functions to utilize the new logging and tracking features, ensuring consistency across the backtesting framework. Impact: - These enhancements improve the robustness and transparency of the Optuna backtesting process, facilitating better analysis and optimization of trading strategies.
This commit is contained in:
@@ -40,20 +40,44 @@ def _live_feed_providers() -> Tuple[str, str]:
|
||||
|
||||
|
||||
class FeedPrefixLoggerAdapter(logging.LoggerAdapter):
|
||||
"""탈락/스캔 로그(🔍 [) 앞에 T:시세|O:호가 provider 접두어를 붙인다.
|
||||
"""탈락/스캔 로그(🔍 [) 앞에 T:설정|O:설정|R:실제읽기 접두어를 붙인다.
|
||||
|
||||
예: 🔍 [탈락-RSI] → 🔍 [T:kiwoom|O:kiwoom|탈락-RSI]
|
||||
(피드 출처 디버깅용 · 매매 수치 아님)
|
||||
예: 🔍 [탈락-RSI] → 🔍 [T:kis|O:kiwoom|R:kis(1차)|탈락-RSI]
|
||||
T/O = LIVE_*_PROVIDER(DB). R = get_tick_feed_label(code) — 직전 get_price 읽기.
|
||||
extra={'scan_code': code} 로 R: 활성화 (_scan_log 헬퍼 사용).
|
||||
TRIGGER_FEED_DETAIL_LOG(기본 true) 이면 틱가·틱타임·호가·1/2/3차 체인 꼬리 추가.
|
||||
"""
|
||||
|
||||
def process(self, msg, kwargs):
|
||||
if isinstance(msg, str) and "🔍 [" in msg and "시세:" not in msg and "LIVE_TICK_PROVIDER" in self.extra:
|
||||
try:
|
||||
# 이미 T:|O: 접두가 있으면 중복 삽입 금지 (매수체크 로그 등)
|
||||
if "🔍 [T:" not in msg[:24]:
|
||||
if "🔍 [T:" not in msg[:32]:
|
||||
tick_p, ob_p = _live_feed_providers()
|
||||
if tick_p or ob_p:
|
||||
read_lab = ""
|
||||
extra = kwargs.get("extra") or {}
|
||||
scan_code = str(extra.get("scan_code") or "").strip()
|
||||
ws = self.extra.get("ws")
|
||||
if scan_code and ws is not None and hasattr(ws, "get_tick_feed_label"):
|
||||
try:
|
||||
read_lab = str(ws.get_tick_feed_label(scan_code) or "").strip()
|
||||
except Exception:
|
||||
read_lab = ""
|
||||
if read_lab:
|
||||
msg = msg.replace(
|
||||
"🔍 [",
|
||||
f"🔍 [T:{tick_p}|O:{ob_p}|R:{read_lab}|",
|
||||
1,
|
||||
)
|
||||
elif tick_p or ob_p:
|
||||
msg = msg.replace("🔍 [", f"🔍 [T:{tick_p}|O:{ob_p}|", 1)
|
||||
if scan_code and ws is not None and hasattr(ws, "get_trigger_feed_trace"):
|
||||
try:
|
||||
detail = str(ws.get_trigger_feed_trace(scan_code) or "").strip()
|
||||
except Exception:
|
||||
detail = ""
|
||||
if detail and "틱1차설정=" not in msg:
|
||||
msg = f"{msg} · {detail}"
|
||||
except Exception:
|
||||
pass
|
||||
return msg, kwargs
|
||||
@@ -124,7 +148,10 @@ class BaseStrategy(ABC, threading.Thread):
|
||||
self.ls_condition_mgr = ls_condition_mgr
|
||||
self.market_guard = market_guard # MarketGuard (선택, None 이면 가드 없음)
|
||||
base_logger = get_logger(f"kis_trader.strategy.{self.strategy_id}")
|
||||
self.logger = FeedPrefixLoggerAdapter(base_logger, {"db": self.db, "LIVE_TICK_PROVIDER": True})
|
||||
self.logger = FeedPrefixLoggerAdapter(
|
||||
base_logger,
|
||||
{"db": self.db, "ws": self.ws, "LIVE_TICK_PROVIDER": True},
|
||||
)
|
||||
# MarketGuard PANIC 차단 로그 스팸 방지용 (분당 1회)
|
||||
self._panic_log_ts: float = 0.0
|
||||
|
||||
@@ -605,6 +632,21 @@ class BaseStrategy(ABC, threading.Thread):
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _scan_log(
|
||||
self,
|
||||
level: str,
|
||||
code: Optional[str],
|
||||
msg: str,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""🔍 스캔/탈락 로그 — FeedPrefixLoggerAdapter 가 T/O/R 접두 부착."""
|
||||
extra = dict(kwargs.pop("extra", None) or {})
|
||||
c = str(code or "").strip()
|
||||
if c:
|
||||
extra["scan_code"] = c
|
||||
getattr(self.logger, level)(msg, *args, extra=extra, **kwargs)
|
||||
|
||||
def _resolve_sell_price(self, code: str, *, is_eod: bool, buy_price: float) -> float:
|
||||
"""실매 매도 현재가 — 마지막 WS를 TTL로 버리지 않음. EOD는 매수가 폴백."""
|
||||
from kis_trader.engine.live_sell_price import resolve_live_sell_price
|
||||
@@ -1152,7 +1194,7 @@ class BaseStrategy(ABC, threading.Thread):
|
||||
t_pre0 = time.perf_counter()
|
||||
guard = self._live_portfolio_entry_guard(code, max_stocks)
|
||||
if guard:
|
||||
self.logger.info("🔍 [%s] %s(%s)", guard, name, code)
|
||||
self._scan_log("info", code, "🔍 [%s] %s(%s)", guard, name, code)
|
||||
if prof_scan:
|
||||
dt = (time.perf_counter() - t_pre0) * 1000.0
|
||||
scan_pre_ms += dt
|
||||
|
||||
Reference in New Issue
Block a user