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
This commit is contained in:
+48
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from typing import Any, Literal
|
||||
|
||||
@@ -249,3 +249,50 @@ class AssetCatalogResponse(BaseModel):
|
||||
class AssetCatalogListResponse(BaseModel):
|
||||
items: list[AssetCatalogResponse]
|
||||
total: int
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# GET /v1/portfolios/{id}/trades (REQ-039)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TradeHistoryItem(BaseModel):
|
||||
ledger_entry_id: int
|
||||
portfolio_id: str
|
||||
order_id: str | None = None
|
||||
execution_id: str | None = None
|
||||
side: str
|
||||
quantity: float
|
||||
price: float
|
||||
fee_amount: float
|
||||
tax_amount: float
|
||||
executed_at: datetime
|
||||
recorded_at: datetime | None = None
|
||||
|
||||
|
||||
class TradeHistoryResponse(BaseModel):
|
||||
items: list[TradeHistoryItem]
|
||||
total: int
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# GET /v1/portfolios/{id}/pnl/realized (REQ-040)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class RealizedPnlItem(BaseModel):
|
||||
symbol: str | None = None
|
||||
executed_at: datetime | None = None
|
||||
quantity: float
|
||||
sell_price: float
|
||||
cost_basis_per_unit: float
|
||||
fee_amount: float
|
||||
tax_amount: float
|
||||
realized_pnl: float
|
||||
order_id: str | None = None
|
||||
execution_id: str | None = None
|
||||
|
||||
|
||||
class RealizedPnlResponse(BaseModel):
|
||||
total_realized_pnl: float
|
||||
items: list[RealizedPnlItem]
|
||||
cost_basis_from: datetime | None = None
|
||||
data_completeness_warning: str | None = None
|
||||
|
||||
Reference in New Issue
Block a user