Browse Source

Bugfix/liabilities without market data (#7345)

* Fix liabilities without market data

* Update changelog
pull/7346/head^2
Thomas Kaul 4 days ago
committed by GitHub
parent
commit
def15e544a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 7
      CHANGELOG.md
  2. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts
  3. 76
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts

7
CHANGELOG.md

@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Fixed
- Fixed an issue where the dividends, the interest and the liabilities of asset profiles without market data have been valued at zero in the portfolio calculation
- Fixed an issue where an error has been reported for asset profiles without market data which do not hold any units
## 3.27.0 - 2026-07-15
### Changed

2
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts

@ -113,7 +113,7 @@ describe('PortfolioCalculator', () => {
expect(portfolioSnapshot).toMatchObject({
currentValueInBaseCurrency: new Big('0'),
errors: [],
hasErrors: true,
hasErrors: false,
positions: [],
totalFeesWithCurrencyEffect: new Big('49'),
totalInterestWithCurrencyEffect: new Big('0'),

76
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts

@ -236,6 +236,36 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
};
}
// The dividends, the interest and the liabilities are derived from the
// activities only. Accumulate them upfront so that they survive the bail
// out for symbols without a market price below.
for (const order of orders) {
const exchangeRateAtOrderDate = exchangeRates[order.date];
if (order.type === 'DIVIDEND') {
const dividend = order.quantity.mul(order.unitPrice);
totalDividend = totalDividend.plus(dividend);
totalDividendInBaseCurrency = totalDividendInBaseCurrency.plus(
dividend.mul(exchangeRateAtOrderDate ?? 1)
);
} else if (order.type === 'INTEREST') {
const interest = order.quantity.mul(order.unitPrice);
totalInterest = totalInterest.plus(interest);
totalInterestInBaseCurrency = totalInterestInBaseCurrency.plus(
interest.mul(exchangeRateAtOrderDate ?? 1)
);
} else if (order.type === 'LIABILITY') {
const liabilities = order.quantity.mul(order.unitPrice);
totalLiabilities = totalLiabilities.plus(liabilities);
totalLiabilitiesInBaseCurrency = totalLiabilitiesInBaseCurrency.plus(
liabilities.mul(exchangeRateAtOrderDate ?? 1)
);
}
}
const dateOfFirstTransaction = new Date(orders[0].date);
const endDateString = format(end, DATE_FORMAT);
@ -263,7 +293,20 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
!unitPriceAtEndDate ||
(!unitPriceAtStartDate && isBefore(dateOfFirstTransaction, start))
) {
// A missing market price can only affect the units which are held. The
// dividends, the interest and the liabilities do not hold any units and
// are therefore not in error.
const hasActivitiesWithUnits = orders.some(({ type }) => {
return ['BUY', 'SELL'].includes(type);
});
return {
totalDividend,
totalDividendInBaseCurrency,
totalInterest,
totalInterestInBaseCurrency,
totalLiabilities,
totalLiabilitiesInBaseCurrency,
currentValues: {},
currentValuesWithCurrencyEffect: {},
feesWithCurrencyEffect: new Big(0),
@ -271,7 +314,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
grossPerformancePercentage: new Big(0),
grossPerformancePercentageWithCurrencyEffect: new Big(0),
grossPerformanceWithCurrencyEffect: new Big(0),
hasErrors: true,
hasErrors: hasActivitiesWithUnits,
initialValue: new Big(0),
initialValueWithCurrencyEffect: new Big(0),
investmentValuesAccumulated: {},
@ -288,14 +331,8 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
timeWeightedInvestmentValuesWithCurrencyEffect: {},
timeWeightedInvestmentWithCurrencyEffect: new Big(0),
totalAccountBalanceInBaseCurrency: new Big(0),
totalDividend: new Big(0),
totalDividendInBaseCurrency: new Big(0),
totalInterest: new Big(0),
totalInterestInBaseCurrency: new Big(0),
totalInvestment: new Big(0),
totalInvestmentWithCurrencyEffect: new Big(0),
totalLiabilities: new Big(0),
totalLiabilitiesInBaseCurrency: new Big(0)
totalInvestmentWithCurrencyEffect: new Big(0)
};
}
@ -415,29 +452,6 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
const exchangeRateAtOrderDate = exchangeRates[order.date];
if (order.type === 'DIVIDEND') {
const dividend = order.quantity.mul(order.unitPrice);
totalDividend = totalDividend.plus(dividend);
totalDividendInBaseCurrency = totalDividendInBaseCurrency.plus(
dividend.mul(exchangeRateAtOrderDate ?? 1)
);
} else if (order.type === 'INTEREST') {
const interest = order.quantity.mul(order.unitPrice);
totalInterest = totalInterest.plus(interest);
totalInterestInBaseCurrency = totalInterestInBaseCurrency.plus(
interest.mul(exchangeRateAtOrderDate ?? 1)
);
} else if (order.type === 'LIABILITY') {
const liabilities = order.quantity.mul(order.unitPrice);
totalLiabilities = totalLiabilities.plus(liabilities);
totalLiabilitiesInBaseCurrency = totalLiabilitiesInBaseCurrency.plus(
liabilities.mul(exchangeRateAtOrderDate ?? 1)
);
}
if (order.itemType === 'start') {
// Take the unit price of the order as the market price if there are no
// orders of this symbol before the start date

Loading…
Cancel
Save