Files
kis_trader/docs/화요일확인.md
Your Name 0ecac7cb95 이번에 들어간 내용
한투 호가 = 2번째 앱키 전용
키 없거나 start 실패 시 메인에 H0STASP0 안 붙임. 운영설정 WS_ORDERBOOK_SAVE_KIS 빨간 danger.

LS RAM 합집합
후보∪보유∪영구∪grace. sync_targets와 split reconcile 둘 다. 틱 DB 영구 게이트는 그대로.

분봉 쓰레기 → 다음 소스 봉 통째
그 분 틱 0건이거나 전부 봉끝 대비 LIVE_FEED_FALLBACK_MAX_AGE_SEC 초과면 구멍. 메인 WS → 2차 → LS → REST → rollup. CANDLE_GARBAGE_FALLBACK 기본 true.

파일: feed_fallback.py(신규), ws_manager.py, kis_ws.py, candle_series.py, bt_candle_source.py, live_config_schema.py, database.py, 스모크, MD 2개.

같은 ws_manager/database/kis_ws/live_config에는 직전 커밋 이후 쌓여 있던 시세 폴백·ENV 키 정리도 같이 들어갔습니다. 파일 단위로 나눌 수 없어서입니다.
2026-08-19 22:11:31 +09:00

210 lines
10 KiB
Markdown
Raw Permalink 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.
# 화요일 확인 — ALIGN 폐기 + 호가필터 구멍 + 가격 TTL/EOD
확인일: **2026-08-18 (화) 장중**.
토~월에 쌓인 일이 **세 묶음**. 봉 정합(`T1` 신호 / `T` 진입 / freeze)과 **다른 이야기**.
`*_LIVE_BACKTEST_ALIGN`(봉 진입)은 **끄지 않음**. 없앤 건 유니버스 history 교집합뿐.
| 묶음 | 한 줄 | 화요일 봇 |
|------|--------|-----------|
| A. 유니버스 ALIGN | 키움 RAM ∩ history 교집합 삭제. history는 INSERT만 | 토에 재시작. **또 안 해도 됨** |
| B. 호가 눈가림 | 사진 만료=통과 폐기 + 사진 없으면 안 삼 | 월 23:55 재시작에 포함되면 OK |
| C. 가격 TTL / EOD | 체결 없어도 마지막가 유지. EOD는 `min_hold`·유령삭제에 안 막힘 | **월 23:55 `kis_trader_main` 재시작함** → 화 장부터 이 코드 |
웹: `kis_backtest_web` 재시작됨. 운영 설정만 보면 됨.
시세·호가 = **실키**(키움 `mock=False`, 한투 WS `:21000`). 매매 REST = **한투 모의** (`openapivts`). 이번 패치로 모의키를 시세에 붙인 적 없음.
---
## 왜 고쳤나 (한 줄씩)
- **A.** 운영 ON이던 `LIVE_UNIVERSE_SLOT_ALIGN`이 RAM 후보를 history와 교집합 → 중간 사진 ∩ 실시간 = `universe_wipe`.
- **B.** 호가 저장 TTL과 검사 TTL을 같이 써서 사진이 `None`이면 필터 ON인데 **통과(눈가림 매수)**.
- **C.** REST→WS 바꿀 때 “오래된 캐시=죽음”으로 가격을 `None` → 매도 `continue`. 199원이 체결이 없어도 **계속 199원**인데 지워서 손절·EOD가 안 나감 (8/5 돌파, 금요일 leftover). 호가 B와 **같은 병**.
---
## 적용된 내용
### 1. ALIGN 스위치 완전 삭제 (눈앞·코드·DB·MD)
| 위치 | 결과 |
|------|------|
| 실매 후보 | `base.py` `_post_filter_candidates` — history 교집합 **없음**. RAM에 있으면 후보 |
| UI | 운영 설정에서 `LIVE_UNIVERSE_SLOT_ALIGN` 토글 삭제. `/api/live_config` JSON에도 키 없음 |
| DB | `env_config_ext` 행 DELETE. 전략 config 컬럼 DROP |
| 알림 | `universe_wipe` 발송 경로 삭제 |
| 문서 | `code_architecture.md` · `MODIFICATION_GUIDE.md` · `정합성.md` 유니버스 한 줄 |
실매 진실 = 키움 REAL I/D → RAM 푸시/팝. history는 **백테 재생용 복사본**만.
### 2. 키움 history: INSERT만 + 마이크로초
| 항목 | 전 | 후 |
|------|----|----|
| 쓰기 | 같은 슬롯 DELETE 후 한 줄씩 INSERT (중간 노출) | DELETE 없음. N종목 한 트랜잭션 |
| `event_time` | 초 `varchar(19)` | 마이크로초 `varchar(26)` |
| 같은 초 두 변동 | 두 번째가 첫 장을 지움 | **두 장 다 남음** |
백테: 그 초의 **마지막** 스냅샷. ±1분 슬롯 해킹 없음.
건드리지 않음: `ls_candidates_history`, `WS_TICK_GRACE_SEC` 기본 180.
### 3. 호가 — 대기표 사진 없이 사던 구멍
1. **만료=통과** → 검사 시계 `WS_ORDERBOOK_FILTER_MAX_AGE_SEC` 기본 **0**(마지막 사진). 저장 `WS_ORDERBOOK_TICK_MAX_AGE_SEC`(30초)와 **합치지 말 것**.
2. **사진 0장인데 통과**`WS_ORDERBOOK_FILTER_REJECT_IF_EMPTY` 기본 ON. REST 없음.
한산해서 사진이 **안 바뀌는 것** ≠ 사진이 **없는 것**. 팔 때 지정가·익절/손절 호가매도는 안 바꿈.
### 4. 가격 TTL / EOD (월 밤) — 화요일 실매 본체
초등: 칠판에 199원. 체결이 10분 없어도 **199원**. 지우고 “없다”고 하면 손절·장마감이 **안 돌아간다**.
| 위치 | 결과 |
|------|------|
| 매도 | `live_sell_price.py` — 마지막 WS(나이 무시). 죽은선만 REST 1회·쿨다운 30초. 실패해도 WS 유지 |
| EOD | 타이머 없음. WS 없으면 매수가 폴백. **무조건 청산** |
| `min_hold` | EOD를 **막지 않음** (모멘텀/스캘프/꼬리) |
| 매수 | `_ws_last_quote` / `get_price_last`. `WS_PRICE_MAX_AGE_SEC` 기본 **0** |
| WS 기본 | KIS·키움·LS·해외 `get_price` 기본 `None`(나이 무시). LS 옛 10초·해외 옛 20분 폐기 |
| 40240000 | 잔고검증 **qty>0** 이면 「잔고 없음」 문구로 **ghost_purge 금지** |
| 기동 | `ORPHAN_RECONCILE_ON_STARTUP` — 전략 전 잔고=DB 맞춤(매도 없음) |
옵투나·웹백테는 DB 봉·틱 재생이라 **이 TTL이 봉을 성기게 만들지 않음**. 예전 옵투나 best는 “실매가 안 팔던 세상”과 어긋날 수 있음. 화 하루 쌓인 뒤에 수요일 재탐색이 그 하루만 가깝다. `--apply-best` 하지 말 것.
---
## 재시작 기록
| 때 | 무엇 |
|----|------|
| 토 | 웹 + (ALIGN) 실매 |
| 월 23:55 | `kis_trader_main` 재시작 (PID 바뀜). `🚀 통합 봇 시작` · 키움 LOGIN OK · 시세 실키 · 매매 모의 REST |
| 화 장전 | **또 재시작 불필요** (월 밤에 C묶음까지 올린 프로세스). 의심되면 한 번 더 |
```bash
systemctl is-active kis_trader_main.service
journalctl -u kis_trader_main.service --since '2026-08-18 08:50' --no-pager | head -40
```
정상 시그니처: `🚀 kis_trader 통합 봇 시작`, `키움 WS LOGIN OK`, `실키/실전 도메인`, `heartbeat … dead=[]`.
이상: `Traceback`, `ImportError`, `universe_wipe`, 시세 URL `:31000`(모의 WS).
---
## 화요일 장중 체크리스트
### A. 실매 — 가짜 전량탈락이 없어야 함
1. `kis_trader_main.service` active.
2. 알림/저널에 **`universe_wipe`**, `history=kiwoom 교집합`, `[유니버스슬롯] … 후보 N→0` **없어야** 함.
3. 키움 RAM과 매수 후보가 같이 움직임. HTS가 진짜로 비우면 RAM도 0인 것은 정상.
4. `universe_zero`는 **키움 조건이 진짜 0**일 때만.
```bash
journalctl -u kis_trader_main.service --since '2026-08-18 09:00' --no-pager \
| grep -E 'universe_wipe|유니버스슬롯|교집합|universe_zero' | head -50
```
### B. history 저장 — 중간 1종목 사진이 없어야 함
- `event_time`**점 + 마이크로초**.
- 같은 초 안 두 번 변동이면 **행이 두 세트**.
```sql
SHOW COLUMNS FROM target_candidates_history;
-- event_time varchar(26)
SELECT strategy_id, event_time, COUNT(*) n
FROM target_candidates_history
WHERE event_time >= '2026-08-18 09:00:00'
GROUP BY strategy_id, event_time
ORDER BY event_time DESC
LIMIT 20;
```
pymysql `LIKE``%`는 바인딩.
### C. 웹
`http://192.168.0.149:5050/` → 운영 설정
- **유니버스 히스토리 교집합** 토글 **없음**
- 「호가 사진 없으면 매수 안 함」 **켜짐**
- `WS_ORDERBOOK_FILTER_MAX_AGE_SEC` = **0**
- `WS_PRICE_MAX_AGE_SEC` = **0** (마지막 체결가 유지)
### D. 백테 (여유 있으면)
최근 거래일 1일. 유니버스가 비어 거래 0이면 안 됨. 백테 = **완성 스냅샷 재생**. ALIGN ON 시절 숫자와 같을 필요 없음.
### E. 호가 — 눈가림이 없어야 함
1. 저널 `탈락-호가없음` 이 **가끔**은 정상(구독 직후). **같은 종목 종일만**이면 구독 실패.
2. 「매수호가」가 빨강인데 체결 — 예전 구멍이면 화요일부터 줄어야 함. 빨강 = 나중에 그린 사진일 수도.
3. 한산하다고 거래 **전부 0**이면 안 됨. 사진 한 장이 있으면 검사하고 통과하면 산다.
```bash
journalctl -u kis_trader_main.service --since '2026-08-18 09:00' --no-pager \
| grep -E '탈락-호가없음|호가없음' | head -40
```
### F. 가격 TTL / EOD — 횡보해도 팔아야 함 (화 신규)
1. 보유 중 체결이 뜸해도 저널에 **현재가 없음으로 매도 스킵이 쌓이면 안 됨**.
2. 손절·트레일이 **횡보 종목에서도** 나와야 함 (가격을 지워서 `continue` 하던 패턴 재발 금지).
3. 전략 EOD 시각에 **매도 주문이 나가야** 함. 모멘텀은 살아 있고 돌파만 EOD 0건이면 예전 구멍.
4. `40240000` / 「잔고 없음」인데 계좌에 주식이 있으면 **ghost_purge 로그가 아니라** `실잔고 N주 → 유령정리 안 함` 이어야 함. 그다음 EOD 재시도.
5. `min_hold` 때문에 EOD가 스킵되면 안 됨.
6. leftover(당일 못 판 종목)가 **전날처럼 대량**이면 실패. 장 마감 후 `active_trades` vs 잔고.
```bash
journalctl -u kis_trader_main.service --since '2026-08-18 09:00' --no-pager \
| grep -E '유령정리 안 함|ghost_purge|장마감|EOD|sell_ws|현재가 없음|탈락-가격' | head -60
```
장 마감 후: 당일 매수 → 당일 EOD/손절 주문 유무. 8/5 티앤엘처럼 **EOD 0건 다음날 손절**이 반복되면 C묶음 미적용(구 프로세스).
---
## 영향 분류
| 축 | ALIGN | 호가 눈가림 | 가격 TTL/EOD |
|----|--------|-------------|--------------|
| 실매 | 후보가 history에 안 막힘 | 필터 ON이면 사진 없이 안 삼 | 횡보해도 마지막가로 손절·EOD |
| 백테 | history 재생. 타임스탬프만 촘촘 | 호가 검사 ON이면 사진 없는 타점 안 삼 | **봉·틱 재생. TTL 없음** |
| Optuna | 엔진 분기 없음 | 1과목은 호가 끈 채 | 예전 best ≠ 화 실매 예고편. 수요일은 **화 하루**만 가깝다 |
| freeze / SKIP_HTS | 없음 | 없음 | 없음 |
---
## 안 바뀐 것 (헷갈리지 말 것)
- `*_LIVE_BACKTEST_ALIGN` / 형성봉 ALIGN — **봉 진입 정합**. 유니버스 ALIGN 삭제와 다른 키. **ON 유지**.
- `LIVE_PORTFOLIO_BUDGET_ALIGN` — 총한도. 유지.
- `WS_TICK_GRACE_SEC` 180초.
- `*_SKIP_HTS_SCAN_DUPES` false.
- LS t1859 / `ls_candidates_history`.
- 매도 지정가 · 익절/손절 호가매도.
- 프로그램매매 “스냅 없으면 통과”.
- 시세 실키 / 매매 한투 모의 분리.
---
## 화요일에 이상하면
| 증상 | 볼 곳 |
|------|--------|
| 또 N→0 알림 | 교집합 재유입? `universe_zero`(진짜 0) vs `universe_wipe`(없어져야 함) |
| history 초만 찍힘 | 구버전 프로세스 |
| 백테 유니버스 구멍 | `event_time` 문자열. 초 조회 상한 `.999999` |
| 같은 초 명단 유실 | INSERT에 DELETE가 다시 생겼는지 |
| 호가 없이 또 매수 | 구버전 / `REJECT_IF_EMPTY` OFF / 전략 필터 OFF |
| 한산 종목 종일 0건 | 차트 무신호 vs 사진 보고 탈락 vs 사진 0장 |
| `탈락-호가없음` 폭주 | 호가 구독 실패. REST로 메우지 말 것 |
| 횡보인데 손절·EOD 0건 | **가격 TTL 재발**. `WS_PRICE_MAX_AGE_SEC`가 양수인지, 매도가 `get_price_last`인지 |
| EOD 주문 0 + 다음날 손절 | 8/5와 동일. 봇 PID가 월 23:55 이후인지 |
| 「잔고 없음」으로 포지션 DB 삭제 | qty>0인데 ghost_purge 탄 것. 패치 미적용 |
| 시세가 모의 | WS `:31000` / 키움 `mock=True`. 매매만 `openapivts`는 정상 |