#!/bin/bash # 4전략 Optuna mode=tpe 순차 실행 (병렬 X — RAM/틱 로딩 OOM 방지) # 기본 기간: 어제~오늘(호출 시 START/END 오버라이드) # --apply-best 없음 — 결과 JSON만. apply 는 사용자 승인 후. # # 사용: # nohup bash scripts/run_optuna_4strat_tpe_seq.sh >> logs/optuna_4strat_tpe_master.log 2>&1 & # tail -f logs/optuna_4strat_tpe_latest_master.logpath # 경로만 # tail -f "$(cat logs/optuna_4strat_tpe_latest_master.logpath)" # # START=2026-07-20 END=2026-07-21 TRIALS=200 bash scripts/run_optuna_4strat_tpe_seq.sh set -euo pipefail cd /home/hoon/kis_bot mkdir -p logs kis_trader/backtest/results START="${START:-2026-07-20}" END="${END:-2026-07-21}" MODE="${MODE:-tpe}" TRIALS="${TRIALS:-200}" STUDY_TRIALS="${STUDY_TRIALS:-}" MIN_TRADES="${MIN_TRADES:-1}" # 탐색 게이트 OFF — TPE 학습. 사후 후보는 JSON results_gated (REPORT_MIN_*) MIN_WIN_RATE="${MIN_WIN_RATE:-0}" MIN_PF="${MIN_PF:-0}" # 공백 구분 — 기본 국내4 (해외 us_momentum 은 STRATEGIES 에 넣을 때만) # STRATEGIES="momentum tail" bash ... # STRATEGIES="us_momentum momentum" bash ... STRATEGIES="${STRATEGIES:-momentum tail breakout scalp}" # 꼬리 TPE 진입모드 — 한 스터디에 섞지 않음. 공백 구분 시 순차 2회. # TAIL_OPTUNA_ENTRY_MODES="align limit_atr" TAIL_OPTUNA_ENTRY_MODES="${TAIL_OPTUNA_ENTRY_MODES:-align}" # 돌파 TPE 손절모드 — 한 스터디에 섞지 않음. 공백 구분 시 순차. # BREAKOUT_OPTUNA_SL_MODES="fixed atr" BREAKOUT_OPTUNA_SL_MODES="${BREAKOUT_OPTUNA_SL_MODES:-fixed}" # 돌파 TPE 호가 스위치 — trial 축 아님. 손절×호가 최대 4순차. # BREAKOUT_OPTUNA_OB_MODES="off on" BREAKOUT_OPTUNA_OB_MODES="${BREAKOUT_OPTUNA_OB_MODES:-off}" # kiwoom|ls — 웹 Optuna 이력소스 / CLI UNIVERSE_HISTORY_SOURCE UNIVERSE_HISTORY_SOURCE="${UNIVERSE_HISTORY_SOURCE:-${BACKTEST_UNIVERSE_HISTORY_SOURCE:-kiwoom}}" # 웹 순차 잡 ID (전략/조합별 1·2차 state 파일 prefix) OPTUNA_SEQ_JOB_ID="${OPTUNA_SEQ_JOB_ID:-seq}" SORT_BY="${SORT_BY:-score}" PY="${PY:-.venv/bin/python}" TS0="$(date +%Y%m%d_%H%M%S)" MASTER="logs/optuna_4strat_tpe_${START}_${END}_${TS0}_master.log" { echo "======== Optuna 4전략 TPE 순차 시작 $(date -Is) ========" echo "START=$START END=$END MODE=$MODE TRIALS=$TRIALS STUDY_TRIALS=${STUDY_TRIALS:-}" echo "STRATEGIES=$STRATEGIES" echo "TAIL_OPTUNA_ENTRY_MODES=$TAIL_OPTUNA_ENTRY_MODES" echo "BREAKOUT_OPTUNA_SL_MODES=$BREAKOUT_OPTUNA_SL_MODES" echo "BREAKOUT_OPTUNA_OB_MODES=$BREAKOUT_OPTUNA_OB_MODES" echo "UNIVERSE_HISTORY_SOURCE=$UNIVERSE_HISTORY_SOURCE" echo "min_wr=$MIN_WIN_RATE min_pf=$MIN_PF min_trades=$MIN_TRADES" echo "apply-best=OFF · 전략/조합마다 1·2차 TPE 연쇄 · n_jobs=1 (사후 results_gated + briefing.md)" echo "master_log=$MASTER" free -h | sed -n '1,2p' df -h / | tail -1 } | tee -a "$MASTER" echo "$MASTER" > logs/optuna_4strat_tpe_latest_master.logpath run_one() { local strat="$1" local entry_mode="${2:-}" local sl_mode="${3:-}" local ob_mode="${4:-off}" local ts step_job_id refine_log state_file sort_by bo_extra extra min_trades_arg ts="$(date +%Y%m%d_%H%M%S)" sort_by="${SORT_BY:-score}" case "$sort_by" in score|score_legacy|pnl|daily_avg|win_rate) ;; *) sort_by="score" ;; esac if [[ "$strat" == "breakout" && -n "$sl_mode" ]]; then bo_extra="${sl_mode}_ob_${ob_mode}" extra="$bo_extra" elif [[ "$strat" == "tail" && -n "$entry_mode" ]]; then extra="$entry_mode" else extra="" fi step_job_id="${OPTUNA_SEQ_JOB_ID}_${strat}${extra:+_${extra}}_${ts}" refine_log="logs/optuna_seq_refine_${step_job_id}.log" state_file="logs/${step_job_id}_refine_state.json" min_trades_arg=$("$PY" -c "from kis_trader.backtest.optuna_common import resolve_optuna_min_trades; print(resolve_optuna_min_trades('${START}', '${END}', '${strat}')['min_trades'])") { echo "" echo "-------- [$strat${entry_mode:+/$entry_mode}${sl_mode:+/$sl_mode}${bo_extra:+/$bo_extra}] START $(date -Is) 1·2차 step=$step_job_id --------" } | tee -a "$MASTER" if [[ -n "${OPTUNA_SEQ_ACTIVE_FILE:-}" ]]; then { echo "strategy=$strat" echo "entry_mode=${entry_mode:-}" echo "sl_mode=${sl_mode:-}" echo "ob_mode=${ob_mode:-}" echo "extra=${extra}" echo "refine_state_path=$state_file" } > "$OPTUNA_SEQ_ACTIVE_FILE" fi set +e local refine_args=( --job-id "$step_job_id" --strategy "$strat" --mode "$MODE" --start "$START" --end "$END" --trials "$TRIALS" --sort-by "$sort_by" --min-trades "$min_trades_arg" --universe-history-source "$UNIVERSE_HISTORY_SOURCE" ) if [[ -n "${STUDY_TRIALS:-}" && "${STUDY_TRIALS}" != "0" ]]; then refine_args+=(--study-trials "$STUDY_TRIALS") fi if [[ "$strat" == "tail" && -n "$entry_mode" ]]; then refine_args+=(--entry-mode "$entry_mode") fi if [[ "$strat" == "breakout" && -n "$sl_mode" ]]; then refine_args+=(--sl-mode "$sl_mode" --ob-mode "$ob_mode") fi if [[ -n "${CANDLE_SOURCE:-}" ]]; then refine_args+=(--candle-source "$CANDLE_SOURCE") fi if [[ -n "${TICK_SOURCE:-}" ]]; then refine_args+=(--tick-source "$TICK_SOURCE") fi if [[ -n "${OB_SOURCE:-}" ]]; then refine_args+=(--ob-source "$OB_SOURCE") fi "$PY" -u kis_trader/backtest/optuna_mode_refine_runner.py "${refine_args[@]}" >"$refine_log" 2>&1 local rc=$? set -e local result_json briefing_md result_json="" briefing_md="" if [[ -f "$state_file" ]]; then result_json=$("$PY" -c "import json; print(json.load(open('${state_file}')).get('result_json') or '')" 2>/dev/null || true) if [[ -n "$result_json" && -f "$result_json" ]]; then echo "OPTUNA_RESULT_JSON=$result_json" | tee -a "$MASTER" briefing_md="${result_json%.json}.briefing.md" if [[ -f "$briefing_md" ]]; then echo "OPTUNA_BRIEFING_MD=$briefing_md" | tee -a "$MASTER" fi fi fi if [[ -z "$result_json" ]]; then grep -E 'OPTUNA_RESULT_JSON=' "$refine_log" | tail -n 1 | tee -a "$MASTER" || true fi { echo "-------- [$strat${entry_mode:+/$entry_mode}${sl_mode:+/$sl_mode}${bo_extra:+/$bo_extra}] END rc=$rc $(date -Is) --------" echo "REFINE_LOG=$refine_log" echo "STATE=$state_file" grep -E 'OPTUNA_RESULT_JSON=|OPTUNA_BRIEFING_MD=|✅ 1·2차|❌ 1·2차|phase1|phase2|Traceback' "$refine_log" | tail -n 24 || true } | tee -a "$MASTER" if [[ "$rc" -ne 0 ]]; then echo "⚠️ [$strat] 1·2차 실패 rc=$rc — 다음 전략 계속" | tee -a "$MASTER" fi return 0 } for s in $STRATEGIES; do if [[ "$s" == "tail" ]]; then for em in $TAIL_OPTUNA_ENTRY_MODES; do run_one tail "$em" done elif [[ "$s" == "breakout" ]]; then for sm in $BREAKOUT_OPTUNA_SL_MODES; do for om in $BREAKOUT_OPTUNA_OB_MODES; do run_one breakout "" "$sm" "$om" done done else run_one "$s" fi done { echo "" echo "======== ALL DONE $(date -Is) ========" echo "apply 하지 않음. JSON= kis_trader/backtest/results/optuna_*_tpe_*.json" echo "브리핑= 같은 이름 .briefing.md (이전 장 / 앞으로 장)" echo "검증: .venv/bin/python scripts/verify_optuna_tpe_apply_dryrun.py" } | tee -a "$MASTER"