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.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') &&
this.request.user.subscription.type === 'Basic' this.request.user.subscription.type === 'Basic'
) { ) {
for (const rule in report.xRay.rules) { for (const category of report.xRay.categories) {
report.xRay.rules[rule] = null; category.rules = null;
} }
report.xRay.statistics = { report.xRay.statistics = {

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

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

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

@ -22,7 +22,6 @@ export class RulesService {
return { return {
evaluation, evaluation,
value, value,
categoryName: rule.getCategoryName(),
configuration: rule.getConfiguration(), configuration: rule.getConfiguration(),
isActive: true, isActive: true,
key: rule.getKey(), key: rule.getKey(),
@ -30,7 +29,6 @@ export class RulesService {
}; };
} else { } else {
return { return {
categoryName: rule.getCategoryName(),
isActive: false, isActive: false,
key: rule.getKey(), key: rule.getKey(),
name: rule.getName() 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 this.dataService
.fetchPortfolioReport() .fetchPortfolioReport()
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ xRay: { rules, statistics } }) => { .subscribe(({ xRay: { categories, statistics } }) => {
this.inactiveRules = this.mergeInactiveRules(rules); this.inactiveRules = this.mergeInactiveRules(categories);
this.statistics = statistics; this.statistics = statistics;
this.accountClusterRiskRules = this.accountClusterRiskRules =
rules['accountClusterRisk']?.filter(({ isActive }) => { categories
return isActive; .find(({ key }) => key === 'accountClusterRisk')
}) ?? null; ?.rules?.filter(({ isActive }) => isActive) ?? null;
this.assetClassClusterRiskRules = this.assetClassClusterRiskRules =
rules['assetClassClusterRisk']?.filter(({ isActive }) => { categories
return isActive; .find(({ key }) => key === 'assetClassClusterRisk')
}) ?? null; ?.rules?.filter(({ isActive }) => isActive) ?? null;
this.currencyClusterRiskRules = this.currencyClusterRiskRules =
rules['currencyClusterRisk']?.filter(({ isActive }) => { categories
return isActive; .find(({ key }) => key === 'currencyClusterRisk')
}) ?? null; ?.rules?.filter(({ isActive }) => isActive) ?? null;
this.economicMarketClusterRiskRules = this.economicMarketClusterRiskRules =
rules['economicMarketClusterRisk']?.filter(({ isActive }) => { categories
return isActive; .find(({ key }) => key === 'economicMarketClusterRisk')
}) ?? null; ?.rules?.filter(({ isActive }) => isActive) ?? null;
this.emergencyFundRules = this.emergencyFundRules =
rules['emergencyFund']?.filter(({ isActive }) => { categories
return isActive; .find(({ key }) => key === 'emergencyFund')
}) ?? null; ?.rules?.filter(({ isActive }) => isActive) ?? null;
this.feeRules = this.feeRules =
rules['fees']?.filter(({ isActive }) => { categories
return isActive; .find(({ key }) => key === 'fees')
}) ?? null; ?.rules?.filter(({ isActive }) => isActive) ?? null;
this.liquidityRules = this.liquidityRules =
rules['liquidity']?.filter(({ isActive }) => { categories
return isActive; .find(({ key }) => key === 'liquidity')
}) ?? null; ?.rules?.filter(({ isActive }) => isActive) ?? null;
this.regionalMarketClusterRiskRules = this.regionalMarketClusterRiskRules =
rules['regionalMarketClusterRisk']?.filter(({ isActive }) => { categories
return isActive; .find(({ key }) => key === 'regionalMarketClusterRisk')
}) ?? null; ?.rules?.filter(({ isActive }) => isActive) ?? null;
this.isLoading = false; this.isLoading = false;
@ -167,15 +167,13 @@ export class GfXRayPageComponent {
} }
private mergeInactiveRules( private mergeInactiveRules(
rules: PortfolioReportResponse['xRay']['rules'] categories: PortfolioReportResponse['xRay']['categories']
): PortfolioReportRule[] { ): PortfolioReportRule[] {
let inactiveRules: PortfolioReportRule[] = []; let inactiveRules: PortfolioReportRule[] = [];
for (const category in rules) { for (const category of categories) {
const rulesArray = rules[category] || [];
inactiveRules = inactiveRules.concat( inactiveRules = inactiveRules.concat(
rulesArray.filter(({ isActive }) => { category.rules.filter(({ isActive }) => {
return !isActive; return !isActive;
}) })
); );

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

@ -1,5 +1,4 @@
export interface PortfolioReportRule { export interface PortfolioReportRule {
categoryName: string;
configuration?: { configuration?: {
threshold?: { threshold?: {
max: number; 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 { export interface PortfolioReportResponse {
xRay: { xRay: {
rules: { [group: string]: PortfolioReportRule[] }; categories: {
key: string;
name: string;
rules: PortfolioReportRule[];
}[];
statistics: { statistics: {
rulesActiveCount: number; rulesActiveCount: number;
rulesFulfilledCount: number; rulesFulfilledCount: number;

Loading…
Cancel
Save