Browse Source

Bugfix/market price carry forward on dates with activities (#7702)

* Fix market price carry forward on dates with activities

* Update changelog
pull/7690/head
Thomas Kaul 5 days ago
committed by GitHub
parent
commit
1d00342702
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 4
      CHANGELOG.md
  2. 43
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts
  3. 12
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts

4
CHANGELOG.md

@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Extended the holdings table by the date of first activity in the _Copy AI prompt to clipboard for analysis_ action on the analysis page (experimental) - Extended the holdings table by the date of first activity in the _Copy AI prompt to clipboard for analysis_ action on the analysis page (experimental)
- Extended the holdings table by the date of first activity in the _Copy portfolio data to clipboard for AI prompt_ action on the analysis page (experimental) - Extended the holdings table by the date of first activity in the _Copy portfolio data to clipboard for AI prompt_ action on the analysis page (experimental)
### Fixed
- Fixed the performance calculation for dates without historical market data by carrying forward the market price from dates with activities
## 3.58.0 - 2026-08-22 ## 3.58.0 - 2026-08-22
### Changed ### Changed

43
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts

@ -293,5 +293,48 @@ describe('PortfolioCalculator', () => {
// Closing price on 2021-11-30: 136.6 // Closing price on 2021-11-30: 136.6
expect(snapshotOnBuyDate?.netPerformanceWithCurrencyEffect).toEqual(1.65); // 2 * (136.6 - 135.0) - 1.55 = 1.65 expect(snapshotOnBuyDate?.netPerformanceWithCurrencyEffect).toEqual(1.65); // 2 * (136.6 - 135.0) - 1.55 = 1.65
}); });
it.only('with BALN.SW buy (on a date without historical market data)', async () => {
jest.useFakeTimers().setSystemTime(parseDate('2021-12-18').getTime());
const activities: Activity[] = [
{
...activityDummyData,
assetProfile: {
...assetProfileDummyData,
currency: 'CHF',
dataSource: 'YAHOO',
name: 'Bâloise Holding AG',
symbol: 'BALN.SW'
},
date: new Date('2021-11-30'),
feeInAssetProfileCurrency: 1.55,
feeInBaseCurrency: 1.55,
quantity: 2,
type: 'BUY',
unitPriceInAssetProfileCurrency: 136.6
}
];
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.ROAI,
currency: 'CHF',
userId: userDummyData.id
});
const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
const snapshotOnDateWithoutMarketData =
portfolioSnapshot.historicalData.find(({ date }) => {
return date === '2021-12-05';
});
// No historical market data on 2021-12-05: carry forward the closing
// price of 2021-11-30, which is the date of the activity
expect(snapshotOnDateWithoutMarketData?.value).toEqual(273.2); // 2 * 136.6
expect(
snapshotOnDateWithoutMarketData?.netPerformanceWithCurrencyEffect
).toEqual(-1.55); // 2 * (136.6 - 136.6) - 1.55
});
}); });
}); });

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

@ -391,16 +391,13 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
break; break;
} }
const unitPrice = marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice;
if (ordersByDate[dateString]?.length > 0) { if (ordersByDate[dateString]?.length > 0) {
for (const order of ordersByDate[dateString]) { for (const order of ordersByDate[dateString]) {
order.unitPriceFromMarketData = order.unitPriceFromMarketData = unitPrice;
marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice;
} }
} else { } else if (dateString >= dateStringOfFirstActivity) {
const unitPrice =
marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice;
if (dateString >= dateStringOfFirstActivity) {
orders.push({ orders.push({
assetProfile, assetProfile,
unitPrice, unitPrice,
@ -415,7 +412,6 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
lastUnitPrice = unitPrice; lastUnitPrice = unitPrice;
} }
}
// Sort orders so that the start and end placeholder order are at the correct // Sort orders so that the start and end placeholder order are at the correct
// position // position

Loading…
Cancel
Save