From 466028ae98c979efac00b9be53e78540ba82b9ba Mon Sep 17 00:00:00 2001 From: vitalymatyushik Date: Sun, 20 Oct 2024 23:03:49 +0200 Subject: [PATCH] feat: address review suggestions --- .../src/app/portfolio/portfolio.service.ts | 20 ++++++++---- apps/api/src/app/user/user.service.ts | 8 +++-- .../emerging-markets.ts | 32 +++++++++++-------- .../portfolio/fire/fire-page.component.ts | 8 +++++ .../app/pages/portfolio/fire/fire-page.html | 19 +++++++++++ .../lib/types/x-ray-rules-settings.type.ts | 2 +- 6 files changed, 64 insertions(+), 25 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 9c8feaee8..1835a2215 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1161,7 +1161,7 @@ export class PortfolioService { const userId = await this.getUserId(impersonationId, this.request.user.id); const userSettings = this.request.user.Settings.settings; - const { accounts, holdings, summary, markets } = await this.getDetails({ + const { accounts, holdings, markets, summary } = await this.getDetails({ impersonationId, userId, withMarkets: true, @@ -1181,10 +1181,18 @@ export class PortfolioService { new AccountClusterRiskSingleAccount( this.exchangeRateDataService, accounts - ), + ) + ], + userSettings + ) + : undefined, + allocationClusterRisk: + summary.ordersCount > 0 + ? await this.rulesService.evaluate( + [ new AllocationClusterRiskEmergingMarkets( this.exchangeRateDataService, - summary.committedFunds, + summary.currentValueInBaseCurrency, markets.emergingMarkets.valueInBaseCurrency ) ], @@ -1248,9 +1256,7 @@ export class PortfolioService { await this.orderService.assignTags({ dataSource, symbol, tags, userId }); } - private getAggregatedMarkets(holdings: { - [symbol: string]: PortfolioPosition; - }): { + private getAggregatedMarkets(holdings: Record): { markets: PortfolioDetails['markets']; marketsAdvanced: PortfolioDetails['marketsAdvanced']; } { @@ -1909,7 +1915,7 @@ export class PortfolioService { }: { activities: Activity[]; filters?: Filter[]; - portfolioItemsNow: { [p: string]: TimelinePosition }; + portfolioItemsNow: Record; userCurrency: string; userId: string; withExcludedAccounts?: boolean; diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index dce6e787c..f4f0dad33 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -217,9 +217,11 @@ export class UserService { {} ).getSettings(user.Settings.settings), AllocationClusterRiskEmergingMarkets: - new AllocationClusterRiskEmergingMarkets(undefined, 0, 0).getSettings( - user.Settings.settings - ), + new AllocationClusterRiskEmergingMarkets( + undefined, + undefined, + undefined + ).getSettings(user.Settings.settings), CurrencyClusterRiskBaseCurrencyCurrentInvestment: new CurrencyClusterRiskBaseCurrencyCurrentInvestment( undefined, diff --git a/apps/api/src/models/rules/allocation-cluster-risk/emerging-markets.ts b/apps/api/src/models/rules/allocation-cluster-risk/emerging-markets.ts index 5ba227ece..8ec13f232 100644 --- a/apps/api/src/models/rules/allocation-cluster-risk/emerging-markets.ts +++ b/apps/api/src/models/rules/allocation-cluster-risk/emerging-markets.ts @@ -4,12 +4,12 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate- import { UserSettings } from '@ghostfolio/common/interfaces'; export class AllocationClusterRiskEmergingMarkets extends Rule { + private currentValueInBaseCurrency: number; private emergingMarketsValueInBaseCurrency: number; - private totalInvestment: number; public constructor( protected exchangeRateDataService: ExchangeRateDataService, - totalInvestment: number, + currentValueInBaseCurrency: number, emergingMarketsValueInBaseCurrency: number ) { super(exchangeRateDataService, { @@ -19,38 +19,41 @@ export class AllocationClusterRiskEmergingMarkets extends Rule { this.emergingMarketsValueInBaseCurrency = emergingMarketsValueInBaseCurrency; - this.totalInvestment = totalInvestment; + this.currentValueInBaseCurrency = currentValueInBaseCurrency; } public evaluate(ruleSettings: Settings) { - const emergingMarketsValueRatio = this.totalInvestment - ? this.emergingMarketsValueInBaseCurrency / this.totalInvestment + const emergingMarketsValueRatio = this.currentValueInBaseCurrency + ? this.emergingMarketsValueInBaseCurrency / + this.currentValueInBaseCurrency : 0; if (emergingMarketsValueRatio > ruleSettings.thresholdMax) { return { - evaluation: `The emerging markets contribution exceed ${( + evaluation: `The emerging markets contribution exceeds ${( ruleSettings.thresholdMax * 100 ).toPrecision( 3 - )}% of your initial investment (${(emergingMarketsValueRatio * 100).toPrecision(3)}%)`, + )}% of your current investment (${(emergingMarketsValueRatio * 100).toPrecision(3)}%)`, value: false }; } else if (emergingMarketsValueRatio < ruleSettings.thresholdMin) { return { - evaluation: `The emerging markets contribution does not exceed ${( + evaluation: `The emerging markets contribution is below ${( ruleSettings.thresholdMin * 100 ).toPrecision( 3 - )}% of your initial investment (${(emergingMarketsValueRatio * 100).toPrecision(3)}%)`, + )}% of your current investment (${(emergingMarketsValueRatio * 100).toPrecision(3)}%)`, value: false }; } return { - evaluation: `The emerging markets contribution does not exceed ${ - ruleSettings.thresholdMax * 100 - }% of your initial investment (${(emergingMarketsValueRatio * 100).toPrecision(3)}%)`, + evaluation: `The emerging markets contribution is within the range of ${( + ruleSettings.thresholdMin * 100 + ).toPrecision( + 3 + )}% and ${(ruleSettings.thresholdMax * 100).toPrecision(3)}% of your current investment (${(emergingMarketsValueRatio * 100).toPrecision(3)}%)`, value: true }; } @@ -60,10 +63,11 @@ export class AllocationClusterRiskEmergingMarkets extends Rule { threshold: { max: 1, min: 0, - step: 0.0025, + step: 0.01, unit: '%' }, - thresholdMax: true + thresholdMax: true, + thresholdMin: true }; } diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts index 54f65b531..ea83500c4 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts +++ b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts @@ -22,6 +22,7 @@ import { takeUntil } from 'rxjs/operators'; }) export class FirePageComponent implements OnDestroy, OnInit { public accountClusterRiskRules: PortfolioReportRule[]; + public allocationClusterRiskRules: PortfolioReportRule[]; public currencyClusterRiskRules: PortfolioReportRule[]; public deviceType: string; public emergencyFundRules: PortfolioReportRule[]; @@ -203,6 +204,13 @@ export class FirePageComponent implements OnDestroy, OnInit { } ) ?? null; + this.allocationClusterRiskRules = + portfolioReport.rules['allocationClusterRisk']?.filter( + ({ isActive }) => { + return isActive; + } + ) ?? null; + this.currencyClusterRiskRules = portfolioReport.rules['currencyClusterRisk']?.filter( ({ isActive }) => { diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.html b/apps/client/src/app/pages/portfolio/fire/fire-page.html index c4a521a8c..4eedca300 100644 --- a/apps/client/src/app/pages/portfolio/fire/fire-page.html +++ b/apps/client/src/app/pages/portfolio/fire/fire-page.html @@ -174,6 +174,25 @@ (rulesUpdated)="onRulesUpdated($event)" /> +
+

+ Allocation Cluster Risks + @if (user?.subscription?.type === 'Basic') { + + } +

+ +

Fees diff --git a/libs/common/src/lib/types/x-ray-rules-settings.type.ts b/libs/common/src/lib/types/x-ray-rules-settings.type.ts index a8fc714bb..ffaff41a9 100644 --- a/libs/common/src/lib/types/x-ray-rules-settings.type.ts +++ b/libs/common/src/lib/types/x-ray-rules-settings.type.ts @@ -1,7 +1,7 @@ export type XRayRulesSettings = { AccountClusterRiskCurrentInvestment?: RuleSettings; - AllocationClusterRiskEmergingMarkets?: RuleSettings; AccountClusterRiskSingleAccount?: RuleSettings; + AllocationClusterRiskEmergingMarkets?: RuleSettings; CurrencyClusterRiskBaseCurrencyCurrentInvestment?: RuleSettings; CurrencyClusterRiskCurrentInvestment?: RuleSettings; EmergencyFundSetup?: RuleSettings;