# 화요일 확인 — ALIGN 폐기 + 호가필터 구멍 + 가격 TTL/EOD 확인일: **2026-08-18 (화) 장중**. 토~월에 쌓인 일이 **세 묶음**. 봉 정합(`T−1` 신호 / `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`는 정상 |