docs(operations): 무데이터/죽은 종목 위생 운영자 런북 추가 (dcy-017 후속)
dcy-017 지속 무데이터 알람의 후속 운영 절차를 operations.md §7로 문서화. - pause 시맨틱 코드 검증 결과 기술(신규 매수만 차단, 보유분 exit는 정상) - Step 1 알람검증 / Step 2 포지션확인 / Step 3a pause(가역) / Step 3b 영구제거 - 보유 포지션 안전성 + 영구삭제 시 고아 방지 순서 명시 - 코드 변경 없음(기존 trex-core pause/resume 기능 문서화) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
This commit is contained in:
@@ -223,6 +223,150 @@ psql "$TREX_POSTGRESQL_DSN" -c "SELECT slot_id, from_state, to_state, reason, ac
|
||||
|
||||
---
|
||||
|
||||
## 7. 무데이터/죽은 종목 위생 (dcy-017 후속)
|
||||
|
||||
dcy-017이 "지속 무데이터" WARN 다이제스트를 운영자에게 표시한다. 그 후속 조치로 해당 종목을 매매 유니버스에서 pause 또는 영구 제거하는 절차.
|
||||
|
||||
> **용어**: `portfolio_id` = trex-core에서 종목을 식별하는 키 (portfolio-hub asset_id와 동일). pause/resume 명령의 대상이다.
|
||||
|
||||
### 트리거
|
||||
|
||||
- dcy-017 지속 무데이터 WARN 알람(시세 N회 연속 무응답).
|
||||
- 운영자가 직접 관찰: KRX 거래정지/상장폐지 공시, 종목 이상 감지.
|
||||
|
||||
---
|
||||
|
||||
### pause 시맨틱 (코드 검증 결과)
|
||||
|
||||
> 아래는 코드 직접 확인 결과다. 추측 없이 file:line을 근거로 기술한다.
|
||||
|
||||
**pause가 하는 것 — 신규 진입(매수) 차단**
|
||||
|
||||
`pause_store.pause(portfolio_id)` = `INSERT INTO snapshot_pause (portfolio_id, ...) ON CONFLICT DO UPDATE` (`adapters/portfolio/pause_store.py:23`). 이후 slots RPC 응답에서 해당 slot의 `paused=True` 필드가 반환된다 (`application/portfolio.py:309-313`, `application/messaging_handlers.py:264-273`).
|
||||
|
||||
trex-core 코어 자체(`application/intents.py` `_admit_buy`, line 179~257)에는 pause 체크가 없다. **pause는 전략 데몬(orb 등)이 slots 응답의 `paused=True`를 읽고 그 slot에 buy intent를 보내지 않는 방식으로 신규 진입을 차단한다.** 전략 데몬이 pause를 무시하고 buy intent를 보내면 코어는 수락한다(전략 데몬 쪽 정책).
|
||||
|
||||
**pause가 하지 않는 것 — 기존 보유분 매도는 막지 않는다**
|
||||
|
||||
`application/safety_sell.py`의 `check_forced_close` / `check_prices` / `check_market_close` 모두 `self._holding(now)` (= `slot_repo.list_holding_slots()`)를 직접 조회하고 pause_store를 참조하지 않는다. tsl 전략 SellIntent, `trex-core exit` 명령도 마찬가지다.
|
||||
|
||||
**결론**: HOLDING 슬롯이 있는 종목을 pause해도 그 보유분은 safety-sell, tsl 전략, 운영자 exit 등 모든 매도 경로로 정상 청산된다. **pause는 신규 매수만 막고, 기존 포지션의 exit은 방해하지 않는다.** 포지션이 있어도 pause 명령은 안전하다.
|
||||
|
||||
**resume 원복**
|
||||
|
||||
`pause_store.resume(portfolio_id)` = `DELETE FROM snapshot_pause WHERE portfolio_id = %s` (`adapters/portfolio/pause_store.py:35`). 삭제 즉시 다음 slots RPC 응답부터 `paused=False`로 반환되어 정상 진입이 재개된다.
|
||||
|
||||
---
|
||||
|
||||
### Step 1 — 무데이터 알람 검증
|
||||
|
||||
알람 수신 후 즉시 종목 상태를 확인한다.
|
||||
|
||||
```bash
|
||||
# 해당 종목의 슬롯 상태 확인 (symbol 또는 portfolio_id로 필터)
|
||||
.venv/bin/trex-core slots --symbol <SYMBOL>
|
||||
.venv/bin/trex-core slots --status all # 전체 목록에서 확인
|
||||
```
|
||||
|
||||
KRX 공시/HTS에서 상태 분류:
|
||||
|
||||
| 상태 | 의미 | 권장 조치 |
|
||||
|---|---|---|
|
||||
| 일시적 시세 장애 | 단기 데이터 공백, 종목 정상 | 관망 → 자동 복구 확인 |
|
||||
| 임시 거래정지 (공시/사유 있음) | 거래 재개 예정 가능 | pause (Step 3a) |
|
||||
| 장기 거래정지 / 상폐 예정 | 재개 불명확 | pause 또는 영구 제거 검토 (Step 3b) |
|
||||
| 상장폐지 완료 | 거래 불가 | 포지션 0 확인 후 영구 제거 (Step 3b) |
|
||||
|
||||
---
|
||||
|
||||
### Step 2 — 포지션 확인
|
||||
|
||||
pause 또는 제거 전에 **해당 종목에 보유 포지션이 있는지** 반드시 확인한다.
|
||||
|
||||
```bash
|
||||
# 1) 운영자 리포트 — 보유·대기 주문 한눈에 확인
|
||||
.venv/bin/trex-core report
|
||||
|
||||
# 2) 해당 종목 슬롯 상세 조회
|
||||
.venv/bin/trex-core slots --symbol <SYMBOL>
|
||||
# 또는 portfolio_id를 알고 있을 때
|
||||
.venv/bin/trex-core slots --status holding
|
||||
|
||||
# 3) DB 직접 확인 (정밀 조회)
|
||||
psql "$TREX_POSTGRESQL_DSN" -c \
|
||||
"SELECT slot_id, status, symbol, qty, avg_price, portfolio_id FROM daily_slot WHERE symbol = '<SYMBOL>'"
|
||||
```
|
||||
|
||||
출력의 `status` 확인:
|
||||
- `inactive` — 포지션 없음. pause 또는 제거가 자유롭다.
|
||||
- `holding` — **보유 포지션 있음.** pause는 안전하다(아래 설명). 영구 삭제는 포지션 청산 후에만 한다.
|
||||
- `pending_buy` / `pending_sell` — 주문 대기 중. 완료 대기 또는 `trex-core cancel <slot_id>`로 취소 후 진행.
|
||||
|
||||
---
|
||||
|
||||
### Step 3a — pause (가역, 권장 기본)
|
||||
|
||||
임시 거래정지, 무데이터 장기화, 불확실한 상황에서는 **pause가 기본 선택**이다. 언제든 resume으로 원복 가능하다.
|
||||
|
||||
```bash
|
||||
# pause 적용 (direct-DB write, 데몬 RPC 불필요)
|
||||
.venv/bin/trex-core pause <portfolio_id>
|
||||
# 예: trex-core pause pf-005930
|
||||
|
||||
# pause 상태 확인
|
||||
.venv/bin/trex-core paused
|
||||
|
||||
# 슬롯 조회 시 paused=True 확인
|
||||
.venv/bin/trex-core slots --symbol <SYMBOL>
|
||||
```
|
||||
|
||||
pause 후 동작:
|
||||
- **다음 slots RPC 응답부터** 해당 slot의 `paused=True` 반환 → orb 등 전략 데몬이 그 slot에 buy intent를 보내지 않음 → **신규 매수 차단**.
|
||||
- **기존 HOLDING 포지션은 영향 없음** — safety-sell(watchdog, stop-loss, 장마감 청산), tsl 전략 SellIntent, `trex-core exit` 모두 pause와 무관하게 정상 작동.
|
||||
- pause는 Postgres `snapshot_pause` 테이블에 영속 저장되므로 **데몬 재시작 후에도 유지**된다.
|
||||
|
||||
복구 (종목이 정상화되면):
|
||||
```bash
|
||||
.venv/bin/trex-core resume <portfolio_id>
|
||||
# 예: trex-core resume pf-005930
|
||||
|
||||
# 확인
|
||||
.venv/bin/trex-core paused # 목록에서 사라졌는지
|
||||
.venv/bin/trex-core slots --symbol <SYMBOL> # paused=False 확인
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 3b — 영구 제거 (상장폐지 등, 드문 케이스)
|
||||
|
||||
> **안전 경고**: 영구 제거는 비가역이다. 반드시 포지션이 0인 것을 확인한 후 진행한다. portfolio-hub 삭제는 고아 슬롯 위험이 있으므로 아래 순서를 엄수한다.
|
||||
|
||||
**전제 조건**:
|
||||
1. 해당 종목 slot이 `inactive` 상태 (보유·대기 포지션 없음).
|
||||
2. 포지션이 남아 있으면 먼저 청산(tsl/safety-sell 대기 또는 `trex-core exit`으로 수동 매도) 후 진행.
|
||||
|
||||
**절차**:
|
||||
1. `trex-core pause <portfolio_id>` — 추가 진입 차단(옵션이나 권장).
|
||||
2. `trex-core slots --symbol <SYMBOL>` — `status=inactive`, `qty=None` 확인.
|
||||
3. portfolio-hub에서 해당 portfolio(asset) 삭제 → **portfolio-hub 소관 작업. 직접 invocation은 portfolio-hub 운영자에게 요청하거나 사장님과 협의.** (portfolio-hub가 삭제하면 다음 universe 스냅샷 갱신 시 해당 slot이 자동 retire된다.)
|
||||
4. 다음 날 또는 스냅샷 갱신 후 `trex-core slots`에서 해당 종목이 사라졌는지 확인.
|
||||
|
||||
> portfolio-hub 삭제 없이 trex-core DB에서 slot을 직접 제거하면 고아 원장 레코드가 생길 수 있다. DB 직접 삭제는 금지한다.
|
||||
|
||||
---
|
||||
|
||||
### 안전 경고 요약
|
||||
|
||||
```
|
||||
[PAUSE] 가역·원장보존. 언제든 resume 가능. 포지션 있어도 안전(매도 경로 유지).
|
||||
[DELETE] 영구·비가역. 반드시 포지션 0 확인 후. portfolio-hub와 협의.
|
||||
|
||||
포지션(HOLDING)이 있는 종목은 pause만 적용하라.
|
||||
영구 삭제는 포지션을 완전히 청산한 뒤에만 수행한다.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 관련 문서
|
||||
- `docs/interface-contract.md` — RabbitMQ 토폴로지 + 메시지 payload + reason/actor 어휘
|
||||
- `docs/runtime-flows.md` — 흐름 다이어그램(스냅샷/intent RPC/이벤트/집행 루프/로깅)
|
||||
|
||||
Reference in New Issue
Block a user