diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 553cb8c90..467449090 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -51,6 +51,7 @@ import { format, isAfter, isBefore, + isSameYear, isWithinInterval, min, startOfDay, @@ -784,6 +785,46 @@ export abstract class PortfolioCalculator { return { chart }; } + public async getPerformanceByGroup({ + endDate, + groupBy, + startDate + }: { + endDate: Date; + groupBy: GroupBy; + startDate: Date; + }) { + const interval = { start: startDate, end: endDate }; + const chart: HistoricalDataItem[] = []; + + if (groupBy === 'year') { + for (const year of eachYearOfInterval(interval)) { + const yearStartDate = startOfYear(year); + const yearEndDate = endOfYear(year); + const yearIntervalStartDate = isSameYear(startDate, yearStartDate) + ? startDate + : yearStartDate; + const yearIntervalEndDate = isSameYear(endDate, yearEndDate) + ? endDate + : yearEndDate; + + const { chart: yearChart } = await this.getPerformance({ + end: yearIntervalEndDate, + start: yearIntervalStartDate + }); + + const yearPerformanceItem = { + ...(yearChart.at(-1) ?? ({} as HistoricalDataItem)), + date: format(yearStartDate, DATE_FORMAT) + }; + + chart.push(yearPerformanceItem); + } + } + + return { chart }; + } + public async getSnapshot() { await this.snapshotPromise; diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 73d4320d6..f9758d0b9 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -510,6 +510,7 @@ export class PortfolioController { @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, @Query('dataSource') filterByDataSource?: string, + @Query('groupBy') groupBy?: Extract, @Query('range') dateRange: DateRange = 'max', @Query('symbol') filterBySymbol?: string, @Query('tags') filterByTags?: string, @@ -528,6 +529,7 @@ export class PortfolioController { const performanceInformation = await this.portfolioService.getPerformance({ dateRange, filters, + groupBy, impersonationId, withExcludedAccounts, userId: this.request.user.id diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 5dab27939..d59875575 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -991,11 +991,13 @@ export class PortfolioService { public async getPerformance({ dateRange = 'max', filters, + groupBy, impersonationId, userId }: { dateRange?: DateRange; filters?: Filter[]; + groupBy?: Extract; impersonationId: string; userId: string; withExcludedAccounts?: boolean; @@ -1049,11 +1051,24 @@ export class PortfolioService { const { endDate, startDate } = getIntervalFromDateRange(dateRange); - const { chart } = await portfolioCalculator.getPerformance({ + const { chart: intervalChart } = await portfolioCalculator.getPerformance({ end: endDate, start: startDate }); + let chart = intervalChart; + + if (groupBy) { + const { chart: groupedChart } = + await portfolioCalculator.getPerformanceByGroup({ + startDate, + endDate, + groupBy + }); + + chart = groupedChart; + } + const { netPerformance, netPerformanceInPercentage, @@ -1063,7 +1078,7 @@ export class PortfolioService { totalInvestment, totalInvestmentValueWithCurrencyEffect, valueWithCurrencyEffect - } = chart?.at(-1) ?? { + } = intervalChart?.at(-1) ?? { netPerformance: 0, netPerformanceInPercentage: 0, netPerformanceInPercentageWithCurrencyEffect: 0,