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) { +
+
Dividend
+
+ @if (isNumber(summary?.dividendInBaseCurrency)) { + + + } + +
+
+ }
Fees
- @if (summary?.fees || summary?.fees === 0) { + @if (isNumber(summary?.fees)) { - } (ROAI) } @@ -367,10 +393,7 @@
Liabilities
- @if ( - summary?.liabilitiesInBaseCurrency || - summary?.liabilitiesInBaseCurrency === 0 - ) { + @if (isNumber(summary?.liabilitiesInBaseCurrency)) { - }
-
-
Dividend
-
- + @if (!user?.settings?.isExperimentalFeatures) { +
+
Dividend
+
+ +
-
+ }
diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts index dec65ddad9..1965475c0e 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts @@ -55,6 +55,7 @@ export class GfPortfolioSummaryComponent implements OnChanges { 'BUY_AND_SELL_ACTIVITIES_TOOLTIP' ); + protected readonly isNumber = isNumber; protected readonly PerformanceCalculationType = PerformanceCalculationType; protected isCashExpanded = false; diff --git a/apps/client/src/app/pages/faq/overview/faq-overview-page.html b/apps/client/src/app/pages/faq/overview/faq-overview-page.html index 77c23789e6..66b416fbab 100644 --- a/apps/client/src/app/pages/faq/overview/faq-overview-page.html +++ b/apps/client/src/app/pages/faq/overview/faq-overview-page.html @@ -52,8 +52,8 @@ calculation method based on the average amount of capital invested over time. ROAI aims to provide a more insightful view of investment performance than simpler approaches, especially when contributions are - made over time. Dividends are not part of the - calculation. 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 94a0328755..f393683041 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -167,7 +167,13 @@ [isLoading]="isLoadingInvestmentChart" [locale]="user?.settings?.locale" [unit]="user?.settings?.baseCurrency" - [value]="performance?.netPerformance" + [value]=" + user?.settings?.isExperimentalFeatures && + performance?.netPerformance !== null + ? performance?.netPerformance - + performance?.dividendInBaseCurrency + : performance?.netPerformance + " />
@@ -183,10 +189,54 @@ [isLoading]="isLoadingInvestmentChart" [isPercent]="true" [locale]="user?.settings?.locale" - [value]="performance?.netPerformancePercentage" + [value]=" + user?.settings?.isExperimentalFeatures + ? performance?.netPerformancePercentage - + performance?.dividendPercentage + : performance?.netPerformancePercentage + " /> + @if (user?.settings?.isExperimentalFeatures) { +
+
+ Absolute Dividend Performance + @if (user?.subscription?.type === 'Basic') { + + } +
+
+ +
+
+
+
+ Dividend Performance +
+
+ +
+
+ }
(ROAI) } @@ -279,46 +330,6 @@ />
- @if (user?.settings?.isExperimentalFeatures) { -

-
-
- Absolute Dividend Performance - @if (user?.subscription?.type === 'Basic') { - - } -
-
- -
-
-
-
- Dividend Performance -
-
- -
-
- } diff --git a/libs/common/src/lib/interfaces/historical-data-item.interface.ts b/libs/common/src/lib/interfaces/historical-data-item.interface.ts index a733837d52..7e57b2f99c 100644 --- a/libs/common/src/lib/interfaces/historical-data-item.interface.ts +++ b/libs/common/src/lib/interfaces/historical-data-item.interface.ts @@ -2,6 +2,7 @@ export interface HistoricalDataItem { averagePrice?: number; date: string; dividendInBaseCurrency?: number; + dividendInPercentage?: number; dividendInPercentageWithCurrencyEffect?: number; grossPerformancePercent?: number; investmentValueWithCurrencyEffect?: number; diff --git a/libs/common/src/lib/interfaces/portfolio-performance.interface.ts b/libs/common/src/lib/interfaces/portfolio-performance.interface.ts index da0bb04f40..e843f342d2 100644 --- a/libs/common/src/lib/interfaces/portfolio-performance.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-performance.interface.ts @@ -3,6 +3,7 @@ export interface PortfolioPerformance { currentNetWorth?: number; currentValueInBaseCurrency: number; dividendInBaseCurrency: number; + dividendPercentage?: number; dividendPercentageWithCurrencyEffect?: number; netPerformance: number; netPerformancePercentage: number;