Browse Source

Feature/add switch to choose between tracking or exposed currency in allocation chart

Co-authored-by: Copilot <copilot@github.com>
pull/6969/head
swissbuechi 3 months ago
parent
commit
e91478dbf4
  1. 68
      apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts
  2. 13
      apps/client/src/app/pages/portfolio/allocations/allocations-page.html

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

@ -9,6 +9,7 @@ import {
HoldingWithParents, HoldingWithParents,
PortfolioDetails, PortfolioDetails,
PortfolioPosition, PortfolioPosition,
ToggleOption,
User User
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
@ -17,6 +18,7 @@ import { translate } from '@ghostfolio/ui/i18n';
import { GfPortfolioProportionChartComponent } from '@ghostfolio/ui/portfolio-proportion-chart'; import { GfPortfolioProportionChartComponent } from '@ghostfolio/ui/portfolio-proportion-chart';
import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator';
import { DataService } from '@ghostfolio/ui/services'; import { DataService } from '@ghostfolio/ui/services';
import { GfToggleComponent } from '@ghostfolio/ui/toggle';
import { GfTopHoldingsComponent } from '@ghostfolio/ui/top-holdings'; import { GfTopHoldingsComponent } from '@ghostfolio/ui/top-holdings';
import { GfValueComponent } from '@ghostfolio/ui/value'; import { GfValueComponent } from '@ghostfolio/ui/value';
import { GfWorldMapChartComponent } from '@ghostfolio/ui/world-map-chart'; import { GfWorldMapChartComponent } from '@ghostfolio/ui/world-map-chart';
@ -46,6 +48,7 @@ import { DeviceDetectorService } from 'ngx-device-detector';
imports: [ imports: [
GfPortfolioProportionChartComponent, GfPortfolioProportionChartComponent,
GfPremiumIndicatorComponent, GfPremiumIndicatorComponent,
GfToggleComponent,
GfTopHoldingsComponent, GfTopHoldingsComponent,
GfValueComponent, GfValueComponent,
GfWorldMapChartComponent, GfWorldMapChartComponent,
@ -69,6 +72,14 @@ export class GfAllocationsPageComponent implements OnInit {
public countries: { public countries: {
[code: string]: { name: string; value: number }; [code: string]: { name: string; value: number };
}; };
public currencyHoldings: {
[key: string]: { name: string; value: number };
};
public currencyMode: 'exposure' | 'tracking' = 'tracking';
public currencyModeOptions: ToggleOption[] = [
{ label: $localize`Tracking`, value: 'tracking' },
{ label: $localize`Exposure`, value: 'exposure' }
];
public deviceType: string; public deviceType: string;
public hasImpersonationId: boolean; public hasImpersonationId: boolean;
public holdings: { public holdings: {
@ -120,6 +131,13 @@ export class GfAllocationsPageComponent implements OnInit {
public user: User; public user: User;
public worldMapChartFormat: string; public worldMapChartFormat: string;
private currencyHoldingsExposure: {
[key: string]: { name: string; value: number };
};
private currencyHoldingsTracking: {
[key: string]: { name: string; value: number };
};
public constructor( public constructor(
private changeDetectorRef: ChangeDetectorRef, private changeDetectorRef: ChangeDetectorRef,
private dataService: DataService, private dataService: DataService,
@ -193,6 +211,15 @@ export class GfAllocationsPageComponent implements OnInit {
} }
} }
public onCurrencyModeChanged(mode: 'exposure' | 'tracking') {
this.currencyMode = mode;
this.currencyHoldings =
mode === 'exposure'
? this.currencyHoldingsExposure
: this.currencyHoldingsTracking;
this.changeDetectorRef.markForCheck();
}
public onSymbolChartClicked({ dataSource, symbol }: AssetProfileIdentifier) { public onSymbolChartClicked({ dataSource, symbol }: AssetProfileIdentifier) {
if (dataSource && symbol) { if (dataSource && symbol) {
this.router.navigate([], { this.router.navigate([], {
@ -237,6 +264,9 @@ export class GfAllocationsPageComponent implements OnInit {
value: 0 value: 0
} }
}; };
this.currencyHoldings = {};
this.currencyHoldingsExposure = {};
this.currencyHoldingsTracking = {};
this.holdings = {}; this.holdings = {};
this.marketsAdvanced = { this.marketsAdvanced = {
[UNKNOWN_KEY]: { [UNKNOWN_KEY]: {
@ -348,6 +378,44 @@ export class GfAllocationsPageComponent implements OnInit {
name: position.assetProfile.name name: position.assetProfile.name
}; };
// For the "By Currency" chart:
// - Exposure: shows crypto names instead of tracking currency
// - Tracking: shows the tracking currency for all assets
const exposureKey =
position.assetProfile.assetSubClass === 'CRYPTOCURRENCY' ||
position.assetProfile.assetSubClass === 'PRECIOUS_METAL'
? position.assetProfile.name
: position.assetProfile.currency;
const trackingKey = position.assetProfile.currency;
if (this.currencyHoldingsExposure[exposureKey]?.value) {
this.currencyHoldingsExposure[exposureKey].value += value;
} else {
this.currencyHoldingsExposure[exposureKey] = {
name: exposureKey,
value
};
}
if (this.currencyHoldingsTracking[trackingKey]?.value) {
this.currencyHoldingsTracking[trackingKey].value += value;
} else {
this.currencyHoldingsTracking[trackingKey] = {
name: trackingKey,
value
};
}
// Set default based on experimental features setting
if (
!this.currencyHoldings ||
Object.keys(this.currencyHoldings).length === 0
) {
this.currencyMode = 'tracking';
this.currencyHoldings = this.currencyHoldingsTracking;
}
if (position.assetProfile.assetClass !== AssetClass.LIQUIDITY) { if (position.assetProfile.assetClass !== AssetClass.LIQUIDITY) {
// Prepare analysis data by continents, countries, holdings and sectors except for liquidity // Prepare analysis data by continents, countries, holdings and sectors except for liquidity

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

@ -63,14 +63,23 @@
<gf-premium-indicator class="ml-1" /> <gf-premium-indicator class="ml-1" />
} }
</mat-card-title> </mat-card-title>
@if (user?.settings?.isExperimentalFeatures) {
<gf-toggle
class="d-none d-lg-block"
[defaultValue]="currencyMode"
[isLoading]="false"
[options]="currencyModeOptions"
(valueChange)="onCurrencyModeChanged($event.value)"
/>
}
</mat-card-header> </mat-card-header>
<mat-card-content> <mat-card-content>
<gf-portfolio-proportion-chart <gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency" [baseCurrency]="user?.settings?.baseCurrency"
[colorScheme]="user?.settings?.colorScheme" [colorScheme]="user?.settings?.colorScheme"
[data]="holdings" [data]="currencyHoldings"
[isInPercentage]="showValuesInPercentage()" [isInPercentage]="showValuesInPercentage()"
[keys]="['currency']" [keys]="['name']"
[locale]="user?.settings?.locale" [locale]="user?.settings?.locale"
/> />
</mat-card-content> </mat-card-content>

Loading…
Cancel
Save