|
|
|
@ -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 |
|
|
|
); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
|