Files
portfolio-hub/docs/batches/bat-017_20260618_trade-history-and-pnl-api/implementation.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

2.9 KiB

BAT-017 Implementation

Status: Complete

Changed Files

New Files

File Purpose
app/domain/pnl.py WAC realized PnL calculation (REQ-041) — pure Python, no DB dependency
tests/test_wac_calculation.py WAC unit tests — 20 tests, DB-free (REQ-042)
tests/test_v1_portfolios_trades.py GET /trades integration tests — 12 tests (REQ-042)
tests/test_v1_portfolios_pnl.py GET /pnl/realized integration tests — 18 tests (REQ-042)

Modified Files

File Changes
app/schemas/v1.py Added date import; added TradeHistoryItem, TradeHistoryResponse, RealizedPnlItem, RealizedPnlResponse
app/api/v1_portfolios.py Added date, datetime, timedelta, timezone imports; added calculate_realized_pnl import; added schema imports; added _parse_date_param() helper; added list_portfolio_trades() endpoint (REQ-039); added get_realized_pnl() endpoint (REQ-040)
app/repositories/postgres.py Added list_trades_by_date() method (REQ-039); added get_all_trades_for_pnl() method (REQ-040/041)
app/repositories/portfolio_repository.py Added list_trades_by_date() and get_all_trades_for_pnl() abstract method signatures
docs/batches/index.md Added BAT-017 register row

Batch Documents

File Purpose
docs/batches/bat-017_.../index.md Batch index
docs/batches/bat-017_.../planning.md Planning
docs/batches/bat-017_.../design.md Design
docs/batches/bat-017_.../implementation.md This file
docs/batches/bat-017_.../verification.md Verification

Key Implementation Decisions

WAC 계산 함수 위치

  • app/domain/pnl.py 신규 — domain 계층 (REQ-041 Notes: domain 계층 권장)
  • app/services/portfolio_service.py 수정 없음 — WAC 함수는 domain에 독립 배치

_parse_date_param 날짜 형식 강제

  • Python 3.11+ date.fromisoformat()은 YYYYMMDD(대시 없음)도 수용함
  • REQ-039 AC-4 준수를 위해 re.fullmatch(r"\d{4}-\d{2}-\d{2}", value) 사전 검증 추가

get_all_trades_for_pnl 쿼리 설계

  • WAC 정확성 확보를 위해 집계 기간(from/to) 제약 없이 portfolio의 모든 buy/sell 이력 조회
  • Python domain 함수에서 from_dt/to_dt 파라미터로 sell 집계 필터 적용

list_trades_by_date 날짜 경계

  • date 단일: [date 00:00 UTC, date+1day 00:00 UTC) 반개구간
  • to_ 포함 경계: to_ + timedelta(days=1) exclusive upper bound 적용

data_completeness_warning 경고

  • running_qty=0에서 sell 발생 또는 sell qty > running_qty 시 경고 필드 설정
  • 계산은 중단하지 않고 최선 추정 계속 (REQ-041 AC-3/AC-4)

서비스/클라이언트 토큰 접근 제한

  • 두 엔드포인트 모두 token_type in ("service", "client") → 403
  • DB 토큰 또는 env 토큰(read 이상)만 접근 가능