change rule service interface

pull/239/head
Valentin Zickner 3 years ago committed by Thomas
parent 9834c52739
commit 72dbe00091

@ -1,17 +1,9 @@
import { PortfolioPosition } from '@ghostfolio/common/interfaces';
import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface'; import { UserSettings } from '@ghostfolio/api/models/interfaces/user-settings.interface';
import { EvaluationResult } from './evaluation-result.interface'; import { EvaluationResult } from './evaluation-result.interface';
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
export interface RuleInterface<T extends RuleSettings> { export interface RuleInterface<T extends RuleSettings> {
evaluate( evaluate(aRuleSettings: T): EvaluationResult;
aPortfolioPositionMap: {
[symbol: string]: PortfolioPosition;
},
aFees: number,
aRuleSettings: T
): EvaluationResult;
getSettings(aUserSettings: UserSettings): T; getSettings(aUserSettings: UserSettings): T;
} }

@ -450,42 +450,51 @@ export class Portfolio implements PortfolioInterface {
return { return {
rules: { rules: {
accountClusterRisk: await this.rulesService.evaluate( accountClusterRisk: await this.rulesService.evaluate(
details,
fees,
[ [
new AccountClusterRiskInitialInvestment( new AccountClusterRiskInitialInvestment(
this.exchangeRateDataService this.exchangeRateDataService,
details
), ),
new AccountClusterRiskCurrentInvestment( new AccountClusterRiskCurrentInvestment(
this.exchangeRateDataService this.exchangeRateDataService,
details
), ),
new AccountClusterRiskSingleAccount(this.exchangeRateDataService) new AccountClusterRiskSingleAccount(
this.exchangeRateDataService,
details
)
], ],
{ baseCurrency: this.user.Settings.currency } { baseCurrency: this.user.Settings.currency }
), ),
currencyClusterRisk: await this.rulesService.evaluate( currencyClusterRisk: await this.rulesService.evaluate(
details,
fees,
[ [
new CurrencyClusterRiskBaseCurrencyInitialInvestment( new CurrencyClusterRiskBaseCurrencyInitialInvestment(
this.exchangeRateDataService this.exchangeRateDataService,
details
), ),
new CurrencyClusterRiskBaseCurrencyCurrentInvestment( new CurrencyClusterRiskBaseCurrencyCurrentInvestment(
this.exchangeRateDataService this.exchangeRateDataService,
details
), ),
new CurrencyClusterRiskInitialInvestment( new CurrencyClusterRiskInitialInvestment(
this.exchangeRateDataService this.exchangeRateDataService,
details
), ),
new CurrencyClusterRiskCurrentInvestment( new CurrencyClusterRiskCurrentInvestment(
this.exchangeRateDataService this.exchangeRateDataService,
details
) )
], ],
{ baseCurrency: this.user.Settings.currency } { baseCurrency: this.user.Settings.currency }
), ),
fees: await this.rulesService.evaluate( fees: await this.rulesService.evaluate(
details, [
fees, new FeeRatioInitialInvestment(
[new FeeRatioInitialInvestment(this.exchangeRateDataService)], this.exchangeRateDataService,
details,
fees
)
],
{ baseCurrency: this.user.Settings.currency } { baseCurrency: this.user.Settings.currency }
) )
} }

@ -12,7 +12,7 @@ export abstract class Rule<T extends RuleSettings> implements RuleInterface<T> {
private name: string; private name: string;
public constructor( public constructor(
public exchangeRateDataService: ExchangeRateDataService, protected exchangeRateDataService: ExchangeRateDataService,
{ {
name name
}: { }: {
@ -22,13 +22,7 @@ export abstract class Rule<T extends RuleSettings> implements RuleInterface<T> {
this.name = name; this.name = name;
} }
public abstract evaluate( public abstract evaluate(aRuleSettings: T): EvaluationResult;
aPortfolioPositionMap: {
[symbol: string]: PortfolioPosition;
},
aFees: number,
aRuleSettings: T
): EvaluationResult;
public abstract getSettings(aUserSettings: UserSettings): T; 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'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
export class AccountClusterRiskCurrentInvestment extends Rule<Settings> { export class AccountClusterRiskCurrentInvestment extends Rule<Settings> {
public constructor(public exchangeRateDataService: ExchangeRateDataService) { public constructor(
protected exchangeRateDataService: ExchangeRateDataService,
private positions: { [symbol: string]: PortfolioPosition }
) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Current Investment' name: 'Current Investment'
}); });
} }
public evaluate( public evaluate(ruleSettings: Settings) {
aPositions: { [symbol: string]: PortfolioPosition },
aFees: number,
ruleSettings?: Settings
) {
const accounts: { const accounts: {
[symbol: string]: Pick<PortfolioPosition, 'name'> & { [symbol: string]: Pick<PortfolioPosition, 'name'> & {
investment: number; investment: number;
}; };
} = {}; } = {};
Object.values(aPositions).forEach((position) => { Object.values(this.positions).forEach((position) => {
for (const [account, { current }] of Object.entries(position.accounts)) { for (const [account, { current }] of Object.entries(position.accounts)) {
if (accounts[account]?.investment) { if (accounts[account]?.investment) {
accounts[account].investment += current; 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'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
export class AccountClusterRiskInitialInvestment extends Rule<Settings> { export class AccountClusterRiskInitialInvestment extends Rule<Settings> {
public constructor(public exchangeRateDataService: ExchangeRateDataService) { public constructor(
protected exchangeRateDataService: ExchangeRateDataService,
private positions: { [symbol: string]: PortfolioPosition }
) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Initial Investment' name: 'Initial Investment'
}); });
} }
public evaluate( public evaluate(ruleSettings?: Settings) {
aPositions: { [symbol: string]: PortfolioPosition },
aFees: number,
ruleSettings?: Settings
) {
const platforms: { const platforms: {
[symbol: string]: Pick<PortfolioPosition, 'name'> & { [symbol: string]: Pick<PortfolioPosition, 'name'> & {
investment: number; investment: number;
}; };
} = {}; } = {};
Object.values(aPositions).forEach((position) => { Object.values(this.positions).forEach((position) => {
for (const [account, { original }] of Object.entries(position.accounts)) { for (const [account, { original }] of Object.entries(position.accounts)) {
if (platforms[account]?.investment) { if (platforms[account]?.investment) {
platforms[account].investment += original; 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'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
export class AccountClusterRiskSingleAccount extends Rule<RuleSettings> { export class AccountClusterRiskSingleAccount extends Rule<RuleSettings> {
public constructor(public exchangeRateDataService: ExchangeRateDataService) { public constructor(
protected exchangeRateDataService: ExchangeRateDataService,
private positions: { [symbol: string]: PortfolioPosition }
) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Single Account' name: 'Single Account'
}); });
} }
public evaluate(positions: { [symbol: string]: PortfolioPosition }) { public evaluate() {
const accounts: string[] = []; const accounts: string[] = [];
Object.values(positions).forEach((position) => { Object.values(this.positions).forEach((position) => {
for (const [account] of Object.entries(position.accounts)) { for (const [account] of Object.entries(position.accounts)) {
if (!accounts.includes(account)) { if (!accounts.includes(account)) {
accounts.push(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'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule<Settings> { export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule<Settings> {
public constructor(public exchangeRateDataService: ExchangeRateDataService) { public constructor(
protected exchangeRateDataService: ExchangeRateDataService,
private positions: { [symbol: string]: PortfolioPosition }
) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Current Investment: Base Currency' name: 'Current Investment: Base Currency'
}); });
} }
public evaluate( public evaluate(ruleSettings: Settings) {
aPositions: { [symbol: string]: PortfolioPosition },
aFees: number,
ruleSettings: Settings
) {
const positionsGroupedByCurrency = this.groupPositionsByAttribute( const positionsGroupedByCurrency = this.groupPositionsByAttribute(
aPositions, this.positions,
'currency', 'currency',
ruleSettings.baseCurrency 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'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
export class CurrencyClusterRiskBaseCurrencyInitialInvestment extends Rule<Settings> { export class CurrencyClusterRiskBaseCurrencyInitialInvestment extends Rule<Settings> {
public constructor(public exchangeRateDataService: ExchangeRateDataService) { public constructor(
protected exchangeRateDataService: ExchangeRateDataService,
private positions: { [symbol: string]: PortfolioPosition }
) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Initial Investment: Base Currency' name: 'Initial Investment: Base Currency'
}); });
} }
public evaluate( public evaluate(ruleSettings: Settings) {
aPositions: { [symbol: string]: PortfolioPosition },
aFees: number,
ruleSettings: Settings
) {
const positionsGroupedByCurrency = this.groupPositionsByAttribute( const positionsGroupedByCurrency = this.groupPositionsByAttribute(
aPositions, this.positions,
'currency', 'currency',
ruleSettings.baseCurrency ruleSettings.baseCurrency
); );

@ -7,19 +7,18 @@ import { Currency } from '@prisma/client';
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
export class CurrencyClusterRiskCurrentInvestment extends Rule<Settings> { export class CurrencyClusterRiskCurrentInvestment extends Rule<Settings> {
public constructor(public exchangeRateDataService: ExchangeRateDataService) { public constructor(
public exchangeRateDataService: ExchangeRateDataService,
private positions: { [symbol: string]: PortfolioPosition }
) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Current Investment' name: 'Current Investment'
}); });
} }
public evaluate( public evaluate(ruleSettings: Settings) {
aPositions: { [symbol: string]: PortfolioPosition },
aFees: number,
ruleSettings: Settings
) {
const positionsGroupedByCurrency = this.groupPositionsByAttribute( const positionsGroupedByCurrency = this.groupPositionsByAttribute(
aPositions, this.positions,
'currency', 'currency',
ruleSettings.baseCurrency 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'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
export class CurrencyClusterRiskInitialInvestment extends Rule<Settings> { export class CurrencyClusterRiskInitialInvestment extends Rule<Settings> {
public constructor(public exchangeRateDataService: ExchangeRateDataService) { public constructor(
protected exchangeRateDataService: ExchangeRateDataService,
private positions: { [symbol: string]: PortfolioPosition }
) {
super(exchangeRateDataService, { super(exchangeRateDataService, {
name: 'Initial Investment' name: 'Initial Investment'
}); });
} }
public evaluate( public evaluate(ruleSettings: Settings) {
aPositions: { [symbol: string]: PortfolioPosition },
aFees: number,
ruleSettings: Settings
) {
const positionsGroupedByCurrency = this.groupPositionsByAttribute( const positionsGroupedByCurrency = this.groupPositionsByAttribute(
aPositions, this.positions,
'currency', 'currency',
ruleSettings.baseCurrency 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'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
export class FeeRatioInitialInvestment extends Rule<Settings> { 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, { super(exchangeRateDataService, {
name: 'Initial Investment' name: 'Initial Investment'
}); });
} }
public evaluate( public evaluate(ruleSettings: Settings) {
aPositions: { [symbol: string]: PortfolioPosition },
aFees: number,
ruleSettings: Settings
) {
const positionsGroupedByCurrency = this.groupPositionsByAttribute( const positionsGroupedByCurrency = this.groupPositionsByAttribute(
aPositions, this.positions,
'currency', 'currency',
ruleSettings.baseCurrency ruleSettings.baseCurrency
); );
@ -31,7 +31,7 @@ export class FeeRatioInitialInvestment extends Rule<Settings> {
totalInvestment += groupItem.investment; totalInvestment += groupItem.investment;
}); });
const feeRatio = aFees / totalInvestment; const feeRatio = this.fees / totalInvestment;
if (feeRatio > ruleSettings.threshold) { if (feeRatio > ruleSettings.threshold) {
return { return {

@ -1,6 +1,5 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { Rule } from '../models/rule'; import { Rule } from '../models/rule';
import { PortfolioPosition } from '@ghostfolio/common/interfaces';
import { Currency } from '@prisma/client'; import { Currency } from '@prisma/client';
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface'; import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
@ -9,8 +8,6 @@ export class RulesService {
public constructor() {} public constructor() {}
public async evaluate<T extends RuleSettings>( public async evaluate<T extends RuleSettings>(
details: { [p: string]: PortfolioPosition },
fees: number,
aRules: Rule<T>[], aRules: Rule<T>[],
aUserSettings: { baseCurrency: Currency } aUserSettings: { baseCurrency: Currency }
) { ) {
@ -19,11 +16,7 @@ export class RulesService {
return rule.getSettings(aUserSettings)?.isActive; return rule.getSettings(aUserSettings)?.isActive;
}) })
.map((rule) => { .map((rule) => {
const evaluationResult = rule.evaluate( const evaluationResult = rule.evaluate(rule.getSettings(aUserSettings));
details,
fees,
rule.getSettings(aUserSettings)
);
return { ...evaluationResult, name: rule.getName() }; return { ...evaluationResult, name: rule.getName() };
}); });
} }

Loading…
Cancel
Save