# Optuna 파라미터 탐색 및 호가 수급 최적화 구조 가이드 (옵투나.md) 이 문서는 백테스트 웹·CLI의 **Optuna 2단계**와, 호가 후처리 격자·적용 분리를 정리한다. 관련: `docs/호가.md` §8 · `kis_trader/backtest/optuna_postprocess_topn.py` · `optuna_orderbook_recommend.py` · `optuna_rerun_postprocess.py` 최종 갱신: 2026-08-15 --- ## 1. 투-스테이지 ``` Stage 1 캔들 TPE (param_search_optuna.py) RSI·손익·트레일 등 차트 축. 호가 ON/OFF는 넣지 않음. Stage 2 후처리 (attach_topn_postprocess) gated TopN(+mode/live) 체결을 호가 스냅으로 재생. 진입 스프/잔량/매도벽 · EXIT_OB · STOP_OB · 휩쏘. ``` Stage 2는 **이미 난 체결 + 근처 `ws_orderbook`/`ls_ws_orderbook`**. 실매 “호가 RAM 없음 → 필터 ON인데 통과” 는 `WS_ORDERBOOK_FILTER_REJECT_IF_EMPTY`(기본 true) + `WS_ORDERBOOK_FILTER_MAX_AGE_SEC` (B안, `docs/호가.md`). 1과목 차트 TPE와 별개. 구 JSON만 Stage 2 다시: ```bash python3 -u kis_trader/backtest/optuna_rerun_postprocess.py \ --result-json kis_trader/backtest/results/optuna_<전략>_tpe_.json # --apply-best 없음. 실매 DB 안 바뀜. ``` 웹 Optuna 버튼도 완료 시 후처리를 붙인다 (`optuna_postprocess_topn`). `orderbook_recommend` 블록 + `postprocess_topn` 이 JSON에 실림. --- ## 2. 진입 후처리 격자 (env_config_ext) `ensure_optuna_gate_env_defaults` → `OPTUNA_OB_*`. `OPTUNA_OB_COMBO_TRIALS_SINGLE`(기본 150) / `DOUBLE`(200) / `TRIPLE`(250) = 8방 중 켜진 축 개수별 trial. 방 000은 TPE 없음. 모멘텀·돌파 합 150×3+200×3+250=1,300. 꼬리·스캘프는 진입 on/off만(150). 구 `OPTUNA_OB_AXIS_TRIALS`(500)는 축 독립 탐색용 잔여 키 — 8방 경로에서는 안 씀. | 키 | 널널 검사 기본 (2026-08-15) | |----|------------------------------| | `OPTUNA_OB_ENTRY_SPREAD_MIN` / `MAX` | 0.1 ~ 8.0 | | `OPTUNA_OB_ENTRY_RATIO_MIN` / `MAX` | 0.05 ~ 1.5 | | `OPTUNA_OB_ENTRY_ASK_MULT_MIN` / `MAX` | 1.0 ~ 80.0 (매도벽, L3 `ask_qty_l3`) | | `OPTUNA_OB_LOOKBACK_MIN` | 30 (분) | 잔여 체결 < 원본 **30%** → trial 무효. 너무 센 컷은 고르지 못하게 하는 가드. 결과는 `orderbook_filter_enabled=True` 고정(후처리가 “끌지”를 탐색하지 않음). apply 패치에 벽이 있으면 `{전략}_ORDERBOOK_ENTRY_ASK_MAX_MULT`. --- ## 3. 꼬리 TPE 진입모드 (웹 체크) 엔진 실매 기본은 `TAIL_ENTRY_MODE` → **`limit_atr`** (`limit_entry_common.short_entry_mode`). 웹 꼬리 탭 셀렉트 기본도 limit_atr. **Optuna TPE는 예외: 진입을 탐색하지 않고 스터디마다 고정.** 예전 코드는 **`align` 하드코딩**. 웹 Optuna 탭: **align** / **limit_atr** 체크. - 기본: align만 (기존 TPE와 동일). - 둘 다: **스터디 2개 순차** (한 TPE에 categorical 혼입 없음). `--apply-best` 없음. CLI: `--entry-mode align|limit_atr` · 순차 스크립트 `TAIL_OPTUNA_ENTRY_MODES="align limit_atr"`. --- ## 4. 실매 DB 적용 분리 | 구분 | 차트 캔들 | 호가 후처리 | |------|-----------|-------------| | `--apply-best` (기본 미사용) | 차트 축 | 호가 자동 각인 아님 | | 웹 Optuna 「이 방 적용」 | 차트 + **8방 중 하나** (`build_combo_env_patch`) | 켠 축만 ON, 끈 축 ENABLED=false | | `whipsaw` | 차트 + **111방** + 휩쏘 | 휩쏘는 8방 밖 | | 구 upto `entry/exit/stop` | 별칭 → `e` / `ex` / `exs` | 하위호환만 | **8방 ≠ 표 5열.** 8 = 진입×익절×손절(2³). 예전 UI의 「기본·진입·익절·손절·휩쏘」5열 누적은 레거시. 후처리 **재실행만** 하면 JSON만 갱신. DB는 안 바뀜. --- ## 5. 웹 표기 `out_data["orderbook_recommend"]` · `postprocess_topn.postprocess_by_anchor` · `postprocess_consensus`. ### 5-1. 앵커별 8방 표 각 Top5 「상세」 아래 **호가 8방** 표 + 방마다 「이 방 적용」. 휩쏘는 8방 밖 별도 행. | 방 | 켜진 축 | |---|---| | 000 | 타점만(호가 OFF) | | 100 / 010 / 001 | 1축 | | 110 / 101 / 011 | 2축 스택 | | 111 | 진입+익절+손절 | ### 5-2. 합의(consensus) — 8방 기준 (2026-08-17~) 상세 위 **`합의(gated+mode)`** 한 줄: - 사후합격 Top5 + mode_combo 앵커의 **8방 결과**만 모음 (stable·live 제외) - **median PnL이 가장 높은 방 1개** 선택 (동일 방 내 파라미터는 median) - 예: `호가 방: 011 익절+손절 · 5앵커 · PnL … · WR …` - 구 JSON(8방 없음)이면 축분리 median 폴백 + 「후처리 재실행 권장」 휩쏘·다단트레일 합의는 예전과 동일(median/최빈). **8방에 포함되지 않음.** ### 5-3. 레거시(정리·미삭제) | 항목 | 상태 | |------|------| | `OPTUNA_OB_AXIS_TRIALS`(500) | 8방 미사용 잔여키 | | `entry`/`exit`/`stop` JSON 중첩 | 구 JSON·apply 호환용 | | 모멘텀 `pattern_*`·시가컷 | 그리드/UI 잔여(실매 TRIGGER와 별축) | | `docs/layered_exit_design.md` | 옛 설계서 → `docs/호가.md` 참고 | | `remove/legacy_standalone_bots/` | 비활성 보관 |