Browse Source

fix yearly boundary

pull/6258/head
Sven Günther 5 days ago
parent
commit
aaffd20a42
  1. 163
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts
  2. 15
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts

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

@ -526,5 +526,168 @@ describe('PortfolioCalculator', () => {
expect(portfolioSnapshot).toHaveProperty('annualizedDividendYield');
expect(portfolioSnapshot.annualizedDividendYield).toBeCloseTo(0.0184, 4);
});
it('ignores dividends older than 12 months when aggregating portfolio yield', async () => {
jest.useFakeTimers().setSystemTime(parseDate('2023-07-10').getTime());
const activities: Activity[] = [
// MSFT: 1 share @ 300, 3 dividends total (one older than 12 months)
{
...activityDummyData,
date: new Date('2021-09-16'),
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
currency: 'USD',
dataSource: 'YAHOO',
name: 'Microsoft Inc.',
symbol: 'MSFT'
},
type: 'BUY',
unitPriceInAssetProfileCurrency: 300
},
{
...activityDummyData,
date: new Date('2021-11-16'),
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
currency: 'USD',
dataSource: 'YAHOO',
name: 'Microsoft Inc.',
symbol: 'MSFT'
},
type: 'DIVIDEND',
unitPriceInAssetProfileCurrency: 0.62
},
{
...activityDummyData,
date: new Date('2022-08-16'),
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
currency: 'USD',
dataSource: 'YAHOO',
name: 'Microsoft Inc.',
symbol: 'MSFT'
},
type: 'DIVIDEND',
unitPriceInAssetProfileCurrency: 0.65
},
{
...activityDummyData,
date: new Date('2023-05-16'),
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
currency: 'USD',
dataSource: 'YAHOO',
name: 'Microsoft Inc.',
symbol: 'MSFT'
},
type: 'DIVIDEND',
unitPriceInAssetProfileCurrency: 0.65
},
// IBM: 1 share @ 200, 2 dividends total (one older than 12 months)
{
...activityDummyData,
date: new Date('2021-10-01'),
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
currency: 'USD',
dataSource: 'YAHOO',
name: 'IBM',
symbol: 'IBM'
},
type: 'BUY',
unitPriceInAssetProfileCurrency: 200
},
{
...activityDummyData,
date: new Date('2022-06-01'),
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
currency: 'USD',
dataSource: 'YAHOO',
name: 'IBM',
symbol: 'IBM'
},
type: 'DIVIDEND',
unitPriceInAssetProfileCurrency: 1.65
},
{
...activityDummyData,
date: new Date('2023-06-01'),
feeInAssetProfileCurrency: 0,
feeInBaseCurrency: 0,
quantity: 1,
SymbolProfile: {
...symbolProfileDummyData,
currency: 'USD',
dataSource: 'YAHOO',
name: 'IBM',
symbol: 'IBM'
},
type: 'DIVIDEND',
unitPriceInAssetProfileCurrency: 1.65
}
];
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
calculationType: PerformanceCalculationType.ROAI,
currency: 'USD',
userId: userDummyData.id
});
const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
const msftPosition = portfolioSnapshot.positions.find(
({ symbol }) => symbol === 'MSFT'
);
const ibmPosition = portfolioSnapshot.positions.find(
({ symbol }) => symbol === 'IBM'
);
expect(msftPosition.dividendInBaseCurrency).toEqual(new Big('1.92'));
expect(ibmPosition.dividendInBaseCurrency).toEqual(new Big('3.3'));
const msftDividendLast12Months = new Big('1.3');
const ibmDividendLast12Months = new Big('1.65');
const totalInvestment = new Big('500');
expect(msftPosition.annualizedDividendYield).toBeCloseTo(
msftDividendLast12Months.div(new Big('300')).toNumber(),
6
);
expect(ibmPosition.annualizedDividendYield).toBeCloseTo(
ibmDividendLast12Months.div(new Big('200')).toNumber(),
6
);
const expectedAnnualizedDividendYield = msftDividendLast12Months
.plus(ibmDividendLast12Months)
.div(totalInvestment)
.toNumber();
expect(portfolioSnapshot.annualizedDividendYield).toBeCloseTo(
expectedAnnualizedDividendYield,
6
);
});
});
});

15
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts

@ -34,7 +34,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
let grossPerformanceWithCurrencyEffect = new Big(0);
let hasErrors = false;
let netPerformance = new Big(0);
let totalDividendsInBaseCurrency = new Big(0);
let totalDividendsLast12MonthsInBaseCurrency = new Big(0);
let totalFeesWithCurrencyEffect = new Big(0);
const totalInterestWithCurrencyEffect = new Big(0);
let totalInvestment = new Big(0);
@ -47,10 +47,13 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
return includeInTotalAssetValue;
}
)) {
if (currentPosition.dividendInBaseCurrency) {
totalDividendsInBaseCurrency = totalDividendsInBaseCurrency.plus(
currentPosition.dividendInBaseCurrency
);
if (currentPosition.investmentWithCurrencyEffect) {
totalDividendsLast12MonthsInBaseCurrency =
totalDividendsLast12MonthsInBaseCurrency.plus(
new Big(currentPosition.annualizedDividendYield ?? 0).mul(
currentPosition.investmentWithCurrencyEffect
)
);
}
if (currentPosition.feeInBaseCurrency) {
@ -114,7 +117,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
// Calculate annualized dividend yield for the entire portfolio
const annualizedDividendYield = totalInvestmentWithCurrencyEffect.gt(0)
? totalDividendsInBaseCurrency
? totalDividendsLast12MonthsInBaseCurrency
.div(totalInvestmentWithCurrencyEffect)
.toNumber()
: 0;

Loading…
Cancel
Save