fix: 한투 호가 2키 전용, LS RAM 합집합, 분봉 쓰레기면 다음 소스 통째

메인 시세 41에 H0STASP0를 붙이는 폴백을 없앤다. MINIMAL과 무관하게
후보∪보유∪영구를 LS RAM에 붙인다. 그 분 틱이 없거나 봉끝 대비 늦으면
그 WS 봉을 버리고 2차·LS·REST 봉을 통째로 쓴다.

같은 파일에 직전 커밋 이후 쌓인 시세 폴백/ENV 키 정리도 포함된다.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Your Name
2026-08-19 22:09:03 +09:00
parent 6d2a706a48
commit d1dc274f0e
10 changed files with 2146 additions and 459 deletions

View File

@@ -17,6 +17,17 @@
**grep을 생략해도 되는 유일한 경우**: 주석/docstring 텍스트만 바꾸는 경우.
### 실매 코어 스모크 (중요 코드 수정 후 필수 1회)
엔진/호가/WS(구독·해제·spill·갭보정·freeze)/env/스키마를 고친 뒤에는 완료 보고 전:
```bash
python3 -u scripts/test_live_execution_validation.py
# 로그: logs/test_live_execution_validation_YYYYMMDD_HHMMSS.log
```
통과: `최종: 통과` + `👑 [최종 판정] 완결!`. 실패 시 고치고 1회만 재실행. 룰: `.cursor/rules/live-execution-validation.mdc`
---
## 🔍 수정 유형별 필수 grep 목록
@@ -59,7 +70,23 @@ grep -r "E_MIN_CHG_PCT" /home/hoon/kis_bot/kis_trader/engine/momentum_env_keys.p
호가 필터 나이: `WS_ORDERBOOK_FILTER_MAX_AGE_SEC`(기본 0=마지막 RAM) ≠ 저장 TTL `WS_ORDERBOOK_TICK_MAX_AGE_SEC`.
후처리 TPE 진입 격자: `OPTUNA_OB_ENTRY_SPREAD_*` / `RATIO_*` / `ASK_MULT_*` (`optuna_common.ensure_optuna_gate_env_defaults`).
꼬리 TPE 진입모드는 탐색 축이 아님(웹 체크 → 스터디 고정/순차 2회). `*_SKIP_HTS_SCAN_DUPES` true 금지.
꼬리 TPE 진입모드는 탐색 축이 아님(웹 체크 → 스터디 고정/순차 2회).
돌파 TPE 손절모드(fixed/atr)도 탐색 축이 아님(웹 체크 → 스터디 고정/순차 2회).
align 스터디는 `limit_atr_mult` 제외. fixed 스터디는 `atr_sl_*` 제외.
`*_SKIP_HTS_SCAN_DUPES` true 금지.
유령정리: `INQUIRE_PSBL_RVSECNCL_BEFORE_GHOST` · 잔고는 `hldg_qty`(보유)와 `ord_psbl_qty`(매도가능) 분리. 매도가능 0 ≠ ghost.
시세·호가 읽기 폴백 (실매=옵투나 같은 읽기):
- `LIVE_FEED_FALLBACK_MAX_AGE_SEC`(기본 3) = **그 틱의 체결시각(FID20/chetime) vs 이 서버 지금**. 1·2·3차 동일. 벤더끼리 시각 비교 금지.
- 분봉 쓰레기=`CANDLE_GARBAGE_FALLBACK`(기본 true). 그 분 그 소스 틱 0건이거나 전부 **봉 끝시각** 대비 읽기나이 초과면 그 WS 봉을 구멍 → 다음 소스 **봉 통째**. 한 봉 안 키움+한투 혼합 금지. 실매 링이 그 소스·그 분을 커버 못하면 유지.
- 한투 호가=`WS_ORDERBOOK_SAVE_KIS`: **2번째 앱키(`KIS_APP_KEY_OB_REAL`) 전용 세션만**. 키 없거나 start 실패 시 메인에 H0STASP0 붙이지 않음(시세 41 합산 금지).
- `LS_FEED_FALLBACK_SUBSCRIBE`(기본 true) → 후보보유영구grace 를 LS RAM 미러. **MINIMAL ON/OFF 무관** (`sync_targets` + split reconcile 둘 다). DB 틱 `should_persist_ls`(영구만) 이번 범위 밖.
- 키움 RAM/리스너/봉 skip = 읽기 나이. `ws_ticks` 적재는 기본 전부(`KIWOOM_TICK_LIVE_MAX_LAG_SEC=0`). 같이 내리지 말 것.
- 시세 REST 키 = `KIWOOM_WS_FORCE_REAL`(기본 true) 실키. `_get_kiwoom_creds``KIS_MOCK` 모의키로 가면 안 됨 (8001).
- `LS_GAP_FILL_CANDIDATES` 기본 OFF.
- `LS_WS_TICK_SAVE` 기본 false = `ls_ws_ticks` INSERT 만 OFF. `_tick_recorder` 를 같이 끄면 호가 틱동기도 0건. `LS_WS_ALSO_HOGA` 기본 true(UH1 구독). `LS_WS_ORDERBOOK_SAVE` 기본 true(구독 종목). 호가필터 `FILTER_MAX_AGE=0` 을 저장 TTL 과 다시 합치지 말 것.
- 매수 루프 전 종목 REST 금지. 매도 4차만 키움 `ka10007` + `SELL_WS_STALE_REST_COOLDOWN_SEC`. 한투 60초 캐시 금지.
- MM 체결 알림: `시세: kiwoom(1차) | 호가: ls(3차)`.
**확인 후 수정해야 할 곳 체크리스트**:
- [ ] `database.py` — CREATE TABLE에 컬럼 추가
@@ -204,6 +231,13 @@ grep -rn "trigger_e_confirm" /home/hoon/kis_bot --include="*.py"
## 🚨 이 프로젝트 특이 사항 (절대 무시 금지)
### 키움 0B catch-up / REG refresh
```
KIWOOM_TICK_LIVE_MAX_LAG_SEC (기본 5): FID20 vs 수신시각 lag 초과 → RAM·봉·호가동기·ws_ticks 미반영.
KIWOOM_TICK_TIME_MAX_LAG_SEC (기본 120): 같은 FID20 가 이 초 이상일 때만 아침 동결 예외.
KIWOOM_WS_REG_REFRESH (기본 1): 0은 LOGIN 일괄 REG 첫 청크만. 장중 추가 REG는 항상 1.
```
### SKIP_HTS_SCAN_DUPES 규칙
```
`*_SKIP_HTS_SCAN_DUPES` 는 사용자가 언급하기 전까지 false 유지.
@@ -231,11 +265,16 @@ database.py의 CREATE TABLE 컬럼에 있는 키 → 해당 config_* 테이블
database.py의 CREATE TABLE에 없는 키 → env_config_ext (key-value 테이블)
새 env 키 추가 시 두 경로 중 어디에 저장될지 확인 필요.
Optuna 후처리(실매 엔진 비영향): OPTUNA_POST_TOP_N / INCLUDE_MODE / INCLUDE_LIVE /
OB·WHIPSAW trial 수 · OPTUNA_OB_AXIS_TRIALS · 진입/익절/STOP 탐색 범위 —
OB·WHIPSAW trial 수 · OPTUNA_OB_COMBO_TRIALS_* · OPTUNA_OB_AXIS_TRIALS · 진입/익절/STOP 탐색 범위 —
ensure_optuna_gate_env_defaults → env_config_ext.
모듈: kis_trader/backtest/optuna_postprocess_topn.py · optuna_orderbook_recommend.py
· optuna_rerun_postprocess.py (구 JSON 「이 잡 후처리 재실행」)
후처리 앵커: gated TopN + stable TopN(표/적용) + mode + live(참고). 합의·과적합 가점은 gated+mode만.
웹 Optuna: 학습/gated/stable Top5 행에 안정점수(↑·만점없음·원) + 과적합%(↓·0~100). 1위 비교표·mode_combo 실측행은 표시 안 함.
진입 격자(2026-08-15): OPTUNA_OB_ENTRY_SPREAD 0.1~8 / RATIO 0.05~1.5 / ASK_MULT 1~80 / LOOKBACK 30분.
8방 스택(2026-08-16/17): OPTUNA_OB_COMBO_TRIALS_SINGLE=150 / DOUBLE=200 / TRIPLE=250.
적용=방 단위(build_combo_env_patch). 합의=8방 중 median PnL 최고 방(_consensus_from_anchors).
OPTUNA_OB_AXIS_TRIALS=500 은 축독립 잔여키(8방 미사용).
실매 필터 나이: WS_ORDERBOOK_FILTER_MAX_AGE_SEC(0) ≠ WS_ORDERBOOK_TICK_MAX_AGE_SEC(저장).
사진 한 장도 없으면: WS_ORDERBOOK_FILTER_REJECT_IF_EMPTY(기본 true) → 필터 ON일 때 안 삼.
```