Files
portfolio-hub/docs/discovery/dcy-008_20260625_current-holding-wac-cost-basis-read.md
T
genichinandClaude Opus 4.8 d93c0bcaf5 feat(holdings): REQ-043 현재 보유 평단(WAC) read — GET /v1/portfolios/{id}/holdings/cost-basis (BAT-018, PR #14)
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
2026-06-26 00:07:43 +09:00

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-coldstart FR-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_pnl running_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

섹션 참조

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 플래그를 갱신한다.