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:
Your Name
2026-08-21 19:05:23 +09:00
parent 0ecac7cb95
commit 0780b2cdd0
76 changed files with 4648 additions and 516 deletions

View File

@@ -346,27 +346,28 @@ def load_tail_candles_by_code(
peak_sel = ", holding_peak" if has_holding_peak else ""
ind_cols = ws_candles_select_indicator_cols(db)
from kis_trader.backtest.bt_candle_source import (
fetch_ws_candles_for_code,
list_ws_candle_codes,
)
from kis_trader.backtest.bt_candle_source import fetch_ws_candles_by_code_bulk
codes = list_ws_candle_codes(db, tail_tf, start_key, end_key)
# 3분 합성 시 1분만 있는 종목도 후보에 포함
synth_on = (
tail_tf == 3
and get_env_bool("TAIL_BT_SYNTH_3M_FROM_1M", True)
)
loaded_tf = fetch_ws_candles_by_code_bulk(
db, tail_tf, start_key, end_key,
extra_select=ind_cols,
peak_sel=peak_sel,
confirmed_only=True,
)
loaded_1m: Dict[str, List[Dict]] = {}
if synth_on:
try:
codes_1m = list_ws_candle_codes(db, 1, start_key, end_key)
for c in codes_1m:
if c not in codes:
codes.append(c)
codes = sorted(set(codes))
except Exception:
pass
loaded_1m = fetch_ws_candles_by_code_bulk(
db, 1, start_key, end_key,
extra_select=ind_cols,
peak_sel=peak_sel,
confirmed_only=True,
)
codes = sorted(set(list(loaded_tf.keys()) + list(loaded_1m.keys())))
candles_by_code: Dict[str, List[Dict]] = {}
total_candles = 0
@@ -374,16 +375,11 @@ def load_tail_candles_by_code(
synth_filled_total = 0
for code in codes:
bars = fetch_ws_candles_for_code(
db, code, tail_tf, start_key, end_key,
extra_select=ind_cols,
peak_sel=peak_sel,
confirmed_only=True,
)
bars = list(loaded_tf.get(code) or [])
if synth_on:
bars, n_fill = _synth_fill_3m_holes_from_1m(
db, code, bars, start_key, end_key, peak_sel=peak_sel,
rows_1m=loaded_1m.get(code) or [],
)
synth_filled_total += n_fill
@@ -428,17 +424,19 @@ def _synth_fill_3m_holes_from_1m(
end_key: str,
*,
peak_sel: str = "",
rows_1m: Optional[List[Dict]] = None,
) -> Tuple[List[Dict], int]:
"""DB 3분 리스트에 없는 시각만 1분→3분 롤업으로 보강."""
from kis_trader.engine.candle_rollup import merge_fill_holes, rollup_1m_bars_to_tf
from kis_trader.backtest.bt_candle_source import fetch_ws_candles_for_code
try:
rows_1m = fetch_ws_candles_for_code(
db, code, 1, start_key, end_key,
peak_sel=peak_sel,
confirmed_only=True,
)
if rows_1m is None:
rows_1m = fetch_ws_candles_for_code(
db, code, 1, start_key, end_key,
peak_sel=peak_sel,
confirmed_only=True,
)
except Exception:
return bars_3m, 0
if not rows_1m: