Files
portfolio-hub/docs/srs/Interface/req-040_realized-pnl-query-endpoint.md
T
genichinandClaude Opus 4.8 bd34450ee9 feat(pnl): trade history + realized PnL API (WAC) — BAT-017, REQ-039~042 Implemented
- GET /v1/portfolios/{id}/trades and GET /v1/portfolios/{id}/pnl/realized endpoints
- Weighted Average Cost (WAC) realized PnL calculation in app/domain/pnl.py
- cost_basis and data_completeness_warning returned in pnl API response
- Test coverage: 50 passed (WAC 20 + trades 12 + pnl 18), full 427 passed regression ✓
- WAC validated against 199,300 unit e2e test cases
- DB migration: none required
- QC: qc-reviewer PASS-WITH-NOTES; team lead confirm-batch-verification → release-candidate
- Remaining non-blocking: symbol filter edge case testing, HTTP_422 deprecation

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VHtM5Ws1HKCKQ4JGi6GRb5
2026-06-18 16:45:01 +09:00

7.3 KiB
Raw Blame History

REQ-040: GET /v1/portfolios/{id}/pnl/realized 실현 PnL 집계 엔드포인트 신설

  • Status: Implemented
  • Type: Interface
  • Priority: High
  • Owner: Justin Ko

Intent

  • 지정 기간 내 매도(side='sell') 체결에 대해 수수료·세금을 반영한 실현 PnL 합계 및 건별 내역을 반환하는 GET 엔드포인트를 신설한다.
  • WAC(weighted average cost, 가중평균 취득단가) 방식으로 산출된 cost_basis 기반 실현 손익을 API 단일 호출로 제공하여 trex_core ledger_outbox 수기 계산 의존을 제거한다(dcy-007 FR-2, S-2).
  • R-1(이력 완전성) 리스크를 완화하기 위해, cost_basis 산출 시작 시점을 응답에 포함하고 이력이 불완전할 경우 경고 필드(data_completeness_warning)를 응답에 포함한다(dcy-007 R-1 완화 방안).

Requirement

  • 시스템은 GET /v1/portfolios/{portfolio_id}/pnl/realized 엔드포인트를 제공해야 한다.
  • from/to 날짜 범위 파라미터(YYYY-MM-DD)로 집계 기간을 지정하며, 두 파라미터 모두 필수다.
  • 선택적 symbol 파라미터로 특정 종목 필터링을 지원한다.
  • 응답은 다음을 포함해야 한다: 기간 합계 실현 PnL(total_realized_pnl), 건별 매도 내역 배열(items), cost_basis 산출 시작 시점(cost_basis_from), 이력 불완전 경고 필드(data_completeness_warning: str | null).
  • 건별 항목은 symbol(또는 portfolio 식별 가능 필드), executed_at, quantity, sell_price, cost_basis_per_unit, fee_amount, tax_amount, realized_pnl을 포함해야 한다.
  • 인증은 기존 read_token 이상 권한(DB 토큰)으로 접근 가능해야 하며, 별도 권한 추가는 없다(dcy-007 FR-4, A-3).
  • 호출자 소유권 확인: 비소유자 비관리자 호출은 HTTP 403을 반환해야 한다.
  • PnL 산출은 REQ-041(WAC 산출 로직)에 위임하며, 이 엔드포인트는 service 계층을 통해 산출 결과를 수신하고 HTTP 응답으로 직렬화한다.

Acceptance Criteria

  1. Given read_token 이상 권한, portfolio에 buy 100주@10,000 + buy 100주@12,000 이력 존재 후 sell 50주@15,000 fee=500 tax=200 실행, When GET /v1/portfolios/{id}/pnl/realized?from=2026-06-01&to=2026-06-30, Then HTTP 200 + total_realized_pnl이 WAC 공식((15,000 - 11,000) × 50 - 500 - 200 = 199,300)과 일치 + items 배열에 해당 매도 1건 포함 + 각 항목에 cost_basis_per_unit=11,000 포함(WAC = (100×10,000 + 100×12,000) / 200 = 11,000).
  2. Given 동일 포트폴리오, When GET /v1/portfolios/{id}/pnl/realized?from=2026-06-01&to=2026-06-30&symbol=005930.KS, Then symbol 필터가 적용되어 해당 symbol의 매도 건만 집계.
  3. Given from 파라미터 누락 또는 to 파라미터 누락, When 호출, Then HTTP 422 반환.
  4. Given 지정 기간에 매도 체결 0건, When 호출, Then HTTP 200 + total_realized_pnl=0 + items=[] 반환(404 아님).
  5. Given portfolio_ledger 이력이 포트폴리오 생성 초기부터 불완전한 경우(buy 이력 일부 누락 감지), When 호출, Then 응답 data_completeness_warning 필드에 경고 메시지 포함 + cost_basis_from에 집계 시작 시점 명시(R-1 완화 반영).
  6. Given portfolio_ledger 이력이 완전한 경우, When 호출, Then 응답 data_completeness_warning 필드가 null.
  7. Given 비소유자 사용자 token(admin 아님), When 타인 portfolio_id 조회, Then HTTP 403 반환.
  8. Given 존재하지 않는 portfolio_id, When 호출, Then HTTP 404 반환.
  9. Given 엔드포인트 구현 완료, When OpenAPI /docs 또는 openapi.json 확인, Then GET /v1/portfolios/{portfolio_id}/pnl/realized 경로가 파라미터 설명 및 응답 스키마(data_completeness_warning 포함)와 함께 문서화되어 있음(NFR-2 반영).
  10. Given 30일 범위 쿼리, When portfolio_ledger 인덱스 활용 환경에서 호출, Then p95 응답 시간 500ms 이하(NFR-1 반영 — 통합/성능 테스트 환경에서 검증).

Impacted Area

  • Docs:
    • docs/runtime-flows.md — GET /v1/portfolios/{id}/pnl/realized 흐름 추가 필요
    • docs/project-structure.md — app/api/v1_portfolios.py 책임 갱신, app/schemas/v1.py RealizedPnlResponse 추가
  • Modules:
    • app/api/v1_portfolios.py — GET 엔드포인트 추가(날짜/symbol 파라미터 파싱, 소유권 확인, service 계층 위임)
    • app/services/portfolio_service.py 또는 신규 — REQ-041 WAC 산출 로직 호출 + data_completeness_warning 판단
    • app/repositories/postgres.py — aggregate_realized_pnl(portfolio_id, from_, to_, symbol) 메서드 추가 (매도 이력 + WAC 산출용 buy 이력 조회)
    • app/repositories/portfolio_repository.py — abstract method 추가
    • app/schemas/v1.py — RealizedPnlItem, RealizedPnlResponse 스키마 추가(data_completeness_warning: str | None, cost_basis_from: date | None 포함)
  • Tests:
    • tests/test_v1_portfolios_pnl.py 신규 — AC-1~10 커버

Notes

  • AC-1의 수치 근거: WAC = (100×10,000 + 100×12,000) / 200 = 11,000. 실현 PnL = (15,000 - 11,000) × 50 - 500 - 200 = 200,000 - 700 = 199,300.
  • data_completeness_warning 트리거 조건(이력 불완전 감지 기준)은 REQ-041 구현 단계에서 구체화. 현재 가정: portfolio 생성 시점보다 이른 buy 이력이 없거나, cost_basis 산출 대상 buy 합산 수량이 매도 수량보다 적을 경우.
  • 미실현 PnL(현재가 연동)은 Out of Scope(dcy-007 범위 경계 확인).
  • 전체 portfolio 집계 PnL 뷰(OQ-2 결정: Out of Scope) — 단일 portfolio 단위만.
  • Source: dcy-007 FR-2, FR-3, FR-4, NFR-1, NFR-2, R-1, S-2.

Change Log

CHG-20260618-01

  • Date: 2026-06-18
  • Author: Justin Ko

Change Summary

  • 최초 생성 — dcy-007 confirm-discovery 후 draft-req 실행. 실현 PnL 집계 API 산출물.

Intent

  • dcy-007 FR-2/FR-4(실현 PnL 엔드포인트 신설 + read_token 인증)를 구현 가능한 Interface REQ로 정규화. R-1 완화 방안(경고 필드 + cost_basis_from)을 AC-5/AC-6에 반드시 반영.

Acceptance Criteria Delta

  • Added:
    • AC-1~10 최초 작성

Impacted Area Delta

  • Docs: docs/runtime-flows.md, docs/project-structure.md — 최초 지정
  • Modules: app/api/v1_portfolios.py, app/services/portfolio_service.py, app/repositories/postgres.py, app/repositories/portfolio_repository.py, app/schemas/v1.py — 최초 지정
  • Tests: tests/test_v1_portfolios_pnl.py — 최초 지정

Delivery Trace Delta

  • Batches: none (미정)
  • Releases: none (미정)

Revalidation Impact

  • Reverification Needed: no
  • Existing Implementation Invalidated: no
  • Status Recommendation: keep-current
  • Follow-up Action: confirm-req 후 batch 계획 편입; REQ-041 의존성 확인

Validation Plan

  • pytest TestClient로 AC-1~9 검증; AC-10 성능은 통합/성능 테스트 환경에서 검증

CHG-20260618-02

  • Date: 2026-06-18
  • Author: 팀장 (Claude)

Change Summary

  • confirm-req: Proposed → Approved. WAC 수치 AC-1(199,300)·R-1 경고 필드 AC-5/AC-6 확인, OQ-2 OoS 반영, blocker 없음. REQ-041 의존(동일 batch). M1 fast-track.

CHG-20260618-03

  • Date: 2026-06-18
  • Author: 팀장 (Claude)

Change Summary

  • confirm-req-implemented: Approved → Implemented. Evidence: BAT-017 release-candidate, 독립 QC PASS-WITH-NOTES, WAC 199,300 단위+e2e 검증, R-1 경고필드 정상, AC-1~9 PASS(AC-10 환경제약). 잔여(비차단): symbol 필터 edge 테스트 공백.