Browse Source

Merge pull request #146 from dandevaud/feature/Show-Tag-Allocation-in-PF-Allocation

Feature/show tag allocation in pf allocation
pull/5027/head
dandevaud 5 months ago
committed by GitHub
parent
commit
67d3651604
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      apps/api/src/app/portfolio/portfolio.controller.ts
  2. 8
      apps/api/src/app/portfolio/portfolio.service.ts
  3. 45
      apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts
  4. 18
      apps/client/src/app/pages/portfolio/allocations/allocations-page.html

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

@ -177,6 +177,7 @@ export class PortfolioController {
? portfolioPosition.markets
: undefined;
portfolioPosition.sectors = hasDetails ? portfolioPosition.sectors : [];
portfolioPosition.tags = hasDetails ? portfolioPosition.tags : [];
}
for (const [name, { valueInBaseCurrency }] of Object.entries(accounts)) {
@ -243,6 +244,7 @@ export class PortfolioController {
currency: hasDetails ? portfolioPosition.currency : undefined,
holdings: hasDetails ? portfolioPosition.holdings : [],
markets: hasDetails ? portfolioPosition.markets : undefined,
tags: hasDetails ? portfolioPosition.tags : [],
marketsAdvanced: hasDetails
? portfolioPosition.marketsAdvanced
: undefined,

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

@ -78,7 +78,7 @@ import {
parseISO,
set
} from 'date-fns';
import { isEmpty, uniq } from 'lodash';
import { isEmpty, uniq, uniqBy } from 'lodash';
import { CPRPortfolioCalculator } from './calculator/constantPortfolioReturn/portfolio-calculator';
import { PortfolioCalculator } from './calculator/portfolio-calculator';
@ -486,13 +486,17 @@ export class PortfolioService {
}));
}
const tagsInternal = tags.concat(
symbolProfiles.find((sp) => sp.symbol === symbol)?.tags ?? []
);
holdings[symbol] = {
currency,
markets,
marketsAdvanced,
marketPrice,
symbol,
tags,
tags: uniqBy(tagsInternal, 'id'),
transactionCount,
allocationInPercentage: filteredValueInBaseCurrency.eq(0)
? 0

45
apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts

@ -7,6 +7,7 @@ import { MAX_TOP_HOLDINGS, UNKNOWN_KEY } from '@ghostfolio/common/config';
import { prettifySymbol } from '@ghostfolio/common/helper';
import {
AssetProfileIdentifier,
Holding,
HoldingWithParents,
PortfolioDetails,
PortfolioPosition,
@ -91,6 +92,10 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
public topHoldingsMap: {
[name: string]: { name: string; value: number };
};
public tagHoldings: Holding[];
public tagHoldingsMap: {
[name: string]: { name: string; value: number };
};
public totalValueInEtf = 0;
public UNKNOWN_KEY = UNKNOWN_KEY;
public user: User;
@ -282,6 +287,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
}
};
this.topHoldingsMap = {};
this.tagHoldingsMap = {};
}
private initializeAllocationsData() {
@ -417,6 +423,22 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
}
}
if (position.tags.length > 0) {
for (const tag of position.tags) {
const { name } = tag;
if (this.tagHoldingsMap[name]?.value) {
this.tagHoldingsMap[name].value +=
position.valueInBaseCurrency ?? 0;
} else {
this.tagHoldingsMap[name] = {
name,
value: position.valueInBaseCurrency ?? 0
};
}
}
}
if (position.sectors.length > 0) {
for (const sector of position.sectors) {
const { name, weight } = sector;
@ -480,6 +502,29 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
};
}
this.tagHoldings = Object.values(this.tagHoldingsMap)
.map(({ name, value }) => {
if (this.hasImpersonationId || this.user.settings.isRestrictedView) {
return {
name,
allocationInPercentage: value,
valueInBaseCurrency: null
};
}
return {
name,
allocationInPercentage:
this.portfolioDetails.summary.currentValueInBaseCurrency > 0
? value / this.portfolioDetails.summary.currentValueInBaseCurrency
: 0,
valueInBaseCurrency: value
};
})
.sort((a, b) => {
return b.allocationInPercentage - a.allocationInPercentage;
});
this.topHoldings = Object.values(this.topHoldingsMap)
.map(({ name, value }) => {
if (this.hasImpersonationId || this.user.settings.isRestrictedView) {

18
apps/client/src/app/pages/portfolio/allocations/allocations-page.html

@ -327,6 +327,24 @@
'd-none': !user?.settings?.isExperimentalFeatures
}"
>
<mat-card appearance="outlined" class="mb-3">
<mat-card-header class="overflow-hidden w-100">
<mat-card-title class="align-items-center d-flex text-truncate">
<span i18n>By Tag Holding</span>
@if (user?.subscription?.type === 'Basic') {
<gf-premium-indicator class="ml-1" />
}
</mat-card-title>
</mat-card-header>
<mat-card-content>
<gf-top-holdings
[baseCurrency]="user?.settings?.baseCurrency"
[locale]="user?.settings?.locale"
[pageSize]="10"
[topHoldings]="tagHoldings"
/>
</mat-card-content>
</mat-card>
<mat-card appearance="outlined" class="mb-3">
<mat-card-header class="overflow-hidden w-100">
<mat-card-title class="align-items-center d-flex text-truncate">

Loading…
Cancel
Save