Browse Source

Clean up initial (original) values from X-Ray

pull/1914/head
Thomas 2 years ago
parent
commit
f21f98e509
  1. 3
      apps/api/src/app/portfolio/portfolio.controller.ts
  2. 37
      apps/api/src/app/portfolio/portfolio.service.ts
  3. 2
      apps/api/src/models/rules/account-cluster-risk/current-investment.ts
  4. 88
      apps/api/src/models/rules/account-cluster-risk/initial-investment.ts
  5. 2
      apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts
  6. 71
      apps/api/src/models/rules/currency-cluster-risk/base-currency-initial-investment.ts
  7. 2
      apps/api/src/models/rules/currency-cluster-risk/current-investment.ts
  8. 72
      apps/api/src/models/rules/currency-cluster-risk/initial-investment.ts
  9. 2
      apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts
  10. 1
      libs/common/src/lib/interfaces/portfolio-details.interface.ts

3
apps/api/src/app/portfolio/portfolio.controller.ts

@ -136,9 +136,8 @@ export class PortfolioController {
portfolioPosition.value / totalValue;
}
for (const [name, { current, original }] of Object.entries(accounts)) {
for (const [name, { current }] of Object.entries(accounts)) {
accounts[name].current = current / totalValue;
accounts[name].original = original / totalInvestment;
}
}

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

