fix: count brokerage cash once and skip short-position return percent (WealthLedger/backend#140)

This commit is contained in:
2026-10-28 08:00:20 +03:00
parent 97fc41fa29
commit f2843e30bd
6 changed files with 65 additions and 8 deletions
@@ -19,6 +19,7 @@ import {
} from './brokerage-account.dto';
const PERCENT_DECIMAL_PLACES = 2;
const ZERO_QUANTITY = 0n;
function unrealizedReturns(positions: PortfolioPositionDto[]): UnrealizedReturnDto[] {
// Cash-like CURRENCY positions must not duplicate the separately returned cash balances.
@@ -47,6 +48,13 @@ function unrealizedReturns(positions: PortfolioPositionDto[]): UnrealizedReturnD
return money ? [money.currency] : [];
}),
);
// A short position has negative cost basis, so a percent would flip sign or net out.
const withShorts = new Set(
investments.flatMap((position) => {
const money = position.absoluteReturn ?? position.averagePurchasePrice ?? position.currentValue;
return money && decimalFromString(position.quantity).value < ZERO_QUANTITY ? [money.currency] : [];
}),
);
const currencies = new Set([...absolute, ...costs].map((money) => money.currency));
return [...new Set([...currencies, ...partial])]
.sort((left, right) => left.localeCompare(right))
@@ -58,7 +66,7 @@ function unrealizedReturns(positions: PortfolioPositionDto[]): UnrealizedReturnD
currency,
absolute: absoluteReturn,
costBasis,
percent: isZero(cost)
percent: isZero(cost) || withShorts.has(currency)
? null
: formatDecimal(divide(
multiply(decimalFromString(absoluteReturn), decimalFromString('100')),