diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts index 543985424..dab40443c 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts @@ -154,25 +154,25 @@ describe('PortfolioCalculator', () => { dividendInBaseCurrency: new Big('0.62'), fee: new Big('19'), firstBuyDate: '2021-09-16', - grossPerformance: new Big('33.25'), - grossPerformancePercentage: new Big('0.11136043941322258691'), + grossPerformance: new Big('33.87'), + grossPerformancePercentage: new Big('0.11343693482483756447'), grossPerformancePercentageWithCurrencyEffect: new Big( - '0.11136043941322258691' + '0.11343693482483756447' ), - grossPerformanceWithCurrencyEffect: new Big('33.25'), + grossPerformanceWithCurrencyEffect: new Big('33.87'), investment: new Big('298.58'), investmentWithCurrencyEffect: new Big('298.58'), marketPrice: 331.83, marketPriceInBaseCurrency: 331.83, - netPerformance: new Big('14.25'), - netPerformancePercentage: new Big('0.04772590260566682296'), + netPerformance: new Big('14.87'), + netPerformancePercentage: new Big('0.04980239801728180052'), netPerformancePercentageWithCurrencyEffectMap: { - max: new Big('0.04772590260566682296') + max: new Big('0.04980239801728180052') }, netPerformanceWithCurrencyEffectMap: { '1d': new Big('-5.39'), - '5y': new Big('14.25'), - max: new Big('14.25'), + '5y': new Big('14.87'), + max: new Big('14.87'), wtd: new Big('-5.39') }, quantity: new Big('1'), diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts index 059b85441..e5bdb5e59 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts @@ -142,6 +142,8 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { let grossPerformanceAtStartDateWithCurrencyEffect = new Big(0); let grossPerformanceFromSells = new Big(0); let grossPerformanceFromSellsWithCurrencyEffect = new Big(0); + let grossPerformanceFromDividends = new Big(0); + let grossPerformanceFromDividendsWithCurrencyEffect = new Big(0); let initialValue: Big; let initialValueWithCurrencyEffect: Big; let investmentAtStartDate: Big; @@ -559,28 +561,27 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { order.unitPriceInBaseCurrencyWithCurrencyEffect ); - const grossPerformanceFromSell = - order.type === 'SELL' - ? order.unitPriceInBaseCurrency - .minus(lastAveragePrice) - .mul(order.quantity) - : new Big(0); - - const grossPerformanceFromSellWithCurrencyEffect = - order.type === 'SELL' - ? order.unitPriceInBaseCurrencyWithCurrencyEffect - .minus(lastAveragePriceWithCurrencyEffect) - .mul(order.quantity) - : new Big(0); - - grossPerformanceFromSells = grossPerformanceFromSells.plus( - grossPerformanceFromSell - ); - - grossPerformanceFromSellsWithCurrencyEffect = - grossPerformanceFromSellsWithCurrencyEffect.plus( - grossPerformanceFromSellWithCurrencyEffect - ); + ({ + grossPerformanceFromSells, + grossPerformanceFromSellsWithCurrencyEffect + } = this.handleSellOrder( + order, + lastAveragePrice, + lastAveragePriceWithCurrencyEffect, + grossPerformanceFromSells, + grossPerformanceFromSellsWithCurrencyEffect + )); + + ({ + grossPerformanceFromDividends, + grossPerformanceFromDividendsWithCurrencyEffect + } = this.handleDividend( + order, + grossPerformanceFromDividends, + grossPerformanceFromDividendsWithCurrencyEffect, + currentExchangeRate, + exchangeRateAtOrderDate + )); lastAveragePrice = totalQuantityFromBuyTransactions.eq(0) ? new Big(0) @@ -602,19 +603,21 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { grossPerformanceFromSells.toNumber() ); console.log( - 'grossPerformanceFromSellWithCurrencyEffect', - grossPerformanceFromSellWithCurrencyEffect.toNumber() + 'grossPerformanceFromSellsWithCurrencyEffect', + grossPerformanceFromSellsWithCurrencyEffect.toNumber() ); } const newGrossPerformance = valueOfInvestment .minus(totalInvestment) - .plus(grossPerformanceFromSells); + .plus(grossPerformanceFromSells) + .plus(grossPerformanceFromDividends); const newGrossPerformanceWithCurrencyEffect = valueOfInvestmentWithCurrencyEffect .minus(totalInvestmentWithCurrencyEffect) - .plus(grossPerformanceFromSellsWithCurrencyEffect); + .plus(grossPerformanceFromSellsWithCurrencyEffect) + .plus(grossPerformanceFromDividendsWithCurrencyEffect); grossPerformance = newGrossPerformance; @@ -966,4 +969,67 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect }; } + + private handleSellOrder( + order: PortfolioOrderItem, + lastAveragePrice, + lastAveragePriceWithCurrencyEffect, + grossPerformanceFromSells, + grossPerformanceFromSellsWithCurrencyEffect + ) { + if (order.type === 'SELL') { + const grossPerformanceFromSell = order.unitPriceInBaseCurrency + .minus(lastAveragePrice) + .mul(order.quantity); + + const grossPerformanceFromSellWithCurrencyEffect = + order.unitPriceInBaseCurrencyWithCurrencyEffect + .minus(lastAveragePriceWithCurrencyEffect) + .mul(order.quantity); + + grossPerformanceFromSells = grossPerformanceFromSells.plus( + grossPerformanceFromSell + ); + + grossPerformanceFromSellsWithCurrencyEffect = + grossPerformanceFromSellsWithCurrencyEffect.plus( + grossPerformanceFromSellWithCurrencyEffect + ); + } + return { + grossPerformanceFromSells, + grossPerformanceFromSellsWithCurrencyEffect + }; + } + + private handleDividend( + order: PortfolioOrderItem, + grossPerformanceFromDividends, + grossPerformanceFromDividendsWithCurrencyEffect, + currentExchangeRate: number, + exchangeRateAtDateOfOrder: number + ) { + if (order.type === 'DIVIDEND') { + const grossPerformanceFromDividend = order.unitPrice + .mul(currentExchangeRate) + .mul(order.quantity); + + const grossPerformanceFromDividendWithCurrencyEffect = order.unitPrice + .mul(exchangeRateAtDateOfOrder) + .mul(order.quantity); + + grossPerformanceFromDividends = grossPerformanceFromDividends.plus( + grossPerformanceFromDividend + ); + + grossPerformanceFromDividendsWithCurrencyEffect = + grossPerformanceFromDividendsWithCurrencyEffect.plus( + grossPerformanceFromDividendWithCurrencyEffect + ); + } + return { + grossPerformanceFromDividends, + grossPerformanceFromDividendsWithCurrencyEffect + }; + } }