@ -7,12 +7,9 @@ import { PortfolioOrder } from '@ghostfolio/api/app/portfolio/interfaces/portfol
import { TransactionPoint } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point.interface';
import { UserService } from '@ghostfolio/api/app/user/user.service';
import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment';
import { AccountClusterRiskInitialInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/initial-investment';
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 { CurrencyClusterRiskBaseCurrencyInitialInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/base-currency-initial-investment';
import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/current-investment';
import { CurrencyClusterRiskInitialInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/initial-investment';
import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service';
@ -619,8 +616,7 @@ export class PortfolioService {
balance: 0,
currency: userCurrency,
current: emergencyFundInCash,
name: UNKNOWN_KEY,
original: emergencyFundInCash
name: UNKNOWN_KEY
};
holdings[userCurrency] = {
@ -1185,10 +1181,6 @@ export class PortfolioService {
rules: {
accountClusterRisk: await this.rulesService.evaluate(
[
new AccountClusterRiskInitialInvestment(
this.exchangeRateDataService,
accounts
),
new AccountClusterRiskCurrentInvestment(
this.exchangeRateDataService,
accounts
@ -1202,18 +1194,10 @@ export class PortfolioService {
),
currencyClusterRisk: await this.rulesService.evaluate(
[
new CurrencyClusterRiskBaseCurrencyInitialInvestment(
this.exchangeRateDataService,
positions
),
new CurrencyClusterRiskBaseCurrencyCurrentInvestment(
this.exchangeRateDataService,
positions
),
new CurrencyClusterRiskInitialInvestment(
this.exchangeRateDataService,
positions
),
new CurrencyClusterRiskCurrentInvestment(
this.exchangeRateDataService,
positions
@ -1779,12 +1763,7 @@ export class PortfolioService {
account.currency,
userCurrency
),
name: account.name,
original: this.exchangeRateDataService.toCurrency(
account.balance,
account.currency,
userCurrency
)
name: account.name
};
for (const order of ordersByAccount) {
@ -1793,30 +1772,20 @@ export class PortfolioService {
(portfolioItemsNow[order.SymbolProfile.symbol]?.marketPrice ??
order.unitPrice ??
0);
let originalValueOfSymbolInBaseCurrency =
this.exchangeRateDataService.toCurrency(
order.quantity * order.unitPrice,
order.SymbolProfile.currency,
userCurrency
);
if (order.type === 'SELL') {
currentValueOfSymbolInBaseCurrency *= -1;
originalValueOfSymbolInBaseCurrency *= -1;
}
if (accounts[order.Account?.id || UNKNOWN_KEY]?.current) {
accounts[order.Account?.id || UNKNOWN_KEY].current +=
currentValueOfSymbolInBaseCurrency;
accounts[order.Account?.id || UNKNOWN_KEY].original +=
originalValueOfSymbolInBaseCurrency;
} else {
accounts[order.Account?.id || UNKNOWN_KEY] = {
balance: 0,
currency: order.Account?.currency,
current: currentValueOfSymbolInBaseCurrency,
name: account.name,
original: originalValueOfSymbolInBaseCurrency
name: account.name
};
}
}

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

@ -14,7 +14,7 @@ export class AccountClusterRiskCurrentInvestment extends Rule<Settings> {
private accounts: PortfolioDetails['accounts']
) {
super(exchangeRateDataService, {
name: 'Current Investment'
name: 'Investment'
});
}

88
apps/api/src/models/rules/account-cluster-risk/initial-investment.ts

@ -1,88 +0,0 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import {
PortfolioDetails,
PortfolioPosition,
UserSettings
} from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule';
export class AccountClusterRiskInitialInvestment extends Rule<Settings> {
public constructor(
protected exchangeRateDataService: ExchangeRateDataService,
private accounts: PortfolioDetails['accounts']
) {
super(exchangeRateDataService, {
name: 'Initial Investment'
});
}
public evaluate(ruleSettings?: Settings) {
const accounts: {
[symbol: string]: Pick<PortfolioPosition, 'name'> & {
investment: number;
};
} = {};
for (const [accountId, account] of Object.entries(this.accounts)) {
accounts[accountId] = {
name: account.name,
investment: account.original
};
}
let maxItem;
let totalInvestment = 0;
for (const account of Object.values(accounts)) {
if (!maxItem) {
maxItem = account;
}
// Calculate total investment
totalInvestment += account.investment;
// Find maximum
if (account.investment > maxItem?.investment) {
maxItem = account;
}
}
const maxInvestmentRatio = maxItem.investment / totalInvestment;
if (maxInvestmentRatio > ruleSettings.threshold) {
return {
evaluation: `Over ${
ruleSettings.threshold * 100
}% of your initial investment is at ${maxItem.name} (${(
maxInvestmentRatio * 100
).toPrecision(3)}%)`,
value: false
};
}
return {
evaluation: `The major part of your initial investment is at ${
maxItem.name
} (${(maxInvestmentRatio * 100).toPrecision(3)}%) and does not exceed ${
ruleSettings.threshold * 100
}%`,
value: true
};
}
public getSettings(aUserSettings: UserSettings): Settings {
return {
baseCurrency: aUserSettings.baseCurrency,
isActive: true,
threshold: 0.5
};
}
}
interface Settings extends RuleSettings {
baseCurrency: string;
isActive: boolean;
threshold: number;
}

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

@ -10,7 +10,7 @@ export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule<Setti
private positions: TimelinePosition[]
) {
super(exchangeRateDataService, {
name: 'Current Investment: Base Currency'
name: 'Investment: Base Currency'
});
}

71
apps/api/src/models/rules/currency-cluster-risk/base-currency-initial-investment.ts

@ -1,71 +0,0 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { TimelinePosition, UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule';
export class CurrencyClusterRiskBaseCurrencyInitialInvestment extends Rule<Settings> {
public constructor(
protected exchangeRateDataService: ExchangeRateDataService,
private positions: TimelinePosition[]
) {
super(exchangeRateDataService, {
name: 'Initial Investment: Base Currency'
});
}
public evaluate(ruleSettings: Settings) {
const positionsGroupedByCurrency = this.groupCurrentPositionsByAttribute(
this.positions,
'currency',
ruleSettings.baseCurrency
);
let maxItem = positionsGroupedByCurrency[0];
let totalInvestment = 0;
positionsGroupedByCurrency.forEach((groupItem) => {
// Calculate total investment
totalInvestment += groupItem.investment;
// Find maximum
if (groupItem.investment > maxItem.investment) {
maxItem = groupItem;
}
});
const baseCurrencyItem = positionsGroupedByCurrency.find((item) => {
return item.groupKey === ruleSettings.baseCurrency;
});
const baseCurrencyInvestmentRatio =
baseCurrencyItem?.investment / totalInvestment || 0;
if (maxItem.groupKey !== ruleSettings.baseCurrency) {
return {
evaluation: `The major part of your initial investment is not in your base currency (${(
baseCurrencyInvestmentRatio * 100
).toPrecision(3)}% in ${ruleSettings.baseCurrency})`,
value: false
};
}
return {
evaluation: `The major part of your initial investment is in your base currency (${(
baseCurrencyInvestmentRatio * 100
).toPrecision(3)}% in ${ruleSettings.baseCurrency})`,
value: true
};
}
public getSettings(aUserSettings: UserSettings): Settings {
return {
baseCurrency: aUserSettings.baseCurrency,
isActive: true
};
}
}
interface Settings extends RuleSettings {
baseCurrency: string;
}

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

@ -10,7 +10,7 @@ export class CurrencyClusterRiskCurrentInvestment extends Rule<Settings> {
private positions: TimelinePosition[]
) {
super(exchangeRateDataService, {
name: 'Current Investment'
name: 'Investment'
});
}

72
apps/api/src/models/rules/currency-cluster-risk/initial-investment.ts

@ -1,72 +0,0 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { TimelinePosition, UserSettings } from '@ghostfolio/common/interfaces';
import { Rule } from '../../rule';
export class CurrencyClusterRiskInitialInvestment extends Rule<Settings> {
public constructor(
protected exchangeRateDataService: ExchangeRateDataService,
private positions: TimelinePosition[]
) {
super(exchangeRateDataService, {
name: 'Initial Investment'
});
}
public evaluate(ruleSettings: Settings) {
const positionsGroupedByCurrency = this.groupCurrentPositionsByAttribute(
this.positions,
'currency',
ruleSettings.baseCurrency
);
let maxItem = positionsGroupedByCurrency[0];
let totalInvestment = 0;
positionsGroupedByCurrency.forEach((groupItem) => {
// Calculate total investment
totalInvestment += groupItem.investment;
// Find maximum
if (groupItem.investment > maxItem.investment) {
maxItem = groupItem;
}
});
const maxInvestmentRatio = maxItem.investment / totalInvestment;
if (maxInvestmentRatio > ruleSettings.threshold) {
return {
evaluation: `Over ${
ruleSettings.threshold * 100
}% of your initial investment is in ${maxItem.groupKey} (${(
maxInvestmentRatio * 100
).toPrecision(3)}%)`,
value: false
};
}
return {
evaluation: `The major part of your initial investment is in ${
maxItem.groupKey
} (${(maxInvestmentRatio * 100).toPrecision(3)}%) and does not exceed ${
ruleSettings.threshold * 100
}%`,
value: true
};
}
public getSettings(aUserSettings: UserSettings): Settings {
return {
baseCurrency: aUserSettings.baseCurrency,
isActive: true,
threshold: 0.5
};
}
}
interface Settings extends RuleSettings {
baseCurrency: string;
threshold: number;
}

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

@ -11,7 +11,7 @@ export class FeeRatioInitialInvestment extends Rule<Settings> {
private fees: number
) {
super(exchangeRateDataService, {
name: 'Initial Investment'
name: 'Investment'
});
}

1
libs/common/src/lib/interfaces/portfolio-details.interface.ts

@ -10,7 +10,6 @@ export interface PortfolioDetails {
currency: string;
current: number;
name: string;
original: number;
};
};
filteredValueInBaseCurrency?: number;

Loading…
Cancel
Save