Browse Source

Task/improve allocations by ETF holding by refining grouping (#6619)

* Improve grouping of same assets with diverging names

* Prettify asset names

* Update changelog
pull/6614/head^2
Thomas Kaul 3 days ago
committed by GitHub
parent
commit
76355d938d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 30
      apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts
  3. 2
      libs/ui/src/lib/top-holdings/top-holdings.component.html
  4. 28
      libs/ui/src/lib/top-holdings/top-holdings.component.ts

1
CHANGELOG.md

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Improved the allocations by ETF holding on the allocations page by refining the grouping of the same assets with diverging names (experimental)
- Improved the language localization for Polish (`pl`)
- Upgraded `@trivago/prettier-plugin-sort-imports` from version `5.2.2` to `6.0.2`

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

@ -405,17 +405,22 @@ export class GfAllocationsPageComponent implements OnInit {
}
if (position.holdings.length > 0) {
for (const holding of position.holdings) {
const { allocationInPercentage, name, valueInBaseCurrency } =
holding;
for (const {
allocationInPercentage,
name,
valueInBaseCurrency
} of position.holdings) {
const normalizedAssetName = this.normalizeAssetName(name);
if (this.topHoldingsMap[name]?.value) {
this.topHoldingsMap[name].value += isNumber(valueInBaseCurrency)
if (this.topHoldingsMap[normalizedAssetName]?.value) {
this.topHoldingsMap[normalizedAssetName].value += isNumber(
valueInBaseCurrency
)
? valueInBaseCurrency
: allocationInPercentage *
this.portfolioDetails.holdings[symbol].valueInPercentage;
} else {
this.topHoldingsMap[name] = {
this.topHoldingsMap[normalizedAssetName] = {
name,
value: isNumber(valueInBaseCurrency)
? valueInBaseCurrency
@ -518,7 +523,10 @@ export class GfAllocationsPageComponent implements OnInit {
if (holding.holdings.length > 0) {
const currentParentHolding = holding.holdings.find(
(parentHolding) => {
return parentHolding.name === name;
return (
this.normalizeAssetName(parentHolding.name) ===
this.normalizeAssetName(name)
);
}
);
@ -555,6 +563,14 @@ export class GfAllocationsPageComponent implements OnInit {
}
}
private normalizeAssetName(name: string) {
if (!name) {
return '';
}
return name.trim().toLowerCase();
}
private openAccountDetailDialog(aAccountId: string) {
const dialogRef = this.dialog.open<
GfAccountDetailDialogComponent,

2
libs/ui/src/lib/top-holdings/top-holdings.component.html

@ -16,7 +16,7 @@
<ng-container i18n>Name</ng-container>
</th>
<td *matCellDef="let element" class="px-2" mat-cell>
<div class="text-truncate">{{ element?.name | titlecase }}</div>
<div class="text-truncate">{{ prettifyAssetName(element?.name) }}</div>
</td>
</ng-container>

28
libs/ui/src/lib/top-holdings/top-holdings.component.ts

@ -20,15 +20,14 @@ import {
EventEmitter,
Input,
OnChanges,
OnDestroy,
Output,
ViewChild
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
import { capitalize } from 'lodash';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { Subject } from 'rxjs';
import { GfValueComponent } from '../value/value.component';
@ -58,7 +57,7 @@ import { GfValueComponent } from '../value/value.component';
styleUrls: ['./top-holdings.component.scss'],
templateUrl: './top-holdings.component.html'
})
export class GfTopHoldingsComponent implements OnChanges, OnDestroy {
export class GfTopHoldingsComponent implements OnChanges {
@Input() baseCurrency: string;
@Input() locale = getLocale();
@Input() pageSize = Number.MAX_SAFE_INTEGER;
@ -76,8 +75,6 @@ export class GfTopHoldingsComponent implements OnChanges, OnDestroy {
];
public isLoading = true;
private unsubscribeSubject = new Subject<void>();
public ngOnChanges() {
this.isLoading = true;
@ -101,8 +98,23 @@ export class GfTopHoldingsComponent implements OnChanges, OnDestroy {
});
}
public ngOnDestroy() {
this.unsubscribeSubject.next();
this.unsubscribeSubject.complete();
public prettifyAssetName(name: string) {
if (!name) {
return '';
}
return name
.split(' ')
.filter((token) => {
return !token.startsWith('(') && !token.endsWith(')');
})
.map((token) => {
if (token.length <= 2) {
return token.toUpperCase();
}
return capitalize(token);
})
.join(' ');
}
}

Loading…
Cancel
Save