Browse Source

dd new static portfolio analysis rule: Emergency fund setup

pull/2400/head
Thomas 2 years ago
parent
commit
9b024aa513
  1. 5
      apps/api/src/app/portfolio/portfolio.service.ts
  2. 9
      apps/api/src/models/rules/account-cluster-risk/current-investment.ts
  3. 9
      apps/api/src/models/rules/account-cluster-risk/single-account.ts
  4. 9
      apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts
  5. 9
      apps/api/src/models/rules/currency-cluster-risk/current-investment.ts
  6. 41
      apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts
  7. 15
      apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts
  8. 3
      apps/client/src/app/pages/portfolio/fire/fire-page.component.ts
  9. 27
      apps/client/src/app/pages/portfolio/fire/fire-page.html

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

@ -10,6 +10,7 @@ import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rule
import { AccountClusterRiskSingleAccount } from '@ghostfolio/api/models/rules/account-cluster-risk/single-account'; import { AccountClusterRiskSingleAccount } from '@ghostfolio/api/models/rules/account-cluster-risk/single-account';
import { CurrencyClusterRiskBaseCurrencyCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/base-currency-current-investment'; 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 { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/current-investment';
import { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/emergency-fund-setup';
import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment'; import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
@ -1277,6 +1278,10 @@ export class PortfolioService {
], ],
<UserSettings>this.request.user.Settings.settings <UserSettings>this.request.user.Settings.settings
), ),
emergencyFund: await this.rulesService.evaluate(
[new EmergencyFundSetup(this.exchangeRateDataService)],
<UserSettings>this.request.user.Settings.settings
),
fees: await this.rulesService.evaluate( fees: await this.rulesService.evaluate(
[ [
new FeeRatioInitialInvestment( new FeeRatioInitialInvestment(

9
apps/api/src/models/rules/account-cluster-risk/current-investment.ts

@ -1,4 +1,5 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; 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 { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { import {
PortfolioDetails, PortfolioDetails,
@ -6,16 +7,18 @@ import {
UserSettings UserSettings
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule';
export class AccountClusterRiskCurrentInvestment extends Rule<Settings> { export class AccountClusterRiskCurrentInvestment extends Rule<Settings> {
private accounts: PortfolioDetails['accounts'];
public constructor( public constructor(
protected exchangeRateDataService: ExchangeRateDataService, protected exchangeRateDataService: ExchangeRateDataService,
private accounts: PortfolioDetails['accounts'] accounts: PortfolioDetails['accounts']
) { ) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Investment' name: 'Investment'
}); });
this.accounts = accounts;
} }
public evaluate(ruleSettings: Settings) { public evaluate(ruleSettings: Settings) {

9
apps/api/src/models/rules/account-cluster-risk/single-account.ts

@ -1,17 +1,20 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; 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 { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { PortfolioDetails, UserSettings } from '@ghostfolio/common/interfaces'; import { PortfolioDetails, UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule';
export class AccountClusterRiskSingleAccount extends Rule<RuleSettings> { export class AccountClusterRiskSingleAccount extends Rule<RuleSettings> {
private accounts: PortfolioDetails['accounts'];
public constructor( public constructor(
protected exchangeRateDataService: ExchangeRateDataService, protected exchangeRateDataService: ExchangeRateDataService,
private accounts: PortfolioDetails['accounts'] accounts: PortfolioDetails['accounts']
) { ) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Single Account' name: 'Single Account'
}); });
this.accounts = accounts;
} }
public evaluate() { public evaluate() {

9
apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts

@ -1,17 +1,20 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; 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 { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { TimelinePosition, UserSettings } from '@ghostfolio/common/interfaces'; import { TimelinePosition, UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule';
export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule<Settings> { export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule<Settings> {
private positions: TimelinePosition[];
public constructor( public constructor(
protected exchangeRateDataService: ExchangeRateDataService, protected exchangeRateDataService: ExchangeRateDataService,
private positions: TimelinePosition[] positions: TimelinePosition[]
) { ) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Investment: Base Currency' name: 'Investment: Base Currency'
}); });
this.positions = positions;
} }
public evaluate(ruleSettings: Settings) { public evaluate(ruleSettings: Settings) {

9
apps/api/src/models/rules/currency-cluster-risk/current-investment.ts

@ -1,17 +1,20 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; 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 { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { TimelinePosition, UserSettings } from '@ghostfolio/common/interfaces'; import { TimelinePosition, UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule';
export class CurrencyClusterRiskCurrentInvestment extends Rule<Settings> { export class CurrencyClusterRiskCurrentInvestment extends Rule<Settings> {
private positions: TimelinePosition[];
public constructor( public constructor(
protected exchangeRateDataService: ExchangeRateDataService, protected exchangeRateDataService: ExchangeRateDataService,
private positions: TimelinePosition[] positions: TimelinePosition[]
) { ) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Investment' name: 'Investment'
}); });
this.positions = positions;
} }
public evaluate(ruleSettings: Settings) { public evaluate(ruleSettings: Settings) {

41
apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts

@ -0,0 +1,41 @@
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 EmergencyFundSetup extends Rule<Settings> {
public constructor(
protected exchangeRateDataService: ExchangeRateDataService
) {
super(exchangeRateDataService, {
name: 'Emergency Fund: Set up'
});
}
public evaluate(ruleSettings: Settings) {
if (ruleSettings.threshold > 0) {
return {
evaluation: `You have set up an emergency fund`,
value: true
};
}
return {
evaluation: `You have not set up an emergency fund yet`,
value: false
};
}
public getSettings(aUserSettings: UserSettings): Settings {
return {
baseCurrency: aUserSettings.baseCurrency,
isActive: true,
threshold: aUserSettings.emergencyFund
};
}
}
interface Settings extends RuleSettings {
baseCurrency: string;
threshold: number;
}

15
apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts

@ -1,18 +1,23 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; 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 { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { UserSettings } from '@ghostfolio/common/interfaces'; import { UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule';
export class FeeRatioInitialInvestment extends Rule<Settings> { export class FeeRatioInitialInvestment extends Rule<Settings> {
private fees: number;
private totalInvestment: number;
public constructor( public constructor(
protected exchangeRateDataService: ExchangeRateDataService, protected exchangeRateDataService: ExchangeRateDataService,
private totalInvestment: number, totalInvestment: number,
private fees: number fees: number
) { ) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Investment' name: 'Fee Ratio'
}); });
this.fees = fees;
this.totalInvestment = totalInvestment;
} }
public evaluate(ruleSettings: Settings) { public evaluate(ruleSettings: Settings) {

3
apps/client/src/app/pages/portfolio/fire/fire-page.component.ts

@ -18,6 +18,7 @@ export class FirePageComponent implements OnDestroy, OnInit {
public accountClusterRiskRules: PortfolioReportRule[]; public accountClusterRiskRules: PortfolioReportRule[];
public currencyClusterRiskRules: PortfolioReportRule[]; public currencyClusterRiskRules: PortfolioReportRule[];
public deviceType: string; public deviceType: string;
public emergencyFundRules: PortfolioReportRule[];
public feeRules: PortfolioReportRule[]; public feeRules: PortfolioReportRule[];
public fireWealth: Big; public fireWealth: Big;
public hasImpersonationId: boolean; public hasImpersonationId: boolean;
@ -67,6 +68,8 @@ export class FirePageComponent implements OnDestroy, OnInit {
portfolioReport.rules['accountClusterRisk'] || null; portfolioReport.rules['accountClusterRisk'] || null;
this.currencyClusterRiskRules = this.currencyClusterRiskRules =
portfolioReport.rules['currencyClusterRisk'] || null; portfolioReport.rules['currencyClusterRisk'] || null;
this.emergencyFundRules =
portfolioReport.rules['emergencyFund'] || null;
this.feeRules = portfolioReport.rules['fees'] || null; this.feeRules = portfolioReport.rules['fees'] || null;
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();

27
apps/client/src/app/pages/portfolio/fire/fire-page.html

@ -96,8 +96,10 @@
<div class="col"> <div class="col">
<h2 class="h3 mb-3 text-center">X-ray</h2> <h2 class="h3 mb-3 text-center">X-ray</h2>
<p class="mb-4"> <p class="mb-4">
Ghostfolio X-ray uses static analysis to identify potential issues and <span i18n
risks in your portfolio. >Ghostfolio X-ray uses static analysis to identify potential issues
and risks in your portfolio.</span
>
<span class="d-none" <span class="d-none"
>It will be highly configurable in the future: activate / deactivate >It will be highly configurable in the future: activate / deactivate
rules and customize the thresholds to match your personal investment rules and customize the thresholds to match your personal investment
@ -106,7 +108,7 @@
</p> </p>
<div class="mb-4"> <div class="mb-4">
<h4 class="align-items-center d-flex m-0"> <h4 class="align-items-center d-flex m-0">
<span>Currency Cluster Risks</span <span i18n>Currency Cluster Risks</span
><gf-premium-indicator ><gf-premium-indicator
*ngIf="user?.subscription?.type === 'Basic'" *ngIf="user?.subscription?.type === 'Basic'"
class="ml-1" class="ml-1"
@ -119,7 +121,7 @@
</div> </div>
<div class="mb-4"> <div class="mb-4">
<h4 class="align-items-center d-flex m-0"> <h4 class="align-items-center d-flex m-0">
<span>Account Cluster Risks</span <span i18n>Account Cluster Risks</span
><gf-premium-indicator ><gf-premium-indicator
*ngIf="user?.subscription?.type === 'Basic'" *ngIf="user?.subscription?.type === 'Basic'"
class="ml-1" class="ml-1"
@ -130,9 +132,9 @@
[rules]="accountClusterRiskRules" [rules]="accountClusterRiskRules"
></gf-rules> ></gf-rules>
</div> </div>
<div> <div class="mb-4">
<h4 class="align-items-center d-flex m-0"> <h4 class="align-items-center d-flex m-0">
<span>Fees</span <span i18n>Fees</span
><gf-premium-indicator ><gf-premium-indicator
*ngIf="user?.subscription?.type === 'Basic'" *ngIf="user?.subscription?.type === 'Basic'"
class="ml-1" class="ml-1"
@ -143,6 +145,19 @@
[rules]="feeRules" [rules]="feeRules"
></gf-rules> ></gf-rules>
</div> </div>
<div>
<h4 class="align-items-center d-flex m-0">
<span i18n>Emergency Fund</span
><gf-premium-indicator
*ngIf="user?.subscription?.type === 'Basic'"
class="ml-1"
></gf-premium-indicator>
</h4>
<gf-rules
[hasPermissionToCreateOrder]="hasPermissionToCreateOrder"
[rules]="emergencyFundRules"
></gf-rules>
</div>
</div> </div>
</div> </div>
</div> </div>

Loading…
Cancel
Save