Browse Source

Bugfix/end date of calendar year date ranges in portfolio performance (#8095)

* Fix end date of calendar year date ranges

* Update changelog
pull/8093/head
Thomas Kaul 1 day ago
committed by GitHub
parent
commit
8287c1c7ca
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 13
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  3. 44
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.spec.ts

1
CHANGELOG.md

@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed the missing list numbers in the top and bottom holdings on the analysis page in Safari - Fixed the missing list numbers in the top and bottom holdings on the analysis page in Safari
- Fixed the missing first data point in the portfolio evolution chart on the analysis page - Fixed the missing first data point in the portfolio evolution chart on the analysis page
- Fixed the end date of calendar year date ranges in the portfolio performance calculation for instances in time zones with a negative UTC offset
- Fixed the missing mapping for Korea in the country weightings of the _Financial Modeling Prep_ service - Fixed the missing mapping for Korea in the country weightings of the _Financial Modeling Prep_ service
## 3.81.0 - 2026-10-07 ## 3.81.0 - 2026-10-07

13
apps/api/src/app/portfolio/calculator/portfolio-calculator.ts

@ -1407,7 +1407,7 @@ export abstract class PortfolioCalculator {
return this.snapshot.totalLiabilitiesWithCurrencyEffect; return this.snapshot.totalLiabilitiesWithCurrencyEffect;
} }
public async getPerformance({ end, start }) { public async getPerformance({ end, start }: { end: Date; start: Date }) {
await this.snapshotPromise; await this.snapshotPromise;
const { historicalData } = this.snapshot; const { historicalData } = this.snapshot;
@ -1418,14 +1418,13 @@ export abstract class PortfolioCalculator {
let netPerformanceAtStartDate: number; let netPerformanceAtStartDate: number;
let netPerformanceWithCurrencyEffectAtStartDate: number; let netPerformanceWithCurrencyEffectAtStartDate: number;
const startDate = isEqual(start, endOfDay(start)) const endDate = this.toChartDate(end);
? resetHours(start) const startDate = this.toChartDate(start);
: start;
for (const historicalDataItem of historicalData) { for (const historicalDataItem of historicalData) {
const date = resetHours(parseDate(historicalDataItem.date)); const date = resetHours(parseDate(historicalDataItem.date));
if (!isBefore(date, startDate) && !isAfter(date, end)) { if (!isBefore(date, startDate) && !isAfter(date, endDate)) {
// Take the values at the start date from the first day of the date // Take the values at the start date from the first day of the date
// range // range
if (historicalDataItemsOfDateRange.length === 0) { if (historicalDataItemsOfDateRange.length === 0) {
@ -1915,4 +1914,8 @@ export abstract class PortfolioCalculator {
await this.initialize(attempt + 1); await this.initialize(attempt + 1);
} }
} }
private toChartDate(aDate: Date) {
return isEqual(aDate, endOfDay(aDate)) ? resetHours(aDate) : aDate;
}
} }

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

@ -1,3 +1,7 @@
/**
* @jest-environment <rootDir>/jest-environment-tz.js
* @jest-environment-options {"timeZone": "America/New_York"}
*/
import { PortfolioCalculator } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator'; import { PortfolioCalculator } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator';
import { userDummyData } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils'; import { userDummyData } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
@ -9,6 +13,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper';
import { HistoricalDataItem } from '@ghostfolio/common/interfaces'; import { HistoricalDataItem } from '@ghostfolio/common/interfaces';
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type';
@ -183,4 +188,43 @@ describe('PortfolioCalculator', () => {
).toBeCloseTo(0.23, 10); ).toBeCloseTo(0.23, 10);
}); });
}); });
describe('get performance', () => {
it('with a calendar year date range', async () => {
const snapshot = await portfolioCalculator.getSnapshot();
snapshot.historicalData = [
getHistoricalDataItem({
date: '2016-12-31',
investment: 100,
netPerformance: 0
}),
getHistoricalDataItem({
date: '2017-12-31',
investment: 100,
netPerformance: 10
}),
getHistoricalDataItem({
date: '2018-01-01',
investment: 100,
netPerformance: 20
})
];
const { endDate, startDate } = getIntervalFromDateRange({
dateRange: '2017'
});
const { chart } = await portfolioCalculator.getPerformance({
end: endDate,
start: startDate
});
expect(
chart.map(({ date }) => {
return date;
})
).toEqual(['2016-12-31', '2017-12-31']);
});
});
}); });

Loading…
Cancel
Save