Feature/improve chart in account detail dialog (#3314)

* Improve net worth calculation in portfolio performance chart

* Improve account balance management

* Update changelog
pull/3317/head
Thomas Kaul 2 months ago committed by GitHub
parent ab59eb5c92
commit 39bd4a349b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
### Changed
- Improved the chart in the account detail dialog
- Improved the account balance management
## 2.75.0 - 2024-04-21 ## 2.75.0 - 2024-04-21
### Added ### Added

@ -1,12 +1,13 @@
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.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';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { DATE_FORMAT } from '@ghostfolio/common/helper';
import { Filter } from '@ghostfolio/common/interfaces'; import { Filter } from '@ghostfolio/common/interfaces';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { Account, Order, Platform, Prisma } from '@prisma/client'; import { Account, Order, Platform, Prisma } from '@prisma/client';
import { Big } from 'big.js'; import { Big } from 'big.js';
import { parseISO } from 'date-fns'; import { format } from 'date-fns';
import { groupBy } from 'lodash'; import { groupBy } from 'lodash';
import { CashDetails } from './interfaces/cash-details.interface'; import { CashDetails } from './interfaces/cash-details.interface';
@ -86,15 +87,11 @@ export class AccountService {
data data
}); });
await this.prismaService.accountBalance.create({ await this.accountBalanceService.createOrUpdateAccountBalance({
data: { accountId: account.id,
Account: { balance: data.balance,
connect: { date: format(new Date(), DATE_FORMAT),
id_userId: { id: account.id, userId: aUserId } userId: aUserId
}
},
value: data.balance
}
}); });
return account; return account;
@ -197,15 +194,11 @@ export class AccountService {
): Promise<Account> { ): Promise<Account> {
const { data, where } = params; const { data, where } = params;
await this.prismaService.accountBalance.create({ await this.accountBalanceService.createOrUpdateAccountBalance({
data: { accountId: <string>data.id,
Account: { balance: <number>data.balance,
connect: { date: format(new Date(), DATE_FORMAT),
id_userId: where.id_userId userId: aUserId
}
},
value: <number>data.balance
}
}); });
return this.prismaService.account.update({ return this.prismaService.account.update({

@ -1,6 +1,7 @@
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface'; import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.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';
import { HistoricalDataItem } from '@ghostfolio/common/interfaces';
import { DateRange } from '@ghostfolio/common/types'; import { DateRange } from '@ghostfolio/common/types';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
@ -22,11 +23,13 @@ export class PortfolioCalculatorFactory {
) {} ) {}
public createCalculator({ public createCalculator({
accountBalanceItems = [],
activities, activities,
calculationType, calculationType,
currency, currency,
dateRange = 'max' dateRange = 'max'
}: { }: {
accountBalanceItems?: HistoricalDataItem[];
activities: Activity[]; activities: Activity[];
calculationType: PerformanceCalculationType; calculationType: PerformanceCalculationType;
currency: string; currency: string;
@ -35,6 +38,7 @@ export class PortfolioCalculatorFactory {
switch (calculationType) { switch (calculationType) {
case PerformanceCalculationType.MWR: case PerformanceCalculationType.MWR:
return new MWRPortfolioCalculator({ return new MWRPortfolioCalculator({
accountBalanceItems,
activities, activities,
currency, currency,
dateRange, dateRange,
@ -43,6 +47,7 @@ export class PortfolioCalculatorFactory {
}); });
case PerformanceCalculationType.TWR: case PerformanceCalculationType.TWR:
return new TWRPortfolioCalculator({ return new TWRPortfolioCalculator({
accountBalanceItems,
activities, activities,
currency, currency,
currentRateService: this.currentRateService, currentRateService: this.currentRateService,

@ -37,13 +37,15 @@ import {
isBefore, isBefore,
isSameDay, isSameDay,
max, max,
min,
subDays subDays
} from 'date-fns'; } from 'date-fns';
import { last, uniq, uniqBy } from 'lodash'; import { first, last, uniq, uniqBy } from 'lodash';
export abstract class PortfolioCalculator { export abstract class PortfolioCalculator {
protected static readonly ENABLE_LOGGING = false; protected static readonly ENABLE_LOGGING = false;
protected accountBalanceItems: HistoricalDataItem[];
protected orders: PortfolioOrder[]; protected orders: PortfolioOrder[];
private currency: string; private currency: string;
@ -57,18 +59,21 @@ export abstract class PortfolioCalculator {
private transactionPoints: TransactionPoint[]; private transactionPoints: TransactionPoint[];
public constructor({ public constructor({
accountBalanceItems,
activities, activities,
currency, currency,
currentRateService, currentRateService,
dateRange, dateRange,
exchangeRateDataService exchangeRateDataService
}: { }: {
accountBalanceItems: HistoricalDataItem[];
activities: Activity[]; activities: Activity[];
currency: string; currency: string;
currentRateService: CurrentRateService; currentRateService: CurrentRateService;
dateRange: DateRange; dateRange: DateRange;
exchangeRateDataService: ExchangeRateDataService; exchangeRateDataService: ExchangeRateDataService;
}) { }) {
this.accountBalanceItems = accountBalanceItems;
this.currency = currency; this.currency = currency;
this.currentRateService = currentRateService; this.currentRateService = currentRateService;
this.exchangeRateDataService = exchangeRateDataService; this.exchangeRateDataService = exchangeRateDataService;
@ -383,10 +388,6 @@ export abstract class PortfolioCalculator {
dateRange?: DateRange; dateRange?: DateRange;
withDataDecimation?: boolean; withDataDecimation?: boolean;
}): Promise<HistoricalDataItem[]> { }): Promise<HistoricalDataItem[]> {
if (this.getTransactionPoints().length === 0) {
return [];
}
const { endDate, startDate } = getInterval(dateRange, this.getStartDate()); const { endDate, startDate } = getInterval(dateRange, this.getStartDate());
const daysInMarket = differenceInDays(endDate, startDate) + 1; const daysInMarket = differenceInDays(endDate, startDate) + 1;
@ -485,6 +486,7 @@ export abstract class PortfolioCalculator {
investmentValueWithCurrencyEffect: Big; investmentValueWithCurrencyEffect: Big;
totalCurrentValue: Big; totalCurrentValue: Big;
totalCurrentValueWithCurrencyEffect: Big; totalCurrentValueWithCurrencyEffect: Big;
totalAccountBalanceWithCurrencyEffect: Big;
totalInvestmentValue: Big; totalInvestmentValue: Big;
totalInvestmentValueWithCurrencyEffect: Big; totalInvestmentValueWithCurrencyEffect: Big;
totalNetPerformanceValue: Big; totalNetPerformanceValue: Big;
@ -544,9 +546,24 @@ export abstract class PortfolioCalculator {
}; };
} }
let lastDate = format(this.startDate, DATE_FORMAT);
for (const currentDate of dates) { for (const currentDate of dates) {
const dateString = format(currentDate, DATE_FORMAT); const dateString = format(currentDate, DATE_FORMAT);
accumulatedValuesByDate[dateString] = {
investmentValueWithCurrencyEffect: new Big(0),
totalAccountBalanceWithCurrencyEffect: new Big(0),
totalCurrentValue: new Big(0),
totalCurrentValueWithCurrencyEffect: new Big(0),
totalInvestmentValue: new Big(0),
totalInvestmentValueWithCurrencyEffect: new Big(0),
totalNetPerformanceValue: new Big(0),
totalNetPerformanceValueWithCurrencyEffect: new Big(0),
totalTimeWeightedInvestmentValue: new Big(0),
totalTimeWeightedInvestmentValueWithCurrencyEffect: new Big(0)
};
for (const symbol of Object.keys(valuesBySymbol)) { for (const symbol of Object.keys(valuesBySymbol)) {
const symbolValues = valuesBySymbol[symbol]; const symbolValues = valuesBySymbol[symbol];
@ -584,49 +601,94 @@ export abstract class PortfolioCalculator {
dateString dateString
] ?? new Big(0); ] ?? new Big(0);
accumulatedValuesByDate[dateString] = { accumulatedValuesByDate[dateString].investmentValueWithCurrencyEffect =
investmentValueWithCurrencyEffect: ( accumulatedValuesByDate[
accumulatedValuesByDate[dateString] dateString
?.investmentValueWithCurrencyEffect ?? new Big(0) ].investmentValueWithCurrencyEffect.add(
).add(investmentValueWithCurrencyEffect), investmentValueWithCurrencyEffect
totalCurrentValue: ( );
accumulatedValuesByDate[dateString]?.totalCurrentValue ?? new Big(0)
).add(currentValue), accumulatedValuesByDate[dateString].totalCurrentValue =
totalCurrentValueWithCurrencyEffect: ( accumulatedValuesByDate[dateString].totalCurrentValue.add(
accumulatedValuesByDate[dateString] currentValue
?.totalCurrentValueWithCurrencyEffect ?? new Big(0) );
).add(currentValueWithCurrencyEffect),
totalInvestmentValue: ( accumulatedValuesByDate[
accumulatedValuesByDate[dateString]?.totalInvestmentValue ?? dateString
new Big(0) ].totalCurrentValueWithCurrencyEffect = accumulatedValuesByDate[
).add(investmentValueAccumulated), dateString
totalInvestmentValueWithCurrencyEffect: ( ].totalCurrentValueWithCurrencyEffect.add(
accumulatedValuesByDate[dateString] currentValueWithCurrencyEffect
?.totalInvestmentValueWithCurrencyEffect ?? new Big(0) );
).add(investmentValueAccumulatedWithCurrencyEffect),
totalNetPerformanceValue: ( accumulatedValuesByDate[dateString].totalInvestmentValue =
accumulatedValuesByDate[dateString]?.totalNetPerformanceValue ?? accumulatedValuesByDate[dateString].totalInvestmentValue.add(
new Big(0) investmentValueAccumulated
).add(netPerformanceValue), );
totalNetPerformanceValueWithCurrencyEffect: (
accumulatedValuesByDate[dateString] accumulatedValuesByDate[
?.totalNetPerformanceValueWithCurrencyEffect ?? new Big(0) dateString
).add(netPerformanceValueWithCurrencyEffect), ].totalInvestmentValueWithCurrencyEffect = accumulatedValuesByDate[
totalTimeWeightedInvestmentValue: ( dateString
accumulatedValuesByDate[dateString] ].totalInvestmentValueWithCurrencyEffect.add(
?.totalTimeWeightedInvestmentValue ?? new Big(0) investmentValueAccumulatedWithCurrencyEffect
).add(timeWeightedInvestmentValue), );
totalTimeWeightedInvestmentValueWithCurrencyEffect: (
accumulatedValuesByDate[dateString] accumulatedValuesByDate[dateString].totalNetPerformanceValue =
?.totalTimeWeightedInvestmentValueWithCurrencyEffect ?? new Big(0) accumulatedValuesByDate[dateString].totalNetPerformanceValue.add(
).add(timeWeightedInvestmentValueWithCurrencyEffect) netPerformanceValue
}; );
accumulatedValuesByDate[
dateString
].totalNetPerformanceValueWithCurrencyEffect = accumulatedValuesByDate[
dateString
].totalNetPerformanceValueWithCurrencyEffect.add(
netPerformanceValueWithCurrencyEffect
);
accumulatedValuesByDate[dateString].totalTimeWeightedInvestmentValue =
accumulatedValuesByDate[
dateString
].totalTimeWeightedInvestmentValue.add(timeWeightedInvestmentValue);
accumulatedValuesByDate[
dateString
].totalTimeWeightedInvestmentValueWithCurrencyEffect =
accumulatedValuesByDate[
dateString
].totalTimeWeightedInvestmentValueWithCurrencyEffect.add(
timeWeightedInvestmentValueWithCurrencyEffect
);
}
if (
this.accountBalanceItems.some(({ date }) => {
return date === dateString;
})
) {
accumulatedValuesByDate[
dateString
].totalAccountBalanceWithCurrencyEffect = new Big(
this.accountBalanceItems.find(({ date }) => {
return date === dateString;
}).value
);
} else {
accumulatedValuesByDate[
dateString
].totalAccountBalanceWithCurrencyEffect =
accumulatedValuesByDate[lastDate]
?.totalAccountBalanceWithCurrencyEffect ?? new Big(0);
} }
lastDate = dateString;
} }
return Object.entries(accumulatedValuesByDate).map(([date, values]) => { return Object.entries(accumulatedValuesByDate).map(([date, values]) => {
const { const {
investmentValueWithCurrencyEffect, investmentValueWithCurrencyEffect,
totalAccountBalanceWithCurrencyEffect,
totalCurrentValue, totalCurrentValue,
totalCurrentValueWithCurrencyEffect, totalCurrentValueWithCurrencyEffect,
totalInvestmentValue, totalInvestmentValue,
@ -661,6 +723,11 @@ export abstract class PortfolioCalculator {
netPerformance: totalNetPerformanceValue.toNumber(), netPerformance: totalNetPerformanceValue.toNumber(),
netPerformanceWithCurrencyEffect: netPerformanceWithCurrencyEffect:
totalNetPerformanceValueWithCurrencyEffect.toNumber(), totalNetPerformanceValueWithCurrencyEffect.toNumber(),
// TODO: Add valuables
netWorth: totalCurrentValueWithCurrencyEffect
.plus(totalAccountBalanceWithCurrencyEffect)
.toNumber(),
totalAccountBalance: totalAccountBalanceWithCurrencyEffect.toNumber(),
totalInvestment: totalInvestmentValue.toNumber(), totalInvestment: totalInvestmentValue.toNumber(),
totalInvestmentValueWithCurrencyEffect: totalInvestmentValueWithCurrencyEffect:
totalInvestmentValueWithCurrencyEffect.toNumber(), totalInvestmentValueWithCurrencyEffect.toNumber(),
@ -749,9 +816,30 @@ export abstract class PortfolioCalculator {
} }
public getStartDate() { public getStartDate() {
return this.transactionPoints.length > 0 let firstAccountBalanceDate: Date;
? parseDate(this.transactionPoints[0].date) let firstActivityDate: Date;
: new Date();
try {
const firstAccountBalanceDateString = first(
this.accountBalanceItems
)?.date;
firstAccountBalanceDate = firstAccountBalanceDateString
? parseDate(firstAccountBalanceDateString)
: new Date();
} catch (error) {
firstAccountBalanceDate = new Date();
}
try {
const firstActivityDateString = this.transactionPoints[0].date;
firstActivityDate = firstActivityDateString
? parseDate(firstActivityDateString)
: new Date();
} catch (error) {
firstActivityDate = new Date();
}
return min([firstAccountBalanceDate, firstActivityDate]);
} }
protected abstract getSymbolMetrics({ protected abstract getSymbolMetrics({

@ -90,7 +90,12 @@ describe('PortfolioCalculator', () => {
expect(investments).toEqual([]); expect(investments).toEqual([]);
expect(investmentsByMonth).toEqual([]); expect(investmentsByMonth).toEqual([
{
date: '2021-12-01',
investment: 0
}
]);
}); });
}); });
}); });

@ -113,6 +113,8 @@ describe('PortfolioCalculator', () => {
netPerformanceInPercentage: 0, netPerformanceInPercentage: 0,
netPerformanceInPercentageWithCurrencyEffect: 0, netPerformanceInPercentageWithCurrencyEffect: 0,
netPerformanceWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0,
netWorth: 151.6,
totalAccountBalance: 0,
totalInvestment: 151.6, totalInvestment: 151.6,
totalInvestmentValueWithCurrencyEffect: 151.6, totalInvestmentValueWithCurrencyEffect: 151.6,
value: 151.6, value: 151.6,
@ -126,6 +128,8 @@ describe('PortfolioCalculator', () => {
netPerformanceInPercentage: 13.100263852242744, netPerformanceInPercentage: 13.100263852242744,
netPerformanceInPercentageWithCurrencyEffect: 13.100263852242744, netPerformanceInPercentageWithCurrencyEffect: 13.100263852242744,
netPerformanceWithCurrencyEffect: 19.86, netPerformanceWithCurrencyEffect: 19.86,
netWorth: 0,
totalAccountBalance: 0,
totalInvestment: 0, totalInvestment: 0,
totalInvestmentValueWithCurrencyEffect: 0, totalInvestmentValueWithCurrencyEffect: 0,
value: 0, value: 0,

@ -188,6 +188,7 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
[date: string]: Big; [date: string]: Big;
} = {}; } = {};
let totalAccountBalanceInBaseCurrency = new Big(0);
let totalDividend = new Big(0); let totalDividend = new Big(0);
let totalDividendInBaseCurrency = new Big(0); let totalDividendInBaseCurrency = new Big(0);
let totalInterest = new Big(0); let totalInterest = new Big(0);
@ -237,6 +238,7 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
timeWeightedInvestmentValues: {}, timeWeightedInvestmentValues: {},
timeWeightedInvestmentValuesWithCurrencyEffect: {}, timeWeightedInvestmentValuesWithCurrencyEffect: {},
timeWeightedInvestmentWithCurrencyEffect: new Big(0), timeWeightedInvestmentWithCurrencyEffect: new Big(0),
totalAccountBalanceInBaseCurrency: new Big(0),
totalDividend: new Big(0), totalDividend: new Big(0),
totalDividendInBaseCurrency: new Big(0), totalDividendInBaseCurrency: new Big(0),
totalInterest: new Big(0), totalInterest: new Big(0),
@ -286,6 +288,7 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
timeWeightedInvestmentValues: {}, timeWeightedInvestmentValues: {},
timeWeightedInvestmentValuesWithCurrencyEffect: {}, timeWeightedInvestmentValuesWithCurrencyEffect: {},
timeWeightedInvestmentWithCurrencyEffect: new Big(0), timeWeightedInvestmentWithCurrencyEffect: new Big(0),
totalAccountBalanceInBaseCurrency: new Big(0),
totalDividend: new Big(0), totalDividend: new Big(0),
totalDividendInBaseCurrency: new Big(0), totalDividendInBaseCurrency: new Big(0),
totalInterest: new Big(0), totalInterest: new Big(0),
@ -875,6 +878,7 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
netPerformanceValuesWithCurrencyEffect, netPerformanceValuesWithCurrencyEffect,
timeWeightedInvestmentValues, timeWeightedInvestmentValues,
timeWeightedInvestmentValuesWithCurrencyEffect, timeWeightedInvestmentValuesWithCurrencyEffect,
totalAccountBalanceInBaseCurrency,
totalDividend, totalDividend,
totalDividendInBaseCurrency, totalDividendInBaseCurrency,
totalInterest, totalInterest,

@ -64,7 +64,6 @@ import {
differenceInDays, differenceInDays,
format, format,
isAfter, isAfter,
isBefore,
isSameMonth, isSameMonth,
isSameYear, isSameYear,
parseISO, parseISO,
@ -1056,11 +1055,16 @@ export class PortfolioService {
) => { ) => {
const formattedDate = format(date, DATE_FORMAT); const formattedDate = format(date, DATE_FORMAT);
// Store the item in the map, overwriting if the date already exists if (map[formattedDate]) {
map[formattedDate] = { // If the value exists, add the current value to the existing one
date: formattedDate, map[formattedDate].value += valueInBaseCurrency;
value: valueInBaseCurrency } else {
}; // Otherwise, initialize the value for that date
map[formattedDate] = {
date: formattedDate,
value: valueInBaseCurrency
};
}
return map; return map;
}, },
@ -1100,6 +1104,7 @@ export class PortfolioService {
} }
const portfolioCalculator = this.calculatorFactory.createCalculator({ const portfolioCalculator = this.calculatorFactory.createCalculator({
accountBalanceItems,
activities, activities,
dateRange, dateRange,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
@ -1131,6 +1136,8 @@ export class PortfolioService {
let currentNetPerformanceWithCurrencyEffect = let currentNetPerformanceWithCurrencyEffect =
netPerformanceWithCurrencyEffect; netPerformanceWithCurrencyEffect;
let currentNetWorth = 0;
const items = await portfolioCalculator.getChart({ const items = await portfolioCalculator.getChart({
dateRange dateRange
}); });
@ -1153,35 +1160,14 @@ export class PortfolioService {
currentNetPerformanceWithCurrencyEffect = new Big( currentNetPerformanceWithCurrencyEffect = new Big(
itemOfToday.netPerformanceWithCurrencyEffect itemOfToday.netPerformanceWithCurrencyEffect
); );
}
accountBalanceItems = accountBalanceItems.filter(({ date }) => {
return !isBefore(parseDate(date), startDate);
});
const accountBalanceItemOfToday = accountBalanceItems.find(({ date }) => { currentNetWorth = itemOfToday.netWorth;
return date === format(new Date(), DATE_FORMAT);
});
if (!accountBalanceItemOfToday) {
accountBalanceItems.push({
date: format(new Date(), DATE_FORMAT),
value: last(accountBalanceItems)?.value ?? 0
});
} }
const mergedHistoricalDataItems = this.mergeHistoricalDataItems(
accountBalanceItems,
items
);
const currentHistoricalDataItem = last(mergedHistoricalDataItems);
const currentNetWorth = currentHistoricalDataItem?.netWorth ?? 0;
return { return {
errors, errors,
hasErrors, hasErrors,
chart: mergedHistoricalDataItems, chart: items,
firstOrderDate: parseDate(items[0]?.date), firstOrderDate: parseDate(items[0]?.date),
performance: { performance: {
currentNetWorth, currentNetWorth,
@ -1909,44 +1895,4 @@ export class PortfolioService {
return { accounts, platforms }; return { accounts, platforms };
} }
private mergeHistoricalDataItems(
accountBalanceItems: HistoricalDataItem[],
performanceChartItems: HistoricalDataItem[]
): HistoricalDataItem[] {
const historicalDataItemsMap: { [date: string]: HistoricalDataItem } = {};
let latestAccountBalance = 0;
for (const item of accountBalanceItems.concat(performanceChartItems)) {
const isAccountBalanceItem = accountBalanceItems.includes(item);
const totalAccountBalance = isAccountBalanceItem
? item.value
: latestAccountBalance;
if (isAccountBalanceItem && performanceChartItems.length > 0) {
latestAccountBalance = item.value;
} else {
historicalDataItemsMap[item.date] = {
...item,
totalAccountBalance,
netWorth:
(isAccountBalanceItem ? 0 : item.value) + totalAccountBalance
};
}
}
// Convert to an array and sort by date in ascending order
const historicalDataItems = Object.keys(historicalDataItemsMap).map(
(date) => {
return historicalDataItemsMap[date];
}
);
historicalDataItems.sort((a, b) => {
return new Date(a.date).getTime() - new Date(b.date).getTime();
});
return historicalDataItems;
}
} }

@ -84,55 +84,10 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
} }
public ngOnInit() { public ngOnInit() {
this.dataService this.fetchAccount();
.fetchAccount(this.data.accountId)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(
({
balance,
currency,
name,
Platform,
transactionCount,
value,
valueInBaseCurrency
}) => {
this.balance = balance;
this.currency = currency;
if (isNumber(balance) && isNumber(value)) {
this.equity = new Big(value).minus(balance).toNumber();
} else {
this.equity = null;
}
this.name = name;
this.platformName = Platform?.name ?? '-';
this.transactionCount = transactionCount;
this.valueInBaseCurrency = valueInBaseCurrency;
this.changeDetectorRef.markForCheck();
}
);
this.dataService
.fetchPortfolioHoldings({
filters: [
{
type: 'ACCOUNT',
id: this.data.accountId
}
]
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ holdings }) => {
this.holdings = holdings;
this.changeDetectorRef.markForCheck();
});
this.fetchAccountBalances(); this.fetchAccountBalances();
this.fetchActivities(); this.fetchActivities();
this.fetchPortfolioHoldings();
this.fetchPortfolioPerformance(); this.fetchPortfolioPerformance();
} }
@ -155,6 +110,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
}) })
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => { .subscribe(() => {
this.fetchAccount();
this.fetchAccountBalances(); this.fetchAccountBalances();
this.fetchPortfolioPerformance(); this.fetchPortfolioPerformance();
}); });
@ -165,6 +121,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
.deleteAccountBalance(aId) .deleteAccountBalance(aId)
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => { .subscribe(() => {
this.fetchAccount();
this.fetchAccountBalances(); this.fetchAccountBalances();
this.fetchPortfolioPerformance(); this.fetchPortfolioPerformance();
}); });
@ -199,6 +156,39 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
this.fetchActivities(); this.fetchActivities();
} }
private fetchAccount() {
this.dataService
.fetchAccount(this.data.accountId)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(
({
balance,
currency,
name,
Platform,
transactionCount,
value,
valueInBaseCurrency
}) => {
this.balance = balance;
this.currency = currency;
if (isNumber(balance) && isNumber(value)) {
this.equity = new Big(value).minus(balance).toNumber();
} else {
this.equity = null;
}
this.name = name;
this.platformName = Platform?.name ?? '-';
this.transactionCount = transactionCount;
this.valueInBaseCurrency = valueInBaseCurrency;
this.changeDetectorRef.markForCheck();
}
);
}
private fetchAccountBalances() { private fetchAccountBalances() {
this.dataService this.dataService
.fetchAccountBalances(this.data.accountId) .fetchAccountBalances(this.data.accountId)
@ -230,6 +220,24 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
}); });
} }
private fetchPortfolioHoldings() {
this.dataService
.fetchPortfolioHoldings({
filters: [
{
type: 'ACCOUNT',
id: this.data.accountId
}
]
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ holdings }) => {
this.holdings = holdings;
this.changeDetectorRef.markForCheck();
});
}
private fetchPortfolioPerformance() { private fetchPortfolioPerformance() {
this.isLoadingChart = true; this.isLoadingChart = true;
@ -251,11 +259,7 @@ export class AccountDetailDialog implements OnDestroy, OnInit {
({ date, netWorth, netWorthInPercentage }) => { ({ date, netWorth, netWorthInPercentage }) => {
return { return {
date, date,
value: value: isNumber(netWorth) ? netWorth : netWorthInPercentage
this.data.hasImpersonationId ||
this.user.settings.isRestrictedView
? netWorthInPercentage
: netWorth
}; };
} }
); );

@ -233,6 +233,8 @@ export class AccountsPageComponent implements OnDestroy, OnInit {
.afterClosed() .afterClosed()
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => { .subscribe(() => {
this.fetchAccounts();
this.router.navigate(['.'], { relativeTo: this.route }); this.router.navigate(['.'], { relativeTo: this.route });
}); });
} }

@ -40,6 +40,7 @@ export interface SymbolMetrics {
[date: string]: Big; [date: string]: Big;
}; };
timeWeightedInvestmentWithCurrencyEffect: Big; timeWeightedInvestmentWithCurrencyEffect: Big;
totalAccountBalanceInBaseCurrency: Big;
totalDividend: Big; totalDividend: Big;
totalDividendInBaseCurrency: Big; totalDividendInBaseCurrency: Big;
totalInterest: Big; totalInterest: Big;

Loading…
Cancel
Save