From 6eb4eae4a9564de77f6a1101253bf43c14b1736b Mon Sep 17 00:00:00 2001 From: gizmodus Date: Wed, 9 Feb 2022 09:29:43 +0100 Subject: [PATCH] Feature/fix twr performance 2 (#684) * Fix TWR performance * Weight holding period returns according to their investment value Co-authored-by: Reto Kaul --- .../app/portfolio/portfolio-calculator-new.ts | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/apps/api/src/app/portfolio/portfolio-calculator-new.ts b/apps/api/src/app/portfolio/portfolio-calculator-new.ts index ae5896e0d..6f95fd3a9 100644 --- a/apps/api/src/app/portfolio/portfolio-calculator-new.ts +++ b/apps/api/src/app/portfolio/portfolio-calculator-new.ts @@ -344,6 +344,12 @@ export class PortfolioCalculatorNew { let totalInvestment = new Big(0); let totalUnits = new Big(0); + const holdingPeriodPerformances: { + grossReturn: Big; + netReturn: Big; + valueOfInvestment: Big; + }[] = []; + // Add a synthetic order at the start and the end date orders.push({ symbol, @@ -463,7 +469,7 @@ export class PortfolioCalculatorNew { ); const netHoldingPeriodReturn = valueOfInvestmentBeforeTransaction - .sub(fees.sub(order.fee)) + .sub(fees.minus(feesAtStartDate)) .sub( lastValueOfInvestmentBeforeTransaction.plus( lastTransactionInvestment @@ -479,6 +485,14 @@ export class PortfolioCalculatorNew { timeWeightedNetPerformancePercentage.mul( new Big(1).plus(netHoldingPeriodReturn) ); + + holdingPeriodPerformances.push({ + grossReturn: grossHoldingPeriodReturn, + netReturn: netHoldingPeriodReturn, + valueOfInvestment: lastValueOfInvestmentBeforeTransaction.plus( + lastTransactionInvestment + ) + }); } grossPerformance = newGrossPerformance; @@ -508,13 +522,39 @@ export class PortfolioCalculatorNew { .minus(grossPerformanceAtStartDate) .minus(fees.minus(feesAtStartDate)); + let valueOfInvestmentSum = new Big(0); + + for (const holdingPeriodPerformance of holdingPeriodPerformances) { + valueOfInvestmentSum = valueOfInvestmentSum.add( + holdingPeriodPerformance.valueOfInvestment + ); + } + + let totalWeightedGrossPerformance = new Big(0); + let totalWeightedNetPerformance = new Big(0); + + // Weight the holding period returns according to their value of investment + for (const holdingPeriodPerformance of holdingPeriodPerformances) { + totalWeightedGrossPerformance = totalWeightedGrossPerformance.plus( + holdingPeriodPerformance.grossReturn + .mul(holdingPeriodPerformance.valueOfInvestment) + .div(valueOfInvestmentSum) + ); + + totalWeightedNetPerformance = totalWeightedNetPerformance.plus( + holdingPeriodPerformance.netReturn + .mul(holdingPeriodPerformance.valueOfInvestment) + .div(valueOfInvestmentSum) + ); + } + return { initialValue, hasErrors: !initialValue || !unitPriceAtEndDate, netPerformance: totalNetPerformance, - netPerformancePercentage: timeWeightedNetPerformancePercentage, + netPerformancePercentage: totalWeightedNetPerformance, grossPerformance: totalGrossPerformance, - grossPerformancePercentage: timeWeightedGrossPerformancePercentage + grossPerformancePercentage: totalWeightedGrossPerformance }; }