Browse Source

Set up Asset Class Cluster Risk rule (fixed income)

pull/4128/head
Thomas Kaul 8 months ago
parent
commit
c231771571
  1. 5
      apps/api/src/app/portfolio/portfolio.service.ts
  2. 5
      apps/api/src/app/user/user.service.ts
  3. 95
      apps/api/src/models/rules/asset-class-cluster-risk/fixed-income.ts
  4. 1
      libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts

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

@ -8,6 +8,7 @@ import { getFactor } from '@ghostfolio/api/helper/portfolio.helper';
import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment';
import { AccountClusterRiskSingleAccount } from '@ghostfolio/api/models/rules/account-cluster-risk/single-account';
import { AssetClassClusterRiskEquity } from '@ghostfolio/api/models/rules/asset-class-cluster-risk/equity';
import { AssetClassClusterRiskFixedIncome } from '@ghostfolio/api/models/rules/asset-class-cluster-risk/fixed-income';
import { CurrencyClusterRiskBaseCurrencyCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/base-currency-current-investment';
import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/current-investment';
import { EconomicMarketClusterRiskDevelopedMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/developed-markets';
@ -1206,6 +1207,10 @@ export class PortfolioService {
new AssetClassClusterRiskEquity(
this.exchangeRateDataService,
Object.values(holdings)
),
new AssetClassClusterRiskFixedIncome(
this.exchangeRateDataService,
Object.values(holdings)
)
],
userSettings

5
apps/api/src/app/user/user.service.ts

@ -6,6 +6,7 @@ import { getRandomString } from '@ghostfolio/api/helper/string.helper';
import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment';
import { AccountClusterRiskSingleAccount } from '@ghostfolio/api/models/rules/account-cluster-risk/single-account';
import { AssetClassClusterRiskEquity } from '@ghostfolio/api/models/rules/asset-class-cluster-risk/equity';
import { AssetClassClusterRiskFixedIncome } from '@ghostfolio/api/models/rules/asset-class-cluster-risk/fixed-income';
import { CurrencyClusterRiskBaseCurrencyCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/base-currency-current-investment';
import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/current-investment';
import { EconomicMarketClusterRiskDevelopedMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/developed-markets';
@ -231,6 +232,10 @@ export class UserService {
undefined,
undefined
).getSettings(user.Settings.settings),
AssetClassClusterRiskFixedIncome: new AssetClassClusterRiskFixedIncome(
undefined,
undefined
).getSettings(user.Settings.settings),
CurrencyClusterRiskBaseCurrencyCurrentInvestment:
new CurrencyClusterRiskBaseCurrencyCurrentInvestment(
undefined,

95
apps/api/src/models/rules/asset-class-cluster-risk/fixed-income.ts

@ -0,0 +1,95 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { Rule } from '@ghostfolio/api/models/rule';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { PortfolioPosition, UserSettings } from '@ghostfolio/common/interfaces';
export class AssetClassClusterRiskFixedIncome extends Rule<Settings> {
private holdings: PortfolioPosition[];
public constructor(
protected exchangeRateDataService: ExchangeRateDataService,
holdings: PortfolioPosition[]
) {
super(exchangeRateDataService, {
key: AssetClassClusterRiskFixedIncome.name,
name: 'Fixed Income'
});
this.holdings = holdings;
}
public evaluate(ruleSettings: Settings) {
const holdingsGroupedByAssetClass = this.groupCurrentHoldingsByAttribute(
this.holdings,
'assetClass',
ruleSettings.baseCurrency
);
let totalValue = 0;
const fixedIncomeValueInBaseCurrency =
holdingsGroupedByAssetClass.find(({ groupKey }) => {
return groupKey === 'FIXED_INCOME';
})?.value ?? 0;
for (const { value } of holdingsGroupedByAssetClass) {
totalValue += value;
}
const fixedIncomeValueRatio = totalValue
? fixedIncomeValueInBaseCurrency / totalValue
: 0;
if (fixedIncomeValueRatio > ruleSettings.thresholdMax) {
return {
evaluation: `The fixed income contribution of your current investment (${(fixedIncomeValueRatio * 100).toPrecision(3)}%) exceeds ${(
ruleSettings.thresholdMax * 100
).toPrecision(3)}%`,
value: false
};
} else if (fixedIncomeValueRatio < ruleSettings.thresholdMin) {
return {
evaluation: `The fixed income contribution of your current investment (${(fixedIncomeValueRatio * 100).toPrecision(3)}%) is below ${(
ruleSettings.thresholdMin * 100
).toPrecision(3)}%`,
value: false
};
}
return {
evaluation: `The fixed income contribution of your current investment (${(fixedIncomeValueRatio * 100).toPrecision(3)}%) is within the range of ${(
ruleSettings.thresholdMin * 100
).toPrecision(
3
)}% and ${(ruleSettings.thresholdMax * 100).toPrecision(3)}%`,
value: true
};
}
public getConfiguration() {
return {
threshold: {
max: 1,
min: 0,
step: 0.01,
unit: '%'
},
thresholdMax: true,
thresholdMin: true
};
}
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
return {
baseCurrency,
isActive: xRayRules?.[this.getKey()]?.isActive ?? true,
thresholdMax: xRayRules?.[this.getKey()]?.thresholdMax ?? 0.22,
thresholdMin: xRayRules?.[this.getKey()]?.thresholdMin ?? 0.18
};
}
}
interface Settings extends RuleSettings {
baseCurrency: string;
thresholdMin: number;
thresholdMax: number;
}

1
libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts

@ -2,6 +2,7 @@ export interface XRayRulesSettings {
AccountClusterRiskCurrentInvestment?: RuleSettings;
AccountClusterRiskSingleAccount?: RuleSettings;
AssetClassClusterRiskEquity?: RuleSettings;
AssetClassClusterRiskFixedIncome?: RuleSettings;
CurrencyClusterRiskBaseCurrencyCurrentInvestment?: RuleSettings;
CurrencyClusterRiskCurrentInvestment?: RuleSettings;
EconomicMarketClusterRiskDevelopedMarkets?: RuleSettings;

Loading…
Cancel
Save