dcy-030 (issue #28, P0 체결 복구): - REQ-083 KRX 호가단위(tick) 순수 유틸 (domain/pricing.py) - REQ-070 CHG: 슬리피지 실효가 호가단위 스냅 — 상한 준수(매수 floor/매도 ceil) + band<1tick 하한/상한 보장 + 부동소수 epsilon 가드. 147700→148400/54500→54700. - BAT-044 release-candidate dcy-029 (issue #29, 운영 관측성): - REQ-084 구조화 로깅 기반 (runtime/logging_setup.py): ISO8601 KST·레벨·Loki JSON ·correlation id(slot_id) - REQ-085 주문 결과 로깅 (event=order_submit|fill|reject) - REQ-087 거부 ERROR 가시성 (조용한 롤백 제거) - REQ-086 청산 reason+actor 동반 노출 (안전망/전략 구분, 신규 필드 없음) - REQ-088 운영 조회 CLI report (application/operator_report.py, 보유·오늘 체결 ·실현 PnL net·대기, direct-DB) - REQ-089 운영자 런북 docs/operations.md - REQ-090 baseline 정합 (runtime-flows·project-structure·interface-contract) - BAT-045(P0)·BAT-046(P1) release-candidate REL-007: confirmed → feedback-captured (운영 인스턴스 라이브 검증 + #28/#29 환류 정규화). BAT-037~041 released. 검증: 537 passed, 47 skipped, 회귀 0, ruff clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.2 KiB
trex-core 운영자 런북 (Operations Runbook)
대상: trex-core 데몬을 배포·운영·디버깅하는 운영자. 범위: 배포/실행, 운영자 CLI, 로깅/관측성, 디버깅/트러블슈팅. 출처: dcy-029(REQ-089) —
.claude/skills/run-trex-core-daemon/SKILL.md사실 자료 + 관측성 기능(REQ-084~088) 사용법 통합.
1. 배포 / 실행
trex-core 데몬은 HTTP 표면이 없다(BAT-007). 모든 전략-facing 트래픽은 RabbitMQ로 흐른다(스냅샷/슬롯 RPC, intent RPC, 슬롯 이벤트). 운영자 조작은 trex-core CLI.
필수 인프라
PostgreSQL + RabbitMQ가 떠 있어야 한다. (paper 브로커는 외부 증권사 불필요.)
환경 변수 (config/.env, gitignore)
| 변수 | 필수 | 설명 |
|---|---|---|
TREX_POSTGRESQL_DSN |
예 | psycopg DSN |
TREX_RABBITMQ_URL |
실사용 시 예 | 예 amqp://admin:admin@localhost:5672/ (미설정 시 in-memory stub — 전략 모듈 도달 불가) |
TREX_BROKER |
아니오 | paper(기본) 또는 kis |
TREX_PORTFOLIO_HUB_BASE_URL |
아니오 | 설정 시 실제 portfolio-hub universe+ledger, 미설정 시 stub universe(pf-005930/pf-000660) |
TREX_LOG_FORMAT |
아니오 | text(기본, 사람용) 또는 json(Loki 적재용) — §3 |
TREX_EXECUTION_INTERVAL_SEC / TREX_LEDGER_INTERVAL_SEC |
아니오 | 루프 간격(기본 1.0) |
인스턴스 TOML
--config <name> (BAT-013 이후 필수)는 config/<name>.toml을 해석 — instance_key(큐 이름 trex.intent.req.<key> 등; default는 literal), max_active_slots(M cap).
기동 / 종료
# 기동 (로그 리다이렉트). 테스트는 trex_core_test DB로 — 라이브 DB 금지.
.venv/bin/trex-core-daemon --config <instance> &> /tmp/trex-core.log &
# 종료 (SIGTERM → 워커 join + RabbitMQ close, 마지막 로그 'Normal shutdown')
pkill -TERM -f trex-core-daemon
데몬은 TCP 포트를 열지 않는다. "ready" = 4개 워커 스레드 + RabbitMQ 토폴로지 선언 완료. /tmp/trex-core.log에 ERROR/traceback이 없으면 부팅 성공.
안전 수칙
config/.env는 라이브 KIS 키 + portfolio_hub 토큰 + 라이브 PostgreSQL DSN을 담는다 — 커밋 금지, 라이브 DB에 파괴적 작업 금지.- 테스트는
TREX_BROKER=paper+ 파생trex_core_testDSN.
2. 운영자 CLI
.venv/bin/trex-core <command> [options] # 콘솔 스크립트
| 명령 | 용도 | 경로 |
|---|---|---|
slots [--status all|holding|buyable|pending|error] |
슬롯/포지션 목록 | RPC |
universe |
오늘 universe 자산 | RPC |
enter <portfolio_id> [--qty/--entry-price/--stop-loss/--take-profit/--forced-close-at] |
매수 intent | RPC |
exit <slot_id> [--price] |
매도 intent | RPC |
cancel <slot_id> |
대기 주문 취소(백스톱) | RPC |
pause/resume/paused |
portfolio 일시정지 | direct-DB |
report [--json] |
보유·오늘 체결·실현 PnL·대기 주문 | direct-DB (REQ-088) |
- enter/exit 안전장치: 확인 프롬프트 기본 ON,
--yes(paper 생략), live(broker=kis)는--yes --live이중 ack,--dry-run미리보기.--json은 비대화형이라 enter/exit에--yes필수. - 인스턴스 라우팅:
--config <toml>또는--instance <key>, 미지정 시default.
report — 일일 운영 리포트 (REQ-088 / dcy-029)
.venv/bin/trex-core report # 사람용 표
.venv/bin/trex-core report --json # 자동화용 JSON
출력: 현재 보유(symbol/qty/avg_price), 오늘(KST) 체결 건수, 오늘 실현 PnL(= ledger_outbox net 매매 현금흐름 = Σ매도(대금−수수료−세금) − Σ매수(대금+수수료), 수수료·세금 반영 BAT-038 정책), 대기 주문.
- "오늘" 경계는 trading_date(KST 00:00~익일 00:00). 전일 체결은 제외.
- 일중 진입·청산 전략에서는 net ≈ 실현손익. 미청산 보유의 평가손익은 포함하지 않는다(실현분만).
3. 로깅 / 관측성 (REQ-084~087 / dcy-029)
포맷
- 모든 로그 라인:
<ISO8601 KST> <LEVEL> <logger> [cid=<slot_id>] <msg>. TREX_LOG_FORMAT=json→ Loki 적재용 한 줄 JSON(ts/level/logger/msg/correlation_id+ 구조화 필드). Grafana/LogQL 대시보드용.- correlation id =
slot_id(intent→order→fill 공통 조인 키). 한 슬롯의 submit/fill/reject 로그가 같은cid를 공유 → 한 거래 추적.
주문 결과 로그 (grep 키)
grep "event=order_submit" /tmp/trex-core.log # 제출 주문
grep "event=order_fill" /tmp/trex-core.log # 체결(fill_price/filled_qty/fee/tax)
grep "event=order_reject" /tmp/trex-core.log # 거부 — ERROR 레벨
- 거부는 ERROR 레벨로 즉시 보인다(조용한 롤백 제거). 호가단위 위반(issue #28) 같은 거부가
event=order_reject ... reason=...로 노출.
청산 사유 해석 — reason + actor (REQ-086)
safety-sell fired: ... reason=<r> actor=trex-safety-sell→ 안전망 자율청산(전략 침묵으로 watchdog가 슬롯 소유).reason=stop_loss여도 이는 "전략 손절"이 아니라 안전망이 SL선에서 청산한 것.actor=execution_loop→ 집행 루프 정상 체결/롤백. 전략 SellIntent 매도는 전략 actor.- 즉 reason(조건)과 actor(주체)를 함께 보고 안전망/전략을 구분한다.
4. 디버깅 / 트러블슈팅
| 증상 | 원인 | 조치 |
|---|---|---|
| 매수가 계속 거부 | (구) 슬리피지 한계가 호가단위 위반(issue #28) | dcy-030으로 수정됨(호가단위 스냅). grep event=order_reject로 사유 확인 |
slots returned: 0 |
universe reconcile 미실행(hub down/boot race) | 스케줄러 로그 slot reconcile: 확인; hub 미설정 시 stub 2슬롯 |
intent rejected: unknown_slot |
slot_id/portfolio_id가 인스턴스 슬롯셋에 없음 | 먼저 slots로 조회 후 그 slot_id 사용 |
intent rejected: capacity_full |
max_active_slots(M) 도달 |
매도 후 재시도 또는 M 상향 |
매도 미발생 + WARN sell dispatch skipped |
브로커 잔고 0(divergence) | reconcile(운영자) — 미러 fallback 없음(설계) |
RpcTimeoutError |
데몬 미기동/소비 스레드 크래시 | /tmp/trex-core.log traceback 확인 |
미체결 pending_* 고착 |
취소 감지 누락/timeout 미설정 | trex-core cancel <slot_id> 백스톱; pending stale WARN 확인 |
DB 직접 조회
# 슬롯 상태 분포
psql "$TREX_POSTGRESQL_DSN" -c "SELECT instance_key, status, COUNT(*) FROM daily_slot GROUP BY 1,2 ORDER BY 1,2"
# ledger outbox 상태
psql "$TREX_POSTGRESQL_DSN" -c "SELECT status, last_outcome, COUNT(*) FROM ledger_outbox GROUP BY 1,2"
# 슬롯 전이 이력(reason+actor)
psql "$TREX_POSTGRESQL_DSN" -c "SELECT slot_id, from_state, to_state, reason, actor, created_at FROM slot_transition_log ORDER BY created_at DESC LIMIT 20"
관련 문서
docs/interface-contract.md— RabbitMQ 토폴로지 + 메시지 payload + reason/actor 어휘docs/runtime-flows.md— 흐름 다이어그램(스냅샷/intent RPC/이벤트/집행 루프/로깅).claude/skills/run-trex-core-daemon/SKILL.md— AI 에이전트용 실행 레시피(이 런북의 사실 자료 출처)