Browse Source

Bugfix/improve portfolio calculation for activity with no market data (#5130)

* Improve portfolio calculation for activity with no market data

* Update changelog
pull/5153/head
Kenrick Tandrian 2 weeks ago
committed by GitHub
parent
commit
92d3079f2d
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 44
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts
  3. 20
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts

1
CHANGELOG.md

@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### 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 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 Catalan (`ca`)
- Improved the language localization for Portuguese (`pt`) - Improved the language localization for Portuguese (`pt`)

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

@ -114,14 +114,8 @@ describe('PortfolioCalculator', () => {
expect(portfolioSnapshot).toMatchObject({ expect(portfolioSnapshot).toMatchObject({
currentValueInBaseCurrency: new Big('500000'), currentValueInBaseCurrency: new Big('500000'),
// TODO: [] errors: [],
errors: [ hasErrors: false,
{
dataSource: 'MANUAL',
symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde'
}
],
hasErrors: true, // TODO: false
positions: [ positions: [
{ {
averagePrice: new Big('500000'), averagePrice: new Big('500000'),
@ -132,31 +126,35 @@ describe('PortfolioCalculator', () => {
fee: new Big('0'), fee: new Big('0'),
feeInBaseCurrency: new Big('0'), feeInBaseCurrency: new Big('0'),
firstBuyDate: '2022-01-01', firstBuyDate: '2022-01-01',
grossPerformance: null, grossPerformance: new Big('0'),
grossPerformancePercentage: null, grossPerformancePercentage: new Big('0'),
grossPerformancePercentageWithCurrencyEffect: null, grossPerformancePercentageWithCurrencyEffect: new Big('0'),
grossPerformanceWithCurrencyEffect: null, grossPerformanceWithCurrencyEffect: new Big('0'),
investment: new Big('0'), // TODO: new Big('500000') investment: new Big('500000'),
investmentWithCurrencyEffect: new Big('0'), // TODO: new Big('500000') investmentWithCurrencyEffect: new Big('500000'),
marketPrice: null, marketPrice: null,
marketPriceInBaseCurrency: 500000, marketPriceInBaseCurrency: 500000,
netPerformance: null, netPerformance: new Big('0'),
netPerformancePercentage: null, netPerformancePercentage: new Big('0'),
netPerformancePercentageWithCurrencyEffectMap: null, netPerformancePercentageWithCurrencyEffectMap: {
netPerformanceWithCurrencyEffectMap: null, max: new Big('0')
},
netPerformanceWithCurrencyEffectMap: {
max: new Big('0')
},
quantity: new Big('1'), quantity: new Big('1'),
symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde', symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde',
tags: [], tags: [],
timeWeightedInvestment: new Big('0'), timeWeightedInvestment: new Big('500000'),
timeWeightedInvestmentWithCurrencyEffect: new Big('0'), timeWeightedInvestmentWithCurrencyEffect: new Big('500000'),
transactionCount: 1, transactionCount: 1,
valueInBaseCurrency: new Big('500000') valueInBaseCurrency: new Big('500000')
} }
], ],
totalFeesWithCurrencyEffect: new Big('0'), totalFeesWithCurrencyEffect: new Big('0'),
totalInterestWithCurrencyEffect: new Big('0'), totalInterestWithCurrencyEffect: new Big('0'),
totalInvestment: new Big('0'), // TODO: new Big('500000') totalInvestment: new Big('500000'),
totalInvestmentWithCurrencyEffect: new Big('0'), // TODO: new Big('500000') totalInvestmentWithCurrencyEffect: new Big('500000'),
totalLiabilitiesWithCurrencyEffect: new Big('0') totalLiabilitiesWithCurrencyEffect: new Big('0')
}); });
@ -166,7 +164,7 @@ describe('PortfolioCalculator', () => {
netPerformanceInPercentage: 0, netPerformanceInPercentage: 0,
netPerformanceInPercentageWithCurrencyEffect: 0, netPerformanceInPercentageWithCurrencyEffect: 0,
netPerformanceWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0,
totalInvestmentValueWithCurrencyEffect: 0 // TODO: 500000 totalInvestmentValueWithCurrencyEffect: 500000
}) })
); );
}); });

20
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 startDateString = format(start, DATE_FORMAT);
const unitPriceAtStartDate = marketSymbolMap[startDateString]?.[symbol]; 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 ( if (
!unitPriceAtEndDate || !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 // Sort orders so that the start and end placeholder order are at the correct

Loading…
Cancel
Save