Browse Source

Added Performance Interceptor and removed Caculation from asset page

pull/5027/head
Dan 1 year ago
parent
commit
bffbc4c1c7
  1. 162
      apps/api/src/app/portfolio/portfolio-calculator.ts
  2. 8
      apps/api/src/app/portfolio/portfolio.controller.ts
  3. 71
      apps/api/src/app/portfolio/portfolio.service.ts
  4. 5
      apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts
  5. 16
      apps/client/src/app/services/data.service.ts

162
apps/api/src/app/portfolio/portfolio-calculator.ts

@ -1,3 +1,4 @@
import { LogPerformance } from '@ghostfolio/api/aop/logging.interceptor';
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 { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces';
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper'; import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
@ -80,6 +81,7 @@ export class PortfolioCalculator {
}); });
} }
@LogPerformance
public computeTransactionPoints() { public computeTransactionPoints() {
this.transactionPoints = []; this.transactionPoints = [];
const symbols: { [symbol: string]: TransactionPointSymbol } = {}; const symbols: { [symbol: string]: TransactionPointSymbol } = {};
@ -123,6 +125,7 @@ export class PortfolioCalculator {
} }
} }
@LogPerformance
private getCurrentTransactionPointItem( private getCurrentTransactionPointItem(
oldAccumulatedSymbol: TransactionPointSymbol, oldAccumulatedSymbol: TransactionPointSymbol,
order: PortfolioOrder, order: PortfolioOrder,
@ -154,6 +157,7 @@ export class PortfolioCalculator {
return currentTransactionPointItem; return currentTransactionPointItem;
} }
@LogPerformance
private handleSubsequentTransactions( private handleSubsequentTransactions(
order: PortfolioOrder, order: PortfolioOrder,
factor: number, factor: number,
@ -196,6 +200,7 @@ export class PortfolioCalculator {
return currentTransactionPointItem; return currentTransactionPointItem;
} }
@LogPerformance
public getAnnualizedPerformancePercent({ public getAnnualizedPerformancePercent({
daysInMarket, daysInMarket,
netPerformancePercent netPerformancePercent
@ -221,6 +226,7 @@ export class PortfolioCalculator {
this.transactionPoints = transactionPoints; this.transactionPoints = transactionPoints;
} }
@LogPerformance
public async getChartData({ public async getChartData({
start, start,
end = new Date(Date.now()), end = new Date(Date.now()),
@ -345,6 +351,7 @@ export class PortfolioCalculator {
}); });
} }
@LogPerformance
private calculatePerformance( private calculatePerformance(
date: Date, date: Date,
previousDate: Date, previousDate: Date,
@ -479,6 +486,7 @@ export class PortfolioCalculator {
}; };
} }
@LogPerformance
private accumulatedValuesByDate( private accumulatedValuesByDate(
valuesBySymbol: { valuesBySymbol: {
[symbol: string]: { [symbol: string]: {
@ -587,6 +595,7 @@ export class PortfolioCalculator {
return accumulatedValuesByDate; return accumulatedValuesByDate;
} }
@LogPerformance
private populateSymbolMetrics( private populateSymbolMetrics(
symbols: { [symbol: string]: boolean }, symbols: { [symbol: string]: boolean },
end: Date, end: Date,
@ -648,6 +657,7 @@ export class PortfolioCalculator {
} }
} }
@LogPerformance
private populateMarketSymbolMap( private populateMarketSymbolMap(
marketSymbols: GetValueObject[], marketSymbols: GetValueObject[],
marketSymbolMap: { [date: string]: { [symbol: string]: Big } } marketSymbolMap: { [date: string]: { [symbol: string]: Big } }
@ -665,6 +675,7 @@ export class PortfolioCalculator {
} }
} }
@LogPerformance
private async getInformationFromCurrentRateService( private async getInformationFromCurrentRateService(
currencies: { [symbol: string]: string }, currencies: { [symbol: string]: string },
dataGatheringItems: IDataGatheringItem[], dataGatheringItems: IDataGatheringItem[],
@ -681,6 +692,7 @@ export class PortfolioCalculator {
}); });
} }
@LogPerformance
private pushDataGatheringsSymbols( private pushDataGatheringsSymbols(
transactionPointsBeforeEndDate: TransactionPoint[], transactionPointsBeforeEndDate: TransactionPoint[],
firstIndex: number, firstIndex: number,
@ -700,6 +712,7 @@ export class PortfolioCalculator {
} }
} }
@LogPerformance
private getRelevantStartAndEndDates( private getRelevantStartAndEndDates(
start: Date, start: Date,
end: Date, end: Date,
@ -718,9 +731,11 @@ export class PortfolioCalculator {
} }
} }
@LogPerformance
public async getCurrentPositions( public async getCurrentPositions(
start: Date, start: Date,
end = new Date(Date.now()) end = new Date(Date.now()),
calculatePerformance = true
): Promise<CurrentPositions> { ): Promise<CurrentPositions> {
const transactionPointsBeforeEndDate = const transactionPointsBeforeEndDate =
this.transactionPoints?.filter((transactionPoint) => { this.transactionPoints?.filter((transactionPoint) => {
@ -883,7 +898,8 @@ export class PortfolioCalculator {
start, start,
exchangeRates: exchangeRates:
exchangeRatesByCurrency[`${item.currency}${this.currency}`], exchangeRatesByCurrency[`${item.currency}${this.currency}`],
symbol: item.symbol symbol: item.symbol,
calculatePerformance
}); });
hasAnySymbolMetricsErrors = hasAnySymbolMetricsErrors || hasErrors; hasAnySymbolMetricsErrors = hasAnySymbolMetricsErrors || hasErrors;
@ -956,6 +972,7 @@ export class PortfolioCalculator {
return this.dataProviderInfos; return this.dataProviderInfos;
} }
@LogPerformance
public getInvestments(): { date: string; investment: Big }[] { public getInvestments(): { date: string; investment: Big }[] {
if (this.transactionPoints.length === 0) { if (this.transactionPoints.length === 0) {
return []; return [];
@ -973,6 +990,7 @@ export class PortfolioCalculator {
}); });
} }
@LogPerformance
public getInvestmentsByGroup({ public getInvestmentsByGroup({
data, data,
groupBy groupBy
@ -996,6 +1014,7 @@ export class PortfolioCalculator {
})); }));
} }
@LogPerformance
private calculateOverallPerformance(positions: TimelinePosition[]) { private calculateOverallPerformance(positions: TimelinePosition[]) {
let currentValue = new Big(0); let currentValue = new Big(0);
let grossPerformance = new Big(0); let grossPerformance = new Big(0);
@ -1121,6 +1140,7 @@ export class PortfolioCalculator {
return factor; return factor;
} }
@LogPerformance
private getSymbolMetrics({ private getSymbolMetrics({
end, end,
exchangeRates, exchangeRates,
@ -1128,7 +1148,8 @@ export class PortfolioCalculator {
marketSymbolMap, marketSymbolMap,
start, start,
step = 1, step = 1,
symbol symbol,
calculatePerformance = true
}: { }: {
end: Date; end: Date;
exchangeRates: { [dateString: string]: number }; exchangeRates: { [dateString: string]: number };
@ -1139,6 +1160,7 @@ export class PortfolioCalculator {
start: Date; start: Date;
step?: number; step?: number;
symbol: string; symbol: string;
calculatePerformance?: boolean;
}): SymbolMetrics { }): SymbolMetrics {
const currentExchangeRate = exchangeRates[format(new Date(), DATE_FORMAT)]; const currentExchangeRate = exchangeRates[format(new Date(), DATE_FORMAT)];
const currentValues: WithCurrencyEffect<{ [date: string]: Big }> = { const currentValues: WithCurrencyEffect<{ [date: string]: Big }> = {
@ -1359,7 +1381,8 @@ export class PortfolioCalculator {
unitPriceAtEndDate, unitPriceAtEndDate,
symbol, symbol,
exchangeRates, exchangeRates,
currentExchangeRate currentExchangeRate,
calculatePerformance
); );
return { return {
@ -1403,6 +1426,7 @@ export class PortfolioCalculator {
}; };
} }
@LogPerformance
private calculatePerformanceOfSymbol( private calculatePerformanceOfSymbol(
orders: PortfolioOrderItem[], orders: PortfolioOrderItem[],
indexOfStartOrder: number, indexOfStartOrder: number,
@ -1435,7 +1459,8 @@ export class PortfolioCalculator {
unitPriceAtEndDate: Big, unitPriceAtEndDate: Big,
symbol: string, symbol: string,
exchangeRates: { [dateString: string]: number }, exchangeRates: { [dateString: string]: number },
currentExchangeRate: number currentExchangeRate: number,
calculatePerformance: boolean
) { ) {
let totalInvestmentDays = 0; let totalInvestmentDays = 0;
let sumOfTimeWeightedInvestments = { let sumOfTimeWeightedInvestments = {
@ -1490,9 +1515,51 @@ export class PortfolioCalculator {
sumOfTimeWeightedInvestments, sumOfTimeWeightedInvestments,
timeWeightedInvestmentValues, timeWeightedInvestmentValues,
exchangeRates, exchangeRates,
currentExchangeRate currentExchangeRate,
calculatePerformance
)); ));
if (!calculatePerformance) {
return {
currentValues,
grossPerformancePercentage: {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
},
initialValue,
investmentValues,
maxInvestmentValues,
netPerformancePercentage: {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
},
netPerformanceValues,
grossPerformance: { Value: new Big(0), WithCurrencyEffect: new Big(0) },
hasErrors: totalUnits.gt(0) && (!initialValue || !unitPriceAtEndDate),
netPerformance: { Value: new Big(0), WithCurrencyEffect: new Big(0) },
averagePriceAtStartDate,
totalUnits,
totalInvestment,
investmentAtStartDate,
valueAtStartDate,
maxTotalInvestment,
averagePriceAtEndDate,
fees,
lastAveragePrice,
grossPerformanceFromSells,
totalInvestmentWithGrossPerformanceFromSell,
feesAtStartDate,
grossPerformanceAtStartDate,
netPerformanceValuesPercentage,
investmentValuesAccumulated,
timeWeightedInvestmentValues,
timeWeightedAverageInvestmentBetweenStartAndEndDate: {
Value: new Big(0),
WithCurrencyEffect: new Big(0)
}
};
}
const totalGrossPerformance = { const totalGrossPerformance = {
Value: grossPerformance.Value.minus(grossPerformanceAtStartDate.Value), Value: grossPerformance.Value.minus(grossPerformanceAtStartDate.Value),
WithCurrencyEffect: grossPerformance.WithCurrencyEffect.minus( WithCurrencyEffect: grossPerformance.WithCurrencyEffect.minus(
@ -1601,6 +1668,7 @@ export class PortfolioCalculator {
}; };
} }
@LogPerformance
private handleOrders( private handleOrders(
orders: PortfolioOrderItem[], orders: PortfolioOrderItem[],
indexOfStartOrder: number, indexOfStartOrder: number,
@ -1632,18 +1700,21 @@ export class PortfolioCalculator {
sumOfTimeWeightedInvestments: WithCurrencyEffect<Big>, sumOfTimeWeightedInvestments: WithCurrencyEffect<Big>,
timeWeightedInvestmentValues: WithCurrencyEffect<{ [date: string]: Big }>, timeWeightedInvestmentValues: WithCurrencyEffect<{ [date: string]: Big }>,
exchangeRates: { [dateString: string]: number }, exchangeRates: { [dateString: string]: number },
currentExchangeRate: number currentExchangeRate: number,
calculatePerformance: boolean
) { ) {
for (let i = 0; i < orders.length; i += 1) { for (let i = 0; i < orders.length; i += 1) {
const order = orders[i]; const order = orders[i];
const previousOrderDateString = i > 0 ? orders[i - 1].date : ''; const previousOrderDateString = i > 0 ? orders[i - 1].date : '';
this.calculateNetPerformancePercentageForDateAndSymbol( if (calculatePerformance) {
i, this.calculateNetPerformancePercentageForDateAndSymbol(
orders, i,
order, orders,
netPerformanceValuesPercentage, order,
marketSymbolMap netPerformanceValuesPercentage,
); marketSymbolMap
);
}
if (PortfolioCalculator.ENABLE_LOGGING) { if (PortfolioCalculator.ENABLE_LOGGING) {
console.log(); console.log();
@ -1704,16 +1775,18 @@ export class PortfolioCalculator {
fees fees
)); ));
({ if (calculatePerformance) {
grossPerformanceFromSells, ({
totalInvestmentWithGrossPerformanceFromSell grossPerformanceFromSells,
} = this.calculateSellOrders( totalInvestmentWithGrossPerformanceFromSell
order, } = this.calculateSellOrders(
lastAveragePrice, order,
grossPerformanceFromSells, lastAveragePrice,
totalInvestmentWithGrossPerformanceFromSell, grossPerformanceFromSells,
transactionInvestment totalInvestmentWithGrossPerformanceFromSell,
)); transactionInvestment
));
}
lastAveragePrice.Value = totalUnits.eq(0) lastAveragePrice.Value = totalUnits.eq(0)
? new Big(0) ? new Big(0)
@ -1744,6 +1817,26 @@ export class PortfolioCalculator {
); );
} }
if (!calculatePerformance) {
return {
lastAveragePrice,
grossPerformance,
feesAtStartDate,
grossPerformanceAtStartDate,
averagePriceAtStartDate,
totalUnits,
totalInvestment,
investmentAtStartDate,
valueAtStartDate,
maxTotalInvestment,
averagePriceAtEndDate,
initialValue,
fees,
netPerformanceValuesPercentage,
totalInvestmentDays
};
}
const newGrossPerformance = valueOfInvestment.Value.minus( const newGrossPerformance = valueOfInvestment.Value.minus(
totalInvestment.Value totalInvestment.Value
).plus(grossPerformanceFromSells.Value); ).plus(grossPerformanceFromSells.Value);
@ -1829,6 +1922,7 @@ export class PortfolioCalculator {
}; };
} }
@LogPerformance
private handleFeeAndUnitPriceOfOrder( private handleFeeAndUnitPriceOfOrder(
order: PortfolioOrderItem, order: PortfolioOrderItem,
currentExchangeRate: number, currentExchangeRate: number,
@ -1852,6 +1946,7 @@ export class PortfolioCalculator {
} }
} }
@LogPerformance
private calculateNetPerformancePercentageForDateAndSymbol( private calculateNetPerformancePercentageForDateAndSymbol(
i: number, i: number,
orders: PortfolioOrderItem[], orders: PortfolioOrderItem[],
@ -1895,6 +1990,7 @@ export class PortfolioCalculator {
} }
} }
@LogPerformance
private handleIfPreviousOrderIsStake( private handleIfPreviousOrderIsStake(
netPerformanceValuesPercentage: { [date: string]: Big }, netPerformanceValuesPercentage: { [date: string]: Big },
order: PortfolioOrderItem, order: PortfolioOrderItem,
@ -1906,6 +2002,7 @@ export class PortfolioCalculator {
.minus(1); .minus(1);
} }
@LogPerformance
private stakeHandling( private stakeHandling(
previousOrder: PortfolioOrderItem, previousOrder: PortfolioOrderItem,
marketSymbolMap: { [date: string]: { [symbol: string]: Big } }, marketSymbolMap: { [date: string]: { [symbol: string]: Big } },
@ -1925,6 +2022,7 @@ export class PortfolioCalculator {
: new Big(0); : new Big(0);
} }
@LogPerformance
private ispreviousOrderStakeAndHasInformation( private ispreviousOrderStakeAndHasInformation(
previousOrder: PortfolioOrderItem, previousOrder: PortfolioOrderItem,
marketSymbolMap: { [date: string]: { [symbol: string]: Big } } marketSymbolMap: { [date: string]: { [symbol: string]: Big } }
@ -1936,6 +2034,7 @@ export class PortfolioCalculator {
); );
} }
@LogPerformance
private needsStakeHandling( private needsStakeHandling(
order: PortfolioOrderItem, order: PortfolioOrderItem,
marketSymbolMap: { [date: string]: { [symbol: string]: Big } }, marketSymbolMap: { [date: string]: { [symbol: string]: Big } },
@ -1952,6 +2051,7 @@ export class PortfolioCalculator {
); );
} }
@LogPerformance
private handleLoggingOfInvestmentMetrics( private handleLoggingOfInvestmentMetrics(
totalInvestment: WithCurrencyEffect<Big>, totalInvestment: WithCurrencyEffect<Big>,
order: PortfolioOrderItem, order: PortfolioOrderItem,
@ -1986,6 +2086,7 @@ export class PortfolioCalculator {
} }
} }
@LogPerformance
private calculateNetPerformancePercentage( private calculateNetPerformancePercentage(
timeWeightedAverageInvestmentBetweenStartAndEndDate: WithCurrencyEffect<Big>, timeWeightedAverageInvestmentBetweenStartAndEndDate: WithCurrencyEffect<Big>,
totalNetPerformance: WithCurrencyEffect<Big> totalNetPerformance: WithCurrencyEffect<Big>
@ -2007,6 +2108,7 @@ export class PortfolioCalculator {
}; };
} }
@LogPerformance
private calculateInvestmentSpecificMetrics( private calculateInvestmentSpecificMetrics(
averagePriceAtStartDate: Big, averagePriceAtStartDate: Big,
i: number, i: number,
@ -2132,6 +2234,7 @@ export class PortfolioCalculator {
}; };
} }
@LogPerformance
private calculatePerformancesForDateAndReturnTotalInvestmentDays( private calculatePerformancesForDateAndReturnTotalInvestmentDays(
isChartMode: boolean, isChartMode: boolean,
i: number, i: number,
@ -2234,6 +2337,7 @@ export class PortfolioCalculator {
return totalInvestmentDays; return totalInvestmentDays;
} }
@LogPerformance
private calculateSellOrders( private calculateSellOrders(
order: PortfolioOrderItem, order: PortfolioOrderItem,
lastAveragePrice: WithCurrencyEffect<Big>, lastAveragePrice: WithCurrencyEffect<Big>,
@ -2280,6 +2384,7 @@ export class PortfolioCalculator {
}; };
} }
@LogPerformance
private calculateInitialValue( private calculateInitialValue(
i: number, i: number,
indexOfStartOrder: number, indexOfStartOrder: number,
@ -2315,6 +2420,7 @@ export class PortfolioCalculator {
}; };
} }
@LogPerformance
private calculateAveragePriceAtEnd( private calculateAveragePriceAtEnd(
i: number, i: number,
indexOfEndOrder: number, indexOfEndOrder: number,
@ -2328,6 +2434,7 @@ export class PortfolioCalculator {
return averagePriceAtEndDate; return averagePriceAtEndDate;
} }
@LogPerformance
private getTransactionInvestment( private getTransactionInvestment(
order: PortfolioOrderItem, order: PortfolioOrderItem,
totalUnits: Big, totalUnits: Big,
@ -2350,6 +2457,7 @@ export class PortfolioCalculator {
: new Big(0); : new Big(0);
} }
@LogPerformance
private calculateAveragePrice( private calculateAveragePrice(
averagePriceAtStartDate: Big, averagePriceAtStartDate: Big,
i: number, i: number,
@ -2367,6 +2475,7 @@ export class PortfolioCalculator {
return averagePriceAtStartDate; return averagePriceAtStartDate;
} }
@LogPerformance
private handleStartOrder( private handleStartOrder(
order: PortfolioOrderItem, order: PortfolioOrderItem,
indexOfStartOrder: number, indexOfStartOrder: number,
@ -2384,6 +2493,7 @@ export class PortfolioCalculator {
} }
} }
@LogPerformance
private handleLogging( private handleLogging(
symbol: string, symbol: string,
orders: PortfolioOrderItem[], orders: PortfolioOrderItem[],
@ -2429,6 +2539,7 @@ export class PortfolioCalculator {
} }
} }
@LogPerformance
private sortOrdersByTime(orders: PortfolioOrderItem[]) { private sortOrdersByTime(orders: PortfolioOrderItem[]) {
return sortBy(orders, (order) => { return sortBy(orders, (order) => {
let sortIndex = new Date(order.date); let sortIndex = new Date(order.date);
@ -2445,6 +2556,7 @@ export class PortfolioCalculator {
}); });
} }
@LogPerformance
private handleChartMode( private handleChartMode(
isChartMode: boolean, isChartMode: boolean,
orders: PortfolioOrderItem[], orders: PortfolioOrderItem[],
@ -2480,6 +2592,7 @@ export class PortfolioCalculator {
return { day, lastUnitPrice }; return { day, lastUnitPrice };
} }
@LogPerformance
private handleDay( private handleDay(
datesWithOrders: {}, datesWithOrders: {},
day: Date, day: Date,
@ -2519,6 +2632,7 @@ export class PortfolioCalculator {
} }
} }
@LogPerformance
private addSyntheticStartAndEndOrders( private addSyntheticStartAndEndOrders(
orders: PortfolioOrderItem[], orders: PortfolioOrderItem[],
symbol: string, symbol: string,

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

@ -1,3 +1,4 @@
import { LogPerformance } from '@ghostfolio/api/aop/logging.interceptor';
import { AccessService } from '@ghostfolio/api/app/access/access.service'; import { AccessService } from '@ghostfolio/api/app/access/access.service';
import { UserService } from '@ghostfolio/api/app/user/user.service'; import { UserService } from '@ghostfolio/api/app/user/user.service';
import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard';
@ -71,7 +72,8 @@ export class PortfolioController {
@Query('accounts') filterByAccounts?: string, @Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string, @Query('assetClasses') filterByAssetClasses?: string,
@Query('range') dateRange: DateRange = 'max', @Query('range') dateRange: DateRange = 'max',
@Query('tags') filterByTags?: string @Query('tags') filterByTags?: string,
@Query('isAllocation') isAllocation: boolean = false
): Promise<PortfolioDetails & { hasError: boolean }> { ): Promise<PortfolioDetails & { hasError: boolean }> {
let hasDetails = true; let hasDetails = true;
let hasError = false; let hasError = false;
@ -104,7 +106,8 @@ export class PortfolioController {
dateRange, dateRange,
filters, filters,
impersonationId, impersonationId,
userId: this.request.user.id userId: this.request.user.id,
isAllocation
}); });
if (hasErrors || hasNotDefinedValuesInObject(holdings)) { if (hasErrors || hasNotDefinedValuesInObject(holdings)) {
@ -375,6 +378,7 @@ export class PortfolioController {
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(TransformDataSourceInResponseInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor)
@Version('2') @Version('2')
@LogPerformance
public async getPerformanceV2( public async getPerformanceV2(
@Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string,
@Query('accounts') filterByAccounts?: string, @Query('accounts') filterByAccounts?: string,

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

@ -1,3 +1,4 @@
import { LogPerformance } from '@ghostfolio/api/aop/logging.interceptor';
import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service';
import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { AccountService } from '@ghostfolio/api/app/account/account.service';
import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface'; import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface';
@ -113,6 +114,7 @@ export class PortfolioService {
private readonly userService: UserService private readonly userService: UserService
) {} ) {}
@LogPerformance
public async getAccounts({ public async getAccounts({
filters, filters,
userId, userId,
@ -182,6 +184,7 @@ export class PortfolioService {
}); });
} }
@LogPerformance
public async getAccountsWithAggregations({ public async getAccountsWithAggregations({
filters, filters,
userId, userId,
@ -218,6 +221,7 @@ export class PortfolioService {
}; };
} }
@LogPerformance
public async getDividends({ public async getDividends({
dateRange, dateRange,
filters, filters,
@ -259,6 +263,7 @@ export class PortfolioService {
}); });
} }
@LogPerformance
public async getInvestments({ public async getInvestments({
dateRange, dateRange,
filters, filters,
@ -332,18 +337,21 @@ export class PortfolioService {
}; };
} }
@LogPerformance
public async getDetails({ public async getDetails({
dateRange = 'max', dateRange = 'max',
filters, filters,
impersonationId, impersonationId,
userId, userId,
withExcludedAccounts = false withExcludedAccounts = false,
isAllocation = false
}: { }: {
dateRange?: DateRange; dateRange?: DateRange;
filters?: Filter[]; filters?: Filter[];
impersonationId: string; impersonationId: string;
userId: string; userId: string;
withExcludedAccounts?: boolean; withExcludedAccounts?: boolean;
isAllocation?: boolean;
}): Promise<PortfolioDetails & { hasErrors: boolean }> { }): Promise<PortfolioDetails & { hasErrors: boolean }> {
userId = await this.getUserId(impersonationId, userId); userId = await this.getUserId(impersonationId, userId);
const user = await this.userService.user({ id: userId }); const user = await this.userService.user({ id: userId });
@ -373,8 +381,11 @@ export class PortfolioService {
transactionPoints[0]?.date ?? format(new Date(), DATE_FORMAT) transactionPoints[0]?.date ?? format(new Date(), DATE_FORMAT)
); );
const startDate = this.getStartDate(dateRange, portfolioStart); const startDate = this.getStartDate(dateRange, portfolioStart);
const currentPositions = const currentPositions = await portfolioCalculator.getCurrentPositions(
await portfolioCalculator.getCurrentPositions(startDate); startDate,
new Date(Date.now()),
!isAllocation
);
const cashDetails = await this.accountService.getCashDetails({ const cashDetails = await this.accountService.getCashDetails({
filters, filters,
@ -465,17 +476,19 @@ export class PortfolioService {
accounts, accounts,
holdings holdings
); );
let summary;
const summary = await this.getSummary({ if (!isAllocation) {
impersonationId, summary = await this.getSummary({
userCurrency, impersonationId,
userId, userCurrency,
balanceInBaseCurrency: cashDetails.balanceInBaseCurrency, userId,
emergencyFundPositionsValueInBaseCurrency: balanceInBaseCurrency: cashDetails.balanceInBaseCurrency,
this.getEmergencyFundPositionsValueInBaseCurrency({ emergencyFundPositionsValueInBaseCurrency:
holdings this.getEmergencyFundPositionsValueInBaseCurrency({
}) holdings
}); })
});
}
return { return {
accounts, accounts,
@ -483,14 +496,20 @@ export class PortfolioService {
platforms, platforms,
summary, summary,
filteredValueInBaseCurrency: filteredValueInBaseCurrency.toNumber(), filteredValueInBaseCurrency: filteredValueInBaseCurrency.toNumber(),
filteredValueInPercentage: summary.netWorth filteredValueInPercentage: summary?.netWorth
? filteredValueInBaseCurrency.div(summary.netWorth).toNumber() ? filteredValueInBaseCurrency.div(summary.netWorth).toNumber()
: 0, : 0,
hasErrors: currentPositions.hasErrors, hasErrors: currentPositions.hasErrors,
totalValueInBaseCurrency: summary.netWorth totalValueInBaseCurrency:
summary?.netWorth ??
Object.keys(holdings).reduce(
(s, k) => s + holdings[k].valueInBaseCurrency ?? 0,
0
)
}; };
} }
@LogPerformance
private handlePositions( private handlePositions(
currentPositions: CurrentPositions, currentPositions: CurrentPositions,
portfolioItemsNow: { [symbol: string]: TimelinePosition }, portfolioItemsNow: { [symbol: string]: TimelinePosition },
@ -567,6 +586,7 @@ export class PortfolioService {
} }
} }
@LogPerformance
private async handleCashPosition( private async handleCashPosition(
filters: Filter[], filters: Filter[],
isFilteredByAccount: boolean, isFilteredByAccount: boolean,
@ -592,6 +612,7 @@ export class PortfolioService {
} }
} }
@LogPerformance
private async handleEmergencyFunds( private async handleEmergencyFunds(
filters: Filter[], filters: Filter[],
cashDetails: CashDetails, cashDetails: CashDetails,
@ -647,6 +668,7 @@ export class PortfolioService {
return filteredValueInBaseCurrency; return filteredValueInBaseCurrency;
} }
@LogPerformance
private calculateMarketsAllocation( private calculateMarketsAllocation(
symbolProfile: EnhancedSymbolProfile, symbolProfile: EnhancedSymbolProfile,
markets: { markets: {
@ -719,6 +741,7 @@ export class PortfolioService {
} }
} }
@LogPerformance
public async getPosition( public async getPosition(
aDataSource: DataSource, aDataSource: DataSource,
aImpersonationId: string, aImpersonationId: string,
@ -1049,6 +1072,7 @@ export class PortfolioService {
} }
} }
@LogPerformance
public async getPositions({ public async getPositions({
dateRange = 'max', dateRange = 'max',
filters, filters,
@ -1192,6 +1216,7 @@ export class PortfolioService {
}; };
} }
@LogPerformance
public async getPerformance({ public async getPerformance({
dateRange = 'max', dateRange = 'max',
filters, filters,
@ -1386,6 +1411,7 @@ export class PortfolioService {
}; };
} }
@LogPerformance
public async getReport(impersonationId: string): Promise<PortfolioReport> { public async getReport(impersonationId: string): Promise<PortfolioReport> {
const userId = await this.getUserId(impersonationId, this.request.user.id); const userId = await this.getUserId(impersonationId, this.request.user.id);
const user = await this.userService.user({ id: userId }); const user = await this.userService.user({ id: userId });
@ -1485,6 +1511,7 @@ export class PortfolioService {
}; };
} }
@LogPerformance
private async getCashPositions({ private async getCashPositions({
cashDetails, cashDetails,
userCurrency, userCurrency,
@ -1535,6 +1562,7 @@ export class PortfolioService {
return cashPositions; return cashPositions;
} }
@LogPerformance
private async getChart({ private async getChart({
dateRange = 'max', dateRange = 'max',
impersonationId, impersonationId,
@ -1599,6 +1627,7 @@ export class PortfolioService {
}; };
} }
@LogPerformance
private getDividendsByGroup({ private getDividendsByGroup({
dividends, dividends,
groupBy groupBy
@ -1661,6 +1690,7 @@ export class PortfolioService {
return dividendsByGroup; return dividendsByGroup;
} }
@LogPerformance
private getEmergencyFundPositionsValueInBaseCurrency({ private getEmergencyFundPositionsValueInBaseCurrency({
holdings holdings
}: { }: {
@ -1684,6 +1714,7 @@ export class PortfolioService {
return valueInBaseCurrencyOfEmergencyFundPositions.toNumber(); return valueInBaseCurrencyOfEmergencyFundPositions.toNumber();
} }
@LogPerformance
private getFees({ private getFees({
activities, activities,
date = new Date(0), date = new Date(0),
@ -1711,6 +1742,7 @@ export class PortfolioService {
); );
} }
@LogPerformance
private getInitialCashPosition({ private getInitialCashPosition({
balance, balance,
currency currency
@ -1743,6 +1775,7 @@ export class PortfolioService {
}; };
} }
@LogPerformance
private getStartDate(aDateRange: DateRange, portfolioStart: Date) { private getStartDate(aDateRange: DateRange, portfolioStart: Date) {
switch (aDateRange) { switch (aDateRange) {
case '1d': case '1d':
@ -1811,6 +1844,7 @@ export class PortfolioService {
return portfolioStart; return portfolioStart;
} }
@LogPerformance
private getStreaks({ private getStreaks({
investments, investments,
savingsRate savingsRate
@ -1833,6 +1867,7 @@ export class PortfolioService {
return { currentStreak, longestStreak }; return { currentStreak, longestStreak };
} }
@LogPerformance
private async getSummary({ private async getSummary({
balanceInBaseCurrency, balanceInBaseCurrency,
emergencyFundPositionsValueInBaseCurrency, emergencyFundPositionsValueInBaseCurrency,
@ -2003,6 +2038,7 @@ export class PortfolioService {
}; };
} }
@LogPerformance
private getSumOfActivityType({ private getSumOfActivityType({
activities, activities,
activityType, activityType,
@ -2036,6 +2072,7 @@ export class PortfolioService {
); );
} }
@LogPerformance
private async getTransactionPoints({ private async getTransactionPoints({
filters, filters,
includeDrafts = false, includeDrafts = false,
@ -2111,6 +2148,7 @@ export class PortfolioService {
return impersonationUserId || aUserId; return impersonationUserId || aUserId;
} }
@LogPerformance
private async getValueOfAccountsAndPlatforms({ private async getValueOfAccountsAndPlatforms({
filters = [], filters = [],
orders, orders,
@ -2261,6 +2299,7 @@ export class PortfolioService {
return { accounts, platforms }; return { accounts, platforms };
} }
@LogPerformance
private mergeHistoricalDataItems( private mergeHistoricalDataItems(
accountBalanceItems: HistoricalDataItem[], accountBalanceItems: HistoricalDataItem[],
performanceChartItems: HistoricalDataItem[] performanceChartItems: HistoricalDataItem[]

5
apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts

@ -205,7 +205,10 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
private fetchPortfolioDetails() { private fetchPortfolioDetails() {
return this.dataService.fetchPortfolioDetails({ return this.dataService.fetchPortfolioDetails({
filters: this.userService.getFilters() filters: this.userService.getFilters(),
parameters: {
isAllocation: true
}
}); });
} }

16
apps/client/src/app/services/data.service.ts

@ -389,13 +389,25 @@ export class DataService {
} }
public fetchPortfolioDetails({ public fetchPortfolioDetails({
filters filters,
parameters
}: { }: {
filters?: Filter[]; filters?: Filter[];
parameters?: {
[param: string]:
| string
| number
| boolean
| readonly (string | number | boolean)[];
};
} = {}): Observable<PortfolioDetails> { } = {}): Observable<PortfolioDetails> {
let params = this.buildFiltersAsQueryParams({ filters }).appendAll(
parameters
);
return this.http return this.http
.get<any>('/api/v1/portfolio/details', { .get<any>('/api/v1/portfolio/details', {
params: this.buildFiltersAsQueryParams({ filters }) params
}) })
.pipe( .pipe(
map((response) => { map((response) => {

Loading…
Cancel
Save