Files
kis_trader/docs/옵투나.md
Your Name 1387fbdf47 feat(옵투나): score·min_trades·후처리 재탐색 및 웹 job 개선
PnL/(MDD+ADD) score·legacy 정렬·거래일×min_trades 게이트를 공통화한다.
후처리 ob_modes·study store·4전략 TPE 순차 스크립트와 문서를 갱신한다.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-28 16:46:27 +09:00

10 KiB
Raw Blame History

Optuna 파라미터 탐색 및 호가 수급 최적화 구조 가이드 (옵투나.md)

이 문서는 현재 코드 기준 Optuna TPE·호가 스터디 스위치·후처리를 정리한다.
관련: docs/호가.md §8 · optuna_tpe_common.py · optuna_breakout_tpe_space.py · optuna_postprocess_topn.py · optuna_orderbook_recommend.py

최종 갱신: 2026-08-28 (구 2026-08-15 「Stage1=호가 축 없음」서술은 폐기 — 아래 §1이 진실)


1. 현재 구조 (코드 진실 · 2026-08-28)

1-0. 한 줄

구분 무엇을 하냐
본 TPE (Stage 1) 차트 축 + (기본) 진입 호가·휩쏘를 trial에서 같이 평가
사후 8방 (Stage 2) 본 TPE에 호가축이 켜져 있으면 기본 스킵. 구 타점-only 모드일 때만 자동

OPTUNA_TPE_INCLUDE_ORDERBOOK 기본 true (optuna_tpe_common.optuna_tpe_include_orderbook).
→ 본 trial이 이미 호가를 쓰므로, 사후 8방으로 또 걸러 “성적 사기” 나지 않게 _run_ob_whipsaw_full()기본 OFF.
강제만: OPTUNA_POST_FORCE_OB_WHIPSAW=true.

구 문서의 「Stage1=캔들만 · 호가ON/OFF 넣지 않음」은 옛 설계. 지금은 기본이 반대다.

[기본 경로]
  Stage 1  TPE — 차트 + 호가 ON/OFF(또는 돌파=스터디 고정) + 임계값 + (전략별) 휩쏘
  Stage 2  사후 8방 — INCLUDE_ORDERBOOK=true 이면 생략 (FORCE 만 예외)

[구 타점-only]
  OPTUNA_TPE_INCLUDE_ORDERBOOK=false
  → Stage 1 차트만 · Stage 2 사후 8방 기본 ON

1-1. 전략별 호가 ON/OFF 넣는 방식 (핵심)

문제: 한 스터디에 호가 ON/OFF를 categorical로 섞으면, ON은 거래수가 줄고 TPE가 OFF만 편애하기 쉽다.
(거래수·PnL 랭킹이 OFF에 유리 → ON 임계값은 사실상 미탐색)

전략 본 TPE 호가 방식 코드
돌파 스터디 스위치 --orderbook-filter off|on · 웹 ob_modes · 한 스터디에 ON/OFF 안 섞음 · ON 스터디만 스프/잔량/벽 축 optuna_breakout_tpe_space.py
꼬리 trial categorical _orderbook_filter_enabled [False,True] + 임계값 매 trial suggest_orderbook_entry_tpe
모멘텀 동일 categorical 위와 같음 optuna_momentum_tpe_space.py
스캘프 동일 categorical 위와 같음 optuna_scalping_tpe_space.py

돌파 손절모드(fixed/atr)도 스터디 스위치(trial 축 아님). 웹은 손절×호가 최대 4순차.

꼬리 진입모드(align / limit_atr)도 스터디 고정·순차 (한 TPE에 categorical 혼입 없음) — §3.

1-2. 분리 vs trial 수 늘리기 (결과 동일 여부)

한 스터디 N trial (ON/OFF 섞음) 스터디 분리 (off N + on N)
TPE 예산 OFF에 몰림 ON·OFF 각자 탐색
best 대개 OFF 쪽 OFF best / ON best 따로 비교
동등성 분리 2×(N/2) 의도적으로 다른 실험

