From a092ff1b2f017fcf3011cce8fb4163146e664620 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 16 Dec 2022 13:16:07 +0000 Subject: [PATCH 1/3] Bump decode-uri-component from 0.2.0 to 0.2.2 Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2. - [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases) - [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2) --- updated-dependencies: - dependency-name: decode-uri-component dependency-type: indirect ... Signed-off-by: dependabot[bot] --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index f9e07f61c..06c6e588a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8950,9 +8950,9 @@ decimal.js@^10.3.1: integrity sha512-Nv6ENEzyPQ6AItkGwLE2PGKinZZ9g59vSh2BeH6NqPu0OTKZ5ruJsVqh/orbAnqXc9pBbgXAIrc2EyaCj8NpGg== decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha512-hjf+xovcEn31w/EUYdTXQh/8smFL/dzYjohQGEIgjyNavaJfBY2p5F527Bo1VPATxv0VYTUC2bOcXvqFwk78Og== + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== dedent@^0.7.0: version "0.7.0" From 5d06b131418a0d650f8436d19f9eb54f3afc4b48 Mon Sep 17 00:00:00 2001 From: Daniel Devaud Date: Wed, 12 Jul 2023 15:59:50 +0200 Subject: [PATCH 2/3] Added STAKE order type - Calculation handling - Displaying - DB & Controller update --- .../portfolio-position-detail.interface.ts | 1 + .../src/app/portfolio/portfolio-calculator.ts | 19 +++++++++++++-- .../src/app/portfolio/portfolio.service.ts | 23 ++++++++++++++++--- .../position-detail-dialog.component.ts | 3 +++ .../position-detail-dialog.html | 16 ++++++++++++- ...ate-or-update-activity-dialog.component.ts | 6 ++++- .../create-or-update-activity-dialog.html | 8 ++++++- .../app/services/import-activities.service.ts | 2 ++ .../activities-table.component.html | 9 ++++++-- .../activities-table.component.scss | 4 ++++ prisma/schema.prisma | 1 + 11 files changed, 82 insertions(+), 10 deletions(-) diff --git a/apps/api/src/app/portfolio/interfaces/portfolio-position-detail.interface.ts b/apps/api/src/app/portfolio/interfaces/portfolio-position-detail.interface.ts index 827aa25fe..df4760bb0 100644 --- a/apps/api/src/app/portfolio/interfaces/portfolio-position-detail.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/portfolio-position-detail.interface.ts @@ -10,6 +10,7 @@ export interface PortfolioPositionDetail { averagePrice: number; dataProviderInfo: DataProviderInfo; dividendInBaseCurrency: number; + stakeRewards: number; feeInBaseCurrency: number; firstBuyDate: string; grossPerformance: number; diff --git a/apps/api/src/app/portfolio/portfolio-calculator.ts b/apps/api/src/app/portfolio/portfolio-calculator.ts index 9addb29dd..07f7339eb 100644 --- a/apps/api/src/app/portfolio/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/portfolio-calculator.ts @@ -92,7 +92,7 @@ export class PortfolioCalculator { let investment = new Big(0); if (newQuantity.gt(0)) { - if (order.type === 'BUY') { + if (order.type === 'BUY' || order.type === 'STAKE') { investment = oldAccumulatedSymbol.investment.plus( order.quantity.mul(unitPrice) ); @@ -931,6 +931,7 @@ export class PortfolioCalculator { switch (type) { case 'BUY': + case 'STAKE': factor = 1; break; case 'SELL': @@ -1087,6 +1088,20 @@ export class PortfolioCalculator { marketSymbolMap[format(day, DATE_FORMAT)]?.[symbol] ?? lastUnitPrice }); + } else { + let orderIndex = orders.findIndex( + (o) => o.date === format(day, DATE_FORMAT) && o.type === 'STAKE' + ); + if (orderIndex >= 0) { + let order = orders[orderIndex]; + orders.splice(orderIndex, 1); + orders.push({ + ...order, + unitPrice: + marketSymbolMap[format(day, DATE_FORMAT)]?.[symbol] ?? + lastUnitPrice + }); + } } lastUnitPrice = last(orders).unitPrice; @@ -1156,7 +1171,7 @@ export class PortfolioCalculator { } const transactionInvestment = - order.type === 'BUY' + order.type === 'BUY' || order.type === 'STAKE' ? order.quantity.mul(order.unitPrice).mul(this.getFactor(order.type)) : totalUnits.gt(0) ? totalInvestment diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 66f3841a4..2d0e0ac23 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -702,6 +702,7 @@ export class PortfolioService { averagePrice: undefined, dataProviderInfo: undefined, dividendInBaseCurrency: undefined, + stakeRewards: undefined, feeInBaseCurrency: undefined, firstBuyDate: undefined, grossPerformance: undefined, @@ -730,7 +731,11 @@ export class PortfolioService { .filter((order) => { tags = tags.concat(order.tags); - return order.type === 'BUY' || order.type === 'SELL'; + return ( + order.type === 'BUY' || + order.type === 'SELL' || + order.type === 'STAKE' + ); }) .map((order) => ({ currency: order.SymbolProfile.currency, @@ -786,6 +791,16 @@ export class PortfolioService { }) ); + const stakeRewards = getSum( + orders + .filter(({ type }) => { + return type === 'STAKE'; + }) + .map(({ quantity }) => { + return new Big(quantity); + }) + ); + // Convert investment, gross and net performance to currency of user const investment = this.exchangeRateDataService.toCurrency( position.investment?.toNumber(), @@ -880,6 +895,7 @@ export class PortfolioService { averagePrice: averagePrice.toNumber(), dataProviderInfo: portfolioCalculator.getDataProviderInfos()?.[0], dividendInBaseCurrency: dividendInBaseCurrency.toNumber(), + stakeRewards: stakeRewards.toNumber(), feeInBaseCurrency: this.exchangeRateDataService.toCurrency( fee.toNumber(), SymbolProfile.currency, @@ -943,6 +959,7 @@ export class PortfolioService { averagePrice: 0, dataProviderInfo: undefined, dividendInBaseCurrency: 0, + stakeRewards: 0, feeInBaseCurrency: 0, firstBuyDate: undefined, grossPerformance: undefined, @@ -1403,7 +1420,7 @@ export class PortfolioService { let valueInBaseCurrencyOfEmergencyFundPositions = new Big(0); for (const order of emergencyFundOrders) { - if (order.type === 'BUY') { + if (order.type === 'BUY' || order.type === 'STAKE') { valueInBaseCurrencyOfEmergencyFundPositions = valueInBaseCurrencyOfEmergencyFundPositions.plus( order.valueInBaseCurrency @@ -1714,7 +1731,7 @@ export class PortfolioService { userCurrency, userId, withExcludedAccounts, - types: ['BUY', 'SELL'] + types: ['BUY', 'SELL', 'STAKE'] }); if (orders.length <= 0) { diff --git a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts index bc68cf231..ffa167a00 100644 --- a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts +++ b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.component.ts @@ -40,6 +40,7 @@ export class PositionDetailDialog implements OnDestroy, OnInit { }; public dataProviderInfo: DataProviderInfo; public dividendInBaseCurrency: number; + public stakeRewards: number; public feeInBaseCurrency: number; public firstBuyDate: string; public grossPerformance: number; @@ -84,6 +85,7 @@ export class PositionDetailDialog implements OnDestroy, OnInit { averagePrice, dataProviderInfo, dividendInBaseCurrency, + stakeRewards, feeInBaseCurrency, firstBuyDate, grossPerformance, @@ -107,6 +109,7 @@ export class PositionDetailDialog implements OnDestroy, OnInit { this.countries = {}; this.dataProviderInfo = dataProviderInfo; this.dividendInBaseCurrency = dividendInBaseCurrency; + this.stakeRewards = stakeRewards; this.feeInBaseCurrency = feeInBaseCurrency; this.firstBuyDate = firstBuyDate; this.grossPerformance = grossPerformance; diff --git a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html index 379250fcd..d6ebc8e86 100644 --- a/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html +++ b/apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html @@ -126,7 +126,10 @@ >Investment -
+
Dividend
+ +
+ Stake Rewards + +
Buy Dividend + Stake reward / Stockdividend Item Liability Sell @@ -102,7 +105,10 @@
-
+
diff --git a/apps/client/src/app/services/import-activities.service.ts b/apps/client/src/app/services/import-activities.service.ts index 02eeb7e03..5235080f7 100644 --- a/apps/client/src/app/services/import-activities.service.ts +++ b/apps/client/src/app/services/import-activities.service.ts @@ -346,6 +346,8 @@ export class ImportActivitiesService { return Type.LIABILITY; case 'sell': return Type.SELL; + case 'stake': + return Type.STAKE; default: break; } diff --git a/libs/ui/src/lib/activities-table/activities-table.component.html b/libs/ui/src/lib/activities-table/activities-table.component.html index 472a46f10..b7406f3e2 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.html +++ b/libs/ui/src/lib/activities-table/activities-table.component.html @@ -163,11 +163,16 @@ dividend: element.type === 'DIVIDEND', item: element.type === 'ITEM', liability: element.type === 'LIABILITY', - sell: element.type === 'SELL' + sell: element.type === 'SELL', + stake: element.type === 'STAKE' }" > Date: Sat, 15 Jul 2023 12:11:23 +0200 Subject: [PATCH 3/3] Refactored performance calculations - Avoiding multiple iterations over same array - Some Refactorings for readability --- .../src/app/portfolio/portfolio-calculator.ts | 56 ++--- .../src/app/portfolio/portfolio.controller.ts | 100 ++++---- .../src/app/portfolio/portfolio.service.ts | 227 ++++++++++++------ 3 files changed, 225 insertions(+), 158 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio-calculator.ts b/apps/api/src/app/portfolio/portfolio-calculator.ts index 07f7339eb..c0c042925 100644 --- a/apps/api/src/app/portfolio/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/portfolio-calculator.ts @@ -3,6 +3,7 @@ import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfac import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper'; import { DataProviderInfo, + HistoricalDataItem, ResponseError, TimelinePosition } from '@ghostfolio/common/interfaces'; @@ -277,46 +278,29 @@ export class PortfolioCalculator { }; } - for (const currentDate of dates) { - const dateString = format(currentDate, DATE_FORMAT); + return dates.map((date) => { + const dateString = format(date, DATE_FORMAT); + let totalCurrentValue = new Big(0); + let totalInvestmentValue = new Big(0); + let maxTotalInvestmentValue = new Big(0); + let totalNetPerformanceValue = new Big(0); for (const symbol of Object.keys(valuesBySymbol)) { const symbolValues = valuesBySymbol[symbol]; - const currentValue = - symbolValues.currentValues?.[dateString] ?? new Big(0); - const investmentValue = - symbolValues.investmentValues?.[dateString] ?? new Big(0); - const maxInvestmentValue = - symbolValues.maxInvestmentValues?.[dateString] ?? new Big(0); - const netPerformanceValue = - symbolValues.netPerformanceValues?.[dateString] ?? new Big(0); - - valuesByDate[dateString] = { - totalCurrentValue: ( - valuesByDate[dateString]?.totalCurrentValue ?? new Big(0) - ).add(currentValue), - totalInvestmentValue: ( - valuesByDate[dateString]?.totalInvestmentValue ?? new Big(0) - ).add(investmentValue), - maxTotalInvestmentValue: ( - valuesByDate[dateString]?.maxTotalInvestmentValue ?? new Big(0) - ).add(maxInvestmentValue), - totalNetPerformanceValue: ( - valuesByDate[dateString]?.totalNetPerformanceValue ?? new Big(0) - ).add(netPerformanceValue) - }; + totalCurrentValue = totalCurrentValue.plus( + symbolValues.currentValues?.[dateString] ?? new Big(0) + ); + totalInvestmentValue = totalInvestmentValue.plus( + symbolValues.investmentValues?.[dateString] ?? new Big(0) + ); + maxTotalInvestmentValue = maxTotalInvestmentValue.plus( + symbolValues.maxInvestmentValues?.[dateString] ?? new Big(0) + ); + totalNetPerformanceValue = totalNetPerformanceValue.plus( + symbolValues.netPerformanceValues?.[dateString] ?? new Big(0) + ); } - } - - return Object.entries(valuesByDate).map(([date, values]) => { - const { - maxTotalInvestmentValue, - totalCurrentValue, - totalInvestmentValue, - totalNetPerformanceValue - } = values; - const netPerformanceInPercentage = maxTotalInvestmentValue.eq(0) ? 0 : totalNetPerformanceValue @@ -325,7 +309,7 @@ export class PortfolioCalculator { .toNumber(); return { - date, + date: dateString, netPerformanceInPercentage, netPerformance: totalNetPerformanceValue.toNumber(), totalInvestment: totalInvestmentValue.toNumber(), diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 06f841e12..d1f76a97c 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -111,21 +111,38 @@ export class PortfolioController { impersonationId || this.userService.isRestrictedView(this.request.user) ) { - const totalInvestment = Object.values(holdings) - .map((portfolioPosition) => { - return portfolioPosition.investment; - }) - .reduce((a, b) => a + b, 0); - - const totalValue = Object.values(holdings) - .map((portfolioPosition) => { - return this.exchangeRateDataService.toCurrency( - portfolioPosition.quantity * portfolioPosition.marketPrice, - portfolioPosition.currency, - this.request.user.Settings.settings.baseCurrency - ); - }) - .reduce((a, b) => a + b, 0); + let investmentTuple: [number, number] = [0, 0]; + for (let holding of Object.entries(holdings)) { + var portfolioPosition = holding[1]; + investmentTuple[0] += portfolioPosition.investment; + investmentTuple[1] += this.exchangeRateDataService.toCurrency( + portfolioPosition.quantity * portfolioPosition.marketPrice, + portfolioPosition.currency, + this.request.user.Settings.settings.baseCurrency + ); + } + const totalInvestment = investmentTuple[0]; + + const totalValue = investmentTuple[1]; + + if (hasDetails === false) { + portfolioSummary = nullifyValuesInObject(summary, [ + 'cash', + 'committedFunds', + 'currentGrossPerformance', + 'currentNetPerformance', + 'currentValue', + 'dividend', + 'emergencyFund', + 'excludedAccountsAndActivities', + 'fees', + 'items', + 'liabilities', + 'netWorth', + 'totalBuy', + 'totalSell' + ]); + } for (const [symbol, portfolioPosition] of Object.entries(holdings)) { portfolioPosition.grossPerformance = null; @@ -135,6 +152,24 @@ export class PortfolioController { portfolioPosition.quantity = null; portfolioPosition.valueInPercentage = portfolioPosition.value / totalValue; + (portfolioPosition.assetClass = hasDetails + ? portfolioPosition.assetClass + : undefined), + (portfolioPosition.assetSubClass = hasDetails + ? portfolioPosition.assetSubClass + : undefined), + (portfolioPosition.countries = hasDetails + ? portfolioPosition.countries + : []), + (portfolioPosition.currency = hasDetails + ? portfolioPosition.currency + : undefined), + (portfolioPosition.markets = hasDetails + ? portfolioPosition.markets + : undefined), + (portfolioPosition.sectors = hasDetails + ? portfolioPosition.sectors + : []); } for (const [name, { valueInBaseCurrency }] of Object.entries(accounts)) { @@ -146,41 +181,6 @@ export class PortfolioController { } } - if ( - hasDetails === false || - impersonationId || - this.userService.isRestrictedView(this.request.user) - ) { - portfolioSummary = nullifyValuesInObject(summary, [ - 'cash', - 'committedFunds', - 'currentGrossPerformance', - 'currentNetPerformance', - 'currentValue', - 'dividend', - 'emergencyFund', - 'excludedAccountsAndActivities', - 'fees', - 'items', - 'liabilities', - 'netWorth', - 'totalBuy', - 'totalSell' - ]); - } - - for (const [symbol, portfolioPosition] of Object.entries(holdings)) { - holdings[symbol] = { - ...portfolioPosition, - assetClass: hasDetails ? portfolioPosition.assetClass : undefined, - assetSubClass: hasDetails ? portfolioPosition.assetSubClass : undefined, - countries: hasDetails ? portfolioPosition.countries : [], - currency: hasDetails ? portfolioPosition.currency : undefined, - markets: hasDetails ? portfolioPosition.markets : undefined, - sectors: hasDetails ? portfolioPosition.sectors : [] - }; - } - return { accounts, filteredValueInBaseCurrency, diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 2d0e0ac23..feb70c861 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -522,11 +522,9 @@ export class PortfolioService { } const portfolioItemsNow: { [symbol: string]: TimelinePosition } = {}; - for (const position of currentPositions.positions) { - portfolioItemsNow[position.symbol] = position; - } for (const item of currentPositions.positions) { + portfolioItemsNow[item.symbol] = item; if (item.quantity.lte(0)) { // Ignore positions without any quantity continue; @@ -542,21 +540,7 @@ export class PortfolioService { otherMarkets: 0 }; - for (const country of symbolProfile.countries) { - if (developedMarkets.includes(country.code)) { - markets.developedMarkets = new Big(markets.developedMarkets) - .plus(country.weight) - .toNumber(); - } else if (emergingMarkets.includes(country.code)) { - markets.emergingMarkets = new Big(markets.emergingMarkets) - .plus(country.weight) - .toNumber(); - } else { - markets.otherMarkets = new Big(markets.otherMarkets) - .plus(country.weight) - .toNumber(); - } - } + this.calculateMarketsAllocation(symbolProfile, markets); holdings[item.symbol] = { markets, @@ -587,6 +571,68 @@ export class PortfolioService { }; } + await this.handleCashPosition( + filters, + isFilteredByAccount, + cashDetails, + userCurrency, + filteredValueInBaseCurrency, + holdings + ); + + const { accounts, platforms } = await this.getValueOfAccountsAndPlatforms({ + filters, + orders, + portfolioItemsNow, + userCurrency, + userId, + withExcludedAccounts + }); + + filteredValueInBaseCurrency = await this.handleEmergencyFunds( + filters, + cashDetails, + userCurrency, + filteredValueInBaseCurrency, + emergencyFund, + orders, + accounts, + holdings + ); + + const summary = await this.getSummary({ + impersonationId, + userCurrency, + userId, + balanceInBaseCurrency: cashDetails.balanceInBaseCurrency, + emergencyFundPositionsValueInBaseCurrency: + this.getEmergencyFundPositionsValueInBaseCurrency({ + activities: orders + }) + }); + + return { + accounts, + holdings, + platforms, + summary, + filteredValueInBaseCurrency: filteredValueInBaseCurrency.toNumber(), + filteredValueInPercentage: summary.netWorth + ? filteredValueInBaseCurrency.div(summary.netWorth).toNumber() + : 0, + hasErrors: currentPositions.hasErrors, + totalValueInBaseCurrency: summary.netWorth + }; + } + + private async handleCashPosition( + filters: Filter[], + isFilteredByAccount: boolean, + cashDetails: CashDetails, + userCurrency: string, + filteredValueInBaseCurrency: Big, + holdings: { [symbol: string]: PortfolioPosition } + ) { const isFilteredByCash = filters?.some((filter) => { return filter.type === 'ASSET_CLASS' && filter.id === 'CASH'; }); @@ -602,16 +648,26 @@ export class PortfolioService { holdings[symbol] = cashPositions[symbol]; } } + } - const { accounts, platforms } = await this.getValueOfAccountsAndPlatforms({ - filters, - orders, - portfolioItemsNow, - userCurrency, - userId, - withExcludedAccounts - }); - + private async handleEmergencyFunds( + filters: Filter[], + cashDetails: CashDetails, + userCurrency: string, + filteredValueInBaseCurrency: Big, + emergencyFund: Big, + orders: Activity[], + accounts: { + [id: string]: { + balance: number; + currency: string; + name: string; + valueInBaseCurrency: number; + valueInPercentage?: number; + }; + }, + holdings: { [symbol: string]: PortfolioPosition } + ) { if ( filters?.length === 1 && filters[0].id === EMERGENCY_FUND_TAG_ID && @@ -646,30 +702,32 @@ export class PortfolioService { value: emergencyFundInCash }; } + return filteredValueInBaseCurrency; + } - const summary = await this.getSummary({ - impersonationId, - userCurrency, - userId, - balanceInBaseCurrency: cashDetails.balanceInBaseCurrency, - emergencyFundPositionsValueInBaseCurrency: - this.getEmergencyFundPositionsValueInBaseCurrency({ - activities: orders - }) - }); - - return { - accounts, - holdings, - platforms, - summary, - filteredValueInBaseCurrency: filteredValueInBaseCurrency.toNumber(), - filteredValueInPercentage: summary.netWorth - ? filteredValueInBaseCurrency.div(summary.netWorth).toNumber() - : 0, - hasErrors: currentPositions.hasErrors, - totalValueInBaseCurrency: summary.netWorth - }; + private calculateMarketsAllocation( + symbolProfile: EnhancedSymbolProfile, + markets: { + developedMarkets: number; + emergingMarkets: number; + otherMarkets: number; + } + ) { + for (const country of symbolProfile.countries) { + if (developedMarkets.includes(country.code)) { + markets.developedMarkets = new Big(markets.developedMarkets) + .plus(country.weight) + .toNumber(); + } else if (emergingMarkets.includes(country.code)) { + markets.emergingMarkets = new Big(markets.emergingMarkets) + .plus(country.weight) + .toNumber(); + } else { + markets.otherMarkets = new Big(markets.otherMarkets) + .plus(country.weight) + .toNumber(); + } + } } public async getPosition( @@ -1607,38 +1665,63 @@ export class PortfolioService { userId }); - const activities = await this.orderService.getOrders({ + const ordersRaw = await this.orderService.getOrders({ userCurrency, - userId - }); - - const excludedActivities = ( - await this.orderService.getOrders({ - userCurrency, - userId, - withExcludedAccounts: true - }) - ).filter(({ Account: account }) => { - return account?.isExcluded ?? false; + userId, + withExcludedAccounts: true }); + const activities: Activity[] = []; + const excludedActivities: Activity[] = []; + let dividend = 0; + let fees = 0; + let items = 0; + + let liabilities = 0; + + let totalBuy = 0; + let totalSell = 0; + for (let order of ordersRaw) { + if (order.Account?.isExcluded ?? false) { + excludedActivities.push(order); + } else { + activities.push(order); + fees += this.exchangeRateDataService.toCurrency( + order.fee, + order.SymbolProfile.currency, + userCurrency + ); + let amount = this.exchangeRateDataService.toCurrency( + new Big(order.quantity).mul(order.unitPrice).toNumber(), + order.SymbolProfile.currency, + userCurrency + ); + switch (order.type) { + case 'DIVIDEND': + dividend += amount; + break; + case 'ITEM': + items += amount; + break; + case 'SELL': + totalSell += amount; + break; + case 'BUY': + totalBuy += amount; + break; + case 'LIABILITY': + liabilities += amount; + } + } + } - const dividend = this.getDividend({ - activities, - userCurrency - }).toNumber(); const emergencyFund = new Big( Math.max( emergencyFundPositionsValueInBaseCurrency, (user.Settings?.settings as UserSettings)?.emergencyFund ?? 0 ) ); - const fees = this.getFees({ activities, userCurrency }).toNumber(); - const firstOrderDate = activities[0]?.date; - const items = this.getItems(activities).toNumber(); - const liabilities = this.getLiabilities(activities).toNumber(); - const totalBuy = this.getTotalByType(activities, userCurrency, 'BUY'); - const totalSell = this.getTotalByType(activities, userCurrency, 'SELL'); + const firstOrderDate = activities[0]?.date; const cash = new Big(balanceInBaseCurrency) .minus(emergencyFund)