From 92d3079f2d361df94ee7828ed02cb0587d4e4af5 Mon Sep 17 00:00:00 2001 From: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com> Date: Fri, 11 Jul 2025 22:13:01 +0700 Subject: [PATCH 1/2] Bugfix/improve portfolio calculation for activity with no market data (#5130) * Improve portfolio calculation for activity with no market data * Update changelog --- CHANGELOG.md | 1 + .../portfolio-calculator-valuable.spec.ts | 44 +++++++++---------- .../calculator/roai/portfolio-calculator.ts | 20 +++++++-- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47042b173..7308e73f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Improved the portfolio calculations for activities without historical market data - Improved the asset profile dialog’s data gathering checkbox of the admin control panel to reflect the global settings - Improved the language localization for Catalan (`ca`) - Improved the language localization for Portuguese (`pt`) diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts index f883e67a2..5e9949dd2 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts @@ -114,14 +114,8 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('500000'), - // TODO: [] - errors: [ - { - dataSource: 'MANUAL', - symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde' - } - ], - hasErrors: true, // TODO: false + errors: [], + hasErrors: false, positions: [ { averagePrice: new Big('500000'), @@ -132,31 +126,35 @@ describe('PortfolioCalculator', () => { fee: new Big('0'), feeInBaseCurrency: new Big('0'), firstBuyDate: '2022-01-01', - grossPerformance: null, - grossPerformancePercentage: null, - grossPerformancePercentageWithCurrencyEffect: null, - grossPerformanceWithCurrencyEffect: null, - investment: new Big('0'), // TODO: new Big('500000') - investmentWithCurrencyEffect: new Big('0'), // TODO: new Big('500000') + grossPerformance: new Big('0'), + grossPerformancePercentage: new Big('0'), + grossPerformancePercentageWithCurrencyEffect: new Big('0'), + grossPerformanceWithCurrencyEffect: new Big('0'), + investment: new Big('500000'), + investmentWithCurrencyEffect: new Big('500000'), marketPrice: null, marketPriceInBaseCurrency: 500000, - netPerformance: null, - netPerformancePercentage: null, - netPerformancePercentageWithCurrencyEffectMap: null, - netPerformanceWithCurrencyEffectMap: null, + netPerformance: new Big('0'), + netPerformancePercentage: new Big('0'), + netPerformancePercentageWithCurrencyEffectMap: { + max: new Big('0') + }, + netPerformanceWithCurrencyEffectMap: { + max: new Big('0') + }, quantity: new Big('1'), symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde', tags: [], - timeWeightedInvestment: new Big('0'), - timeWeightedInvestmentWithCurrencyEffect: new Big('0'), + timeWeightedInvestment: new Big('500000'), + timeWeightedInvestmentWithCurrencyEffect: new Big('500000'), transactionCount: 1, valueInBaseCurrency: new Big('500000') } ], totalFeesWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'), - totalInvestment: new Big('0'), // TODO: new Big('500000') - totalInvestmentWithCurrencyEffect: new Big('0'), // TODO: new Big('500000') + totalInvestment: new Big('500000'), + totalInvestmentWithCurrencyEffect: new Big('500000'), totalLiabilitiesWithCurrencyEffect: new Big('0') }); @@ -166,7 +164,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0, netPerformanceInPercentageWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0, - totalInvestmentValueWithCurrencyEffect: 0 // TODO: 500000 + totalInvestmentValueWithCurrencyEffect: 500000 }) ); }); 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 d697c7c69..d4fad7d93 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts @@ -231,7 +231,20 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { const startDateString = format(start, DATE_FORMAT); const unitPriceAtStartDate = marketSymbolMap[startDateString]?.[symbol]; - const unitPriceAtEndDate = marketSymbolMap[endDateString]?.[symbol]; + let unitPriceAtEndDate = marketSymbolMap[endDateString]?.[symbol]; + + let latestActivity = orders.at(-1); + + if ( + dataSource === 'MANUAL' && + ['BUY', 'SELL'].includes(latestActivity?.type) && + latestActivity?.unitPrice && + !unitPriceAtEndDate + ) { + // 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; + } if ( !unitPriceAtEndDate || @@ -344,9 +357,10 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { }); } - const lastOrder = orders.at(-1); + latestActivity = orders.at(-1); - lastUnitPrice = lastOrder.unitPriceFromMarketData ?? lastOrder.unitPrice; + lastUnitPrice = + latestActivity.unitPriceFromMarketData ?? latestActivity.unitPrice; } // Sort orders so that the start and end placeholder order are at the correct From b424a41c5774c5b665ba96bd83f3470b2f37053f Mon Sep 17 00:00:00 2001 From: TMs Date: Fri, 11 Jul 2025 23:22:42 +0800 Subject: [PATCH 2/2] Feature/improve language localization for ZH 20250711 (#5147) * Improve language localization for ZH * Update changelog --- CHANGELOG.md | 1 + apps/client/src/locales/messages.zh.xlf | 118 ++++++++++++------------ 2 files changed, 60 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7308e73f4..1a8822b3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the portfolio calculations for activities without historical market data - Improved the asset profile dialog’s data gathering checkbox of the admin control panel to reflect the global settings - Improved the language localization for Catalan (`ca`) +- Improved the language localization for Chinese (`zh`) - Improved the language localization for Portuguese (`pt`) - Improved the language localization for Spanish (`es`) - Improved the language localization for Turkish (`tr`) diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 0bfac761b..ca349e49d 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -4,7 +4,7 @@ about - 关于 + about kebab-case libs/common/src/lib/routes/routes.ts @@ -37,7 +37,7 @@ faq - 常见问题 + faq kebab-case libs/common/src/lib/routes/routes.ts @@ -58,7 +58,7 @@ features - 功能 + features kebab-case libs/common/src/lib/routes/routes.ts @@ -71,7 +71,7 @@ license - 许可证 + license kebab-case libs/common/src/lib/routes/routes.ts @@ -84,7 +84,7 @@ markets - 市场 + markets kebab-case libs/common/src/lib/routes/routes.ts @@ -97,7 +97,7 @@ pricing - 价钱 + pricing kebab-case libs/common/src/lib/routes/routes.ts @@ -110,7 +110,7 @@ privacy-policy - 隐私政策 + privacy-policy kebab-case libs/common/src/lib/routes/routes.ts @@ -123,7 +123,7 @@ register - 注册 + register kebab-case libs/common/src/lib/routes/routes.ts @@ -136,7 +136,7 @@ resources - 资源 + resources kebab-case libs/common/src/lib/routes/routes.ts @@ -4749,7 +4749,7 @@ open-source-alternative-to - 开源替代方案 + open-source-alternative-to kebab-case libs/common/src/lib/routes/routes.ts @@ -6046,7 +6046,7 @@ self-hosting - 自托管 + self-hosting kebab-case libs/common/src/lib/routes/routes.ts @@ -6959,7 +6959,7 @@ guides - 指南 + guides kebab-case libs/common/src/lib/routes/routes.ts @@ -6972,7 +6972,7 @@ glossary - 词汇表 + glossary kebab-case libs/common/src/lib/routes/routes.ts @@ -7425,7 +7425,7 @@ terms-of-service - 服务条款 + terms-of-service kebab-case libs/common/src/lib/routes/routes.ts @@ -7598,7 +7598,7 @@ changelog - 变更日志 + changelog kebab-case libs/common/src/lib/routes/routes.ts @@ -7707,7 +7707,7 @@ Live Demo - Live Demo + 现场演示 libs/common/src/lib/routes/routes.ts 231 @@ -7715,7 +7715,7 @@ Open Source Alternative to - Open Source Alternative to + 开源替代方案 libs/common/src/lib/routes/routes.ts 326 @@ -7723,7 +7723,7 @@ Single Account - Single Account + 单一账户 apps/client/src/app/pages/i18n/i18n-page.html 24 @@ -7731,7 +7731,7 @@ Your net worth is managed by a single account - Your net worth is managed by a single account + 您的净资产由单一账户管理 apps/client/src/app/pages/i18n/i18n-page.html 25 @@ -7739,7 +7739,7 @@ Your net worth is managed by ${accountsLength} accounts - Your net worth is managed by ${accountsLength} accounts + 您的净资产由 ${accountsLength} 个账户管理 apps/client/src/app/pages/i18n/i18n-page.html 28 @@ -7747,7 +7747,7 @@ Holdings - Holdings + 持仓 libs/ui/src/lib/assistant/assistant.html 69 @@ -7755,7 +7755,7 @@ personal-finance-tools - personal-finance-tools + personal-finance-tools kebab-case libs/common/src/lib/routes/routes.ts @@ -7772,7 +7772,7 @@ markets - markets + markets kebab-case libs/common/src/lib/routes/routes.ts @@ -7785,7 +7785,7 @@ Fuel your self-hosted Ghostfolio with a powerful data provider to access 80,000+ tickers from over 50 exchanges worldwide. - Fuel your self-hosted Ghostfolio with a powerful data provider to access 80,000+ tickers from over 50 exchanges worldwide. + 使用 强大的数据提供商为您的 自托管 Ghostfolio 提供数据,访问来自全球超过 50 家交易所80,000+ 个股票代码 apps/client/src/app/components/admin-settings/admin-settings.component.html 15 @@ -7793,7 +7793,7 @@ Get Access - Get Access + 获取访问权限 apps/client/src/app/components/admin-settings/admin-settings.component.html 27 @@ -7801,7 +7801,7 @@ Learn more - Learn more + 了解更多 apps/client/src/app/components/admin-settings/admin-settings.component.html 38 @@ -7809,7 +7809,7 @@ new - new + 新增 apps/client/src/app/components/admin-settings/admin-settings.component.html 67 @@ -7817,7 +7817,7 @@ Limited Offer! - Limited Offer! + 限时优惠! apps/client/src/app/pages/pricing/pricing-page.html 311 @@ -7825,7 +7825,7 @@ Get extra - Get extra + 获取额外 apps/client/src/app/pages/pricing/pricing-page.html 313 @@ -7833,7 +7833,7 @@ Available - Available + 可用 apps/client/src/app/components/data-provider-status/data-provider-status.component.html 3 @@ -7841,7 +7841,7 @@ Unavailable - Unavailable + 不可用 apps/client/src/app/components/data-provider-status/data-provider-status.component.html 5 @@ -7849,7 +7849,7 @@ new - new + 新增 apps/client/src/app/pages/admin/admin-page.component.ts 53 @@ -7857,7 +7857,7 @@ Investment - Investment + 投资 apps/client/src/app/pages/i18n/i18n-page.html 14 @@ -7865,7 +7865,7 @@ Over ${thresholdMax}% of your current investment is at ${maxAccountName} (${maxInvestmentRatio}%) - Over ${thresholdMax}% of your current investment is at ${maxAccountName} (${maxInvestmentRatio}%) + 您当前投资中有超过 ${thresholdMax}% 的资金在 ${maxAccountName} (${maxInvestmentRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 15 @@ -7873,7 +7873,7 @@ The major part of your current investment is at ${maxAccountName} (${maxInvestmentRatio}%) and does not exceed ${thresholdMax}% - The major part of your current investment is at ${maxAccountName} (${maxInvestmentRatio}%) and does not exceed ${thresholdMax}% + 您的当前投资大部分位于 ${maxAccountName} (${maxInvestmentRatio}%) 且不超过 ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 19 @@ -7881,7 +7881,7 @@ Equity - Equity + 股权 apps/client/src/app/pages/i18n/i18n-page.html 31 @@ -7889,7 +7889,7 @@ The equity contribution of your current investment (${equityValueRatio}%) exceeds ${thresholdMax}% - The equity contribution of your current investment (${equityValueRatio}%) exceeds ${thresholdMax}% + 您目前投资中股权占比 (${equityValueRatio}%) 超过了 ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 32 @@ -7897,7 +7897,7 @@ The equity contribution of your current investment (${equityValueRatio}%) is below ${thresholdMin}% - The equity contribution of your current investment (${equityValueRatio}%) is below ${thresholdMin}% + 您目前投资中股权占比 (${equityValueRatio}%) 低于 ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 36 @@ -7905,7 +7905,7 @@ The equity contribution of your current investment (${equityValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The equity contribution of your current investment (${equityValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + 您目前投资中股权占比 (${equityValueRatio}%) 在 ${thresholdMin}% 和 ${thresholdMax}% 之间 apps/client/src/app/pages/i18n/i18n-page.html 40 @@ -7913,7 +7913,7 @@ Fixed Income - Fixed Income + 固定收益 apps/client/src/app/pages/i18n/i18n-page.html 45 @@ -7921,7 +7921,7 @@ The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) exceeds ${thresholdMax}% - The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) exceeds ${thresholdMax}% + 您目前投资中固定收益占比 (${fixedIncomeValueRatio}%) 超过了 ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 46 @@ -7929,7 +7929,7 @@ The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is below ${thresholdMin}% - The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is below ${thresholdMin}% + 您目前投资中固定收益占比 (${fixedIncomeValueRatio}%) 低于 ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 50 @@ -7937,7 +7937,7 @@ The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + 您目前投资中固定收益占比 (${fixedIncomeValueRatio}%) 在 ${thresholdMin}% 和 ${thresholdMax}% 之间 apps/client/src/app/pages/i18n/i18n-page.html 55 @@ -7945,7 +7945,7 @@ Investment: Base Currency - Investment: Base Currency + 投资:基础货币 apps/client/src/app/pages/i18n/i18n-page.html 60 @@ -7953,7 +7953,7 @@ The major part of your current investment is not in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) - The major part of your current investment is not in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) + 您的当前投资的主要部分未以您的基础货币计价 ( ${baseCurrency} 仅占 ${baseCurrencyValueRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 63 @@ -7961,7 +7961,7 @@ The major part of your current investment is in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) - The major part of your current investment is in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) + 您的当前投资的主要部分以您的基础货币计价(其中 ${baseCurrency} 占比 ${baseCurrencyValueRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 67 @@ -7969,7 +7969,7 @@ Investment - Investment + 投资 apps/client/src/app/pages/i18n/i18n-page.html 71 @@ -7977,7 +7977,7 @@ Over ${thresholdMax}% of your current investment is in ${currency} (${maxValueRatio}%) - Over ${thresholdMax}% of your current investment is in ${currency} (${maxValueRatio}%) + 超过 ${thresholdMax}% 的当前投资在 ${currency} 中(占比 ${maxValueRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 72 @@ -7985,7 +7985,7 @@ The major part of your current investment is in ${currency} (${maxValueRatio}%) and does not exceed ${thresholdMax}% - The major part of your current investment is in ${currency} (${maxValueRatio}%) and does not exceed ${thresholdMax}% + 您的当前投资的主要部分以 ${currency} 计价(占比 ${maxValueRatio}%),并且未超过 ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 76 @@ -7993,7 +7993,7 @@ start - start + start kebab-case libs/common/src/lib/routes/routes.ts @@ -8006,7 +8006,7 @@ Do you really want to generate a new security token? - Do you really want to generate a new security token? + 您真的想要生成一个新的安全令牌吗? apps/client/src/app/components/user-account-access/user-account-access.component.ts 176 @@ -8014,7 +8014,7 @@ Generate - Generate + 生成 apps/client/src/app/components/user-account-access/user-account-access.html 43 @@ -8022,7 +8022,7 @@ Stocks - Stocks + 股票 apps/client/src/app/components/markets/markets.component.ts 54 @@ -8030,7 +8030,7 @@ Cryptocurrencies - Cryptocurrencies + 加密货币 apps/client/src/app/components/markets/markets.component.ts 55 @@ -8040,8 +8040,8 @@ - - + + apps/client/src/app/components/admin-users/admin-users.html @@ -8050,7 +8050,7 @@ Manage Asset Profile - Manage Asset Profile + 管理资产概况 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 434 @@ -8058,7 +8058,7 @@ Alternative Investment - Alternative Investment + 另类投资 libs/ui/src/lib/i18n.ts 44 @@ -8066,7 +8066,7 @@ Collectible - Collectible + 收藏品 libs/ui/src/lib/i18n.ts 54