Browse Source

Feature/include dividends in portfolio performance (#7961)

* Include dividends in portfolio performance

* Update changelog
pull/7933/head^2
Thomas Kaul 1 week ago
committed by GitHub
parent
commit
26cce42375
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 2
      apps/api/src/app/portfolio/portfolio.service.ts
  3. 58
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html
  4. 31
      apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts
  5. 30
      apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts
  6. 85
      apps/client/src/app/pages/portfolio/analysis/analysis-page.html

2
CHANGELOG.md

@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Extended the net performance on the analysis page to include the dividends (experimental)
- Extended the net performance in the portfolio summary to include the dividends (experimental)
- Improved the get quotes functionality of the _Manual_ service - Improved the get quotes functionality of the _Manual_ service
- Migrated the _ESLint_ configuration to the flat config format without `FlatCompat` - Migrated the _ESLint_ configuration to the flat config format without `FlatCompat`
- Upgraded `chartjs-chart-treemap` from version `4.2.0` to `4.2.2` - Upgraded `chartjs-chart-treemap` from version `4.2.0` to `4.2.2`

2
apps/api/src/app/portfolio/portfolio.service.ts

@ -2140,6 +2140,7 @@ export class PortfolioService {
const { const {
currentValueInBaseCurrency, currentValueInBaseCurrency,
dividendPercentageWithCurrencyEffect,
netPerformance, netPerformance,
netPerformancePercentage, netPerformancePercentage,
netPerformancePercentageWithCurrencyEffect, netPerformancePercentageWithCurrencyEffect,
@ -2236,6 +2237,7 @@ export class PortfolioService {
cash, cash,
currentValueInBaseCurrency, currentValueInBaseCurrency,
dateOfFirstActivity, dateOfFirstActivity,
dividendPercentageWithCurrencyEffect,
excludedAccountsAndActivities, excludedAccountsAndActivities,
netPerformance, netPerformance,
netPerformancePercentage, netPerformancePercentage,

58
apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html

@ -98,10 +98,29 @@
/> />
</div> </div>
</div> </div>
@if (user?.settings?.isExperimentalFeatures) {
<div class="flex-nowrap px-3 py-1 row">
<div class="flex-grow-1 text-truncate" i18n>Dividend</div>
<div class="d-flex justify-content-end">
@if (isNumber(summary?.dividendInBaseCurrency)) {
<span class="mr-1">+</span>
}
<gf-value
class="justify-content-end"
[isCurrency]="true"
[isLoading]="isLoading"
[locale]="locale"
[precision]="precision"
[unit]="displayedCurrency"
[value]="summary?.dividendInBaseCurrency"
/>
</div>
</div>
}
<div class="flex-nowrap px-3 py-1 row"> <div class="flex-nowrap px-3 py-1 row">
<div class="flex-grow-1 text-truncate" i18n>Fees</div> <div class="flex-grow-1 text-truncate" i18n>Fees</div>
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
@if (summary?.fees || summary?.fees === 0) { @if (isNumber(summary?.fees)) {
<span class="mr-1">-</span> <span class="mr-1">-</span>
} }
<gf-value <gf-value
@ -128,7 +147,7 @@
[locale]="locale" [locale]="locale"
[precision]="precision" [precision]="precision"
[unit]="displayedCurrency" [unit]="displayedCurrency"
[value]="summary?.netPerformanceWithCurrencyEffect" [value]="netPerformanceWithCurrencyEffect"
/> />
</div> </div>
</div> </div>
@ -154,7 +173,7 @@
[isLoading]="isLoading" [isLoading]="isLoading"
[isPercent]="true" [isPercent]="true"
[locale]="locale" [locale]="locale"
[value]="summary?.netPerformancePercentageWithCurrencyEffect" [value]="netPerformancePercentageWithCurrencyEffect"
/> />
</div> </div>
</div> </div>
@ -367,10 +386,7 @@
<div class="flex-nowrap px-3 py-1 row"> <div class="flex-nowrap px-3 py-1 row">
<div class="flex-grow-1 text-truncate" i18n>Liabilities</div> <div class="flex-grow-1 text-truncate" i18n>Liabilities</div>
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
@if ( @if (isNumber(summary?.liabilitiesInBaseCurrency)) {
summary?.liabilitiesInBaseCurrency ||
summary?.liabilitiesInBaseCurrency === 0
) {
<span class="mr-1">-</span> <span class="mr-1">-</span>
} }
<gf-value <gf-value
@ -488,18 +504,20 @@
/> />
</div> </div>
</div> </div>
<div class="flex-nowrap px-3 py-1 row"> @if (!user?.settings?.isExperimentalFeatures) {
<div class="flex-grow-1 text-truncate" i18n>Dividend</div> <div class="flex-nowrap px-3 py-1 row">
<div class="justify-content-end"> <div class="flex-grow-1 text-truncate" i18n>Dividend</div>
<gf-value <div class="justify-content-end">
class="justify-content-end" <gf-value
[isCurrency]="true" class="justify-content-end"
[isLoading]="isLoading" [isCurrency]="true"
[locale]="locale" [isLoading]="isLoading"
[precision]="precision" [locale]="locale"
[unit]="displayedCurrency" [precision]="precision"
[value]="summary?.dividendInBaseCurrency" [unit]="displayedCurrency"
/> [value]="summary?.dividendInBaseCurrency"
/>
</div>
</div> </div>
</div> }
</div> </div>

31
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' 'BUY_AND_SELL_ACTIVITIES_TOOLTIP'
); );
protected readonly isNumber = isNumber;
protected readonly PerformanceCalculationType = PerformanceCalculationType; protected readonly PerformanceCalculationType = PerformanceCalculationType;
protected isCashExpanded = false; protected isCashExpanded = false;
@ -136,6 +137,36 @@ export class GfPortfolioSummaryComponent implements OnChanges {
); );
} }
protected get netPerformancePercentageWithCurrencyEffect() {
if (
!this.user?.settings?.isExperimentalFeatures ||
!isNumber(this.summary?.netPerformancePercentageWithCurrencyEffect)
) {
return this.summary?.netPerformancePercentageWithCurrencyEffect;
}
// Include the dividends (total return)
return (
this.summary.netPerformancePercentageWithCurrencyEffect +
(this.summary.dividendPercentageWithCurrencyEffect ?? 0)
);
}
protected get netPerformanceWithCurrencyEffect() {
if (
!this.user?.settings?.isExperimentalFeatures ||
!isNumber(this.summary?.netPerformanceWithCurrencyEffect)
) {
return this.summary?.netPerformanceWithCurrencyEffect;
}
// Include the dividends (total return)
return (
this.summary.netPerformanceWithCurrencyEffect +
this.summary.dividendInBaseCurrency
);
}
public ngOnChanges() { public ngOnChanges() {
if (this.summary) { if (this.summary) {
if ( if (

30
apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts

@ -133,6 +133,36 @@ export class GfAnalysisPageComponent implements OnInit {
addIcons({ copyOutline, ellipsisVertical }); addIcons({ copyOutline, ellipsisVertical });
} }
protected get netPerformancePercentageWithCurrencyEffect() {
if (
!this.user?.settings?.isExperimentalFeatures ||
!isNumber(this.performance?.netPerformancePercentageWithCurrencyEffect)
) {
return this.performance?.netPerformancePercentageWithCurrencyEffect;
}
// Include the dividends (total return)
return (
this.performance.netPerformancePercentageWithCurrencyEffect +
(this.performance.dividendPercentageWithCurrencyEffect ?? 0)
);
}
protected get netPerformanceWithCurrencyEffect() {
if (
!this.user?.settings?.isExperimentalFeatures ||
!isNumber(this.performance?.netPerformanceWithCurrencyEffect)
) {
return this.performance?.netPerformanceWithCurrencyEffect;
}
// Include the dividends (total return)
return (
this.performance.netPerformanceWithCurrencyEffect +
this.performance.dividendInBaseCurrency
);
}
get savingsRate() { get savingsRate() {
if (!this.savingsRatePerMonth) { if (!this.savingsRatePerMonth) {
return undefined; return undefined;

85
apps/client/src/app/pages/portfolio/analysis/analysis-page.html

@ -187,6 +187,45 @@
/> />
</div> </div>
</div> </div>
@if (user?.settings?.isExperimentalFeatures) {
<div class="d-flex py-1">
<div
class="align-items-center d-flex flex-grow-1 mr-2 text-truncate"
>
<span i18n>Absolute Dividend Performance</span>
@if (user?.subscription?.type === 'Basic') {
<gf-premium-indicator class="ml-1" />
}
</div>
<div class="d-flex justify-content-end">
<gf-value
class="justify-content-end"
position="end"
[isCurrency]="true"
[isLoading]="isLoadingInvestmentChart"
[locale]="user?.settings?.locale"
[unit]="user?.settings?.baseCurrency"
[value]="performance?.dividendInBaseCurrency"
/>
</div>
</div>
<div class="d-flex mb-3 ml-3 py-1">
<div class="flex-grow-1 mr-2 text-truncate">
<ng-container i18n>Dividend Performance</ng-container>
</div>
<div class="d-flex justify-content-end">
<gf-value
class="justify-content-end"
position="end"
[colorizeSign]="true"
[isLoading]="isLoadingInvestmentChart"
[isPercent]="true"
[locale]="user?.settings?.locale"
[value]="performance?.dividendPercentageWithCurrencyEffect"
/>
</div>
</div>
}
<div class="d-flex py-1"> <div class="d-flex py-1">
<div <div
class="align-items-center d-flex flex-grow-1 mr-2 text-truncate" class="align-items-center d-flex flex-grow-1 mr-2 text-truncate"
@ -247,7 +286,7 @@
[isLoading]="isLoadingInvestmentChart" [isLoading]="isLoadingInvestmentChart"
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[unit]="user?.settings?.baseCurrency" [unit]="user?.settings?.baseCurrency"
[value]="performance?.netPerformanceWithCurrencyEffect" [value]="netPerformanceWithCurrencyEffect"
/> />
</div> </div>
</div> </div>
@ -273,52 +312,10 @@
[isLoading]="isLoadingInvestmentChart" [isLoading]="isLoadingInvestmentChart"
[isPercent]="true" [isPercent]="true"
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
[value]=" [value]="netPerformancePercentageWithCurrencyEffect"
performance?.netPerformancePercentageWithCurrencyEffect
"
/> />
</div> </div>
</div> </div>
@if (user?.settings?.isExperimentalFeatures) {
<div><hr /></div>
<div class="d-flex py-1">
<div
class="align-items-center d-flex flex-grow-1 mr-2 text-truncate"
>
<span i18n>Absolute Dividend Performance</span>
@if (user?.subscription?.type === 'Basic') {
<gf-premium-indicator class="ml-1" />
}
</div>
<div class="d-flex justify-content-end">
<gf-value
class="justify-content-end"
position="end"
[isCurrency]="true"
[isLoading]="isLoadingInvestmentChart"
[locale]="user?.settings?.locale"
[unit]="user?.settings?.baseCurrency"
[value]="performance?.dividendInBaseCurrency"
/>
</div>
</div>
<div class="d-flex ml-3 py-1">
<div class="flex-grow-1 mr-2 text-truncate">
<ng-container i18n>Dividend Performance</ng-container>
</div>
<div class="d-flex justify-content-end">
<gf-value
class="justify-content-end"
position="end"
[colorizeSign]="true"
[isLoading]="isLoadingInvestmentChart"
[isPercent]="true"
[locale]="user?.settings?.locale"
[value]="performance?.dividendPercentageWithCurrencyEffect"
/>
</div>
</div>
}
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>
</div> </div>

Loading…
Cancel
Save