400번 섞어 돌리기 ≠ off 200 + on 200.
숫자만 늘려도 ON 공간(임계값)은 거의 안 볼 수 있다.
돌파처럼 분리가 맞고, 꼬리·모멘텀·스캘프도 같은 편향이 난다 (아직 categorical).

권장:

  1. 돌파와 동일 — 전략별 off / on 스터디 스위치 (또는 웹 순차)
  2. 또는 OPTUNA_TPE_INCLUDE_ORDERBOOK=false → 차트만 + 사후 8방 (구 Stage1/2 문서 경로)

2. 진입 후처리 격자 (사후 8방 · Stage 2)

ensure_optuna_gate_env_defaultsOPTUNA_OB_*.
본 TPE 호가축 OFF일 때만 기본 자동 실행 (§1-0).

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.

구 JSON만 Stage 2 강제:

# INCLUDE_ORDERBOOK=true 여도 강제하려면
# OPTUNA_POST_FORCE_OB_WHIPSAW=true 또는 rerun 스크립트 경로 확인
python3 -u kis_trader/backtest/optuna_rerun_postprocess.py \
  --result-json kis_trader/backtest/results/optuna_<전략>_tpe_<TS>.json
# --apply-best 없음. 실매 DB 안 바뀜.

후처리 자동 실행 게이트 (kis_study_trials / --study-trials):
끝난 기준 = 시도 수 COMPLETE + PRUNED + FAIL ≥ 목표.
tp_max < tp 같은 pruned도 시도로 친다. COMPLETE만 세서 스킵하지 않음 (2026-08-21).

백테/옵투나 호가·틱 3차 LS 나이 = LIVE_FEED_FALLBACK_MAX_AGE_SEC(기본 3초).
trigger_snapshot_loader / BT_TICK_LS_THIRD_FALLBACK — 실매 RAM 폴백과 동일 env.


3. 꼬리 TPE 진입모드 (웹 체크)

엔진 실매 기본은 TAIL_ENTRY_MODElimit_atr.
Optuna TPE는 진입을 탐색하지 않고 스터디마다 고정.

웹 Optuna 탭: align / limit_atr 체크.

  • 기본: align만.
  • 둘 다: 스터디 2개 순차 (한 TPE에 categorical 혼입 없음). --apply-best 없음.

CLI: --entry-mode align|limit_atr · 순차 TAIL_OPTUNA_ENTRY_MODES="align limit_atr".


4. 실매 DB 적용 분리

구분 차트 캔들 호가
--apply-best (기본 미사용) 차트 축 호가 자동 각인 아님
웹 「이 방 적용」(사후 8방이 있을 때) 차트 + 8방 중 하나 켠 축만 ON
웹 TopN 「적용」upto=full 본 trial 타점·익절·손절·호가·휩쏘 유지 사후 8방으로 OFF 덮어쓰기 안 함
whipsaw 차트 + 휩쏘 8방 밖
구 upto entry/exit/stop 별칭 → e / ex / exs 하위호환만

8방 ≠ 표 5열. 8 = 진입×익절×손절(2³).
후처리 재실행만 하면 JSON만 갱신. DB는 안 바뀜.


5. 웹 표기

out_data["orderbook_recommend"] · postprocess_topn · tpe_includes_orderbook · post_run_ob_whipsaw.

5-1. 앵커별 8방 표 (사후가 돌았을 때만)

각 Top5 「상세」 아래 호가 8방 표 + 방마다 「이 방 적용」. 휩쏘는 8방 밖 별도 행.

켜진 축
000 타점만(호가 OFF)
100 / 010 / 001 1축
110 / 101 / 011 2축 스택
111 진입+익절+손절

본 TPE 호가축 ON이면 보통 이 표가 비거나 생략되고, Top 행에 본 trial 호가 ON/OFF·임계가 표시된다.

