Browse Source

Move total return from experimental to general availability

pull/7990/head
Thomas Kaul 2 weeks ago
parent
commit
d5470416e5
  1. 135
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-fee-and-dividend.spec.ts

135
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-fee-and-dividend.spec.ts

@ -122,8 +122,9 @@ describe('PortfolioCalculator', () => {
{ {
// The first activity of this asset profile is a fee, which is not an // The first activity of this asset profile is a fee, which is not an
// investment activity. Thus the holding is not included in the // investment activity. Thus the holding is not included in the
// holdings of the portfolio summary, and its dividend must not be // holdings of the portfolio summary. But its fee and its dividend are
// included in the chart // part of the net performance, so its dividend is part of the
// dividend of the chart too
...activityDummyData, ...activityDummyData,
assetProfile: { assetProfile: {
...assetProfileDummyData, ...assetProfileDummyData,
@ -167,8 +168,10 @@ describe('PortfolioCalculator', () => {
const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
const dividendInBaseCurrency = const performanceByDateRange = await getPerformanceByDateRange({
await portfolioCalculator.getDividendInBaseCurrency(); portfolioCalculator,
dateRanges: ['max']
});
expect( expect(
portfolioSnapshot.positions.map(({ symbol }) => { portfolioSnapshot.positions.map(({ symbol }) => {
@ -176,12 +179,22 @@ describe('PortfolioCalculator', () => {
}) })
).toEqual(['MSFT']); ).toEqual(['MSFT']);
// The chart and the portfolio summary must show the same dividend expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject({
expect(dividendInBaseCurrency).toEqual(new Big('0.62')); dividendInBaseCurrency: 5.62,
dividendInPercentageWithCurrencyEffect: 0.01882242615044544,
netPerformance: 18.87,
netPerformanceInPercentage: 0.06319914260834618
});
expect( // The portfolio summary takes the dividend of the date range max
portfolioSnapshot.historicalData.at(-1).dividendInBaseCurrency expect(performanceByDateRange).toMatchObject({
).toEqual(0.62); max: {
dividendInBaseCurrency: 5.62,
dividendInPercentageWithCurrencyEffect: 0.01882242615044535,
netPerformance: 18.87,
netPerformanceInPercentage: 0.06319914260834586
}
});
}); });
it('with GOOGL dividend without investment', async () => { it('with GOOGL dividend without investment', async () => {
@ -221,8 +234,9 @@ describe('PortfolioCalculator', () => {
unitPriceInAssetProfileCurrency: 0.62 unitPriceInAssetProfileCurrency: 0.62
}, },
{ {
// The holding has a dividend, but no average investment. Thus the // The holding has a dividend, but no average investment. The dividend
// dividend percentage stays 0, like the dividend yield // is part of the net performance, so the dividend percentage is the
// part of the net performance percentage. The dividend yield stays 0
...activityDummyData, ...activityDummyData,
assetProfile: { assetProfile: {
...assetProfileDummyData, ...assetProfileDummyData,
@ -261,13 +275,108 @@ describe('PortfolioCalculator', () => {
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject({ expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject({
dividendInBaseCurrency: 5.62, dividendInBaseCurrency: 5.62,
dividendInPercentageWithCurrencyEffect: 0 dividendInPercentageWithCurrencyEffect: 0.01882242615044544,
netPerformance: 19.87,
netPerformanceInPercentage: 0.06654832875611226
});
expect(performanceByDateRange).toMatchObject({
max: {
dividendInBaseCurrency: 5.62,
dividendInPercentageWithCurrencyEffect: 0.01882242615044535,
netPerformance: 19.87,
netPerformanceInPercentage: 0.06654832875611194
}
});
});
it('with dividend of a holding without market price', async () => {
jest.useFakeTimers().setSystemTime(parseDate('2023-07-10').getTime());
const activities: Activity[] = [
{
...activityDummyData,
assetProfile: {
...assetProfileDummyData,
currency: 'USD',
dataSource: 'YAHOO',
name: 'Microsoft Inc.',
symbol: 'MSFT'
},
date: new Date('2021-09-16'),
feeInAssetProfileCurrency: 19,
feeInBaseCurrency: 19,
quantity: 1,
type: 'BUY',
unitPriceInAssetProfileCurrency: 298.58
},
{
...activityDummyData,
assetProfile: {
...assetProfileDummyData,
currency: 'USD',
dataSource: 'YAHOO',
name: 'Microsoft Inc.',
symbol: 'MSFT'
},
date: new Date('2021-11-16'),
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1,
type: 'DIVIDEND',
unitPriceInAssetProfileCurrency: 0.62
},
{
// The holding has no market price, thus it has no value. But its
// dividend is part of the net performance, like the dividend of a
// holding with a market price (see the scenario above)
...activityDummyData,
assetProfile: {
...assetProfileDummyData,
currency: 'USD',
dataSource: 'MANUAL',
name: 'Private Equity Fund',
symbol: '3b5ba4a5-4c8e-4bd5-9b4c-5e0d5e7cfc3f'
},
date: new Date('2023-07-10'),
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1,
type: 'DIVIDEND',
unitPriceInAssetProfileCurrency: 5
}
];
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.ROAI,
currency: 'USD',
usePortfolioSnapshotCache: false,
userId: userDummyData.id
});
const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
const performanceByDateRange = await getPerformanceByDateRange({
portfolioCalculator,
dateRanges: ['max']
});
expect(portfolioSnapshot.hasErrors).toBe(false);
expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject({
dividendInBaseCurrency: 5.62,
dividendInPercentageWithCurrencyEffect: 0.01882242615044544,
netPerformance: 19.87,
netPerformanceInPercentage: 0.06654832875611226
}); });
expect(performanceByDateRange).toMatchObject({ expect(performanceByDateRange).toMatchObject({
max: { max: {
dividendInBaseCurrency: 5.62, dividendInBaseCurrency: 5.62,
dividendInPercentageWithCurrencyEffect: 0 dividendInPercentageWithCurrencyEffect: 0.01882242615044535,
netPerformance: 19.87,
netPerformanceInPercentage: 0.06654832875611194
} }
}); });
}); });

Loading…
Cancel
Save