Browse Source

implements interface change

pull/5454/head
tobikugel 4 months ago
parent
commit
fa77976466
  1. 4
      apps/api/src/app/portfolio/portfolio.controller.ts
  2. 365
      apps/api/src/app/portfolio/portfolio.service.ts
  3. 2
      apps/api/src/app/portfolio/rules.service.ts
  4. 60
      apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts
  5. 1
      libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts
  6. 6
      libs/common/src/lib/interfaces/responses/portfolio-report.interface.ts

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

@ -655,8 +655,8 @@ export class PortfolioController {
this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
this.request.user.subscription.type === 'Basic'
) {
for (const rule in report.xRay.rules) {
report.xRay.rules[rule] = null;
for (const category of report.xRay.categories) {
category.rules = null;
}
report.xRay.statistics = {

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

@ -50,6 +50,7 @@ import {
PortfolioPerformanceResponse,
PortfolioPosition,
PortfolioReportResponse,
PortfolioReportRule,
PortfolioSummary,
UserSettings
} from '@ghostfolio/common/interfaces';
@ -1231,176 +1232,210 @@ export class PortfolioService {
})
).toNumber();
const rules: PortfolioReportResponse['xRay']['rules'] = {
accountClusterRisk:
summary.activityCount > 0
? await this.rulesService.evaluate(
[
new AccountClusterRiskCurrentInvestment(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
accounts
),
new AccountClusterRiskSingleAccount(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
accounts
)
],
userSettings
)
: undefined,
assetClassClusterRisk:
summary.activityCount > 0
? await this.rulesService.evaluate(
[
new AssetClassClusterRiskEquity(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
Object.values(holdings)
),
new AssetClassClusterRiskFixedIncome(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
Object.values(holdings)
)
],
userSettings
)
: undefined,
currencyClusterRisk:
summary.activityCount > 0
? await this.rulesService.evaluate(
[
new CurrencyClusterRiskBaseCurrencyCurrentInvestment(
this.exchangeRateDataService,
this.i18nService,
Object.values(holdings),
userSettings.language
),
new CurrencyClusterRiskCurrentInvestment(
this.exchangeRateDataService,
this.i18nService,
Object.values(holdings),
userSettings.language
)
],
userSettings
const categories: PortfolioReportResponse['xRay']['categories'] = [
{
key: 'accountClusterRisk',
name: 'accountClusterRisk',
rules:
summary.activityCount > 0
? await this.rulesService.evaluate(
[
new AccountClusterRiskCurrentInvestment(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
accounts
),
new AccountClusterRiskSingleAccount(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
accounts
)
],
userSettings
)
: undefined
},
{
key: 'assetClassClusterRisk',
name: 'assetClassClusterRisk',
rules:
summary.activityCount > 0
? await this.rulesService.evaluate(
[
new AssetClassClusterRiskEquity(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
Object.values(holdings)
),
new AssetClassClusterRiskFixedIncome(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
Object.values(holdings)
)
],
userSettings
)
: undefined
},
{
key: 'currencyClusterRisk',
name: 'currencyClusterRisk',
rules:
summary.activityCount > 0
? await this.rulesService.evaluate(
[
new CurrencyClusterRiskBaseCurrencyCurrentInvestment(
this.exchangeRateDataService,
this.i18nService,
Object.values(holdings),
userSettings.language
),
new CurrencyClusterRiskCurrentInvestment(
this.exchangeRateDataService,
this.i18nService,
Object.values(holdings),
userSettings.language
)
],
userSettings
)
: undefined
},
{
key: 'economicMarketClusterRisk',
name: 'economicMarketClusterRisk',
rules:
summary.activityCount > 0
? await this.rulesService.evaluate(
[
new EconomicMarketClusterRiskDevelopedMarkets(
this.exchangeRateDataService,
this.i18nService,
marketsTotalInBaseCurrency,
markets.developedMarkets.valueInBaseCurrency,
userSettings.language
),
new EconomicMarketClusterRiskEmergingMarkets(
this.exchangeRateDataService,
this.i18nService,
marketsTotalInBaseCurrency,
markets.emergingMarkets.valueInBaseCurrency,
userSettings.language
)
],
userSettings
)
: undefined
},
{
key: 'emergencyFund',
name: 'emergencyFund',
rules: await this.rulesService.evaluate(
[
new EmergencyFundSetup(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
this.getTotalEmergencyFund({
userSettings,
emergencyFundHoldingsValueInBaseCurrency:
this.getEmergencyFundHoldingsValueInBaseCurrency({ holdings })
}).toNumber()
)
: undefined,
economicMarketClusterRisk:
summary.activityCount > 0
? await this.rulesService.evaluate(
[
new EconomicMarketClusterRiskDevelopedMarkets(
this.exchangeRateDataService,
this.i18nService,
marketsTotalInBaseCurrency,
markets.developedMarkets.valueInBaseCurrency,
userSettings.language
),
new EconomicMarketClusterRiskEmergingMarkets(
this.exchangeRateDataService,
this.i18nService,
marketsTotalInBaseCurrency,
markets.emergingMarkets.valueInBaseCurrency,
userSettings.language
)
],
userSettings
],
userSettings
)
},
{
key: 'fees',
name: 'fees',
rules: await this.rulesService.evaluate(
[
new FeeRatioInitialInvestment(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
summary.committedFunds,
summary.fees
)
: undefined,
emergencyFund: await this.rulesService.evaluate(
[
new EmergencyFundSetup(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
this.getTotalEmergencyFund({
userSettings,
emergencyFundHoldingsValueInBaseCurrency:
this.getEmergencyFundHoldingsValueInBaseCurrency({ holdings })
}).toNumber()
)
],
userSettings
),
fees: await this.rulesService.evaluate(
[
new FeeRatioInitialInvestment(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
summary.committedFunds,
summary.fees
)
],
userSettings
),
liquidity: await this.rulesService.evaluate(
[
new BuyingPower(
this.exchangeRateDataService,
this.i18nService,
summary.cash,
userSettings.language
)
],
userSettings
),
regionalMarketClusterRisk:
summary.activityCount > 0
? await this.rulesService.evaluate(
[
new RegionalMarketClusterRiskAsiaPacific(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
marketsAdvancedTotalInBaseCurrency,
marketsAdvanced.asiaPacific.valueInBaseCurrency
),
new RegionalMarketClusterRiskEmergingMarkets(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
marketsAdvancedTotalInBaseCurrency,
marketsAdvanced.emergingMarkets.valueInBaseCurrency
),
new RegionalMarketClusterRiskEurope(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
marketsAdvancedTotalInBaseCurrency,
marketsAdvanced.europe.valueInBaseCurrency
),
new RegionalMarketClusterRiskJapan(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
marketsAdvancedTotalInBaseCurrency,
marketsAdvanced.japan.valueInBaseCurrency
),
new RegionalMarketClusterRiskNorthAmerica(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
marketsAdvancedTotalInBaseCurrency,
marketsAdvanced.northAmerica.valueInBaseCurrency
)
],
userSettings
],
userSettings
)
},
{
key: 'liquidity',
name: 'liquidity',
rules: await this.rulesService.evaluate(
[
new BuyingPower(
this.exchangeRateDataService,
this.i18nService,
summary.cash,
userSettings.language
)
: undefined
};
],
userSettings
)
},
{
key: 'regionalMarketClusterRisk',
name: 'regionalMarketClusterRisk',
rules:
summary.activityCount > 0
? await this.rulesService.evaluate(
[
new RegionalMarketClusterRiskAsiaPacific(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
marketsAdvancedTotalInBaseCurrency,
marketsAdvanced.asiaPacific.valueInBaseCurrency
),
new RegionalMarketClusterRiskEmergingMarkets(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
marketsAdvancedTotalInBaseCurrency,
marketsAdvanced.emergingMarkets.valueInBaseCurrency
),
new RegionalMarketClusterRiskEurope(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
marketsAdvancedTotalInBaseCurrency,
marketsAdvanced.europe.valueInBaseCurrency
),
new RegionalMarketClusterRiskJapan(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
marketsAdvancedTotalInBaseCurrency,
marketsAdvanced.japan.valueInBaseCurrency
),
new RegionalMarketClusterRiskNorthAmerica(
this.exchangeRateDataService,
this.i18nService,
userSettings.language,
marketsAdvancedTotalInBaseCurrency,
marketsAdvanced.northAmerica.valueInBaseCurrency
)
],
userSettings
)
: undefined
}
];
return {
xRay: {
rules,
statistics: this.getReportStatistics(rules)
categories,
statistics: this.getReportStatistics(
categories.flatMap(({ rules }) => rules ?? [])
)
}
};
}
@ -1822,7 +1857,7 @@ export class PortfolioService {
}
private getReportStatistics(
evaluatedRules: PortfolioReportResponse['xRay']['rules']
evaluatedRules: PortfolioReportRule[]
): PortfolioReportResponse['xRay']['statistics'] {
const rulesActiveCount = Object.values(evaluatedRules)
.flat()

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

@ -22,7 +22,6 @@ export class RulesService {
return {
evaluation,
value,
categoryName: rule.getCategoryName(),
configuration: rule.getConfiguration(),
isActive: true,
key: rule.getKey(),
@ -30,7 +29,6 @@ export class RulesService {
};
} else {
return {
categoryName: rule.getCategoryName(),
isActive: false,
key: rule.getKey(),
name: rule.getName()

60
apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts

@ -116,49 +116,49 @@ export class GfXRayPageComponent {
this.dataService
.fetchPortfolioReport()
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ xRay: { rules, statistics } }) => {
this.inactiveRules = this.mergeInactiveRules(rules);
.subscribe(({ xRay: { categories, statistics } }) => {
this.inactiveRules = this.mergeInactiveRules(categories);
this.statistics = statistics;
this.accountClusterRiskRules =
rules['accountClusterRisk']?.filter(({ isActive }) => {
return isActive;
}) ?? null;
categories
.find(({ key }) => key === 'accountClusterRisk')
?.rules?.filter(({ isActive }) => isActive) ?? null;
this.assetClassClusterRiskRules =
rules['assetClassClusterRisk']?.filter(({ isActive }) => {
return isActive;
}) ?? null;
categories
.find(({ key }) => key === 'assetClassClusterRisk')
?.rules?.filter(({ isActive }) => isActive) ?? null;
this.currencyClusterRiskRules =
rules['currencyClusterRisk']?.filter(({ isActive }) => {
return isActive;
}) ?? null;
categories
.find(({ key }) => key === 'currencyClusterRisk')
?.rules?.filter(({ isActive }) => isActive) ?? null;
this.economicMarketClusterRiskRules =
rules['economicMarketClusterRisk']?.filter(({ isActive }) => {
return isActive;
}) ?? null;
categories
.find(({ key }) => key === 'economicMarketClusterRisk')
?.rules?.filter(({ isActive }) => isActive) ?? null;
this.emergencyFundRules =
rules['emergencyFund']?.filter(({ isActive }) => {
return isActive;
}) ?? null;
categories
.find(({ key }) => key === 'emergencyFund')
?.rules?.filter(({ isActive }) => isActive) ?? null;
this.feeRules =
rules['fees']?.filter(({ isActive }) => {
return isActive;
}) ?? null;
categories
.find(({ key }) => key === 'fees')
?.rules?.filter(({ isActive }) => isActive) ?? null;
this.liquidityRules =
rules['liquidity']?.filter(({ isActive }) => {
return isActive;
}) ?? null;
categories
.find(({ key }) => key === 'liquidity')
?.rules?.filter(({ isActive }) => isActive) ?? null;
this.regionalMarketClusterRiskRules =
rules['regionalMarketClusterRisk']?.filter(({ isActive }) => {
return isActive;
}) ?? null;
categories
.find(({ key }) => key === 'regionalMarketClusterRisk')
?.rules?.filter(({ isActive }) => isActive) ?? null;
this.isLoading = false;
@ -167,15 +167,13 @@ export class GfXRayPageComponent {
}
private mergeInactiveRules(
rules: PortfolioReportResponse['xRay']['rules']
categories: PortfolioReportResponse['xRay']['categories']
): PortfolioReportRule[] {
let inactiveRules: PortfolioReportRule[] = [];
for (const category in rules) {
const rulesArray = rules[category] || [];
for (const category of categories) {
inactiveRules = inactiveRules.concat(
rulesArray.filter(({ isActive }) => {
category.rules.filter(({ isActive }) => {
return !isActive;
})
);

1
libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts

@ -1,5 +1,4 @@
export interface PortfolioReportRule {
categoryName: string;
configuration?: {
threshold?: {
max: number;

6
libs/common/src/lib/interfaces/responses/portfolio-report.interface.ts

@ -2,7 +2,11 @@ import { PortfolioReportRule } from '../portfolio-report-rule.interface';
export interface PortfolioReportResponse {
xRay: {
rules: { [group: string]: PortfolioReportRule[] };
categories: {
key: string;
name: string;
rules: PortfolioReportRule[];
}[];
statistics: {
rulesActiveCount: number;
rulesFulfilledCount: number;

Loading…
Cancel
Save