diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index d9efa9f86c..537a227b9a 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -544,6 +544,12 @@ export abstract class PortfolioCalculator { } } + const totalDividendValueByDate = this.getTotalDividendValueByDate({ + chartDates, + exchangeRatesByCurrency, + holdings: positions + }); + const assetProfileIdentifiers = Object.keys(valuesByAssetProfileIdentifier); for (const dateString of chartDates) { @@ -620,6 +626,7 @@ export abstract class PortfolioCalculator { accumulatedValuesByDate[dateString] ?.totalCurrentValueWithCurrencyEffect ?? new Big(0) ).add(currentValueWithCurrencyEffect), + totalDividendValue: totalDividendValueByDate[dateString], totalInvestmentValue: ( accumulatedValuesByDate[dateString]?.totalInvestmentValue ?? new Big(0) @@ -656,6 +663,7 @@ export abstract class PortfolioCalculator { totalCashValueWithCurrencyEffect, totalCurrentValue, totalCurrentValueWithCurrencyEffect, + totalDividendValue, totalInvestmentValue, totalInvestmentValueWithCurrencyEffect, totalNetPerformanceValue, @@ -666,6 +674,7 @@ export abstract class PortfolioCalculator { return { ...performancePercentagesByDate[date], date, + dividendInBaseCurrency: totalDividendValue.toNumber(), investmentValueWithCurrencyEffect: investmentValueWithCurrencyEffect.toNumber(), netPerformance: totalNetPerformanceValue.toNumber(), @@ -1343,6 +1352,7 @@ export abstract class PortfolioCalculator { const historicalDataItemsOfDateRange: HistoricalDataItem[] = []; + let dividendInBaseCurrencyAtStartDate: number; let netPerformanceAtStartDate: number; let netPerformanceWithCurrencyEffectAtStartDate: number; @@ -1353,6 +1363,9 @@ export abstract class PortfolioCalculator { // Take the values at the start date from the first day of the date // range if (historicalDataItemsOfDateRange.length === 0) { + dividendInBaseCurrencyAtStartDate = + historicalDataItem.dividendInBaseCurrency ?? 0; + netPerformanceAtStartDate = historicalDataItem.netPerformance; netPerformanceWithCurrencyEffectAtStartDate = @@ -1361,6 +1374,11 @@ export abstract class PortfolioCalculator { historicalDataItemsOfDateRange.push({ ...historicalDataItem, + // TODO: Remove the fallback to 0 with the next release, when each + // cached portfolio snapshot contains the dividend + dividendInBaseCurrency: + (historicalDataItem.dividendInBaseCurrency ?? 0) - + dividendInBaseCurrencyAtStartDate, netPerformance: historicalDataItem.netPerformance - netPerformanceAtStartDate, netPerformanceWithCurrencyEffect: @@ -1734,6 +1752,74 @@ export abstract class PortfolioCalculator { return chartDateMap; } + private getTotalDividendValueByDate({ + chartDates, + exchangeRatesByCurrency, + holdings + }: { + chartDates: string[]; + exchangeRatesByCurrency: { + [currencyPair: string]: { [dateString: string]: number }; + }; + holdings: PortfolioCalculatorHolding[]; + }): { [date: string]: Big } { + // Take the dividend from the same holdings as the portfolio summary, so + // that the response shows one dividend only + const assetProfileIdentifiersIncludedInHoldings = new Set( + holdings + .filter(({ includeInHoldings }) => { + return includeInHoldings; + }) + .map(({ dataSource, symbol }) => { + return getAssetProfileIdentifier({ dataSource, symbol }); + }) + ); + + const dividendActivities = this.activities.filter( + ({ assetProfile, type }) => { + return ( + type === 'DIVIDEND' && + assetProfileIdentifiersIncludedInHoldings.has( + getAssetProfileIdentifier(assetProfile) + ) + ); + } + ); + + const totalDividendValueByDate: { [date: string]: Big } = {}; + + let index = 0; + let totalDividendValue = new Big(0); + + // The activities and the chart dates are sorted by date, so one pass over + // both gives the dividends received up to each chart date + for (const chartDate of chartDates) { + while ( + index < dividendActivities.length && + dividendActivities[index].date <= chartDate + ) { + const { assetProfile, date, quantity, unitPrice } = + dividendActivities[index]; + + totalDividendValue = totalDividendValue.plus( + quantity + .mul(unitPrice) + .mul( + exchangeRatesByCurrency[ + `${assetProfile.currency}${this.currency}` + ]?.[date] ?? 1 + ) + ); + + index++; + } + + totalDividendValueByDate[chartDate] = totalDividendValue; + } + + return totalDividendValueByDate; + } + @LogPerformance private async initialize(attempt = 1) { const startTimeTotal = performance.now(); 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 aadf2e23a0..ed8841b167 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 @@ -142,6 +142,8 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData[0]).toEqual({ date: '2021-12-11', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, netPerformanceInPercentage: 0, @@ -160,6 +162,8 @@ describe('PortfolioCalculator', () => { */ expect(portfolioSnapshot.historicalData[1]).toEqual({ date: '2021-12-12', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 44558.42, netPerformance: 5535.42, // 1 * (50098.3 - 44558.42) - 4.46 = 5535.42 netPerformanceInPercentage: 0.12422837255001412, // 5535.42 ÷ 44558.42 = 0.12422837255001412 @@ -179,6 +183,8 @@ describe('PortfolioCalculator', () => { ] ).toEqual({ date: '2022-01-14', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: -1463.18, netPerformanceInPercentage: -0.032837340282712, 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 fe86d9d457..e0cfeb8227 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 @@ -142,6 +142,8 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData[0]).toEqual({ date: '2021-12-11', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, netPerformanceInPercentage: 0, @@ -160,6 +162,8 @@ describe('PortfolioCalculator', () => { */ expect(portfolioSnapshot.historicalData[1]).toEqual({ date: '2021-12-12', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 44558.42, netPerformance: 5535.42, // 1 * (50098.3 - 44558.42) - 4.46 = 5535.42 netPerformanceInPercentage: 0.12422837255001412, // 5535.42 ÷ 44558.42 = 0.12422837255001412 @@ -179,6 +183,8 @@ describe('PortfolioCalculator', () => { ] ).toEqual({ date: '2022-01-14', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: -1463.18, netPerformanceInPercentage: -0.032837340282712, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts index 23c806483c..b98aa9e5f2 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts @@ -321,6 +321,8 @@ describe('PortfolioCalculator', () => { */ expect(portfolioSnapshot.historicalData.at(-1)).toEqual({ date: '2025-01-01', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, netPerformanceInPercentage: 0, @@ -459,6 +461,8 @@ describe('PortfolioCalculator', () => { */ expect(portfolioSnapshot.historicalData.at(-1)).toEqual({ date: '2025-01-01', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, netPerformanceInPercentage: 0, @@ -601,6 +605,8 @@ describe('PortfolioCalculator', () => { */ expect(portfolioSnapshot.historicalData.at(-1)).toEqual({ date: '2025-01-01', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, netPerformanceInPercentage: 0, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-fee-and-dividend.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-fee-and-dividend.spec.ts new file mode 100644 index 0000000000..7b948be474 --- /dev/null +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-fee-and-dividend.spec.ts @@ -0,0 +1,186 @@ +import { + activityDummyData, + assetProfileDummyData, + userDummyData +} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils'; +import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; +import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; +import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock'; +import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; +import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; +import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.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 { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; +import { parseDate } from '@ghostfolio/common/helper'; +import { Activity } from '@ghostfolio/common/interfaces'; +import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; + +import { Big } from 'big.js'; + +jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { + return { + CurrentRateService: jest.fn().mockImplementation(() => { + return CurrentRateServiceMock; + }) + }; +}); + +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + +jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { + return { + RedisCacheService: jest.fn().mockImplementation(() => { + return RedisCacheServiceMock; + }) + }; +}); + +describe('PortfolioCalculator', () => { + let configurationService: ConfigurationService; + let currentRateService: CurrentRateService; + let exchangeRateDataService: ExchangeRateDataService; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; + let redisCacheService: RedisCacheService; + + beforeEach(() => { + PortfolioSnapshotServiceMock.reset(); + RedisCacheServiceMock.reset(); + + configurationService = new ConfigurationService(); + + currentRateService = new CurrentRateService(null, null, null); + + exchangeRateDataService = new ExchangeRateDataService( + null, + null, + null, + null + ); + + portfolioSnapshotService = new PortfolioSnapshotService(null, null); + + redisCacheService = new RedisCacheService(null, null); + + portfolioCalculatorFactory = new PortfolioCalculatorFactory( + configurationService, + currentRateService, + exchangeRateDataService, + portfolioSnapshotService, + redisCacheService + ); + }); + + describe('get current positions', () => { + it('with GOOGL fee and dividend', async () => { + jest.useFakeTimers().setSystemTime(parseDate('2023-07-10').getTime()); + + const activities: Activity[] = [ + { + ...activityDummyData, + assetProfile: { + ...assetProfileDummyData, + currency: 'USD', + dataSource: 'YAHOO', + name: 'Microsoft Inc.', + symbol: 'MSFT' + }, + date: new Date('2021-09-16'), + feeInAssetProfileCurrency: 19, + feeInBaseCurrency: 19, + quantity: 1, + type: 'BUY', + unitPriceInAssetProfileCurrency: 298.58 + }, + { + ...activityDummyData, + assetProfile: { + ...assetProfileDummyData, + currency: 'USD', + dataSource: 'YAHOO', + name: 'Microsoft Inc.', + symbol: 'MSFT' + }, + date: new Date('2021-11-16'), + feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, + quantity: 1, + type: 'DIVIDEND', + unitPriceInAssetProfileCurrency: 0.62 + }, + { + // The first activity of this asset profile is a fee, which is not an + // investment activity. Thus the holding is not included in the + // holdings of the portfolio summary, and its dividend must not be + // included in the chart + ...activityDummyData, + assetProfile: { + ...assetProfileDummyData, + currency: 'USD', + dataSource: 'YAHOO', + name: 'Alphabet Inc.', + symbol: 'GOOGL' + }, + date: new Date('2023-01-03'), + feeInAssetProfileCurrency: 1, + feeInBaseCurrency: 1, + quantity: 0, + type: 'FEE', + unitPriceInAssetProfileCurrency: 0 + }, + { + ...activityDummyData, + assetProfile: { + ...assetProfileDummyData, + currency: 'USD', + dataSource: 'YAHOO', + name: 'Alphabet Inc.', + symbol: 'GOOGL' + }, + date: new Date('2023-07-10'), + feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, + quantity: 1, + type: 'DIVIDEND', + unitPriceInAssetProfileCurrency: 5 + } + ]; + + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ + activities, + calculationType: PerformanceCalculationType.ROAI, + currency: 'USD', + usePortfolioSnapshotCache: false, + userId: userDummyData.id + }); + + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); + + const dividendInBaseCurrency = + await portfolioCalculator.getDividendInBaseCurrency(); + + expect( + portfolioSnapshot.positions.map(({ symbol }) => { + return symbol; + }) + ).toEqual(['MSFT']); + + // The chart and the portfolio summary must show the same dividend + expect(dividendInBaseCurrency).toEqual(new Big('0.62')); + + expect( + portfolioSnapshot.historicalData.at(-1).dividendInBaseCurrency + ).toEqual(0.62); + }); + }); +}); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts index 18dc5ab246..2c6ff79b6d 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts @@ -198,6 +198,8 @@ describe('PortfolioCalculator', () => { expect(performanceByDateRange).toMatchObject({ '1d': { date: '2023-07-10', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, netPerformance: -5.390000000000001, netPerformanceInPercentage: -0.015983630864124312, netPerformanceInPercentageWithCurrencyEffect: -0.015983630864124312, @@ -207,6 +209,8 @@ describe('PortfolioCalculator', () => { }, max: { date: '2023-07-10', + dividendInBaseCurrency: 0.62, + dividendInPercentageWithCurrencyEffect: 0.002076495411614967, netPerformance: 14.25, netPerformanceInPercentage: 0.04772590260566659, netPerformanceInPercentageWithCurrencyEffect: 0.04772590260566659, @@ -216,6 +220,8 @@ describe('PortfolioCalculator', () => { }, ytd: { date: '2023-07-10', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, netPerformance: -7.68, netPerformanceInPercentage: -0.022620835910577012, netPerformanceInPercentageWithCurrencyEffect: -0.022620835910577012, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts index feb9a3c20e..46e1b14aa4 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts @@ -139,6 +139,8 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData[0]).toEqual({ date: '2022-03-06', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, netPerformanceInPercentage: 0, @@ -158,6 +160,8 @@ describe('PortfolioCalculator', () => { */ expect(portfolioSnapshot.historicalData[1]).toEqual({ date: '2022-03-07', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 151.6, netPerformance: 0, // 2 * (75.8 - 75.8) = 0 netPerformanceInPercentage: 0, // 0 ÷ 151.6 = 0 @@ -177,6 +181,8 @@ describe('PortfolioCalculator', () => { ] ).toEqual({ date: '2022-04-11', + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 19.86, netPerformanceInPercentage: 0.13100263852242744, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts index 39a1b4188b..abf771aabb 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts @@ -178,11 +178,18 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { { totalAverageInvestmentValue, totalAverageInvestmentValueWithCurrencyEffect, + totalDividendValue, totalNetPerformanceValue, totalNetPerformanceValueWithCurrencyEffect } ] of Object.entries(accumulatedValuesByDate)) { performancePercentagesByDate[date] = { + dividendInPercentageWithCurrencyEffect: + totalAverageInvestmentValueWithCurrencyEffect.eq(0) + ? 0 + : totalDividendValue + .div(totalAverageInvestmentValueWithCurrencyEffect) + .toNumber(), netPerformanceInPercentage: totalAverageInvestmentValue.eq(0) ? 0 : totalNetPerformanceValue @@ -254,6 +261,11 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { : 0; performancePercentagesByDate[historicalDataItem.date] = { + dividendInPercentageWithCurrencyEffect: + averageInvestmentValueWithCurrencyEffect > 0 + ? historicalDataItem.dividendInBaseCurrency / + averageInvestmentValueWithCurrencyEffect + : 0, netPerformanceInPercentage: averageInvestmentValue > 0 ? historicalDataItem.netPerformance / averageInvestmentValue diff --git a/apps/api/src/app/portfolio/interfaces/accumulated-values.interface.ts b/apps/api/src/app/portfolio/interfaces/accumulated-values.interface.ts index 919dccc227..2f9bbb09a8 100644 --- a/apps/api/src/app/portfolio/interfaces/accumulated-values.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/accumulated-values.interface.ts @@ -7,6 +7,7 @@ export interface AccumulatedValues { totalCashValueWithCurrencyEffect: Big; totalCurrentValue: Big; totalCurrentValueWithCurrencyEffect: Big; + totalDividendValue: Big; totalInvestmentValue: Big; totalInvestmentValueWithCurrencyEffect: Big; totalNetPerformanceValue: Big; diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index a65186100a..2a77455902 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -565,6 +565,7 @@ export class PortfolioController { [ 'currentNetWorth', 'currentValueInBaseCurrency', + 'dividendInBaseCurrency', 'grossPerformance', 'grossPerformanceWithCurrencyEffect', 'netPerformance', diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 1476db4ae0..34009a33d9 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1220,6 +1220,8 @@ export class PortfolioService { performance: { currentNetWorth: 0, currentValueInBaseCurrency: 0, + dividendInBaseCurrency: 0, + dividendPercentageWithCurrencyEffect: 0, netPerformance: 0, netPerformancePercentage: 0, netPerformancePercentageWithCurrencyEffect: 0, @@ -1251,6 +1253,8 @@ export class PortfolioService { }); const { + dividendInBaseCurrency, + dividendInPercentageWithCurrencyEffect, netPerformance, netPerformanceInPercentage, netPerformanceInPercentageWithCurrencyEffect, @@ -1260,6 +1264,8 @@ export class PortfolioService { totalInvestmentValueWithCurrencyEffect, valueWithCurrencyEffect } = chart?.at(-1) ?? { + dividendInBaseCurrency: 0, + dividendInPercentageWithCurrencyEffect: 0, netPerformance: 0, netPerformanceInPercentage: 0, netPerformanceInPercentageWithCurrencyEffect: 0, @@ -1275,12 +1281,15 @@ export class PortfolioService { hasErrors, dateOfFirstActivity: parseDate(historicalData[0]?.date), performance: { + dividendInBaseCurrency, netPerformance, netPerformanceWithCurrencyEffect, totalInvestment, totalInvestmentValueWithCurrencyEffect, currentNetWorth: netWorth, currentValueInBaseCurrency: valueWithCurrencyEffect, + dividendPercentageWithCurrencyEffect: + dividendInPercentageWithCurrencyEffect, netPerformancePercentage: netPerformanceInPercentage, netPerformancePercentageWithCurrencyEffect: netPerformanceInPercentageWithCurrencyEffect @@ -2125,6 +2134,7 @@ export class PortfolioService { const { currentValueInBaseCurrency, + dividendPercentageWithCurrencyEffect, netPerformance, netPerformancePercentage, netPerformancePercentageWithCurrencyEffect, @@ -2224,6 +2234,7 @@ export class PortfolioService { cash, currentValueInBaseCurrency, dateOfFirstActivity, + dividendPercentageWithCurrencyEffect, excludedAccountsAndActivities, netPerformance, netPerformancePercentage, diff --git a/apps/api/src/app/portfolio/types/performance-percentages.type.ts b/apps/api/src/app/portfolio/types/performance-percentages.type.ts index 99521e516e..590e25895a 100644 --- a/apps/api/src/app/portfolio/types/performance-percentages.type.ts +++ b/apps/api/src/app/portfolio/types/performance-percentages.type.ts @@ -3,6 +3,7 @@ import { HistoricalDataItem } from '@ghostfolio/common/interfaces'; export type PerformancePercentages = Required< Pick< HistoricalDataItem, + | 'dividendInPercentageWithCurrencyEffect' | 'netPerformanceInPercentage' | 'netPerformanceInPercentageWithCurrencyEffect' > diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html index abf2de00ee..a2af892ce3 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -279,6 +279,50 @@ /> + @if (user?.settings?.isExperimentalFeatures) { +