diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e705c788e..cc679c1edc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Changed + +- Changed the performance calculation to include the dividends (total return) + ## 3.74.0 - 2026-09-27 ### Added diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index d868b65b3f..5c0e5ea4bd 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -946,6 +946,7 @@ export abstract class PortfolioCalculator { const currentExchangeRate = exchangeRates[format(new Date(), DATE_FORMAT)]; const currentValues: { [date: string]: Big } = {}; const currentValuesWithCurrencyEffect: { [date: string]: Big } = {}; + let dividends = new Big(0); let fees = new Big(0); let feesAtStartDate = new Big(0); let feesAtStartDateWithCurrencyEffect = new Big(0); @@ -1123,6 +1124,16 @@ export abstract class PortfolioCalculator { activity.feeInBaseCurrencyWithCurrencyEffect ?? 0 ); + if (activity.type === 'DIVIDEND') { + // The amount of a dividend in the base currency is the same with and + // without currency effect, like the dividend of the holding + dividends = dividends.plus( + activity.quantity + .mul(activity.unitPrice) + .mul(exchangeRateAtActivityDate ?? 1) + ); + } + totalQuantity = totalQuantity.plus( activity.quantity.mul(getFactor(activity.type)) ); @@ -1190,12 +1201,14 @@ export abstract class PortfolioCalculator { const newGrossPerformance = valueOfInvestment .minus(totalInvestment) - .plus(grossPerformanceFromSells); + .plus(grossPerformanceFromSells) + .plus(dividends); const newGrossPerformanceWithCurrencyEffect = valueOfInvestmentWithCurrencyEffect .minus(totalInvestmentWithCurrencyEffect) - .plus(grossPerformanceFromSellsWithCurrencyEffect); + .plus(grossPerformanceFromSellsWithCurrencyEffect) + .plus(dividends); grossPerformance = newGrossPerformance; 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 ed8841b167..935ab7ca0d 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 @@ -143,6 +143,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData[0]).toEqual({ date: '2021-12-11', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, @@ -163,6 +164,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData[1]).toEqual({ date: '2021-12-12', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 44558.42, netPerformance: 5535.42, // 1 * (50098.3 - 44558.42) - 4.46 = 5535.42 @@ -184,6 +186,7 @@ describe('PortfolioCalculator', () => { ).toEqual({ date: '2022-01-14', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: -1463.18, 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 e0cfeb8227..0ed27800aa 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 @@ -143,6 +143,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData[0]).toEqual({ date: '2021-12-11', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, @@ -163,6 +164,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData[1]).toEqual({ date: '2021-12-12', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 44558.42, netPerformance: 5535.42, // 1 * (50098.3 - 44558.42) - 4.46 = 5535.42 @@ -184,6 +186,7 @@ describe('PortfolioCalculator', () => { ).toEqual({ date: '2022-01-14', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: -1463.18, 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 b98aa9e5f2..4f3105daec 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 @@ -322,6 +322,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData.at(-1)).toEqual({ date: '2025-01-01', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, @@ -462,6 +463,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData.at(-1)).toEqual({ date: '2025-01-01', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, @@ -606,6 +608,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData.at(-1)).toEqual({ date: '2025-01-01', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, 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 2c6ff79b6d..259a40ed35 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 @@ -155,25 +155,25 @@ describe('PortfolioCalculator', () => { '0.001144362748184' ), fee: new Big('19'), - grossPerformance: new Big('33.25'), - grossPerformancePercentage: new Big('0.11136043941322258691'), + grossPerformance: new Big('33.87'), + grossPerformancePercentage: new Big('0.11343693482483756447'), grossPerformancePercentageWithCurrencyEffect: new Big( - '0.11136043941322258691' + '0.11343693482483756447' ), - grossPerformanceWithCurrencyEffect: new Big('33.25'), + grossPerformanceWithCurrencyEffect: new Big('33.87'), investment: new Big('298.58'), investmentWithCurrencyEffect: new Big('298.58'), marketPrice: 331.83, marketPriceInBaseCurrency: 331.83, - netPerformance: new Big('14.25'), - netPerformancePercentage: new Big('0.04772590260566682296'), + netPerformance: new Big('14.87'), + netPerformancePercentage: new Big('0.04980239801728180052'), netPerformancePercentageWithCurrencyEffectMap: { - max: new Big('0.04772590260566682296') + max: new Big('0.04980239801728180052') }, netPerformanceWithCurrencyEffectMap: { '1d': new Big('-5.39'), - '5y': new Big('14.25'), - max: new Big('14.25'), + '5y': new Big('14.87'), + max: new Big('14.87'), wtd: new Big('-5.39') }, quantity: new Big('1'), @@ -199,11 +199,12 @@ describe('PortfolioCalculator', () => { '1d': { date: '2023-07-10', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, - netPerformance: -5.390000000000001, - netPerformanceInPercentage: -0.015983630864124312, - netPerformanceInPercentageWithCurrencyEffect: -0.015983630864124312, - netPerformanceWithCurrencyEffect: -5.390000000000001, + netPerformance: -5.390000000000002, + netPerformanceInPercentage: -0.015983630864124316, + netPerformanceInPercentageWithCurrencyEffect: -0.015983630864124316, + netPerformanceWithCurrencyEffect: -5.390000000000002, totalInvestmentValueWithCurrencyEffect: 298.58, valueWithCurrencyEffect: 331.83 }, @@ -211,21 +212,22 @@ describe('PortfolioCalculator', () => { date: '2023-07-10', dividendInBaseCurrency: 0.62, dividendInPercentageWithCurrencyEffect: 0.002076495411614967, - netPerformance: 14.25, - netPerformanceInPercentage: 0.04772590260566659, - netPerformanceInPercentageWithCurrencyEffect: 0.04772590260566659, - netPerformanceWithCurrencyEffect: 14.25, + netPerformance: 14.87, + netPerformanceInPercentage: 0.049802398017281556, + netPerformanceInPercentageWithCurrencyEffect: 0.049802398017281556, + netPerformanceWithCurrencyEffect: 14.87, totalInvestmentValueWithCurrencyEffect: 298.58, valueWithCurrencyEffect: 331.83 }, ytd: { date: '2023-07-10', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, - netPerformance: -7.68, - netPerformanceInPercentage: -0.022620835910577012, - netPerformanceInPercentageWithCurrencyEffect: -0.022620835910577012, - netPerformanceWithCurrencyEffect: -7.68, + netPerformance: -7.6800000000000015, + netPerformanceInPercentage: -0.022620835910577015, + netPerformanceInPercentageWithCurrencyEffect: -0.022620835910577015, + netPerformanceWithCurrencyEffect: -7.6800000000000015, totalInvestmentValueWithCurrencyEffect: 298.58, valueWithCurrencyEffect: 331.83 } 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 46e1b14aa4..5c2fd995fa 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 @@ -140,6 +140,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData[0]).toEqual({ date: '2022-03-06', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 0, @@ -161,6 +162,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData[1]).toEqual({ date: '2022-03-07', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 151.6, netPerformance: 0, // 2 * (75.8 - 75.8) = 0 @@ -182,6 +184,7 @@ describe('PortfolioCalculator', () => { ).toEqual({ date: '2022-04-11', dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, investmentValueWithCurrencyEffect: 0, netPerformance: 19.86, 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 2b7b4e6dce..72729e3a1f 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts @@ -192,6 +192,13 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { } ] of Object.entries(accumulatedValuesByDate)) { performancePercentagesByDate[date] = { + dividendInPercentage: + hasDividendWithoutAverageInvestment || + totalAverageInvestmentValue.eq(0) + ? 0 + : totalDividendValueWithCurrencyEffect + .div(totalAverageInvestmentValue) + .toNumber(), dividendInPercentageWithCurrencyEffect: hasDividendWithoutAverageInvestment || totalAverageInvestmentValueWithCurrencyEffect.eq(0) @@ -275,6 +282,10 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { : 0; performancePercentagesByDate[historicalDataItem.date] = { + dividendInPercentage: + !hasDividendWithoutAverageInvestment && averageInvestmentValue > 0 + ? historicalDataItem.dividendInBaseCurrency / averageInvestmentValue + : 0, dividendInPercentageWithCurrencyEffect: !hasDividendWithoutAverageInvestment && averageInvestmentValueWithCurrencyEffect > 0 diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index e5866ca3b2..8e362846f7 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1222,6 +1222,7 @@ export class PortfolioService { currentNetWorth: 0, currentValueInBaseCurrency: 0, dividendInBaseCurrency: 0, + dividendPercentage: 0, dividendPercentageWithCurrencyEffect: 0, netPerformance: 0, netPerformancePercentage: 0, @@ -1255,6 +1256,7 @@ export class PortfolioService { const { dividendInBaseCurrency, + dividendInPercentage, dividendInPercentageWithCurrencyEffect, netPerformance, netPerformanceInPercentage, @@ -1266,6 +1268,7 @@ export class PortfolioService { valueWithCurrencyEffect } = chart?.at(-1) ?? { dividendInBaseCurrency: 0, + dividendInPercentage: 0, dividendInPercentageWithCurrencyEffect: 0, netPerformance: 0, netPerformanceInPercentage: 0, @@ -1289,6 +1292,7 @@ export class PortfolioService { totalInvestmentValueWithCurrencyEffect, currentNetWorth: netWorth, currentValueInBaseCurrency: valueWithCurrencyEffect, + dividendPercentage: dividendInPercentage, dividendPercentageWithCurrencyEffect: dividendInPercentageWithCurrencyEffect, netPerformancePercentage: netPerformanceInPercentage, 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 590e25895a..a87b3580d3 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, + | 'dividendInPercentage' | 'dividendInPercentageWithCurrencyEffect' | 'netPerformanceInPercentage' | 'netPerformanceInPercentageWithCurrencyEffect' diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html index 8846c14a7c..5fc332158c 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -94,14 +94,39 @@ [locale]="locale" [precision]="precision" [unit]="displayedCurrency" - [value]="summary?.grossPerformanceWithCurrencyEffect" + [value]=" + user?.settings?.isExperimentalFeatures && + summary?.grossPerformanceWithCurrencyEffect !== null + ? summary?.grossPerformanceWithCurrencyEffect - + summary?.dividendInBaseCurrency + : summary?.grossPerformanceWithCurrencyEffect + " /> + @if (user?.settings?.isExperimentalFeatures) { +