diff options
Diffstat (limited to 'services/portfolio-manager/src')
| -rw-r--r-- | services/portfolio-manager/src/portfolio_manager/main.py | 2 | ||||
| -rw-r--r-- | services/portfolio-manager/src/portfolio_manager/portfolio.py | 13 |
2 files changed, 12 insertions, 3 deletions
diff --git a/services/portfolio-manager/src/portfolio_manager/main.py b/services/portfolio-manager/src/portfolio_manager/main.py index c453745..a7f1a14 100644 --- a/services/portfolio-manager/src/portfolio_manager/main.py +++ b/services/portfolio-manager/src/portfolio_manager/main.py @@ -34,7 +34,7 @@ async def save_snapshot( unrealized = sum(p.unrealized_pnl for p in positions) await db.insert_portfolio_snapshot( total_value=total_value, - realized_pnl=Decimal("0"), # TODO: track realized PnL + realized_pnl=tracker.realized_pnl, unrealized_pnl=unrealized, ) await notifier.send_daily_summary(positions, total_value, unrealized) diff --git a/services/portfolio-manager/src/portfolio_manager/portfolio.py b/services/portfolio-manager/src/portfolio_manager/portfolio.py index 2c93643..4a7a11f 100644 --- a/services/portfolio-manager/src/portfolio_manager/portfolio.py +++ b/services/portfolio-manager/src/portfolio_manager/portfolio.py @@ -18,6 +18,11 @@ class PortfolioTracker: def __init__(self) -> None: self._positions: dict[str, _PositionState] = {} + self._realized_pnl: Decimal = Decimal("0") + + @property + def realized_pnl(self) -> Decimal: + return self._realized_pnl def _get_or_create(self, symbol: str) -> _PositionState: if symbol not in self._positions: @@ -35,8 +40,12 @@ class PortfolioTracker: if state.quantity > Decimal("0"): state.avg_entry = total_cost / state.quantity elif order.side == OrderSide.SELL: - state.quantity -= order.quantity - # Keep avg_entry unchanged unless fully sold + # Calculate realized PnL for this sell + sell_quantity = min(order.quantity, state.quantity) + if sell_quantity > 0 and state.avg_entry > 0: + self._realized_pnl += sell_quantity * (order.price - state.avg_entry) + + state.quantity -= sell_quantity if state.quantity <= Decimal("0"): state.quantity = Decimal("0") state.avg_entry = Decimal("0") |
