Browse Source

Bugfix/total fee calculation related to activities in custom currency (part 2) (#6199)

* Fix total fee calculation related to activities in custom currency

* Update changelog
pull/6200/head
Thomas Kaul 2 days ago
committed by GitHub
parent
commit
d9a4d261e4
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 14
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  3. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts
  4. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts
  5. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts
  6. 3
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts
  7. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur-in-base-currency-eur.spec.ts
  8. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts
  9. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts
  10. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-short.spec.ts
  11. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts
  12. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts
  13. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts
  14. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts
  15. 7
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-and-sell.spec.ts
  16. 2
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts
  17. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts
  18. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts
  19. 1
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts
  20. 1
      apps/api/src/app/portfolio/interfaces/portfolio-order-item.interface.ts
  21. 1
      apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts
  22. 1
      apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts

2
CHANGELOG.md

@ -15,6 +15,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Fixed a numeric parsing error related to cash positions on the _X-ray_ page - Fixed a numeric parsing error related to cash positions on the _X-ray_ page
- Fixed the total fee calculation in the holding detail dialog related to activities in a custom currency
- Fixed the total fee calculation in the summary related to activities in a custom currency
## 2.230.0 - 2026-01-14 ## 2.230.0 - 2026-01-14

14
apps/api/src/app/portfolio/calculator/portfolio-calculator.ts

@ -120,6 +120,7 @@ export abstract class PortfolioCalculator {
({ ({
date, date,
feeInAssetProfileCurrency, feeInAssetProfileCurrency,
feeInBaseCurrency,
quantity, quantity,
SymbolProfile, SymbolProfile,
tags = [], tags = [],
@ -142,6 +143,7 @@ export abstract class PortfolioCalculator {
type, type,
date: format(date, DATE_FORMAT), date: format(date, DATE_FORMAT),
fee: new Big(feeInAssetProfileCurrency), fee: new Big(feeInAssetProfileCurrency),
feeInBaseCurrency: new Big(feeInBaseCurrency),
quantity: new Big(quantity), quantity: new Big(quantity),
unitPrice: new Big(unitPriceInAssetProfileCurrency) unitPrice: new Big(unitPriceInAssetProfileCurrency)
}; };
@ -336,12 +338,6 @@ export abstract class PortfolioCalculator {
} = {}; } = {};
for (const item of lastTransactionPoint.items) { for (const item of lastTransactionPoint.items) {
const feeInBaseCurrency = item.fee.mul(
exchangeRatesByCurrency[`${item.currency}${this.currency}`]?.[
lastTransactionPoint.date
] ?? 1
);
const marketPriceInBaseCurrency = ( const marketPriceInBaseCurrency = (
marketSymbolMap[endDateString]?.[item.symbol] ?? item.averagePrice marketSymbolMap[endDateString]?.[item.symbol] ?? item.averagePrice
).mul( ).mul(
@ -408,7 +404,6 @@ export abstract class PortfolioCalculator {
} }
positions.push({ positions.push({
feeInBaseCurrency,
includeInTotalAssetValue, includeInTotalAssetValue,
timeWeightedInvestment, timeWeightedInvestment,
timeWeightedInvestmentWithCurrencyEffect, timeWeightedInvestmentWithCurrencyEffect,
@ -418,6 +413,7 @@ export abstract class PortfolioCalculator {
dividend: totalDividend, dividend: totalDividend,
dividendInBaseCurrency: totalDividendInBaseCurrency, dividendInBaseCurrency: totalDividendInBaseCurrency,
fee: item.fee, fee: item.fee,
feeInBaseCurrency: item.feeInBaseCurrency,
firstBuyDate: item.firstBuyDate, firstBuyDate: item.firstBuyDate,
grossPerformance: !hasErrors ? (grossPerformance ?? null) : null, grossPerformance: !hasErrors ? (grossPerformance ?? null) : null,
grossPerformancePercentage: !hasErrors grossPerformancePercentage: !hasErrors
@ -937,6 +933,7 @@ export abstract class PortfolioCalculator {
for (const { for (const {
date, date,
fee, fee,
feeInBaseCurrency,
quantity, quantity,
SymbolProfile, SymbolProfile,
tags, tags,
@ -1001,6 +998,8 @@ export abstract class PortfolioCalculator {
: investment.div(newQuantity).abs(), : investment.div(newQuantity).abs(),
dividend: new Big(0), dividend: new Big(0),
fee: oldAccumulatedSymbol.fee.plus(fee), fee: oldAccumulatedSymbol.fee.plus(fee),
feeInBaseCurrency:
oldAccumulatedSymbol.feeInBaseCurrency.plus(feeInBaseCurrency),
firstBuyDate: oldAccumulatedSymbol.firstBuyDate, firstBuyDate: oldAccumulatedSymbol.firstBuyDate,
includeInHoldings: oldAccumulatedSymbol.includeInHoldings, includeInHoldings: oldAccumulatedSymbol.includeInHoldings,
quantity: newQuantity, quantity: newQuantity,
@ -1013,6 +1012,7 @@ export abstract class PortfolioCalculator {
currency, currency,
dataSource, dataSource,
fee, fee,
feeInBaseCurrency,
skipErrors, skipErrors,
symbol, symbol,
tags, tags,

2
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts

@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-11-22'), date: new Date('2021-11-22'),
feeInAssetProfileCurrency: 1.55, feeInAssetProfileCurrency: 1.55,
feeInBaseCurrency: 1.55,
quantity: 2, quantity: 2,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
@ -102,6 +103,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-11-30'), date: new Date('2021-11-30'),
feeInAssetProfileCurrency: 1.65, feeInAssetProfileCurrency: 1.65,
feeInBaseCurrency: 1.65,
quantity: 2, quantity: 2,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts

@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-11-22'), date: new Date('2021-11-22'),
feeInAssetProfileCurrency: 1.55, feeInAssetProfileCurrency: 1.55,
feeInBaseCurrency: 1.55,
quantity: 2, quantity: 2,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
@ -102,6 +103,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-11-30'), date: new Date('2021-11-30'),
feeInAssetProfileCurrency: 1.65, feeInAssetProfileCurrency: 1.65,
feeInBaseCurrency: 1.65,
quantity: 1, quantity: 1,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
@ -117,6 +119,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-11-30'), date: new Date('2021-11-30'),
feeInAssetProfileCurrency: 0, feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1, quantity: 1,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,

2
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts

@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-11-22'), date: new Date('2021-11-22'),
feeInAssetProfileCurrency: 1.55, feeInAssetProfileCurrency: 1.55,
feeInBaseCurrency: 1.55,
quantity: 2, quantity: 2,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
@ -102,6 +103,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-11-30'), date: new Date('2021-11-30'),
feeInAssetProfileCurrency: 1.65, feeInAssetProfileCurrency: 1.65,
feeInBaseCurrency: 1.65,
quantity: 2, quantity: 2,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,

3
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts

@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-11-30'), date: new Date('2021-11-30'),
feeInAssetProfileCurrency: 1.55, feeInAssetProfileCurrency: 1.55,
feeInBaseCurrency: 1.55,
quantity: 2, quantity: 2,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
@ -208,6 +209,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-11-30'), date: new Date('2021-11-30'),
feeInAssetProfileCurrency: 1.55, feeInAssetProfileCurrency: 1.55,
feeInBaseCurrency: 1.55,
quantity: 2, quantity: 2,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
@ -247,6 +249,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-11-30'), date: new Date('2021-11-30'),
feeInAssetProfileCurrency: 1.55, feeInAssetProfileCurrency: 1.55,
feeInBaseCurrency: 1.55,
quantity: 2, quantity: 2,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur-in-base-currency-eur.spec.ts

@ -110,6 +110,7 @@ describe('PortfolioCalculator', () => {
...activity, ...activity,
date: parseDate(activity.date), date: parseDate(activity.date),
feeInAssetProfileCurrency: 4.46, feeInAssetProfileCurrency: 4.46,
feeInBaseCurrency: 3.94,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
currency: 'USD', currency: 'USD',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts

@ -98,6 +98,7 @@ describe('PortfolioCalculator', () => {
...activity, ...activity,
date: parseDate(activity.date), date: parseDate(activity.date),
feeInAssetProfileCurrency: 4.46, feeInAssetProfileCurrency: 4.46,
feeInBaseCurrency: 4.46,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
currency: 'USD', currency: 'USD',

2
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts

@ -100,6 +100,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2015-01-01'), date: new Date('2015-01-01'),
feeInAssetProfileCurrency: 0, feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 2, quantity: 2,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
@ -115,6 +116,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2017-12-31'), date: new Date('2017-12-31'),
feeInAssetProfileCurrency: 0, feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1, quantity: 1,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-short.spec.ts

@ -98,6 +98,7 @@ describe('PortfolioCalculator', () => {
...activity, ...activity,
date: parseDate(activity.date), date: parseDate(activity.date),
feeInAssetProfileCurrency: activity.fee, feeInAssetProfileCurrency: activity.fee,
feeInBaseCurrency: activity.fee,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
currency: 'USD', currency: 'USD',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts

@ -98,6 +98,7 @@ describe('PortfolioCalculator', () => {
...activity, ...activity,
date: parseDate(activity.date), date: parseDate(activity.date),
feeInAssetProfileCurrency: 4.46, feeInAssetProfileCurrency: 4.46,
feeInBaseCurrency: 4.46,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
currency: 'USD', currency: 'USD',

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts

@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-09-01'), date: new Date('2021-09-01'),
feeInAssetProfileCurrency: 49, feeInAssetProfileCurrency: 49,
feeInBaseCurrency: 49,
quantity: 0, quantity: 0,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts

@ -99,6 +99,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2023-01-03'), date: new Date('2023-01-03'),
feeInAssetProfileCurrency: 1, feeInAssetProfileCurrency: 1,
feeInBaseCurrency: 0.9238,
quantity: 1, quantity: 1,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts

@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2023-01-01'), // Date in future date: new Date('2023-01-01'), // Date in future
feeInAssetProfileCurrency: 0, feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1, quantity: 1,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,

7
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-and-sell.spec.ts

@ -80,6 +80,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2024-03-08'), date: new Date('2024-03-08'),
feeInAssetProfileCurrency: 0, feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 0.3333333333333333, quantity: 0.3333333333333333,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
@ -94,8 +95,9 @@ describe('PortfolioCalculator', () => {
{ {
...activityDummyData, ...activityDummyData,
date: new Date('2024-03-13'), date: new Date('2024-03-13'),
quantity: 0.6666666666666666,
feeInAssetProfileCurrency: 0, feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 0.6666666666666666,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
currency: 'USD', currency: 'USD',
@ -109,8 +111,9 @@ describe('PortfolioCalculator', () => {
{ {
...activityDummyData, ...activityDummyData,
date: new Date('2024-03-14'), date: new Date('2024-03-14'),
quantity: 1,
feeInAssetProfileCurrency: 0, feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
currency: 'USD', currency: 'USD',

2
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts

@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-09-16'), date: new Date('2021-09-16'),
feeInAssetProfileCurrency: 19, feeInAssetProfileCurrency: 19,
feeInBaseCurrency: 19,
quantity: 1, quantity: 1,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
@ -102,6 +103,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2021-11-16'), date: new Date('2021-11-16'),
feeInAssetProfileCurrency: 0, feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1, quantity: 1,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts

@ -101,6 +101,7 @@ describe('PortfolioCalculator', () => {
...activity, ...activity,
date: parseDate(activity.date), date: parseDate(activity.date),
feeInAssetProfileCurrency: activity.fee, feeInAssetProfileCurrency: activity.fee,
feeInBaseCurrency: activity.fee,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
currency: activity.currency, currency: activity.currency,

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts

@ -101,6 +101,7 @@ describe('PortfolioCalculator', () => {
...activity, ...activity,
date: parseDate(activity.date), date: parseDate(activity.date),
feeInAssetProfileCurrency: activity.fee, feeInAssetProfileCurrency: activity.fee,
feeInBaseCurrency: activity.fee,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,
currency: activity.currency, currency: activity.currency,

1
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts

@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => {
...activityDummyData, ...activityDummyData,
date: new Date('2022-01-01'), date: new Date('2022-01-01'),
feeInAssetProfileCurrency: 0, feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1, quantity: 1,
SymbolProfile: { SymbolProfile: {
...symbolProfileDummyData, ...symbolProfileDummyData,

1
apps/api/src/app/portfolio/interfaces/portfolio-order-item.interface.ts

@ -3,7 +3,6 @@ import { Big } from 'big.js';
import { PortfolioOrder } from './portfolio-order.interface'; import { PortfolioOrder } from './portfolio-order.interface';
export interface PortfolioOrderItem extends PortfolioOrder { export interface PortfolioOrderItem extends PortfolioOrder {
feeInBaseCurrency?: Big;
feeInBaseCurrencyWithCurrencyEffect?: Big; feeInBaseCurrencyWithCurrencyEffect?: Big;
itemType?: 'end' | 'start'; itemType?: 'end' | 'start';
unitPriceFromMarketData?: Big; unitPriceFromMarketData?: Big;

1
apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts

@ -3,6 +3,7 @@ import { Activity } from '@ghostfolio/common/interfaces';
export interface PortfolioOrder extends Pick<Activity, 'tags' | 'type'> { export interface PortfolioOrder extends Pick<Activity, 'tags' | 'type'> {
date: string; date: string;
fee: Big; fee: Big;
feeInBaseCurrency: Big;
quantity: Big; quantity: Big;
SymbolProfile: Pick< SymbolProfile: Pick<
Activity['SymbolProfile'], Activity['SymbolProfile'],

1
apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts

@ -8,6 +8,7 @@ export interface TransactionPointSymbol {
dataSource: DataSource; dataSource: DataSource;
dividend: Big; dividend: Big;
fee: Big; fee: Big;
feeInBaseCurrency: Big;
firstBuyDate: string; firstBuyDate: string;
includeInHoldings: boolean; includeInHoldings: boolean;
investment: Big; investment: Big;

Loading…
Cancel
Save