From 4aa71b5e22542dfe9ce17a32a879a7a7aa8f4ded Mon Sep 17 00:00:00 2001 From: KenTandrian Date: Fri, 2 Jan 2026 13:36:23 +0700 Subject: [PATCH] feat(api): do not fetch cash asset market price --- .../calculator/portfolio-calculator.ts | 28 +++++++++++++------ .../calculator/roai/portfolio-calculator.ts | 7 +++++ .../interfaces/portfolio-order.interface.ts | 2 +- .../transaction-point-symbol.interface.ts | 1 + .../src/app/portfolio/portfolio.service.ts | 3 +- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index ee4219b58..6c16efbca 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -136,12 +136,15 @@ export abstract class PortfolioCalculator { } return { - SymbolProfile, tags, type, date: format(date, DATE_FORMAT), fee: new Big(feeInAssetProfileCurrency), quantity: new Big(quantity), + SymbolProfile: { + ...SymbolProfile, + assetSubClass: SymbolProfile.assetSubClass + }, unitPrice: new Big(unitPriceInAssetProfileCurrency) }; } @@ -203,13 +206,19 @@ export abstract class PortfolioCalculator { let totalInterestWithCurrencyEffect = new Big(0); let totalLiabilitiesWithCurrencyEffect = new Big(0); - for (const { currency, dataSource, symbol } of transactionPoints[ - firstIndex - 1 - ].items) { - dataGatheringItems.push({ - dataSource, - symbol - }); + for (const { + assetSubClass, + currency, + dataSource, + symbol + } of transactionPoints[firstIndex - 1].items) { + // Gather data for all assets except CASH + if (assetSubClass !== 'CASH') { + dataGatheringItems.push({ + dataSource, + symbol + }); + } currencies[symbol] = currency; } @@ -933,6 +942,7 @@ export abstract class PortfolioCalculator { } of this.activities) { let currentTransactionPointItem: TransactionPointSymbol; + const assetSubClass = SymbolProfile.assetSubClass; const currency = SymbolProfile.currency; const dataSource = SymbolProfile.dataSource; const factor = getFactor(type); @@ -977,6 +987,7 @@ export abstract class PortfolioCalculator { } currentTransactionPointItem = { + assetSubClass, currency, dataSource, investment, @@ -995,6 +1006,7 @@ export abstract class PortfolioCalculator { }; } else { currentTransactionPointItem = { + assetSubClass, currency, dataSource, fee, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts index d4fad7d93..738ba8446 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts @@ -188,6 +188,8 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { }) ); + const isCash = orders[0]?.SymbolProfile?.assetSubClass === 'CASH'; + if (orders.length <= 0) { return { currentValues: {}, @@ -244,6 +246,8 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { // For BUY / SELL activities with a MANUAL data source where no historical market price is available, // the calculation should fall back to using the activity’s unit price. unitPriceAtEndDate = latestActivity.unitPrice; + } else if (isCash) { + unitPriceAtEndDate = new Big(1); } if ( @@ -294,6 +298,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { itemType: 'start', quantity: new Big(0), SymbolProfile: { + assetSubClass: isCash ? 'CASH' : undefined, dataSource, symbol }, @@ -307,6 +312,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { feeInBaseCurrency: new Big(0), itemType: 'end', SymbolProfile: { + assetSubClass: isCash ? 'CASH' : undefined, dataSource, symbol }, @@ -347,6 +353,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { feeInBaseCurrency: new Big(0), quantity: new Big(0), SymbolProfile: { + assetSubClass: isCash ? 'CASH' : undefined, dataSource, symbol }, diff --git a/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts b/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts index 9362184c7..fcc8322fc 100644 --- a/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts @@ -6,7 +6,7 @@ export interface PortfolioOrder extends Pick { quantity: Big; SymbolProfile: Pick< Activity['SymbolProfile'], - 'currency' | 'dataSource' | 'name' | 'symbol' | 'userId' + 'assetSubClass' | 'currency' | 'dataSource' | 'name' | 'symbol' | 'userId' >; unitPrice: Big; } diff --git a/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts b/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts index f4ceadf3b..d81b67ce6 100644 --- a/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts @@ -2,6 +2,7 @@ import { DataSource, Tag } from '@prisma/client'; import { Big } from 'big.js'; export interface TransactionPointSymbol { + assetSubClass?: string; averagePrice: Big; currency: string; dataSource: DataSource; diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index d86cb133f..1708bca0d 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -487,7 +487,7 @@ export class PortfolioService { (user.settings?.settings as UserSettings)?.emergencyFund ?? 0 ); - // Activities for non-cash assets + // Activities for cash and non-cash assets const { activities } = await this.orderService.getOrdersForPortfolioCalculator({ filters, @@ -495,7 +495,6 @@ export class PortfolioService { userId }); - // Synthetic activities for cash const cashDetails = await this.accountService.getCashDetails({ filters, userId,