diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 553cb8c90..bf5ac055d 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -18,12 +18,7 @@ import { PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_HIGH, PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_LOW } from '@ghostfolio/common/config'; -import { - DATE_FORMAT, - getSum, - parseDate, - resetHours -} from '@ghostfolio/common/helper'; +import { DATE_FORMAT, getSum, parseDate } from '@ghostfolio/common/helper'; import { Activity, AssetProfileIdentifier, @@ -57,7 +52,7 @@ import { startOfYear, subDays } from 'date-fns'; -import { isNumber, sortBy, sum, uniqBy } from 'lodash'; +import { groupBy as ldGroupBy, isNumber, sortBy, sum, uniqBy } from 'lodash'; export abstract class PortfolioCalculator { protected static readonly ENABLE_LOGGING = false; @@ -716,68 +711,89 @@ export abstract class PortfolioCalculator { return this.snapshot.totalLiabilitiesWithCurrencyEffect; } - public async getPerformance({ end, start }) { - await this.snapshotPromise; - - const { historicalData } = this.snapshot; - + public getPerformance({ data }: { data: HistoricalDataItem[] }) { const chart: HistoricalDataItem[] = []; let netPerformanceAtStartDate: number; let netPerformanceWithCurrencyEffectAtStartDate: number; const totalInvestmentValuesWithCurrencyEffect: number[] = []; - for (const historicalDataItem of historicalData) { - const date = resetHours(parseDate(historicalDataItem.date)); + for (const historicalDataItem of data) { + if (!isNumber(netPerformanceAtStartDate)) { + netPerformanceAtStartDate = historicalDataItem.netPerformance; - if (!isBefore(date, start) && !isAfter(date, end)) { - if (!isNumber(netPerformanceAtStartDate)) { - netPerformanceAtStartDate = historicalDataItem.netPerformance; + netPerformanceWithCurrencyEffectAtStartDate = + historicalDataItem.netPerformanceWithCurrencyEffect; + } - netPerformanceWithCurrencyEffectAtStartDate = - historicalDataItem.netPerformanceWithCurrencyEffect; - } + const netPerformanceSinceStartDate = + historicalDataItem.netPerformance - netPerformanceAtStartDate; + + const netPerformanceWithCurrencyEffectSinceStartDate = + historicalDataItem.netPerformanceWithCurrencyEffect - + netPerformanceWithCurrencyEffectAtStartDate; - const netPerformanceSinceStartDate = - historicalDataItem.netPerformance - netPerformanceAtStartDate; + if (historicalDataItem.totalInvestmentValueWithCurrencyEffect > 0) { + totalInvestmentValuesWithCurrencyEffect.push( + historicalDataItem.totalInvestmentValueWithCurrencyEffect + ); + } - const netPerformanceWithCurrencyEffectSinceStartDate = - historicalDataItem.netPerformanceWithCurrencyEffect - - netPerformanceWithCurrencyEffectAtStartDate; + const timeWeightedInvestmentValue = + totalInvestmentValuesWithCurrencyEffect.length > 0 + ? sum(totalInvestmentValuesWithCurrencyEffect) / + totalInvestmentValuesWithCurrencyEffect.length + : 0; - if (historicalDataItem.totalInvestmentValueWithCurrencyEffect > 0) { - totalInvestmentValuesWithCurrencyEffect.push( - historicalDataItem.totalInvestmentValueWithCurrencyEffect - ); - } + chart.push({ + ...historicalDataItem, + netPerformance: + historicalDataItem.netPerformance - netPerformanceAtStartDate, + netPerformanceWithCurrencyEffect: + netPerformanceWithCurrencyEffectSinceStartDate, + netPerformanceInPercentage: + timeWeightedInvestmentValue === 0 + ? 0 + : netPerformanceSinceStartDate / timeWeightedInvestmentValue, + netPerformanceInPercentageWithCurrencyEffect: + timeWeightedInvestmentValue === 0 + ? 0 + : netPerformanceWithCurrencyEffectSinceStartDate / + timeWeightedInvestmentValue + // TODO: Add net worth + // netWorth: totalCurrentValueWithCurrencyEffect + // .plus(totalAccountBalanceWithCurrencyEffect) + // .toNumber() + // netWorth: 0 + }); + } - const timeWeightedInvestmentValue = - totalInvestmentValuesWithCurrencyEffect.length > 0 - ? sum(totalInvestmentValuesWithCurrencyEffect) / - totalInvestmentValuesWithCurrencyEffect.length - : 0; - - chart.push({ - ...historicalDataItem, - netPerformance: - historicalDataItem.netPerformance - netPerformanceAtStartDate, - netPerformanceWithCurrencyEffect: - netPerformanceWithCurrencyEffectSinceStartDate, - netPerformanceInPercentage: - timeWeightedInvestmentValue === 0 - ? 0 - : netPerformanceSinceStartDate / timeWeightedInvestmentValue, - netPerformanceInPercentageWithCurrencyEffect: - timeWeightedInvestmentValue === 0 - ? 0 - : netPerformanceWithCurrencyEffectSinceStartDate / - timeWeightedInvestmentValue - // TODO: Add net worth - // netWorth: totalCurrentValueWithCurrencyEffect - // .plus(totalAccountBalanceWithCurrencyEffect) - // .toNumber() - // netWorth: 0 + return { chart }; + } + + public getPerformanceByGroup({ + data, + groupBy + }: { + data: HistoricalDataItem[]; + groupBy: Extract; + }) { + const chart: HistoricalDataItem[] = []; + + if (groupBy === 'year') { + const dataByYear = ldGroupBy(data, (item) => item.date.slice(0, 4)); + + for (const year of Object.keys(dataByYear)) { + const { chart: yearChart } = this.getPerformance({ + data: Object.values(dataByYear[year]) }); + + const yearPerformanceItem = { + ...(yearChart.at(-1) ?? ({} as HistoricalDataItem)), + date: format(startOfYear(year), DATE_FORMAT) + }; + + chart.push(yearPerformanceItem); } } diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts index 9a93d0419..7f6bd3623 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts @@ -138,6 +138,11 @@ describe('PortfolioCalculator', () => { groupBy: 'year' }); + const performanceByYear = portfolioCalculator.getPerformanceByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('595.6'), errors: [], @@ -212,6 +217,16 @@ describe('PortfolioCalculator', () => { expect(investmentsByYear).toEqual([ { date: '2021-01-01', investment: 559 } ]); + + expect(performanceByYear.chart).toEqual([ + expect.objectContaining({ + date: '2021-01-01', + netPerformance: 33.4, + netPerformanceInPercentage: 0.06986689805847808, + netPerformanceInPercentageWithCurrencyEffect: 0.06986689805847808, + netPerformanceWithCurrencyEffect: 33.4 + }) + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts index c876d0db1..7eea1b609 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts @@ -154,6 +154,11 @@ describe('PortfolioCalculator', () => { groupBy: 'year' }); + const performanceByYear = portfolioCalculator.getPerformanceByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('0'), errors: [], @@ -226,6 +231,16 @@ describe('PortfolioCalculator', () => { expect(investmentsByYear).toEqual([ { date: '2021-01-01', investment: 0 } ]); + + expect(performanceByYear.chart).toEqual([ + expect.objectContaining({ + date: '2021-01-01', + netPerformance: -15.8, + netPerformanceInPercentage: -0.05528341497550735, + netPerformanceInPercentageWithCurrencyEffect: -0.05528341497550735, + netPerformanceWithCurrencyEffect: -15.8 + }) + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts index ae921d6d9..d952ed709 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts @@ -138,6 +138,11 @@ describe('PortfolioCalculator', () => { groupBy: 'year' }); + const performanceByYear = portfolioCalculator.getPerformanceByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('0'), errors: [], @@ -210,6 +215,16 @@ describe('PortfolioCalculator', () => { expect(investmentsByYear).toEqual([ { date: '2021-01-01', investment: 0 } ]); + + expect(performanceByYear.chart).toEqual([ + expect.objectContaining({ + date: '2021-01-01', + netPerformance: -15.8, + netPerformanceInPercentage: -0.05528341497550735, + netPerformanceInPercentageWithCurrencyEffect: -0.05528341497550735, + netPerformanceWithCurrencyEffect: -15.8 + }) + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts index 6207f1417..f0d4ae491 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts @@ -128,6 +128,11 @@ describe('PortfolioCalculator', () => { groupBy: 'year' }); + const performanceByYear = portfolioCalculator.getPerformanceByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('297.8'), errors: [], @@ -209,6 +214,16 @@ describe('PortfolioCalculator', () => { expect(investmentsByYear).toEqual([ { date: '2021-01-01', investment: 273.2 } ]); + + expect(performanceByYear.chart).toEqual([ + expect.objectContaining({ + date: '2021-01-01', + netPerformance: 23.05, + netPerformanceInPercentage: 0.08437042459736459, + netPerformanceInPercentageWithCurrencyEffect: 0.08437042459736459, + netPerformanceWithCurrencyEffect: 23.05 + }) + ]); }); it.only('with BALN.SW buy (with unit price lower than closing price)', async () => { diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts index 055356325..c6ac9e3e3 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts @@ -137,6 +137,11 @@ describe('PortfolioCalculator', () => { groupBy: 'year' }); + const performanceByYear = portfolioCalculator.getPerformanceByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot.historicalData[0]).toEqual({ date: '2021-12-11', investmentValueWithCurrencyEffect: 0, @@ -255,6 +260,23 @@ describe('PortfolioCalculator', () => { { date: '2021-01-01', investment: 44558.42 }, { date: '2022-01-01', investment: 0 } ]); + + expect(performanceByYear.chart).toEqual([ + expect.objectContaining({ + date: '2021-01-01', + netPerformance: -1463.18, + netPerformanceInPercentage: -0.03283734028271199, + netPerformanceInPercentageWithCurrencyEffect: -0.03283734028271199, + netPerformanceWithCurrencyEffect: -1463.18 + }), + expect.objectContaining({ + date: '2022-01-01', + netPerformance: 0, + netPerformanceInPercentage: 0, + netPerformanceInPercentageWithCurrencyEffect: 0, + netPerformanceWithCurrencyEffect: 0 + }) + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts index 11765fc49..a61e0a62d 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts @@ -151,6 +151,11 @@ describe('PortfolioCalculator', () => { groupBy: 'year' }); + const performanceByYear = portfolioCalculator.getPerformanceByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('13298.425356'), errors: [], @@ -266,6 +271,40 @@ describe('PortfolioCalculator', () => { { date: '2017-01-01', investment: -318.54266729999995 }, { date: '2018-01-01', investment: 0 } ]); + + expect(performanceByYear.chart).toEqual([ + expect.objectContaining({ + date: '2014-01-01', + netPerformance: 0, + netPerformanceInPercentage: 0, + netPerformanceInPercentageWithCurrencyEffect: 0, + netPerformanceWithCurrencyEffect: 0 + }), + expect.objectContaining({ + date: '2015-01-01', + netPerformance: 25984.861407, + netPerformanceInPercentage: 40.787097105782344, + netPerformanceInPercentageWithCurrencyEffect: 41.893291864515064, + netPerformanceWithCurrencyEffect: 26689.601865 + }), + expect.objectContaining({ + date: '2016-01-01', + netPerformance: 0, + netPerformanceInPercentage: 0, + netPerformanceInPercentageWithCurrencyEffect: 0, + netPerformanceWithCurrencyEffect: 0 + }), + expect.objectContaining({ + date: '2017-01-01', + netPerformance: 972.1720319999986, + netPerformanceInPercentage: 1.5306926710921496, + netPerformanceInPercentageWithCurrencyEffect: 0.6224618479468005, + netPerformanceWithCurrencyEffect: 395.3373599999977 + }), + expect.objectContaining({ + date: '2018-01-01' + }) + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts index 64882061f..406792ba7 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts @@ -137,6 +137,11 @@ describe('PortfolioCalculator', () => { groupBy: 'year' }); + const performanceByYear = portfolioCalculator.getPerformanceByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot.historicalData[0]).toEqual({ date: '2021-12-11', investmentValueWithCurrencyEffect: 0, @@ -255,6 +260,23 @@ describe('PortfolioCalculator', () => { { date: '2021-01-01', investment: 44558.42 }, { date: '2022-01-01', investment: 0 } ]); + + expect(performanceByYear.chart).toEqual([ + expect.objectContaining({ + date: '2021-01-01', + netPerformance: -1463.18, + netPerformanceInPercentage: -0.03283734028271199, + netPerformanceInPercentageWithCurrencyEffect: -0.03283734028271199, + netPerformanceWithCurrencyEffect: -1463.18 + }), + expect.objectContaining({ + date: '2022-01-01', + netPerformance: 0, + netPerformanceInPercentage: 0, + netPerformanceInPercentageWithCurrencyEffect: 0, + netPerformanceWithCurrencyEffect: 0 + }) + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts index 122a9aaed..8374e4a8e 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts @@ -134,6 +134,11 @@ describe('PortfolioCalculator', () => { groupBy: 'year' }); + const performanceByYear = portfolioCalculator.getPerformanceByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('103.10483'), errors: [], @@ -228,6 +233,16 @@ describe('PortfolioCalculator', () => { expect(investmentsByYear).toEqual([ { date: '2023-01-01', investment: 82.329056 } ]); + + expect(performanceByYear.chart).toEqual([ + expect.objectContaining({ + date: '2023-01-01', + netPerformance: 23.312582, + netPerformanceInPercentage: 0.2831634799747973, + netPerformanceInPercentageWithCurrencyEffect: 0.2411296201428566, + netPerformanceWithCurrencyEffect: 19.851974 + }) + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-jnug-buy-and-sell-and-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-jnug-buy-and-sell-and-buy-and-sell.spec.ts index d5b22e864..9d49f5c9e 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-jnug-buy-and-sell-and-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-jnug-buy-and-sell-and-buy-and-sell.spec.ts @@ -134,6 +134,11 @@ describe('PortfolioCalculator', () => { groupBy: 'year' }); + const performanceByYear = portfolioCalculator.getPerformanceByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('0'), errors: [], @@ -185,6 +190,16 @@ describe('PortfolioCalculator', () => { expect(investmentsByYear).toEqual([ { date: '2025-01-01', investment: 0 } ]); + + expect(performanceByYear.chart).toEqual([ + expect.objectContaining({ + date: '2025-01-01', + netPerformance: 39.95, + netPerformanceInPercentage: 0.020208978362720148, + netPerformanceInPercentageWithCurrencyEffect: 0.020208978362720148, + netPerformanceWithCurrencyEffect: 39.95 + }) + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts index 6c47af7ca..2dc3bd56c 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts @@ -98,6 +98,11 @@ describe('PortfolioCalculator', () => { groupBy: 'year' }); + const performanceByYear = portfolioCalculator.getPerformanceByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big(0), hasErrors: false, @@ -115,6 +120,8 @@ describe('PortfolioCalculator', () => { expect(investmentsByMonth).toEqual([]); expect(investmentsByYear).toEqual([]); + + expect(performanceByYear.chart).toEqual([]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts index 3034e3a1f..8e20b03e6 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts @@ -134,6 +134,11 @@ describe('PortfolioCalculator', () => { groupBy: 'year' }); + const performanceByYear = portfolioCalculator.getPerformanceByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('87.8'), errors: [], @@ -208,6 +213,16 @@ describe('PortfolioCalculator', () => { expect(investmentsByYear).toEqual([ { date: '2022-01-01', investment: 75.8 } ]); + + expect(performanceByYear.chart).toEqual([ + expect.objectContaining({ + date: '2022-01-01', + netPerformance: 17.68, + netPerformanceInPercentage: 0.12348284960422161, + netPerformanceInPercentageWithCurrencyEffect: 0.12348284960422161, + netPerformanceWithCurrencyEffect: 17.68 + }) + ]); }); }); }); 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..103d95a7a 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; @@ -1004,6 +1006,8 @@ export class PortfolioService { const user = await this.userService.user({ id: userId }); const userCurrency = this.getUserCurrency(user); + const { endDate, startDate } = getIntervalFromDateRange(dateRange); + const [accountBalanceItems, { activities }] = await Promise.all([ this.accountBalanceService.getAccountBalanceItems({ filters, @@ -1047,13 +1051,27 @@ export class PortfolioService { const { errors, hasErrors, historicalData } = await portfolioCalculator.getSnapshot(); - const { endDate, startDate } = getIntervalFromDateRange(dateRange); + const items = historicalData.filter(({ date }) => { + return !isBefore(date, startDate) && !isAfter(date, endDate); + }); - const { chart } = await portfolioCalculator.getPerformance({ - end: endDate, - start: startDate + const { chart: intervalChart } = portfolioCalculator.getPerformance({ + data: items }); + let chart = intervalChart; + + if (groupBy) { + const { chart: groupedChart } = portfolioCalculator.getPerformanceByGroup( + { + data: items, + groupBy + } + ); + + chart = groupedChart; + } + const { netPerformance, netPerformanceInPercentage, @@ -1063,7 +1081,7 @@ export class PortfolioService { totalInvestment, totalInvestmentValueWithCurrencyEffect, valueWithCurrencyEffect - } = chart?.at(-1) ?? { + } = intervalChart?.at(-1) ?? { netPerformance: 0, netPerformanceInPercentage: 0, netPerformanceInPercentageWithCurrencyEffect: 0,