Files
kis_trader/docs/호가.md

449 lines
22 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 호가.md — 진입 필터 · 익절 지정가 · IOC(13) · 수익구간 호가매도 · 손실구간 호가매도
이 문서는 대화·코드·DB 기준으로 **호가 관련 기능을 역할별로 구분**해 정리한다.
이름이 비슷해도 **서로 다른 스위치**이므로 혼동하지 말 것.
아래에서는 **L3 / SL-OB 같은 줄임말을 쓰지 않고** 한글로 푼다.
---
## 0-0. 「호가 쌓기」는 설계가 아니다 (헷갈림 방지)
**DB에 호가 한 장씩 넣는 것(저장)은 이미 돌아가는 수집 기능이다.**
새 매매 로직·새 설계 항목이 **아니다.**
| 말 | 진짜 뜻 |
|----|---------|
| “호가 INSERT / 쌓기” | 봇이 장중 호가를 `ws_orderbook` / `ls_ws_orderbook` 에 **기록**하는 중 (지금 하고 있음) |
| “필터·호가매도 끄고 쌓기만” | **끄는 건 매매 스위치**다. 저장은 켠 채, **매수 막을지 / 호가로 팔지** 스위치만 OFF |
| 설계에 적어 둔 이유 | “저장이 새 기능”이 아니라 **스위치 켜서 실험하지 말자**는 **운영 메모** |
초등 비유:
일기장에 날씨를 매일 적는 것 = **쌓기(이미 함)**.
일기 보고 “비 오면 우산 사기” 규칙을 켜는 것 = **필터·호가매도 ON**.
규칙은 아직 끄고, 일기만 모으자는 뜻이었다.
### 2026-08-03 장일 확인 (틱 동기)
| 테이블 | 오늘 | 방식 | 판정 |
|--------|------|------|------|
| `ls_ws_orderbook` (`ls_uh1`) | **약 274만 행** / 88종목 | 체결 1건 ≈ 호가 1장 (비율 ≈ **0.999**) | **틱 동기화로 쌓임 ✅** |
| `ws_orderbook` (`kiwoom_0d`) | **약 12.5만 행** / 38종목 | 간격 중앙값 **약 3초** | 연속 저장 ✅ · **틱 1:1은 아님** |
| `ws_orderbook` (`filter_eval`) | 29행 | 진입 판정 순간 1장 | 필터 판정 로그용 |
모멘텀 실매 매수 **오늘 0건** (유니버스 이슈) → 매도쪽 측정 스크립트는 **오늘 모수 없음**.
최근 모수: **2026-07-31** 모멘텀 7건 + 키움 호가 (§4 측정).
---
## 0-1. 운영 메모 (스위치 OFF · 저장은 ON)
1. **호가 저장** — 이미 ON. 장중 행 수만 가끔 확인하면 됨.
2. **매수 호가필터** `*_ORDERBOOK_FILTER_ENABLED` = **OFF 유지** (아직 실험 금지)
3. **수익구간 호가매도** `MOMENTUM_EXIT_OB_ENABLED` / `BREAKOUT_EXIT_OB_ENABLED` = **OFF 유지**
4. **손절호가** `MOMENTUM_STOP_OB_ENABLED` / `BREAKOUT_STOP_OB_ENABLED` = **OFF 유지** (코드 배선됨 · 켜기 전 측정)
5. 데이터가 모이면
- 매수필터: 탈락 사유 비율 보고 쓸지 결정
- 수익구간 호가매도: `scripts/measure_ob_exit_early_fire.py` 재측정
- 손실구간 호가매도: 손실·손절 구간 측정 후 구현 여부
6. **Optuna TPE**: 위 스위치들 **당분간 그리드에 넣지 말 것** (§8)
실매·백테는 스위치 OFF면 **예전과 동일**. 저장만 계속된다.
---
## 0. 한눈에 구분
| 구분 | 언제 | 하는 일 | 대표 키 | 상태 |
|------|------|---------|---------|------|
| **호가 저장(쌓기)** | 장중 항상 | DB에 호가 기록 | `LS_WS_ORDERBOOK_SAVE` / `WS_ORDERBOOK_SAVE_ENABLED` 등 | **이미 동작 중** · 설계 아님 |
| **매수 호가필터** | 사기 직전 | 호가 나쁘면 **안 삼** | `{전략}_ORDERBOOK_FILTER_ENABLED` | 코드 있음 · 운영 OFF |
| **익절 호가 ON** | 이미 매도 신호 난 뒤 | 익절을 **지정가**로 냄 | `SELL_USE_ORDERBOOK_ON_PROFIT` | 운영 ON |
| **매도 시장가 IOC(13)** | 시장가로 팔 때 | 실전만 13 | `USE_MARKET_IOC_SELL` | 운영·코드 분리 |
| **수익구간 호가매도** | 들고 있을 때 **이득 난 뒤** | 사려는 사람 줄면 **미리 이익 실현** | `MOMENTUM_EXIT_OB_*` / `BREAKOUT_EXIT_OB_*` | 코드 있음 · **기본 OFF** |
| **손실구간 호가매도** | 들고 있을 때 **손해 난 뒤** | 사려는 사람 줄면 **큰 손절 전에 먼저 나옴** | `MOMENTUM_STOP_OB_*` / `BREAKOUT_STOP_OB_*` | **배선 완료 · 기본 OFF** |
거래내역 **「매수호가」** = 살 때 근처 · **「매도호가」** = 팔 때 근처. 서로 다른 칸.
### 수익구간 호가매도 vs 손실구간 호가매도 (초등)
둘 다 “호가판에 사려는 사람이 확 줄었다”를 본다.
**언제 쓰느냐**만 다르다.
| | 수익구간 호가매도 | 손실구간 호가매도 |
|--|------------------|------------------|
| 내 장부 | **이미 조금 이득**일 때만 | **이미 조금 손해**일 때만 |
| 하는 일 | “이득 났는데 분위기 깨지면 이익 챙기고 나감” | “손해인데 분위기 더 깨지면, −몇% 손절선까지 안 가고 먼저 나감” |
| −몇% 손절선 | **안 건드림** | **공식은 그대로** · 그 **앞에서** 따로 한 번 더 봄 |
| 지금 | 코드 있음, 스위치 OFF | 글만, 코드 없음 |
| 파람서치(TPE) | **당분간 안 넣음** | **당분간 안 넣음** |
---
## 1. 매수 호가필터 (진입)
### 역할
- TRIGGER 단계에서 스프레드·매수/매도 잔량비·얇은 호가·매도벽 등으로 **매수 차단**.
- **청산 신호가 아님.**
### 키 (전략별)
글로벌 `ORDERBOOK_*` 수치 폐기 → 전략 prefix만 사용.
- `SCALP_ORDERBOOK_FILTER_ENABLED`
- `MOMENTUM_ORDERBOOK_FILTER_ENABLED`
- `BREAKOUT_ORDERBOOK_FILTER_ENABLED`
- `TAIL_ORDERBOOK_FILTER_ENABLED` (SHORT → TAIL)
임계 예: `*_ORDERBOOK_MAX_SPREAD_PCT`, `*_MIN_BID_ASK_RATIO`, `*_ENTRY_BID_LEVELS` 등.
### 코드
- 판정 공통: `kis_trader/engine/orderbook_filter.py`
- env: `kis_trader/engine/orderbook_env.py`
- 웹: 예) 모멘텀 「호가필터 ON」(`mom_ob_filter`) — **이 백테 회차 진입 필터**
### 왜 전략별로 갈라졌나
스캘프·모멘텀·돌파·꼬리는 호가 의미가 달라 **ON/OFF·임계를 전략마다** 둔다.
판정 함수는 공유, **설정 키만** 분리.
### 수집 vs 필터
- `KIWOOM_WS_ORDERBOOK_ENABLED` — 호가 WS 수신
- 시계열 `kiwoom_0d` / LS `ls_ws_orderbook` — 저장(필터 OFF여도 저장 가능)
- 필터 ON = 그 스냅으로 **매수 탈락 적용**
### 켜면 매매가 확 줄어드는 이유 (조건식 탓 아님)
- HTS/조건식 = “살 만한 **이야기**(타점)” 선별
- 호가필터 = “지금 이 순간 **대기표가 들어가기 좋은가**” 추가 게이트
- 모멘텀·돌파류는 급등·얇은 종이 많아, 통과 직후 호가가 **스프레드 큼 / 살힘 약함 / 매도벽**인 경우가 흔함
- 거래내역 「매수호가」에 **간격큼·살힘 0.1x대**가 보여도 **데이터가 이상한 게 아니라** 그 타점 유동성이 그런 것
→ “조건식이 잘못 뽑았다”로 단정하지 말 것. **유동성 게이트가 한 겹 더 있어서** 건수가 줄어든다.
### RAM(실매) vs DB 3초(백테)
| | 실매 필터 ON | 백테 필터 ON |
|--|--------------|--------------|
| 보는 것 | **RAM 최신** (`get_orderbook_snapshot`) | DB 스냅 / `filter_eval` 재생 |
| 스냅 없음 | **안 막음**(통과) | 재생·본체 없으면 그 타점 못 탐·탈락 재현 |
DB ~3초 저장은 **백테·표시용**. 실매 차단은 RAM.
“3초라서 가짜로 막는다”보다 **그 시각 근처 호가가 이미 나빴다**에 가깝다.
### 임계값(0.45 · 0.85 …) — 업계 표준 아님
`orderbook_env.py` **프로젝트 시드/시작값** (Optuna·웹에서 변경 가능). “보편적으로 다들 0.45”가 **아님**.
| 기본 | 의미 | 체감 |
|------|------|------|
| 스프레드 **0.45%** | `(askbid)/mid` 상한 | 중소형·급등에서 **자주 걸림** |
| 잔량비 **0.85** | 상위 N호가 매수÷매도 | 살 쪽이 거의 비슷해야 통과 |
| 깊이 **1.2** | 필요수량 ×1.2 ≤ 매수호가 합 | |
| 매도벽 **3.0** | 매도잔량 과다 컷 | |
AND라서 하나라도 깨지면 탈락 → 체감이 셈.
### 이 필터가 굳이 필요한가? → **필수 아님**
| 목표 | 선택 |
|------|------|
| 거래 수·백테 건수 유지 | **OFF** (현 운영 기본) |
| 얇은 호가·큰 갭 진입을 줄이고 싶다 | ON 또는 **임계 완화** |
| 조건식이 이미 유동성 좋은 종만 | 필터 체감↓ |
- **진입 필터** = 살까 말까
- **익절 호가 ON** = 이미 산 뒤 어떻게 팔까 (`SELL_USE_ORDERBOOK_ON_PROFIT`) — **다른 스위치**
호가가 안 좋게 찍힌다는 사실 자체가 “필터 필수” 근거가 아님.
안 좋은 호가에 **들어가느냐를 막을지** 선택일 뿐. 과하면 끄거나 숫자만 푼다.
### 키움 조건 vs LS 조건 (진입·수익구간 호가매도 공통)
- `kiwoom_condition` / `condition` → 호가 **키움 0D RAM** · DB `ws_orderbook`
- `ls_condition` → 호가 **LS UH1 RAM** · DB `ls_ws_orderbook` (키움으로 메우지 않음)
수익구간·손절호가도 같은 스냅샷 API를 탐. **전략 범위: 모멘텀(키움) + 돌파(LS)** · 둘 다 기본 OFF. (진입 필터는 전 전략 키 있음).
---
## 2. 익절 「호가 ON」— 지정가 매도 (실행)
### 역할
청산 **판정(래칫·어깨·트레일)이 이미 난 뒤**, 주문을 **어떻게 내는지**.
| 스위치 | ON | OFF / 호가 없음 |
|--------|----|-----------------|
| `SELL_USE_ORDERBOOK_ON_PROFIT` | 익절·어깨·트레일 → 매수1호가 **지정가(`ORD_DVSN=00`)** · 잔량 부족 시 **대기** | 같은 익절 신호 → **시장가** |
**손절 · 긴급 · 장마감(EOD)** → 이 스위치와 무관, **항상 시장가**.
### 운영 값 (확인 시점 기준)
저장: `config_short`
| 키 | 값 | 의미 |
|----|----|------|
| `SELL_USE_ORDERBOOK_ON_PROFIT` | **true** | 익절 지정가 경로 ON |
| `SELL_ORDERBOOK_BID_LEVELS` | 2 | 매수 1~2호가 잔량 합 검사 |
| `SELL_ORDERBOOK_DEPTH_MULT` | 1.5 | 필요 잔량 = 수량 × 1.5 |
### 코드
- `kis_trader/execution/order_manager.py` — 매도 전송 분기
- `kis_trader/execution/orderbook_sell.py` — 잔량·지정가 가격 산출
전 전략 공통(OrderManager 한 경로). 진입 필터처럼 전략별 키가 아님.
### UI
라이브 스키마에 진입 「호가필터 ON」은 잘 보이지만,
`SELL_USE_ORDERBOOK_ON_PROFIT`**스키마 전용 체크가 약하고 DB(`config_short`)·get_env로 동작**.
---
## 3. 매도 주문코드 13 — 시장가 IOC (실전만)
### 역할
**시장가 매도**를 낼 때의 `ORD_DVSN` 선택.
익절 지정가(00)와는 별개.
| 환경 | 시장가 매도 코드 |
|------|------------------|
| **모의** | 항상 **`01`** (IOC 13 미지원 → 코드에서 고정) |
| **실전** + `USE_MARKET_IOC_SELL=true` | **`13`** (시장가 IOC) |
| **실전** + false | **`01`** (일반 시장가) |
매수용은 별도: `USE_MARKET_IOC` (실전 매수 13 / 모의 01).
### 코드
`kis_trader/execution/kis_client.py`
- `sell_market_order` / `uses_market_sell_ioc()`
- `sell_limit_order` → 항상 `00`
### 운영 UI
`live_config_schema`: 「매도 시장가 IOC」=`USE_MARKET_IOC_SELL`
### 흐름 요약
```
익절 신호
├─ SELL_USE_ORDERBOOK_ON_PROFIT ON + 잔량 OK → 지정가 00
└─ OFF / 호가없음 / 잔량실패 후 시장가
├─ 실전 + IOC ON → 13
└─ 모의 → 01
손절·긴급·EOD → 시장가 (위와 동일하게 실전 13 / 모의 01)
```
---
## 4. 수익구간 호가매도 (코드 있음 · 기본 OFF)
진입 필터·익절 지정가와 **다른 축**:
이미 산 뒤, **이득이 난 상태에서** “사려는 사람이 줄었다”면 **팔지 말지**를 본다.
### 초등으로
1. 주식을 샀다.
2. 가격이 조금 올랐다 (이득).
3. 호가판을 보니 “사고 싶다”는 줄이 확 짧아졌다.
4. 그때 **이익을 챙기고 나간다** = 수익구간 호가매도.
5. **아직 이득이 아니면** 이 규칙으로 안 판다. (그건 손실구간 쪽)
### 왜 맨 위에 두면 안 되나
- 장 초반·급등 초입은 원래 파는 사람이 많다 → “분위기 끝”으로 **오해**하기 쉬움
- 사자마자 팔면 수수료만 나고 기회 날림
**맨 위(1순위) 금지.** 래칫·어깨 **다음**, % 손절 **앞**.
측정(실매 매수 + `ws_orderbook`, 예: 2026-07-27 모멘텀):
- 가드 없이 순간만 보면: 조기 신호 **많음**
- 이득·최소보유 가드 후: **크게 줄어듦**
※ 이 %는 **수익률이 아님** = “산 뒤 N분 안에 이 신호가 뜬 건수 비율”
### 합의된 매도 순서
```
래칫 → 어깨 → 수익구간 호가매도 → 손실구간 호가매도 → % 손절 → 트레일 → …
```
- 코드: 어깨 다음 · 손절 전 = 수익구간(`호가컷`) + 손절호가 · **기본 OFF**
- 모멘텀=키움 호가 · 돌파=LS 호가 (교차 메우기 금지)
- % 손절은 **가격 하나만**. 호가를 손절 % 숫자에 섞지 않음.
### env 키 (모멘텀=키움 · 돌파=LS · 수익구간)
| 키 | 기본 | 역할 |
|----|------|------|
| `MOMENTUM_EXIT_OB_ENABLED` / `BREAKOUT_EXIT_OB_ENABLED` | **false** | 켜기/끄기 |
| `*_EXIT_OB_RATIO_MIN` | 0.4 | 사려는/팔려는 비율 이동평균이 이하면 “줄었다” |
| `*_EXIT_OB_MA_WINDOW` | 5 | 몇 장 평균 볼지 |
| `*_EXIT_OB_MIN_PROFIT_PCT` | 0.005 (+0.5%) | **이만큼 이득일 때만** |
| `*_EXIT_OB_MIN_HOLD_BARS` | 3 | 산 지 최소 N분 |
등록: `database.py` (`config_momentum` / `config_breakout`) · defaults → `exit_ob_*`.
웹 모멘텀·돌파 탭에 컨트롤 있음. **ENABLED 기본 false 유지.**
### 발동 조건 (모두 만족)
| 조건 | |
|------|--|
| 스위치 ON | |
| 비율 이동평균 < 기준 | 스냅 부족 → **안 함** |
| 최소 이득 | |
| 최소 보유 | |
### 배선 상태 (2026-08)
실매·백테 OR 히스토리 주입 ✅ · 웹 ✅ · Optuna **미포함**(§8).
OFF면 예전과 동일.
### 측정 스크립트 (매도쪽 · 필터 켜기 전)
`scripts/measure_ob_exit_early_fire.py`
- 실매 매수 + 실매 호가 테이블
- A) 맨 위+가드없음 / B) 맨 위+가드 / C) 3순위+가드(현 설계)
- 예: `--date 2026-07-31 --ob-table ws_orderbook`
- **2026-08-03**: 모멘텀 매수 0건 → 측정 불가 (호가는 쌓여 있음)
### 2026-07-31 매도쪽 한 줄 (키움 `ws_orderbook`)
모멘텀 7건 전부 호가 있음.
A 28.6% → B/C 14.3% (가드가 핵심).
같은 날 `ls_ws_orderbook`은 그 종목들 스냅 0 → LS로 못 재현 (모멘텀=키움 조건 쪽).
### 전략 범위
파일럿 **모멘텀만**. 진입 필터 키와 **혼용 금지**.
---
## 4-1. 손실구간 호가매도 (배선 완료 · 기본 OFF · 모멘텀+돌파)
수익구간과 **같은 호가 눈**, **반대 장부**.
### 초등으로
1. 주식을 샀다.
2. 가격이 조금 떨어졌다 (손해).
3. 호가판에 사려는 사람이 확 줄었다.
4. 3% 같은 **큰 손절선까지 기다리기 전에** 먼저 나온다.
5. **이득 중이면** 이 규칙으로 안 판다. (그건 수익구간)
### 왜 만드나
% 손절만 있으면, 호가가 이미 무너진 **뒤에** 가격이 손절선에 닿아 **더 나쁜 가격**에 팔 수 있음.
수익구간 규칙만 있으면 **손해 날 때**는 안 도와줌.
### 원칙
1. % 손절 **숫자는 그대로**. 이 규칙은 **앞에서 한 번 더 보는 것**뿐.
2. **손해일 때만.**
3. 맨 위 금지 — 래칫·어깨 다음, % 손절 직전.
4. 호가 스냅 없으면 **안 함** (가격봉으로 호가 지어내기 금지).
5. 나갈 때는 **시장가/IOC**(도망). 익절 지정가「호가 ON」과 다름.
6. 기본 **OFF**. 측정 → 승인 → 코드 → ON.
### 목표 순서
```
1 래칫
2 어깨
3 수익구간 호가매도 ← 이득 + 호가 줄음
4 손실구간 호가매도 ← 손해 + 호가 줄음 ★배선·기본 OFF
5 % 손절 ← 가격만
6 트레일 · 시간 · …
```
### env (모멘텀 · 배선됨) — 한글 뜻
| 키 (영문) | 한글 이름 | 기본 | 한줄 |
|-----------|-----------|------|------|
| `MOMENTUM_STOP_OB_ENABLED` / `BREAKOUT_STOP_OB_ENABLED` | 손절호가 켜기 | **false** | 끄면 이 규칙 전부 무시 |
| `MOMENTUM_STOP_OB_RATIO_MIN` | 호가 붕괴 기준 | 0.4 | 총사÷총팔 평균이 **이보다 작으면** “사람 줄었다” |
| `MOMENTUM_STOP_OB_MA_WINDOW` | 평균 몇 장 | 5 | 위 비율을 **최근 5장** 평균내서 봄 (순간 깜빡임 방지) |
| `MOMENTUM_STOP_OB_MIN_LOSS_PCT` | 최소 손해 폭 | 0.003 (0.3%) | **이만큼은 이미 손해**여야 발동 (수익 중엔 안 씀) |
| `MOMENTUM_STOP_OB_MIN_HOLD_BARS` | 최소 보유 분 | 2 | 산 지 **2분 전**엔 안 씀 |
DDL·컬럼 COMMENT: `scripts/sql/config_momentum_ob_column_comments.sql` · `scripts/sql/config_breakout_ob_column_comments.sql`
### 하드 손절 4%일 때 언제 나감? (손절호가 ON 가정)
1. **산 지 2분 미만** → 손절호가 **안 함**. (4% 하드만 가능)
2. **2분 이상** + 현재가 **0.3% 이하** + OR평균 **< 0.4** → 사유 **`손절호가`** 로 **즉시** 시장가 (하드 4%까지 **안 기다림**)
3. 호가는 안 무너졌는데 가격만 **4%** → 예전처럼 사유 **`손절`**
4. 지금 DB 기본은 **ENABLED=false** → 2번은 아예 없고 **4% 하드만**.
**“얼마나 빨리”** = “0.3%에 OR만 깨지면 그때”. 4%까지 버티는 규칙이 아님.
OR 5장 채우는 시간: LS 틱동기면 체결 몇 번(초 단위) · 키움 ~3초 저장이면 대략 **십수 초**면 충분. 최소보유 **2분**이 보통 더 긴 병목.
**삼성전자급 두꺼운 호가**: 평소 OR이 0.4 아래로 잘 안 떨어짐 → 손절호가가 **거의 안 울릴 수 있음**. 진짜 수급 붕괴·급락 구간에서야 0.3%~4% 사이에서 선제. 얇은 중소형에서 체감이 큼.
사유 문자열: **`손절호가`** (수익구간의 `호가컷`과 구분 · 시장가 긴급).
### 상태
| 항목 | |
|------|--|
| 설계 | ✅ |
| 코드·DB·웹 | ✅ 2026-08-03 배선 |
| 기본값 | **OFF** (켜기 전 측정 권장) |
| TPE | **안 넣음** |
### 측정 (호가 쌓인 뒤 · 모멘텀 매수가 있는 날)
1. 손실→−%손절(또는 큰 손실) 건 중, 손절 **직전**에 이미 호가가 줄었던 비율
2. 손해였다가 회복한 건에서 이 규칙이 **너무 일찍** 나갔을 비율
→ 측정 후 **ON 여부** 결정 (지금 기본 OFF).
---
## 5. 데이터 · UI 참고
| 항목 | 내용 |
|------|------|
| 호가 테이블 | `ws_orderbook` (키움), `ls_ws_orderbook` (LS) |
| 테이블에 **있는** 것 | `best_bid`/`best_ask`, `total_bid_qty`/`total_ask_qty`, `bid_qty_l3`/`ask_qty_l3`**원본** |
| 테이블에 **없는** 것 | `0.45%`·살힘·OR 같은 **계산된 %/비율** — DB 컬럼이 아님 |
| 거래내역 「매수호가」「매도호가」 | `trade_orderbook_enrich.py`가 매수/매도 시각 근처 스냅을 붙인 뒤, **웹 JS가 원본으로 계산·색칠** |
| 기준 숫자(시드) | 매수: 간격≤0.45% · 살힘≥0.85 / 매도 OR: ≈0.40 (수익구간 호가매도 기본) — 업계 표준 아님 |
| LS 오늘 | **틱 동기** (체결≈호가 1:1) |
| 키움 오늘 | 연속 저장 · 간격 **약 3초** (틱 1:1 아님) |
### UI 칸 — 이상(높을수록 / 낮을수록)
| 칸 | 지표 | 이상 | 초등 |
|----|------|------|------|
| **매수호가** | 가격간격 % | **↓ 낮을수록** | 사·팔 가격이 가까울수록 들어가기 쉬움 |
| **매수호가** | 살 힘 (위3칸 사÷팔) | **↑ 높을수록** | 사겠다는 대기가 많을수록 버팀 |
| **매도호가** | OR (총사÷총팔) | **↑ 높을수록** 수급OK · **↓ 낮으면** 약함 | 팔 때 사려는 사람이 많으면 버팀, 적으면 무너짐 |
| **매도호가** | 가격간격 % | **↓ 낮을수록** | 팔 때도 간격 작을수록 체결 덜 미끄러짐 |
열 헤더: `↓간격 ↑살힘` / `↑OR ↓간격` (마우스 올리면 상세).
---
## 6. 하지 말 것 (요약)
1. 매수필터 · 익절지정가 · 수익구간호가매도 · 손실구간호가매도를 **한 스위치로** 취급하지 말 것.
2. “호가 쌓기”를 **새 매매 설계**로 착각하지 말 것 — **이미 있는 저장**.
3. 호가를 % 손절 **공식에 섞지** 말 것.
4. 호가매도를 **1순위**에 두지 말 것.
5. 스냅 없이 OHLC로 호가 **지어내기** 금지.
6. 모의에 ORD_DVSN=13 강제 금지.
7. 측정 없이 ENABLED=true 금지.
8. 데이터 없이 TPE에 넣지 말 것 (§8).
9. 거래대금·시총회전 **만**으로 손절 만들지 말 것.
---
## 7. 관련 파일
| 파일 | 내용 |
|------|------|
| `kis_trader/engine/orderbook_filter.py` | 매수 호가필터 |
| `kis_trader/engine/orderbook_env.py` | 전략별 진입 env |
| `kis_trader/execution/orderbook_sell.py` | 익절 지정가·잔량 |
| `kis_trader/execution/order_manager.py` | 매도 실행 분기 |
| `kis_trader/execution/kis_client.py` | 00/01/13 주문 |
| `kis_trader/backtest/trade_orderbook_enrich.py` | 거래내역 호가 표시 |
| `kis_trader/engine/momentum_hts_logic.py` | 수익구간·손절호가 판정 (모멘텀·돌파 공용) |
| `kis_trader/engine/momentum_engine.py` | `exit_ob_*` defaults |
| `kis_trader/engine/momentum_env_keys.py` · `BREAKOUT_*_OB_*`(database/config_breakout) | 전략별 env |
| `kis_trader/strategies/momentum.py` | 실매 OR append |
| `scripts/measure_ob_exit_early_fire.py` | 매도쪽 조기신호 측정 |
| `docs/layered_exit_design.md` | 옛 설계서 (현행은 본 MD §4·§4-1) |
| `docs/호가.md` | 본 문서 |
---
## 8. Optuna / TPE 넣을까?
### 결론 (당분간) — **넣지 않음**
매수필터 · 수익구간 호가매도 · 손실구간 호가매도 모두.
켜기/끄기를 TPE에 넣으면: 끈 구간=예전 점수, 켠 구간=호가 날씨에 흔들려 **순위가 엉망**이 된다.
나중에라도: 호가 충분 + 측정 숫자 + 사용자가 **전용 mode**를 말할 때만.
그때도 본체 `tpe`/`fine`이 아니라 **좁은 mode**에서 숫자만.
### 지금
쌓여 있는 호가로 **측정** → (승인) 코드 → OFF 스모크 → ON 여부. **TPE는 그 다음.**
---
## 9. env 등록 주의
신규 키는 `database.py` ENV 등록 + `get_env_from_db` 재조회 검증.