Browse Source

feat: add emerging markets rule

pull/3949/head
vitalymatyushik 10 months ago
committed by Thomas Kaul
parent
commit
0385f527ac
  1. 8
      apps/api/src/app/portfolio/portfolio.service.ts
  2. 5
      apps/api/src/app/user/user.service.ts
  3. 84
      apps/api/src/models/rules/allocation-cluster-risk/emerging-markets.ts
  4. 1
      libs/common/src/lib/types/x-ray-rules-settings.type.ts

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

@ -7,6 +7,7 @@ import { UserService } from '@ghostfolio/api/app/user/user.service';
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 { AllocationClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/allocation-cluster-risk/emerging-markets';
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 { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/emergency-fund-setup';
@ -1160,7 +1161,7 @@ export class PortfolioService {
const userId = await this.getUserId(impersonationId, this.request.user.id);
const userSettings = <UserSettings>this.request.user.Settings.settings;
const { accounts, holdings, summary } = await this.getDetails({
const { accounts, holdings, summary, markets } = await this.getDetails({
impersonationId,
userId,
withMarkets: true,
@ -1180,6 +1181,11 @@ export class PortfolioService {
new AccountClusterRiskSingleAccount(
this.exchangeRateDataService,
accounts
),
new AllocationClusterRiskEmergingMarkets(
this.exchangeRateDataService,
summary.committedFunds,
markets.emergingMarkets.valueInBaseCurrency
)
],
userSettings

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

@ -4,6 +4,7 @@ import { environment } from '@ghostfolio/api/environments/environment';
import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event';
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 { AllocationClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/allocation-cluster-risk/emerging-markets';
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 { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/emergency-fund-setup';
@ -215,6 +216,10 @@ export class UserService {
undefined,
{}
).getSettings(user.Settings.settings),
AllocationClusterRiskEmergingMarkets:
new AllocationClusterRiskEmergingMarkets(undefined, 0, 0).getSettings(
user.Settings.settings
),
CurrencyClusterRiskBaseCurrencyCurrentInvestment:
new CurrencyClusterRiskBaseCurrencyCurrentInvestment(
undefined,

84
apps/api/src/models/rules/allocation-cluster-risk/emerging-markets.ts

@ -0,0 +1,84 @@
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 { UserSettings } from '@ghostfolio/common/interfaces';
export class AllocationClusterRiskEmergingMarkets extends Rule<Settings> {
private emergingMarketsValueInBaseCurrency: number;
private totalInvestment: number;
public constructor(
protected exchangeRateDataService: ExchangeRateDataService,
totalInvestment: number,
emergingMarketsValueInBaseCurrency: number
) {
super(exchangeRateDataService, {
key: AllocationClusterRiskEmergingMarkets.name,
name: 'Emerging Markets'
});
this.emergingMarketsValueInBaseCurrency =
emergingMarketsValueInBaseCurrency;
this.totalInvestment = totalInvestment;
}
public evaluate(ruleSettings: Settings) {
const emergingMarketsValueRatio = this.totalInvestment
? this.emergingMarketsValueInBaseCurrency / this.totalInvestment
: 0;
if (emergingMarketsValueRatio > ruleSettings.thresholdMax) {
return {
evaluation: `The emerging markets contribution exceed ${(
ruleSettings.thresholdMax * 100
).toPrecision(
3
)}% of your initial investment (${(emergingMarketsValueRatio * 100).toPrecision(3)}%)`,
value: false
};
} else if (emergingMarketsValueRatio < ruleSettings.thresholdMin) {
return {
evaluation: `The emerging markets contribution does not exceed ${(
ruleSettings.thresholdMin * 100
).toPrecision(
3
)}% of your initial 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)}%)`,
value: true
};
}
public getConfiguration() {
return {
threshold: {
max: 1,
min: 0,
step: 0.0025,
unit: '%'
},
thresholdMax: true
};
}
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
return {
baseCurrency,
isActive: xRayRules?.[this.getKey()]?.isActive ?? true,
thresholdMax: xRayRules?.[this.getKey()]?.thresholdMax ?? 0.32,
thresholdMin: xRayRules?.[this.getKey()]?.thresholdMin ?? 0.28
};
}
}
interface Settings extends RuleSettings {
baseCurrency: string;
thresholdMin: number;
thresholdMax: number;
}

1
libs/common/src/lib/types/x-ray-rules-settings.type.ts

@ -1,5 +1,6 @@
export type XRayRulesSettings = {
AccountClusterRiskCurrentInvestment?: RuleSettings;
AllocationClusterRiskEmergingMarkets?: RuleSettings;
AccountClusterRiskSingleAccount?: RuleSettings;
CurrencyClusterRiskBaseCurrencyCurrentInvestment?: RuleSettings;
CurrencyClusterRiskCurrentInvestment?: RuleSettings;

Loading…
Cancel
Save