From 85c1bde3078f6754945e2a49776b0512a6394016 Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Wed, 1 Oct 2025 23:15:09 +0700 Subject: [PATCH 01/13] feat(api): calculate net performance with currency effect for cash positions --- .../src/app/portfolio/portfolio.service.ts | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index f5b4ab1c6..d31beecb0 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -662,9 +662,26 @@ export class PortfolioService { }; } + const { endDate, startDate } = getIntervalFromDateRange( + dateRange, + portfolioCalculator.getStartDate() + ); + + // Gather historical exchange rate data for all currencies in cash positions + const exchangeRatesByCurrency = + await this.exchangeRateDataService.getExchangeRatesByCurrency({ + currencies: [ + ...new Set(cashDetails.accounts.map(({ currency }) => currency)) + ], + endDate, + startDate, + targetCurrency: userCurrency + }); + if (filters?.length === 0 || isFilteredByAccount || isFilteredByCash) { const cashPositions = this.getCashPositions({ cashDetails, + exchangeRatesByCurrency, userCurrency, value: filteredValueInBaseCurrency }); @@ -690,6 +707,7 @@ export class PortfolioService { ) { const emergencyFundCashPositions = this.getCashPositions({ cashDetails, + exchangeRatesByCurrency, userCurrency, value: filteredValueInBaseCurrency }); @@ -1625,10 +1643,14 @@ export class PortfolioService { private getCashPositions({ cashDetails, + exchangeRatesByCurrency, userCurrency, value }: { cashDetails: CashDetails; + exchangeRatesByCurrency: Awaited< + ReturnType + >; userCurrency: string; value: Big; }) { @@ -1650,24 +1672,48 @@ export class PortfolioService { continue; } + const exchangeRates = + exchangeRatesByCurrency[`${account.currency}${userCurrency}`]; + + // Calculate the performance of the cash position including currency effects + const netPerformanceWithCurrencyEffect = new Big(account.balance) + .mul(exchangeRates?.[format(new Date(), DATE_FORMAT)] ?? 1) + .minus( + new Big(account.balance).mul( + exchangeRates?.[format(account.createdAt, DATE_FORMAT)] ?? 1 + ) + ) + .toNumber(); + if (cashPositions[account.currency]) { cashPositions[account.currency].investment += convertedBalance; + cashPositions[account.currency].netPerformanceWithCurrencyEffect += + netPerformanceWithCurrencyEffect; cashPositions[account.currency].valueInBaseCurrency += convertedBalance; } else { cashPositions[account.currency] = this.getInitialCashPosition({ balance: convertedBalance, currency: account.currency }); + + cashPositions[account.currency].netPerformanceWithCurrencyEffect = + netPerformanceWithCurrencyEffect; } } for (const symbol of Object.keys(cashPositions)) { - // Calculate allocations for each currency + // Calculate allocations and net performances for each currency cashPositions[symbol].allocationInPercentage = value.gt(0) ? new Big(cashPositions[symbol].valueInBaseCurrency) .div(value) .toNumber() : 0; + cashPositions[symbol].netPerformancePercentWithCurrencyEffect = + cashPositions[symbol].investment > 0 + ? new Big(cashPositions[symbol].netPerformanceWithCurrencyEffect) + .div(cashPositions[symbol].investment) + .toNumber() + : 0; } return cashPositions; From ca812639e910f05480a93bae14692724458a63b4 Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Wed, 1 Oct 2025 23:15:20 +0700 Subject: [PATCH 02/13] feat(docs): update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eca7c850c..846181a0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased +### Added + +- Extended holdings endpoint by performance with currency effect for cash + ### Changed - Improved the language localization for German (`de`) From 1713a0e9d531bebfc9774f1777e41b06e3777f36 Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Wed, 1 Oct 2025 23:21:42 +0700 Subject: [PATCH 03/13] fix(api): update comment --- apps/api/src/app/portfolio/portfolio.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index d31beecb0..8415e24a5 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1702,7 +1702,7 @@ export class PortfolioService { } for (const symbol of Object.keys(cashPositions)) { - // Calculate allocations and net performances for each currency + // Calculate allocations and net performance percentages for each currency cashPositions[symbol].allocationInPercentage = value.gt(0) ? new Big(cashPositions[symbol].valueInBaseCurrency) .div(value) From b452b6cb00fd363857d5f02a68b325ed8e6cc8ae Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Sun, 12 Oct 2025 15:45:13 +0700 Subject: [PATCH 04/13] feat(types): create ExchangeRatesByCurrency interface --- apps/api/src/app/portfolio/portfolio.service.ts | 5 ++--- .../exchange-rate-data/exchange-rate-data.service.ts | 4 +++- .../interfaces/exchange-rate-data.interface.ts | 5 +++++ 3 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 apps/api/src/services/exchange-rate-data/interfaces/exchange-rate-data.interface.ts diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index bb8ad2130..cc6d57954 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -24,6 +24,7 @@ import { RegionalMarketClusterRiskNorthAmerica } from '@ghostfolio/api/models/ru import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; +import { ExchangeRatesByCurrency } from '@ghostfolio/api/services/exchange-rate-data/interfaces/exchange-rate-data.interface'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; @@ -1648,9 +1649,7 @@ export class PortfolioService { value }: { cashDetails: CashDetails; - exchangeRatesByCurrency: Awaited< - ReturnType - >; + exchangeRatesByCurrency: ExchangeRatesByCurrency; userCurrency: string; value: Big; }) { diff --git a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts index 433547c94..42551a3e2 100644 --- a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts +++ b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts @@ -26,6 +26,8 @@ import { import { isNumber } from 'lodash'; import ms from 'ms'; +import { ExchangeRatesByCurrency } from './interfaces/exchange-rate-data.interface'; + @Injectable() export class ExchangeRateDataService { private currencies: string[] = []; @@ -58,7 +60,7 @@ export class ExchangeRateDataService { endDate?: Date; startDate: Date; targetCurrency: string; - }) { + }): Promise { if (!startDate) { return {}; } diff --git a/apps/api/src/services/exchange-rate-data/interfaces/exchange-rate-data.interface.ts b/apps/api/src/services/exchange-rate-data/interfaces/exchange-rate-data.interface.ts new file mode 100644 index 000000000..8e0d2c0d4 --- /dev/null +++ b/apps/api/src/services/exchange-rate-data/interfaces/exchange-rate-data.interface.ts @@ -0,0 +1,5 @@ +export interface ExchangeRatesByCurrency { + [currency: string]: { + [dateString: string]: number; + }; +} From c15c3d0fbd91ed40d0a21daaa3ccbc92464e7edf Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Sun, 12 Oct 2025 15:51:09 +0700 Subject: [PATCH 05/13] fix(api): calculate from startDate to endDate --- apps/api/src/app/portfolio/portfolio.service.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index cc6d57954..b8f34b60a 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -682,7 +682,9 @@ export class PortfolioService { if (filters?.length === 0 || isFilteredByAccount || isFilteredByCash) { const cashPositions = this.getCashPositions({ cashDetails, + endDate, exchangeRatesByCurrency, + startDate, userCurrency, value: filteredValueInBaseCurrency }); @@ -708,7 +710,9 @@ export class PortfolioService { ) { const emergencyFundCashPositions = this.getCashPositions({ cashDetails, + endDate, exchangeRatesByCurrency, + startDate, userCurrency, value: filteredValueInBaseCurrency }); @@ -1644,12 +1648,16 @@ export class PortfolioService { private getCashPositions({ cashDetails, + endDate, exchangeRatesByCurrency, + startDate, userCurrency, value }: { cashDetails: CashDetails; + endDate: Date; exchangeRatesByCurrency: ExchangeRatesByCurrency; + startDate: Date; userCurrency: string; value: Big; }) { @@ -1676,10 +1684,10 @@ export class PortfolioService { // Calculate the performance of the cash position including currency effects const netPerformanceWithCurrencyEffect = new Big(account.balance) - .mul(exchangeRates?.[format(new Date(), DATE_FORMAT)] ?? 1) + .mul(exchangeRates?.[format(endDate, DATE_FORMAT)] ?? 1) .minus( new Big(account.balance).mul( - exchangeRates?.[format(account.createdAt, DATE_FORMAT)] ?? 1 + exchangeRates?.[format(startDate, DATE_FORMAT)] ?? 1 ) ) .toNumber(); From 194daab9ceda8a4107cc6dac89a992971856c81a Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Sun, 12 Oct 2025 16:57:10 +0700 Subject: [PATCH 06/13] fix(docs): update changelog --- CHANGELOG.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a967989f..39b04a775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added a _Storybook_ story for the holdings table component +- Extended holdings endpoint by performance with currency effect for cash ### Changed @@ -61,10 +62,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 2.206.0 - 2025-10-04 -### Added - -- Extended holdings endpoint by performance with currency effect for cash - ### Changed - Localized the number formatting in the settings dialog to customize the rule thresholds of the _X-ray_ page From fd5d4bb4455b17c0d6e6e05f693cb1153fd78246 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 13 Oct 2025 20:53:44 +0200 Subject: [PATCH 07/13] Refactoring --- apps/api/src/app/portfolio/portfolio.service.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index b8f34b60a..53bfc7679 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -671,11 +671,15 @@ export class PortfolioService { // Gather historical exchange rate data for all currencies in cash positions const exchangeRatesByCurrency = await this.exchangeRateDataService.getExchangeRatesByCurrency({ - currencies: [ - ...new Set(cashDetails.accounts.map(({ currency }) => currency)) - ], endDate, startDate, + currencies: [ + ...new Set( + cashDetails.accounts.map(({ currency }) => { + return currency; + }) + ) + ], targetCurrency: userCurrency }); @@ -1694,8 +1698,10 @@ export class PortfolioService { if (cashPositions[account.currency]) { cashPositions[account.currency].investment += convertedBalance; + cashPositions[account.currency].netPerformanceWithCurrencyEffect += netPerformanceWithCurrencyEffect; + cashPositions[account.currency].valueInBaseCurrency += convertedBalance; } else { cashPositions[account.currency] = this.getInitialCashPosition({ @@ -1715,6 +1721,7 @@ export class PortfolioService { .div(value) .toNumber() : 0; + cashPositions[symbol].netPerformancePercentWithCurrencyEffect = cashPositions[symbol].investment > 0 ? new Big(cashPositions[symbol].netPerformanceWithCurrencyEffect) From 579cd00de778e110ad2ecc4370924842fb4182ba Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 13 Oct 2025 20:55:28 +0200 Subject: [PATCH 08/13] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 39b04a775..0ed4c1fa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Extended the holdings endpoint to include the performance with currency effect for cash - Added a _Storybook_ story for the holdings table component -- Extended holdings endpoint by performance with currency effect for cash ### Changed From c4b756ce06440e393416bc22d26bd2bf2923c749 Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Sat, 25 Oct 2025 08:27:46 +0700 Subject: [PATCH 09/13] fix(docs): update changelog --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a8cd85f1..4a20e4904 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ 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/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Extended the holdings endpoint to include the performance with currency effect for cash + ## 2.211.0-beta.0 - 2025-10-24 ### Added @@ -29,7 +35,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added support for data gathering by date range in the asset profile details dialog of the admin control panel -- Extended the holdings endpoint to include the performance with currency effect for cash ### Changed From c9fe50d9e75961c15d3242f230ffbbb501e5bb2e Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Sun, 26 Oct 2025 13:03:17 +0700 Subject: [PATCH 10/13] feat(api): create get cash activities method --- .../src/app/portfolio/portfolio.service.ts | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index e2836e643..53efc34a3 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -320,6 +320,92 @@ export class PortfolioService { }; } + public async getCashActivities({ + cashDetails, + userCurrency, + userId + }: { + cashDetails: CashDetails; + userCurrency: string; + userId: string; + }) { + const syntheticActivities: Activity[] = []; + + for (const account of cashDetails.accounts) { + const { balances } = await this.accountBalanceService.getAccountBalances({ + filters: [{ id: account.id, type: 'ACCOUNT' }], + userCurrency, + userId + }); + + let currentBalance = 0; + let currentBalanceInBaseCurrency = 0; + for (const balanceItem of balances) { + const syntheticActivityTemplate: Activity = { + userId, + accountId: account.id, + accountUserId: account.userId, + comment: account.name, + createdAt: new Date(balanceItem.date), + currency: account.currency, + date: new Date(balanceItem.date), + fee: 0, + feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, + id: balanceItem.id, + isDraft: false, + quantity: 1, + SymbolProfile: { + activitiesCount: 0, + assetClass: 'LIQUIDITY', + assetSubClass: 'CASH', + countries: [], + createdAt: new Date(balanceItem.date), + currency: account.currency, + dataSource: 'YAHOO', + holdings: [], + id: account.currency, + isActive: true, + sectors: [], + symbol: account.currency, + updatedAt: new Date(balanceItem.date) + }, + symbolProfileId: account.currency, + type: 'BUY', + unitPrice: 1, + unitPriceInAssetProfileCurrency: 1, + updatedAt: new Date(balanceItem.date), + valueInBaseCurrency: 0, + value: 0 + }; + + if (currentBalance < balanceItem.value) { + // BUY + syntheticActivities.push({ + ...syntheticActivityTemplate, + type: 'BUY', + value: balanceItem.value - currentBalance, + valueInBaseCurrency: + balanceItem.valueInBaseCurrency - currentBalanceInBaseCurrency + }); + } else if (currentBalance > balanceItem.value) { + // SELL + syntheticActivities.push({ + ...syntheticActivityTemplate, + type: 'SELL', + value: currentBalance - balanceItem.value, + valueInBaseCurrency: + currentBalanceInBaseCurrency - balanceItem.valueInBaseCurrency + }); + } + currentBalance = balanceItem.value; + currentBalanceInBaseCurrency = balanceItem.valueInBaseCurrency; + } + } + + return syntheticActivities; + } + public async getDividends({ activities, groupBy From 2bfd92cb9cb3599b3c37a26dbac3dfc5bf73b340 Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Sun, 26 Oct 2025 13:04:48 +0700 Subject: [PATCH 11/13] feat(api): add synthetic activities into calculator --- .../src/app/portfolio/portfolio.service.ts | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 53efc34a3..081575001 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -575,6 +575,7 @@ export class PortfolioService { (user.settings?.settings as UserSettings)?.emergencyFund ?? 0 ); + // Activities for non-cash assets const { activities } = await this.orderService.getOrdersForPortfolioCalculator({ filters, @@ -582,23 +583,29 @@ export class PortfolioService { userId }); - const portfolioCalculator = this.calculatorFactory.createCalculator({ - activities, + // Synthetic activities for cash + const cashDetails = await this.accountService.getCashDetails({ filters, userId, - calculationType: this.getUserPerformanceCalculationType(user), currency: userCurrency }); + const cashActivities = await this.getCashActivities({ + cashDetails, + userCurrency, + userId + }); - const { createdAt, currentValueInBaseCurrency, hasErrors, positions } = - await portfolioCalculator.getSnapshot(); - - const cashDetails = await this.accountService.getCashDetails({ + const portfolioCalculator = this.calculatorFactory.createCalculator({ filters, userId, + activities: [...activities, ...cashActivities], + calculationType: this.getUserPerformanceCalculationType(user), currency: userCurrency }); + const { createdAt, currentValueInBaseCurrency, hasErrors, positions } = + await portfolioCalculator.getSnapshot(); + const holdings: PortfolioDetails['holdings'] = {}; const totalValueInBaseCurrency = currentValueInBaseCurrency.plus( From 2dd6aeca3a136b9459a15172aebab44894bb17cd Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Sun, 26 Oct 2025 13:06:24 +0700 Subject: [PATCH 12/13] fix(api): revert changes on getCashPositions --- .../src/app/portfolio/portfolio.service.ts | 61 +------------------ 1 file changed, 1 insertion(+), 60 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 081575001..ac5091bfb 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -24,7 +24,6 @@ import { RegionalMarketClusterRiskNorthAmerica } from '@ghostfolio/api/models/ru import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; -import { ExchangeRatesByCurrency } from '@ghostfolio/api/services/exchange-rate-data/interfaces/exchange-rate-data.interface'; import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; @@ -756,32 +755,9 @@ export class PortfolioService { }; } - const { endDate, startDate } = getIntervalFromDateRange( - dateRange, - portfolioCalculator.getStartDate() - ); - - // Gather historical exchange rate data for all currencies in cash positions - const exchangeRatesByCurrency = - await this.exchangeRateDataService.getExchangeRatesByCurrency({ - endDate, - startDate, - currencies: [ - ...new Set( - cashDetails.accounts.map(({ currency }) => { - return currency; - }) - ) - ], - targetCurrency: userCurrency - }); - if (filters?.length === 0 || isFilteredByAccount || isFilteredByCash) { const cashPositions = this.getCashPositions({ cashDetails, - endDate, - exchangeRatesByCurrency, - startDate, userCurrency, value: filteredValueInBaseCurrency }); @@ -807,9 +783,6 @@ export class PortfolioService { ) { const emergencyFundCashPositions = this.getCashPositions({ cashDetails, - endDate, - exchangeRatesByCurrency, - startDate, userCurrency, value: filteredValueInBaseCurrency }); @@ -1745,16 +1718,10 @@ export class PortfolioService { private getCashPositions({ cashDetails, - endDate, - exchangeRatesByCurrency, - startDate, userCurrency, value }: { cashDetails: CashDetails; - endDate: Date; - exchangeRatesByCurrency: ExchangeRatesByCurrency; - startDate: Date; userCurrency: string; value: Big; }) { @@ -1776,51 +1743,25 @@ export class PortfolioService { continue; } - const exchangeRates = - exchangeRatesByCurrency[`${account.currency}${userCurrency}`]; - - // Calculate the performance of the cash position including currency effects - const netPerformanceWithCurrencyEffect = new Big(account.balance) - .mul(exchangeRates?.[format(endDate, DATE_FORMAT)] ?? 1) - .minus( - new Big(account.balance).mul( - exchangeRates?.[format(startDate, DATE_FORMAT)] ?? 1 - ) - ) - .toNumber(); - if (cashPositions[account.currency]) { cashPositions[account.currency].investment += convertedBalance; - cashPositions[account.currency].netPerformanceWithCurrencyEffect += - netPerformanceWithCurrencyEffect; - cashPositions[account.currency].valueInBaseCurrency += convertedBalance; } else { cashPositions[account.currency] = this.getInitialCashPosition({ balance: convertedBalance, currency: account.currency }); - - cashPositions[account.currency].netPerformanceWithCurrencyEffect = - netPerformanceWithCurrencyEffect; } } for (const symbol of Object.keys(cashPositions)) { - // Calculate allocations and net performance percentages for each currency + // Calculate allocations for each currency cashPositions[symbol].allocationInPercentage = value.gt(0) ? new Big(cashPositions[symbol].valueInBaseCurrency) .div(value) .toNumber() : 0; - - cashPositions[symbol].netPerformancePercentWithCurrencyEffect = - cashPositions[symbol].investment > 0 - ? new Big(cashPositions[symbol].netPerformanceWithCurrencyEffect) - .div(cashPositions[symbol].investment) - .toNumber() - : 0; } return cashPositions; From e8918b147f892a32b505ddb427f5ef23b1530bb9 Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Sun, 26 Oct 2025 13:08:25 +0700 Subject: [PATCH 13/13] fix(api): revert changes on getCashPositions --- apps/api/src/app/portfolio/portfolio.service.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index ac5091bfb..eaebed09e 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1745,7 +1745,6 @@ export class PortfolioService { if (cashPositions[account.currency]) { cashPositions[account.currency].investment += convertedBalance; - cashPositions[account.currency].valueInBaseCurrency += convertedBalance; } else { cashPositions[account.currency] = this.getInitialCashPosition({