From bffbc4c1c7cb16bd7a08b4fb510c11dd54e461b0 Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 2 Mar 2024 12:59:54 +0100 Subject: [PATCH] Added Performance Interceptor and removed Caculation from asset page --- .../src/app/portfolio/portfolio-calculator.ts | 162 +++++++++++++++--- .../src/app/portfolio/portfolio.controller.ts | 8 +- .../src/app/portfolio/portfolio.service.ts | 71 ++++++-- .../allocations/allocations-page.component.ts | 5 +- apps/client/src/app/services/data.service.ts | 16 +- 5 files changed, 217 insertions(+), 45 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio-calculator.ts b/apps/api/src/app/portfolio/portfolio-calculator.ts index 01369743b..00b0b522b 100644 --- a/apps/api/src/app/portfolio/portfolio-calculator.ts +++ b/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 { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper'; @@ -80,6 +81,7 @@ export class PortfolioCalculator { }); } + @LogPerformance public computeTransactionPoints() { this.transactionPoints = []; const symbols: { [symbol: string]: TransactionPointSymbol } = {}; @@ -123,6 +125,7 @@ export class PortfolioCalculator { } } + @LogPerformance private getCurrentTransactionPointItem( oldAccumulatedSymbol: TransactionPointSymbol, order: PortfolioOrder, @@ -154,6 +157,7 @@ export class PortfolioCalculator { return currentTransactionPointItem; } + @LogPerformance private handleSubsequentTransactions( order: PortfolioOrder, factor: number, @@ -196,6 +200,7 @@ export class PortfolioCalculator { return currentTransactionPointItem; } + @LogPerformance public getAnnualizedPerformancePercent({ daysInMarket, netPerformancePercent @@ -221,6 +226,7 @@ export class PortfolioCalculator { this.transactionPoints = transactionPoints; } + @LogPerformance public async getChartData({ start, end = new Date(Date.now()), @@ -345,6 +351,7 @@ export class PortfolioCalculator { }); } + @LogPerformance private calculatePerformance( date: Date, previousDate: Date, @@ -479,6 +486,7 @@ export class PortfolioCalculator { }; } + @LogPerformance private accumulatedValuesByDate( valuesBySymbol: { [symbol: string]: { @@ -587,6 +595,7 @@ export class PortfolioCalculator { return accumulatedValuesByDate; } + @LogPerformance private populateSymbolMetrics( symbols: { [symbol: string]: boolean }, end: Date, @@ -648,6 +657,7 @@ export class PortfolioCalculator { } } + @LogPerformance private populateMarketSymbolMap( marketSymbols: GetValueObject[], marketSymbolMap: { [date: string]: { [symbol: string]: Big } } @@ -665,6 +675,7 @@ export class PortfolioCalculator { } } + @LogPerformance private async getInformationFromCurrentRateService( currencies: { [symbol: string]: string }, dataGatheringItems: IDataGatheringItem[], @@ -681,6 +692,7 @@ export class PortfolioCalculator { }); } + @LogPerformance private pushDataGatheringsSymbols( transactionPointsBeforeEndDate: TransactionPoint[], firstIndex: number, @@ -700,6 +712,7 @@ export class PortfolioCalculator { } } + @LogPerformance private getRelevantStartAndEndDates( start: Date, end: Date, @@ -718,9 +731,11 @@ export class PortfolioCalculator { } } + @LogPerformance public async getCurrentPositions( start: Date, - end = new Date(Date.now()) + end = new Date(Date.now()), + calculatePerformance = true ): Promise { const transactionPointsBeforeEndDate = this.transactionPoints?.filter((transactionPoint) => { @@ -883,7 +898,8 @@ export class PortfolioCalculator { start, exchangeRates: exchangeRatesByCurrency[`${item.currency}${this.currency}`], - symbol: item.symbol + symbol: item.symbol, + calculatePerformance }); hasAnySymbolMetricsErrors = hasAnySymbolMetricsErrors || hasErrors; @@ -956,6 +972,7 @@ export class PortfolioCalculator { return this.dataProviderInfos; } + @LogPerformance public getInvestments(): { date: string; investment: Big }[] { if (this.transactionPoints.length === 0) { return []; @@ -973,6 +990,7 @@ export class PortfolioCalculator { }); } + @LogPerformance public getInvestmentsByGroup({ data, groupBy @@ -996,6 +1014,7 @@ export class PortfolioCalculator { })); } + @LogPerformance private calculateOverallPerformance(positions: TimelinePosition[]) { let currentValue = new Big(0); let grossPerformance = new Big(0); @@ -1121,6 +1140,7 @@ export class PortfolioCalculator { return factor; } + @LogPerformance private getSymbolMetrics({ end, exchangeRates, @@ -1128,7 +1148,8 @@ export class PortfolioCalculator { marketSymbolMap, start, step = 1, - symbol + symbol, + calculatePerformance = true }: { end: Date; exchangeRates: { [dateString: string]: number }; @@ -1139,6 +1160,7 @@ export class PortfolioCalculator { start: Date; step?: number; symbol: string; + calculatePerformance?: boolean; }): SymbolMetrics { const currentExchangeRate = exchangeRates[format(new Date(), DATE_FORMAT)]; const currentValues: WithCurrencyEffect<{ [date: string]: Big }> = { @@ -1359,7 +1381,8 @@ export class PortfolioCalculator { unitPriceAtEndDate, symbol, exchangeRates, - currentExchangeRate + currentExchangeRate, + calculatePerformance ); return { @@ -1403,6 +1426,7 @@ export class PortfolioCalculator { }; } + @LogPerformance private calculatePerformanceOfSymbol( orders: PortfolioOrderItem[], indexOfStartOrder: number, @@ -1435,7 +1459,8 @@ export class PortfolioCalculator { unitPriceAtEndDate: Big, symbol: string, exchangeRates: { [dateString: string]: number }, - currentExchangeRate: number + currentExchangeRate: number, + calculatePerformance: boolean ) { let totalInvestmentDays = 0; let sumOfTimeWeightedInvestments = { @@ -1490,9 +1515,51 @@ export class PortfolioCalculator { sumOfTimeWeightedInvestments, timeWeightedInvestmentValues, 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 = { Value: grossPerformance.Value.minus(grossPerformanceAtStartDate.Value), WithCurrencyEffect: grossPerformance.WithCurrencyEffect.minus( @@ -1601,6 +1668,7 @@ export class PortfolioCalculator { }; } + @LogPerformance private handleOrders( orders: PortfolioOrderItem[], indexOfStartOrder: number, @@ -1632,18 +1700,21 @@ export class PortfolioCalculator { sumOfTimeWeightedInvestments: WithCurrencyEffect, timeWeightedInvestmentValues: WithCurrencyEffect<{ [date: string]: Big }>, exchangeRates: { [dateString: string]: number }, - currentExchangeRate: number + currentExchangeRate: number, + calculatePerformance: boolean ) { for (let i = 0; i < orders.length; i += 1) { const order = orders[i]; const previousOrderDateString = i > 0 ? orders[i - 1].date : ''; - this.calculateNetPerformancePercentageForDateAndSymbol( - i, - orders, - order, - netPerformanceValuesPercentage, - marketSymbolMap - ); + if (calculatePerformance) { + this.calculateNetPerformancePercentageForDateAndSymbol( + i, + orders, + order, + netPerformanceValuesPercentage, + marketSymbolMap + ); + } if (PortfolioCalculator.ENABLE_LOGGING) { console.log(); @@ -1704,16 +1775,18 @@ export class PortfolioCalculator { fees )); - ({ - grossPerformanceFromSells, - totalInvestmentWithGrossPerformanceFromSell - } = this.calculateSellOrders( - order, - lastAveragePrice, - grossPerformanceFromSells, - totalInvestmentWithGrossPerformanceFromSell, - transactionInvestment - )); + if (calculatePerformance) { + ({ + grossPerformanceFromSells, + totalInvestmentWithGrossPerformanceFromSell + } = this.calculateSellOrders( + order, + lastAveragePrice, + grossPerformanceFromSells, + totalInvestmentWithGrossPerformanceFromSell, + transactionInvestment + )); + } lastAveragePrice.Value = totalUnits.eq(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( totalInvestment.Value ).plus(grossPerformanceFromSells.Value); @@ -1829,6 +1922,7 @@ export class PortfolioCalculator { }; } + @LogPerformance private handleFeeAndUnitPriceOfOrder( order: PortfolioOrderItem, currentExchangeRate: number, @@ -1852,6 +1946,7 @@ export class PortfolioCalculator { } } + @LogPerformance private calculateNetPerformancePercentageForDateAndSymbol( i: number, orders: PortfolioOrderItem[], @@ -1895,6 +1990,7 @@ export class PortfolioCalculator { } } + @LogPerformance private handleIfPreviousOrderIsStake( netPerformanceValuesPercentage: { [date: string]: Big }, order: PortfolioOrderItem, @@ -1906,6 +2002,7 @@ export class PortfolioCalculator { .minus(1); } + @LogPerformance private stakeHandling( previousOrder: PortfolioOrderItem, marketSymbolMap: { [date: string]: { [symbol: string]: Big } }, @@ -1925,6 +2022,7 @@ export class PortfolioCalculator { : new Big(0); } + @LogPerformance private ispreviousOrderStakeAndHasInformation( previousOrder: PortfolioOrderItem, marketSymbolMap: { [date: string]: { [symbol: string]: Big } } @@ -1936,6 +2034,7 @@ export class PortfolioCalculator { ); } + @LogPerformance private needsStakeHandling( order: PortfolioOrderItem, marketSymbolMap: { [date: string]: { [symbol: string]: Big } }, @@ -1952,6 +2051,7 @@ export class PortfolioCalculator { ); } + @LogPerformance private handleLoggingOfInvestmentMetrics( totalInvestment: WithCurrencyEffect, order: PortfolioOrderItem, @@ -1986,6 +2086,7 @@ export class PortfolioCalculator { } } + @LogPerformance private calculateNetPerformancePercentage( timeWeightedAverageInvestmentBetweenStartAndEndDate: WithCurrencyEffect, totalNetPerformance: WithCurrencyEffect @@ -2007,6 +2108,7 @@ export class PortfolioCalculator { }; } + @LogPerformance private calculateInvestmentSpecificMetrics( averagePriceAtStartDate: Big, i: number, @@ -2132,6 +2234,7 @@ export class PortfolioCalculator { }; } + @LogPerformance private calculatePerformancesForDateAndReturnTotalInvestmentDays( isChartMode: boolean, i: number, @@ -2234,6 +2337,7 @@ export class PortfolioCalculator { return totalInvestmentDays; } + @LogPerformance private calculateSellOrders( order: PortfolioOrderItem, lastAveragePrice: WithCurrencyEffect, @@ -2280,6 +2384,7 @@ export class PortfolioCalculator { }; } + @LogPerformance private calculateInitialValue( i: number, indexOfStartOrder: number, @@ -2315,6 +2420,7 @@ export class PortfolioCalculator { }; } + @LogPerformance private calculateAveragePriceAtEnd( i: number, indexOfEndOrder: number, @@ -2328,6 +2434,7 @@ export class PortfolioCalculator { return averagePriceAtEndDate; } + @LogPerformance private getTransactionInvestment( order: PortfolioOrderItem, totalUnits: Big, @@ -2350,6 +2457,7 @@ export class PortfolioCalculator { : new Big(0); } + @LogPerformance private calculateAveragePrice( averagePriceAtStartDate: Big, i: number, @@ -2367,6 +2475,7 @@ export class PortfolioCalculator { return averagePriceAtStartDate; } + @LogPerformance private handleStartOrder( order: PortfolioOrderItem, indexOfStartOrder: number, @@ -2384,6 +2493,7 @@ export class PortfolioCalculator { } } + @LogPerformance private handleLogging( symbol: string, orders: PortfolioOrderItem[], @@ -2429,6 +2539,7 @@ export class PortfolioCalculator { } } + @LogPerformance private sortOrdersByTime(orders: PortfolioOrderItem[]) { return sortBy(orders, (order) => { let sortIndex = new Date(order.date); @@ -2445,6 +2556,7 @@ export class PortfolioCalculator { }); } + @LogPerformance private handleChartMode( isChartMode: boolean, orders: PortfolioOrderItem[], @@ -2480,6 +2592,7 @@ export class PortfolioCalculator { return { day, lastUnitPrice }; } + @LogPerformance private handleDay( datesWithOrders: {}, day: Date, @@ -2519,6 +2632,7 @@ export class PortfolioCalculator { } } + @LogPerformance private addSyntheticStartAndEndOrders( orders: PortfolioOrderItem[], symbol: string, diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 59d7c2f03..ec33e7b27 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/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 { UserService } from '@ghostfolio/api/app/user/user.service'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; @@ -71,7 +72,8 @@ export class PortfolioController { @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, @Query('range') dateRange: DateRange = 'max', - @Query('tags') filterByTags?: string + @Query('tags') filterByTags?: string, + @Query('isAllocation') isAllocation: boolean = false ): Promise { let hasDetails = true; let hasError = false; @@ -104,7 +106,8 @@ export class PortfolioController { dateRange, filters, impersonationId, - userId: this.request.user.id + userId: this.request.user.id, + isAllocation }); if (hasErrors || hasNotDefinedValuesInObject(holdings)) { @@ -375,6 +378,7 @@ export class PortfolioController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInResponseInterceptor) @Version('2') + @LogPerformance public async getPerformanceV2( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Query('accounts') filterByAccounts?: string, diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 7d39d8d17..44bc16b83 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/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 { AccountService } from '@ghostfolio/api/app/account/account.service'; import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface'; @@ -113,6 +114,7 @@ export class PortfolioService { private readonly userService: UserService ) {} + @LogPerformance public async getAccounts({ filters, userId, @@ -182,6 +184,7 @@ export class PortfolioService { }); } + @LogPerformance public async getAccountsWithAggregations({ filters, userId, @@ -218,6 +221,7 @@ export class PortfolioService { }; } + @LogPerformance public async getDividends({ dateRange, filters, @@ -259,6 +263,7 @@ export class PortfolioService { }); } + @LogPerformance public async getInvestments({ dateRange, filters, @@ -332,18 +337,21 @@ export class PortfolioService { }; } + @LogPerformance public async getDetails({ dateRange = 'max', filters, impersonationId, userId, - withExcludedAccounts = false + withExcludedAccounts = false, + isAllocation = false }: { dateRange?: DateRange; filters?: Filter[]; impersonationId: string; userId: string; withExcludedAccounts?: boolean; + isAllocation?: boolean; }): Promise { userId = await this.getUserId(impersonationId, userId); const user = await this.userService.user({ id: userId }); @@ -373,8 +381,11 @@ export class PortfolioService { transactionPoints[0]?.date ?? format(new Date(), DATE_FORMAT) ); const startDate = this.getStartDate(dateRange, portfolioStart); - const currentPositions = - await portfolioCalculator.getCurrentPositions(startDate); + const currentPositions = await portfolioCalculator.getCurrentPositions( + startDate, + new Date(Date.now()), + !isAllocation + ); const cashDetails = await this.accountService.getCashDetails({ filters, @@ -465,17 +476,19 @@ export class PortfolioService { accounts, holdings ); - - const summary = await this.getSummary({ - impersonationId, - userCurrency, - userId, - balanceInBaseCurrency: cashDetails.balanceInBaseCurrency, - emergencyFundPositionsValueInBaseCurrency: - this.getEmergencyFundPositionsValueInBaseCurrency({ - holdings - }) - }); + let summary; + if (!isAllocation) { + summary = await this.getSummary({ + impersonationId, + userCurrency, + userId, + balanceInBaseCurrency: cashDetails.balanceInBaseCurrency, + emergencyFundPositionsValueInBaseCurrency: + this.getEmergencyFundPositionsValueInBaseCurrency({ + holdings + }) + }); + } return { accounts, @@ -483,14 +496,20 @@ export class PortfolioService { platforms, summary, filteredValueInBaseCurrency: filteredValueInBaseCurrency.toNumber(), - filteredValueInPercentage: summary.netWorth + filteredValueInPercentage: summary?.netWorth ? filteredValueInBaseCurrency.div(summary.netWorth).toNumber() : 0, hasErrors: currentPositions.hasErrors, - totalValueInBaseCurrency: summary.netWorth + totalValueInBaseCurrency: + summary?.netWorth ?? + Object.keys(holdings).reduce( + (s, k) => s + holdings[k].valueInBaseCurrency ?? 0, + 0 + ) }; } + @LogPerformance private handlePositions( currentPositions: CurrentPositions, portfolioItemsNow: { [symbol: string]: TimelinePosition }, @@ -567,6 +586,7 @@ export class PortfolioService { } } + @LogPerformance private async handleCashPosition( filters: Filter[], isFilteredByAccount: boolean, @@ -592,6 +612,7 @@ export class PortfolioService { } } + @LogPerformance private async handleEmergencyFunds( filters: Filter[], cashDetails: CashDetails, @@ -647,6 +668,7 @@ export class PortfolioService { return filteredValueInBaseCurrency; } + @LogPerformance private calculateMarketsAllocation( symbolProfile: EnhancedSymbolProfile, markets: { @@ -719,6 +741,7 @@ export class PortfolioService { } } + @LogPerformance public async getPosition( aDataSource: DataSource, aImpersonationId: string, @@ -1049,6 +1072,7 @@ export class PortfolioService { } } + @LogPerformance public async getPositions({ dateRange = 'max', filters, @@ -1192,6 +1216,7 @@ export class PortfolioService { }; } + @LogPerformance public async getPerformance({ dateRange = 'max', filters, @@ -1386,6 +1411,7 @@ export class PortfolioService { }; } + @LogPerformance public async getReport(impersonationId: string): Promise { const userId = await this.getUserId(impersonationId, this.request.user.id); const user = await this.userService.user({ id: userId }); @@ -1485,6 +1511,7 @@ export class PortfolioService { }; } + @LogPerformance private async getCashPositions({ cashDetails, userCurrency, @@ -1535,6 +1562,7 @@ export class PortfolioService { return cashPositions; } + @LogPerformance private async getChart({ dateRange = 'max', impersonationId, @@ -1599,6 +1627,7 @@ export class PortfolioService { }; } + @LogPerformance private getDividendsByGroup({ dividends, groupBy @@ -1661,6 +1690,7 @@ export class PortfolioService { return dividendsByGroup; } + @LogPerformance private getEmergencyFundPositionsValueInBaseCurrency({ holdings }: { @@ -1684,6 +1714,7 @@ export class PortfolioService { return valueInBaseCurrencyOfEmergencyFundPositions.toNumber(); } + @LogPerformance private getFees({ activities, date = new Date(0), @@ -1711,6 +1742,7 @@ export class PortfolioService { ); } + @LogPerformance private getInitialCashPosition({ balance, currency @@ -1743,6 +1775,7 @@ export class PortfolioService { }; } + @LogPerformance private getStartDate(aDateRange: DateRange, portfolioStart: Date) { switch (aDateRange) { case '1d': @@ -1811,6 +1844,7 @@ export class PortfolioService { return portfolioStart; } + @LogPerformance private getStreaks({ investments, savingsRate @@ -1833,6 +1867,7 @@ export class PortfolioService { return { currentStreak, longestStreak }; } + @LogPerformance private async getSummary({ balanceInBaseCurrency, emergencyFundPositionsValueInBaseCurrency, @@ -2003,6 +2038,7 @@ export class PortfolioService { }; } + @LogPerformance private getSumOfActivityType({ activities, activityType, @@ -2036,6 +2072,7 @@ export class PortfolioService { ); } + @LogPerformance private async getTransactionPoints({ filters, includeDrafts = false, @@ -2111,6 +2148,7 @@ export class PortfolioService { return impersonationUserId || aUserId; } + @LogPerformance private async getValueOfAccountsAndPlatforms({ filters = [], orders, @@ -2261,6 +2299,7 @@ export class PortfolioService { return { accounts, platforms }; } + @LogPerformance private mergeHistoricalDataItems( accountBalanceItems: HistoricalDataItem[], performanceChartItems: HistoricalDataItem[] diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts index 330ae4227..44a95d48f 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts @@ -205,7 +205,10 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { private fetchPortfolioDetails() { return this.dataService.fetchPortfolioDetails({ - filters: this.userService.getFilters() + filters: this.userService.getFilters(), + parameters: { + isAllocation: true + } }); } diff --git a/apps/client/src/app/services/data.service.ts b/apps/client/src/app/services/data.service.ts index 89ff0c3f3..c55d4e818 100644 --- a/apps/client/src/app/services/data.service.ts +++ b/apps/client/src/app/services/data.service.ts @@ -389,13 +389,25 @@ export class DataService { } public fetchPortfolioDetails({ - filters + filters, + parameters }: { filters?: Filter[]; + parameters?: { + [param: string]: + | string + | number + | boolean + | readonly (string | number | boolean)[]; + }; } = {}): Observable { + let params = this.buildFiltersAsQueryParams({ filters }).appendAll( + parameters + ); + return this.http .get('/api/v1/portfolio/details', { - params: this.buildFiltersAsQueryParams({ filters }) + params }) .pipe( map((response) => {