dcy-008(confirmed)/REQ-043(Approved)/BAT-018. trex-core dcy-034 FR-7 cold-start seed 의존. AC 11/11, QC PASS. worktree+PR 워크플로 첫 파일럿. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
13 KiB
13 KiB
0. 문서 상태
이 문서의 현재 상태와 식별 정보를 기록한다. 문서 추적과 승인 흐름에 필요한 최소 메타데이터를 적는다.
- 상태: confirmed
- 문서 ID: dcy-008_20260625_current-holding-wac-cost-basis-read
- 이슈명: 현재 보유 종목별 평단(WAC) 조회 API — trex-core 중장기 cold-start 슬롯 평단 seed 의존
- 작성 시각(KST): 2026-06-25 (KST)
- 마지막 갱신 시각(KST): 2026-06-25 (KST, confirm-discovery — 사장님 승인, OQ-1/OQ-2 Answered)
- 대체됨: 없음
- 후속 Discovery 참조: 없음
- 교차 서비스 발원(driver): trex-core
dcy-034_20260625_slot-account-blocking-reconcile-sync-coldstartFR-7 — trex-core가 cold-start 시 슬롯 평단을 seed하려면 portfolio-hub의 현재 보유분 평단 read가 필요하다. 본 Discovery는 그 의존을 portfolio-hub측 변경 단위로 정식화한다. - 생성된 REQ 참조: REQ-043 (GET /v1/portfolios/{id}/holdings/cost-basis 현재 보유 평단 read, Interface) → req-043 (draft-req, confirm-req 대기)
1. 계획 상태 요약
- 연계 문서 현황:
- 관련 점수 파일: 없음
- 관련 TODO/메모: 교차 서비스 의존 — trex-core dcy-034(M3 중장기 cold-start) FR-7. GitHub 보드 #7 dcy-034 항목.
- 직계 선행: dcy-007(일일 거래내역 + 실현 PnL 조회 API) — WAC cost basis 산출 로직(REQ-041)을 이미 도입한 직계 형제.
- 해석:
- trex-core 중장기 인스턴스가 실계좌에 이미 보유 중인 종목 위에서 cold-start 할 때, 슬롯에 보유분을 onboarding하며 슬롯 평단(cost basis)을 seed해야 한다. 그 평단의 단일 정본 출처는 원장(ledger)을 보유한 portfolio-hub다.
- 그러나 portfolio-hub는 WAC를 내부 계산만 하고(미매도 보유분의 현재 평단을 주는 read가 없음), 외부 노출은 매도 시점
cost_basis_per_unit(dcy-007/REQ-040)뿐이다. 즉 "현재 보유분의 평단"을 조회할 표면이 비어 있다. - 본 Discovery는 그 read 표면을 portfolio-hub 자체 변경(신규 조회 엔드포인트 + 현재 보유 WAC 집계)으로 정의한다.
2. 요구사항 판정 결과
- 판정: 신규
- 근거
- dcy-007은 매도 기준 실현 PnL 집계(GET /pnl/realized, 매도행 cost_basis_per_unit)다. 이번은 미매도 현재 보유분의 평단 조회로, 데이터 대상(미청산 포지션)과 용도(외부 seed)가 다르다.
- 기존 dcy-001~007 중 "현재 보유 평단 read"를 정의한 Discovery가 없다. WAC 산출 로직(REQ-041)은 재사용 가능하나 이를 노출하는 read 계약은 신규다.
3. 문제점의 요약
- 현재 상태
app/domain/pnl.py의calculate_realized_pnl이 매수 누적으로running_wac를 계산하지만, 이 값은 매도 이벤트 행(cost_basis_per_unit)으로만 응답에 노출된다(GET /v1/portfolios/{id}/pnl/realized, REQ-040). 매도가 0건이면 보유분 평단을 알 길이 없다.- portfolio_ledger(TimescaleDB)에 매수/매도 체결이 적재돼 있어 보유 수량·WAC는 산출 가능하나, "현재 보유 종목별 (수량, 평단)"을 반환하는 GET 엔드포인트가 없다.
- 결과: trex-core cold-start가 슬롯 평단을 seed할 외부 read가 없어, 브로커 평균가(dcy-032에서 0/None 케이스 확인) 등 불안정한 폴백에 의존해야 한다.
- 기대 상태
- 포트폴리오의 현재 보유 종목별 보유수량 + 현재 평단(WAC, cost_basis_per_unit) 을 반환하는 read 엔드포인트가 존재한다.
- WAC 산출은 dcy-007/REQ-041의 검증된
running_wac로직을 재사용하고, 원장 이력이 불완전하면 dcy-007과 동일하게data_completeness_warning으로 표면화한다. - 인증/역할은 기존 portfolio read API와 동일 정책이라 daemon 호출자(trex-core)가 소비할 수 있다.
- 이해관계자
- 사장님 — 교차 서비스 계약·범위 승인자
- 팀장(Claude) — Discovery/게이트 관리, 교차 의존 추적자
- portfolio-hub-dev — delivery 담당
- 소비자: trex-core(중장기 cold-start seed), 운영자(보유 평단 가시성)
- 제약사항
- portfolio-hub는 시세(현재가)를 소유하지 않는다(그건 kis-data-hub). 따라서 본 read는 평단/취득원가(cost basis)만 다루고 미실현 손익(현재가 결합)은 범위 밖이다.
- WAC 산출 정본은 원장(portfolio_ledger)이며, 원장 이력 불완전 시 추정 한계가 dcy-007과 동일하게 존재한다.
- 응답 스키마/인증은 기존 v1 portfolio read 계약과 일관해야 한다(프론트/daemon 회귀 방지).
주요 사용자 시나리오
- trex-core(daemon): 중장기 인스턴스 cold-start에서 보유 종목 onboarding 시, 이 엔드포인트로 종목별 현재 평단을 읽어 슬롯 cost basis를 seed한다.
- 운영자: 매도 전이라도 특정 포트폴리오의 현재 보유 평단/취득원가를 조회해 손익 기준선을 확인한다.
4. 이번에 정의할 변경
- 변경 1 — 현재 보유 평단 조회 엔드포인트 신설: 포트폴리오의 미청산 보유 종목별 (symbol, 보유수량, WAC, 보유 cost basis 합)을 반환하는 GET 엔드포인트.
- 변경 2 — 현재 보유 WAC 집계 로직: dcy-007/REQ-041의
running_wac(매수 누적 WAC, 매도 시 수량 차감) 로직을 재사용해 "매도 시점 PnL"이 아니라 "현재 잔여 보유분의 평단"을 산출. 원장 불완전 시data_completeness_warning.
영향 범위
- 코드 영향:
app/api/v1_portfolios.py— 신규 GET 핸들러(기존/pnl/realized핸들러 :710 인증 패턴 재사용).app/domain/pnl.py— 현재 보유 WAC 산출 함수(기존calculate_realized_pnlrunning_wac 로직 재사용/추출).app/schemas/v1.py— 응답 스키마 신설(RealizedPnl* 인근 패턴).app/repositories/postgres.py— 보유 집계 조회(필요 시).
- 문서 영향:
docs/discovery/index.md신규 행, srs/index.md(REQ 생성 시). - 운영 영향: 신규 read 엔드포인트 1개 추가(쓰기·마이그레이션 없음). 인증 정책 변화 없음.
5. 요구사항 목록
기능 요구사항
- FR-1: 포트폴리오의 현재 보유(미청산) 종목별
symbol,quantity,cost_basis_per_unit(WAC)을 반환하는 GET 엔드포인트를 제공한다. - FR-2: WAC는 매수 누적 가중평균(매도 시 수량 차감, 단가 불변)으로 산출한다(dcy-007/REQ-041
running_wac재사용). 매수만 한 보유분은 WAC=가중평균 매수가. - FR-3: 원장 이력이 불완전하면
data_completeness_warning을 응답에 포함한다(dcy-007 패턴 일관). - FR-4: 인증/역할은 기존 portfolio read API(REQ-040/041)와 동일 정책으로, daemon scope 호출자가 사용 가능해야 한다.
비기능 요구사항
- NFR-1: 응답 스키마·인증은 기존 v1 portfolio read 계약과 일관(프론트/daemon 회귀 0).
- NFR-2: 본 엔드포인트는 read-only, 쓰기/스키마 마이그레이션 없음.
- NFR-3: 시세 의존 없음 — 평단/취득원가만(미실현 손익 비포함).
범위 경계
- In Scope
- 현재 보유 종목별 (수량, WAC, cost basis 합) read 엔드포인트 + 산출 로직 + 테스트 + data_completeness_warning.
- Out of Scope
- 미실현 손익(현재가 결합) — portfolio-hub가 시세 비소유.
- trex-core 슬롯 seed 로직 자체(소비측 — trex-core dcy-034).
- 원장 소급 보정(데이터 정합화 별건).
6. 리스크/가정 목록
리스크
- R-1 (Low): 현재 보유 WAC 산출이 dcy-007 매도 기준 계산과 미세하게 갈라질 수 있다(잔여 수량 0 처리 등).
- 완화:
running_wac로직을 단일 출처로 추출/재사용하고, 매수만/부분매도 후 시나리오 테스트로 dcy-007과 정합 확인.
- 완화:
- R-2 (Low): 응답 스키마가 daemon/프론트 양 소비자 요구와 어긋날 수 있다.
- 완화: 기존 RealizedPnl* 스키마 패턴 답습 + trex-core 소비 형태(symbol→평단 맵)를 design에서 확정.
가정
- A-1: portfolio_ledger에 cold-start 대상 종목의 매수 이력이 적재돼 있어 WAC 산출이 가능하다(없으면 data_completeness_warning).
- A-2: trex-core는 포트폴리오 단위(portfolio_id)로 평단을 소비한다(슬롯↔portfolio_id 1:1, trex-core dcy-020).
- A-3: dcy-007/REQ-041의 WAC 로직은 현재 보유 평단 산출에 그대로 재사용 가능하다.
오픈 질문 (전부 Answered — confirm-discovery 사장님 승인 2026-06-25)
- OQ-1 (Answered): 집계 단위 → 포트폴리오별
GET /v1/portfolios/{id}/holdings/cost-basis. trex-core 슬롯↔portfolio_id 1:1 + 기존/v1/portfolios/{id}/패턴 일관. (REQ-043 반영.) - OQ-2 (Answered): 응답 스키마 → 종목별 (symbol, current_quantity, cost_basis_per_unit=WAC, total_cost_basis, cost_basis_from, data_completeness_warning). 보유 cost basis 합계·최초 매수시각 포함. (REQ-043 반영.)
- OQ-3 (Answered, 교차 서비스 — REQ-043 draft-req 제기): service token 소유권 — cold-start가
managed_by_daemon_id=null미배정 포트폴리오 평단을 읽으면 403 blocker 우려. 해소: trex-core cold-start는snapshot_scheduler.run_once에서 whoami→get_portfolios(daemon_id)로 이미 자기 daemon에 배정된 포트폴리오만 가져오므로, 그 포트폴리오들은managed_by_daemon_id==daemon이라 소유권 정책(REQ-029 선례) 성립. null 케이스는 cold-start 경로에 없음(팀장 2026-06-25). REQ-043은 daemon scope 소유권 정책 유지.
오픈 질문 처리 기준
Open: 다음 단계 진행에 영향이 있는 미결. 유지.Answered: 확정. 본문/REQ 반영 후 정리.Deferred: 다음 단계로 이월(대상·이유 명시).Dropped: 무효(사유 명시).
7. 초기 성공 기준
- S-1: 매수만 한 보유분에 대해 엔드포인트가 WAC=가중평균 매수가, 보유수량을 정확히 반환한다.
- S-2: 부분 매도 후 잔여 보유분의 WAC가 매도로 변하지 않고(수량만 감소) 정확히 반환된다.
- S-3: 원장 이력 불완전 시
data_completeness_warning이 응답에 포함된다. - S-4: 인증/역할이 기존 portfolio read와 동일하게 적용된다(무권한 거부, daemon scope 허용).
측정 방식 및 데이터 출처
- S-1/S-2: 매수·부분매도 픽스처 단위/통합 테스트로 WAC·수량 검증 / 신규 테스트 + portfolio_ledger.
- S-3: 불완전 이력 주입 테스트로 warning 단언 / 응답 페이로드.
- S-4: 인증 테스트(무헤더/무권한/daemon scope) / 기존 auth 테스트 패턴.
8. REQ로 넘기기 전 확인 체크
- 범위(In/Out) 확정 — 미실현 손익 제외·평단만 제공 합의(사장님 2026-06-25)
- 성공 지표 측정 방식 확정 — S-1~S-4 이견 없음
- High 리스크 — 현재 없음(R-1/R-2 Low)
- 모든 OQ
Open없음 — OQ-1/OQ-2/OQ-3 전부 Answered - Freeze 확정 담당자(CONFIRMED_BY) 지정 — 팀장(Claude)
9. 파일 처리 결과
- 처리 결과: 생성
- 생성 경로: docs/discovery/dcy-008_20260625_current-holding-wac-cost-basis-read.md
- 참조 문서:
- docs/discovery/dcy-007_20260616_daily-trade-history-and-realized-pnl-query-api.md (WAC cost basis 산출 직계)
- trex-core docs/discovery/dcy-034_...slot-account-blocking-reconcile-sync-coldstart.md (교차 서비스 발원, FR-7)
- app/domain/pnl.py, app/api/v1_portfolios.py(:710), app/schemas/v1.py (현재 구현 근거)
10. 사용자 결정 필요 항목 요약
DECIDE (해소됨 — 사장님 2026-06-25)
- (확정) OQ-1 집계 단위 → 포트폴리오별(
/v1/portfolios/{id}/holdings/cost-basis).
CONFIRM (확정)
- 본 read 엔드포인트를 trex-core dcy-034 FR-7의 portfolio-hub측 의존 단위로 채택 — 사장님 2026-06-25.
- 미실현 손익 제외(평단/취득원가만) 범위 — 확정.
DATA
- 없음(원장 이미 적재, WAC 로직 기존 보유).
11. Discovery Freeze
섹션 참조
- 범위: # 5 > 범위 경계
- 리스크/오픈 질문: # 6
- 성공 기준: # 7
- 인계 전 확인: # 8
- 사용자 결정 필요: # 10
Freeze 플래그
- Handoff Decision: REQ Drafting 진행 가능
- Handoff Rationale: 사장님 승인(2026-06-25). OQ-1(포트폴리오별)·OQ-2(스키마)·OQ-3(소유권 정책) 전부 Answered. REQ-043이 이미 본 Discovery에서 파생 작성됨(confirm-req 대기). 미실현 손익 제외 범위 합의. Open OQ 0건.
- Ready for REQ Drafting: true
- Confirmed By: 팀장(Claude)
- Confirmed At (KST): 2026-06-25 (KST)
12. 작성 가이드
- 이 문서는 portfolio-hub dcy 템플릿 기반이며 Open Questions는 가정으로 대체하지 않는다.
- confirm-discovery 시 OQ-1/OQ-2 처리와 Freeze 플래그를 갱신한다.