5-2. 합의(consensus) — 8방 기준

상세 위 합의(gated+mode) 한 줄 (사후 8방이 있을 때):

  • 사후합격 Top5 + mode_combo 앵커의 8방 결과만 모음 (stable·live 제외)
  • median PnL이 가장 높은 방 1개
  • 구 JSON(8방 없음)이면 축분리 median 폴백 + 「후처리 재실행 권장」

5-3. 돌파 웹 스위치

Optuna 탭: 돌파 호가 off / on 체크(스터디 스위치). 손절 fixed/atr × 호가 → 최대 4순차.
study 이름 예: …_fixed_ob_off_… / …_atr_ob_on_….

5-4. 레거시(정리·미삭제)

항목 상태
OPTUNA_OB_AXIS_TRIALS(500) 8방 미사용 잔여키
entry/exit/stop JSON 중첩 구 JSON·apply 호환용
모멘텀 pattern_*·시가컷 그리드/UI 잔여
「Stage1=호가 축 없음」문구 폐기 — §1 참고
docs/layered_exit_design.md docs/호가.md

6. env 스위치 요약

기본 의미
OPTUNA_TPE_INCLUDE_ORDERBOOK true 본 TPE에 호가 축(꼬리·모멘·스캘 categorical / 돌파는 별도 스위치)
OPTUNA_TPE_INCLUDE_WHIPSAW true 본 TPE 휩쏘 축
OPTUNA_POST_RUN_OB_WHIPSAW true INCLUDE_ORDERBOOK=false 일 때 사후 8방
OPTUNA_POST_FORCE_OB_WHIPSAW false INCLUDE_ORDERBOOK=true 여도 사후 8방 강제
LIVE_FEED_FALLBACK_MAX_AGE_SEC 3 실매·옵투나 호가/틱 3차 나이
BT_TICK_LS_THIRD_FALLBACK true 옵투나 틱 3차 LS
PARAM_SEARCH_OPTUNA_N_JOBS 1 Optuna 병렬 고정 정수 (비율 아님)
OPTUNA_MIN_TRADES_PER_DAY 2 모멘·돌파·스캘 등: min_trades = 거래일×2
OPTUNA_TAIL_MIN_TRADES 1 꼬리만 탐색·gated 공통 min_trades (기간 무관)
OPTUNA_SCORE_MDD_ADD 10000 새 score 분모 MDD + ADD
OPTUNA_SCORE_MDD_FLOOR 10000 (구) score 분모 max(MDD, FLOOR) — sort_by=score_legacy
OPTUNA_SCORE_TRADE_SOFT_DAYS 2 soft_n 기본 = 하루최소건×이 값 (기본 2×2=4). OPTUNA_SCORE_TRADE_SOFT_N 이 있으면 그쪽 우선

6-1. min_trades · 일평균 · 승리식 (2026-08-28)

  • 웹 Optuna min_trades = resolve_optuna_min_trades꼬리=1 고정, 그 외 거래일×하루2. CLI --min_trades 직접 지정 시 유지.
  • 일평균 = total_pnl ÷ 기간 거래일 (period_daily_avg_pnl).

승리식 (전 전략 공통 · 웹 셀렉트)

화면 --sort-by
수익·낙폭·표본 (기본) score (PnL / (MDD + ADD)) × √(min(거래수, soft_n) / soft_n)
(구) PnL/MDD하한 score_legacy PnL / max(MDD, FLOOR) — 전략별 *_SCORE_MDD_FLOOR 또는 OPTUNA_SCORE_MDD_FLOOR
일평균 daily_avg PnL ÷ 거래일수
총손익 pnl PnL
  • 구 score 는 웹 승리식 (구) PnL/MDD하한 / CLI --sort-by score_legacy 로 선택.
  • 웹에 승률 단독 승리식 없음 (CLI win_rate만).
  • 이미 끝난 study는 옛 목적함수 → 새 study-name으로 다시 돌려야 새 식이 적용됨.