change rule service interface
This commit is contained in:
parent
9834c52739
commit
72dbe00091
apps/api/src
@ -1,17 +1,9 @@
|
||||
import { PortfolioPosition } from '@ghostfolio/common/interfaces';
|
||||
|
||||
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
|
||||
import { EvaluationResult } from './evaluation-result.interface';
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
|
||||
export interface RuleInterface<T extends RuleSettings> {
|
||||
evaluate(
|
||||
aPortfolioPositionMap: {
|
||||
[symbol: string]: PortfolioPosition;
|
||||
},
|
||||
aFees: number,
|
||||
aRuleSettings: T
|
||||
): EvaluationResult;
|
||||
evaluate(aRuleSettings: T): EvaluationResult;
|
||||
|
||||
getSettings(aUserSettings: UserSettings): T;
|
||||
}
|
||||
|
@ -450,42 +450,51 @@ export class Portfolio implements PortfolioInterface {
|
||||
return {
|
||||
rules: {
|
||||
accountClusterRisk: await this.rulesService.evaluate(
|
||||
details,
|
||||
fees,
|
||||
[
|
||||
new AccountClusterRiskInitialInvestment(
|
||||
this.exchangeRateDataService
|
||||
this.exchangeRateDataService,
|
||||
details
|
||||
),
|
||||
new AccountClusterRiskCurrentInvestment(
|
||||
this.exchangeRateDataService
|
||||
this.exchangeRateDataService,
|
||||
details
|
||||
),
|
||||
new AccountClusterRiskSingleAccount(this.exchangeRateDataService)
|
||||
new AccountClusterRiskSingleAccount(
|
||||
this.exchangeRateDataService,
|
||||
details
|
||||
)
|
||||
],
|
||||
{ baseCurrency: this.user.Settings.currency }
|
||||
),
|
||||
currencyClusterRisk: await this.rulesService.evaluate(
|
||||
details,
|
||||
fees,
|
||||
[
|
||||
new CurrencyClusterRiskBaseCurrencyInitialInvestment(
|
||||
this.exchangeRateDataService
|
||||
this.exchangeRateDataService,
|
||||
details
|
||||
),
|
||||
new CurrencyClusterRiskBaseCurrencyCurrentInvestment(
|
||||
this.exchangeRateDataService
|
||||
this.exchangeRateDataService,
|
||||
details
|
||||
),
|
||||
new CurrencyClusterRiskInitialInvestment(
|
||||
this.exchangeRateDataService
|
||||
this.exchangeRateDataService,
|
||||
details
|
||||
),
|
||||
new CurrencyClusterRiskCurrentInvestment(
|
||||
this.exchangeRateDataService
|
||||
this.exchangeRateDataService,
|
||||
details
|
||||
)
|
||||
],
|
||||
{ baseCurrency: this.user.Settings.currency }
|
||||
),
|
||||
fees: await this.rulesService.evaluate(
|
||||
details,
|
||||
fees,
|
||||
[new FeeRatioInitialInvestment(this.exchangeRateDataService)],
|
||||
[
|
||||
new FeeRatioInitialInvestment(
|
||||
this.exchangeRateDataService,
|
||||
details,
|
||||
fees
|
||||
)
|
||||
],
|
||||
{ baseCurrency: this.user.Settings.currency }
|
||||
)
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ export abstract class Rule<T extends RuleSettings> implements RuleInterface<T> {
|
||||
private name: string;
|
||||
|
||||
public constructor(
|
||||
public exchangeRateDataService: ExchangeRateDataService,
|
||||
protected exchangeRateDataService: ExchangeRateDataService,
|
||||
{
|
||||
name
|
||||
}: {
|
||||
@ -22,13 +22,7 @@ export abstract class Rule<T extends RuleSettings> implements RuleInterface<T> {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public abstract evaluate(
|
||||
aPortfolioPositionMap: {
|
||||
[symbol: string]: PortfolioPosition;
|
||||
},
|
||||
aFees: number,
|
||||
aRuleSettings: T
|
||||
): EvaluationResult;
|
||||
public abstract evaluate(aRuleSettings: T): EvaluationResult;
|
||||
|
||||
public abstract getSettings(aUserSettings: UserSettings): T;
|
||||
|
||||
|
@ -6,24 +6,23 @@ import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.in
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
|
||||
export class AccountClusterRiskCurrentInvestment extends Rule<Settings> {
|
||||
public constructor(public exchangeRateDataService: ExchangeRateDataService) {
|
||||
public constructor(
|
||||
protected exchangeRateDataService: ExchangeRateDataService,
|
||||
private positions: { [symbol: string]: PortfolioPosition }
|
||||
) {
|
||||
super(exchangeRateDataService, {
|
||||
name: 'Current Investment'
|
||||
});
|
||||
}
|
||||
|
||||
public evaluate(
|
||||
aPositions: { [symbol: string]: PortfolioPosition },
|
||||
aFees: number,
|
||||
ruleSettings?: Settings
|
||||
) {
|
||||
public evaluate(ruleSettings: Settings) {
|
||||
const accounts: {
|
||||
[symbol: string]: Pick<PortfolioPosition, 'name'> & {
|
||||
investment: number;
|
||||
};
|
||||
} = {};
|
||||
|
||||
Object.values(aPositions).forEach((position) => {
|
||||
Object.values(this.positions).forEach((position) => {
|
||||
for (const [account, { current }] of Object.entries(position.accounts)) {
|
||||
if (accounts[account]?.investment) {
|
||||
accounts[account].investment += current;
|
||||
|
@ -6,24 +6,23 @@ import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.in
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
|
||||
export class AccountClusterRiskInitialInvestment extends Rule<Settings> {
|
||||
public constructor(public exchangeRateDataService: ExchangeRateDataService) {
|
||||
public constructor(
|
||||
protected exchangeRateDataService: ExchangeRateDataService,
|
||||
private positions: { [symbol: string]: PortfolioPosition }
|
||||
) {
|
||||
super(exchangeRateDataService, {
|
||||
name: 'Initial Investment'
|
||||
});
|
||||
}
|
||||
|
||||
public evaluate(
|
||||
aPositions: { [symbol: string]: PortfolioPosition },
|
||||
aFees: number,
|
||||
ruleSettings?: Settings
|
||||
) {
|
||||
public evaluate(ruleSettings?: Settings) {
|
||||
const platforms: {
|
||||
[symbol: string]: Pick<PortfolioPosition, 'name'> & {
|
||||
investment: number;
|
||||
};
|
||||
} = {};
|
||||
|
||||
Object.values(aPositions).forEach((position) => {
|
||||
Object.values(this.positions).forEach((position) => {
|
||||
for (const [account, { original }] of Object.entries(position.accounts)) {
|
||||
if (platforms[account]?.investment) {
|
||||
platforms[account].investment += original;
|
||||
|
@ -6,16 +6,19 @@ import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.in
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
|
||||
export class AccountClusterRiskSingleAccount extends Rule<RuleSettings> {
|
||||
public constructor(public exchangeRateDataService: ExchangeRateDataService) {
|
||||
public constructor(
|
||||
protected exchangeRateDataService: ExchangeRateDataService,
|
||||
private positions: { [symbol: string]: PortfolioPosition }
|
||||
) {
|
||||
super(exchangeRateDataService, {
|
||||
name: 'Single Account'
|
||||
});
|
||||
}
|
||||
|
||||
public evaluate(positions: { [symbol: string]: PortfolioPosition }) {
|
||||
public evaluate() {
|
||||
const accounts: string[] = [];
|
||||
|
||||
Object.values(positions).forEach((position) => {
|
||||
Object.values(this.positions).forEach((position) => {
|
||||
for (const [account] of Object.entries(position.accounts)) {
|
||||
if (!accounts.includes(account)) {
|
||||
accounts.push(account);
|
||||
|
@ -7,19 +7,18 @@ import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.in
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
|
||||
export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule<Settings> {
|
||||
public constructor(public exchangeRateDataService: ExchangeRateDataService) {
|
||||
public constructor(
|
||||
protected exchangeRateDataService: ExchangeRateDataService,
|
||||
private positions: { [symbol: string]: PortfolioPosition }
|
||||
) {
|
||||
super(exchangeRateDataService, {
|
||||
name: 'Current Investment: Base Currency'
|
||||
});
|
||||
}
|
||||
|
||||
public evaluate(
|
||||
aPositions: { [symbol: string]: PortfolioPosition },
|
||||
aFees: number,
|
||||
ruleSettings: Settings
|
||||
) {
|
||||
public evaluate(ruleSettings: Settings) {
|
||||
const positionsGroupedByCurrency = this.groupPositionsByAttribute(
|
||||
aPositions,
|
||||
this.positions,
|
||||
'currency',
|
||||
ruleSettings.baseCurrency
|
||||
);
|
||||
|
@ -7,19 +7,18 @@ import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.in
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
|
||||
export class CurrencyClusterRiskBaseCurrencyInitialInvestment extends Rule<Settings> {
|
||||
public constructor(public exchangeRateDataService: ExchangeRateDataService) {
|
||||
public constructor(
|
||||
protected exchangeRateDataService: ExchangeRateDataService,
|
||||
private positions: { [symbol: string]: PortfolioPosition }
|
||||
) {
|
||||
super(exchangeRateDataService, {
|
||||
name: 'Initial Investment: Base Currency'
|
||||
});
|
||||
}
|
||||
|
||||
public evaluate(
|
||||
aPositions: { [symbol: string]: PortfolioPosition },
|
||||
aFees: number,
|
||||
ruleSettings: Settings
|
||||
) {
|
||||
public evaluate(ruleSettings: Settings) {
|
||||
const positionsGroupedByCurrency = this.groupPositionsByAttribute(
|
||||
aPositions,
|
||||
this.positions,
|
||||
'currency',
|
||||
ruleSettings.baseCurrency
|
||||
);
|
||||
|
@ -7,19 +7,18 @@ import { Currency } from '@prisma/client';
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
|
||||
export class CurrencyClusterRiskCurrentInvestment extends Rule<Settings> {
|
||||
public constructor(public exchangeRateDataService: ExchangeRateDataService) {
|
||||
public constructor(
|
||||
public exchangeRateDataService: ExchangeRateDataService,
|
||||
private positions: { [symbol: string]: PortfolioPosition }
|
||||
) {
|
||||
super(exchangeRateDataService, {
|
||||
name: 'Current Investment'
|
||||
});
|
||||
}
|
||||
|
||||
public evaluate(
|
||||
aPositions: { [symbol: string]: PortfolioPosition },
|
||||
aFees: number,
|
||||
ruleSettings: Settings
|
||||
) {
|
||||
public evaluate(ruleSettings: Settings) {
|
||||
const positionsGroupedByCurrency = this.groupPositionsByAttribute(
|
||||
aPositions,
|
||||
this.positions,
|
||||
'currency',
|
||||
ruleSettings.baseCurrency
|
||||
);
|
||||
|
@ -7,19 +7,18 @@ import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.in
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
|
||||
export class CurrencyClusterRiskInitialInvestment extends Rule<Settings> {
|
||||
public constructor(public exchangeRateDataService: ExchangeRateDataService) {
|
||||
public constructor(
|
||||
protected exchangeRateDataService: ExchangeRateDataService,
|
||||
private positions: { [symbol: string]: PortfolioPosition }
|
||||
) {
|
||||
super(exchangeRateDataService, {
|
||||
name: 'Initial Investment'
|
||||
});
|
||||
}
|
||||
|
||||
public evaluate(
|
||||
aPositions: { [symbol: string]: PortfolioPosition },
|
||||
aFees: number,
|
||||
ruleSettings: Settings
|
||||
) {
|
||||
public evaluate(ruleSettings: Settings) {
|
||||
const positionsGroupedByCurrency = this.groupPositionsByAttribute(
|
||||
aPositions,
|
||||
this.positions,
|
||||
'currency',
|
||||
ruleSettings.baseCurrency
|
||||
);
|
||||
|
@ -7,19 +7,19 @@ import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.in
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
|
||||
export class FeeRatioInitialInvestment extends Rule<Settings> {
|
||||
public constructor(public exchangeRateDataService: ExchangeRateDataService) {
|
||||
public constructor(
|
||||
protected exchangeRateDataService: ExchangeRateDataService,
|
||||
private positions: { [symbol: string]: PortfolioPosition },
|
||||
private fees: number
|
||||
) {
|
||||
super(exchangeRateDataService, {
|
||||
name: 'Initial Investment'
|
||||
});
|
||||
}
|
||||
|
||||
public evaluate(
|
||||
aPositions: { [symbol: string]: PortfolioPosition },
|
||||
aFees: number,
|
||||
ruleSettings: Settings
|
||||
) {
|
||||
public evaluate(ruleSettings: Settings) {
|
||||
const positionsGroupedByCurrency = this.groupPositionsByAttribute(
|
||||
aPositions,
|
||||
this.positions,
|
||||
'currency',
|
||||
ruleSettings.baseCurrency
|
||||
);
|
||||
@ -31,7 +31,7 @@ export class FeeRatioInitialInvestment extends Rule<Settings> {
|
||||
totalInvestment += groupItem.investment;
|
||||
});
|
||||
|
||||
const feeRatio = aFees / totalInvestment;
|
||||
const feeRatio = this.fees / totalInvestment;
|
||||
|
||||
if (feeRatio > ruleSettings.threshold) {
|
||||
return {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Rule } from '../models/rule';
|
||||
import { PortfolioPosition } from '@ghostfolio/common/interfaces';
|
||||
import { Currency } from '@prisma/client';
|
||||
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
|
||||
|
||||
@ -9,8 +8,6 @@ export class RulesService {
|
||||
public constructor() {}
|
||||
|
||||
public async evaluate<T extends RuleSettings>(
|
||||
details: { [p: string]: PortfolioPosition },
|
||||
fees: number,
|
||||
aRules: Rule<T>[],
|
||||
aUserSettings: { baseCurrency: Currency }
|
||||
) {
|
||||
@ -19,11 +16,7 @@ export class RulesService {
|
||||
return rule.getSettings(aUserSettings)?.isActive;
|
||||
})
|
||||
.map((rule) => {
|
||||
const evaluationResult = rule.evaluate(
|
||||
details,
|
||||
fees,
|
||||
rule.getSettings(aUserSettings)
|
||||
);
|
||||
const evaluationResult = rule.evaluate(rule.getSettings(aUserSettings));
|
||||
return { ...evaluationResult, name: rule.getName() };
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user