From c82b26acf94d73f6c35fc3bcefe80d90dad40355 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 27 Aug 2026 08:29:22 +0300 Subject: [PATCH] fix: avoid incomplete unrealized result --- backend/src/services/portfolio.ts | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/backend/src/services/portfolio.ts b/backend/src/services/portfolio.ts index c059f35..5538f12 100644 --- a/backend/src/services/portfolio.ts +++ b/backend/src/services/portfolio.ts @@ -252,17 +252,30 @@ export function calculatePortfolioTradeResults(trades: PerformanceTradeRow[], po lots.set(key, queue); result.set(accountId, current); } - const positionCost = new Map(); - for (const [key, queue] of lots) positionCost.set(key, queue.reduce((sum, lot) => sum + lot.cost, 0)); + const incomplete = new Set(); for (const position of positions) { const accountId = Number(position.account_id); const current = result.get(accountId) ?? { fees: 0, realized: 0, unrealized: 0 }; if (position.valuation !== null) { const key = `${accountId}:${position.isin ?? position.instrument}`; - current.unrealized = (current.unrealized ?? 0) + Number(position.valuation) - (positionCost.get(key) ?? 0); + const queue = lots.get(key) ?? []; + let remaining = Number(position.quantity); + let cost = 0; + for (const lot of queue) { + if (remaining <= 0) break; + const used = Math.min(remaining, lot.quantity); + cost += used * (lot.cost / lot.quantity); + remaining -= used; + } + if (remaining > 0.0000001) incomplete.add(accountId); + else if (!incomplete.has(accountId)) current.unrealized = (current.unrealized ?? 0) + Number(position.valuation) - cost; } result.set(accountId, current); } + for (const accountId of incomplete) { + const current = result.get(accountId); + if (current) current.unrealized = null; + } return result; }