From aadc63cbab8eabe8eb87ad609d24e4375516fffa Mon Sep 17 00:00:00 2001 From: Valentin Zickner Date: Sat, 31 Jul 2021 18:16:55 +0200 Subject: [PATCH] fix calculation for overall gross performance percentage --- .../src/app/core/portfolio-calculator.spec.ts | 18 ++-- apps/api/src/app/core/portfolio-calculator.ts | 94 +++++++++++-------- 2 files changed, 63 insertions(+), 49 deletions(-) diff --git a/apps/api/src/app/core/portfolio-calculator.spec.ts b/apps/api/src/app/core/portfolio-calculator.spec.ts index 92c262e4c..e2fd3f2a6 100644 --- a/apps/api/src/app/core/portfolio-calculator.spec.ts +++ b/apps/api/src/app/core/portfolio-calculator.spec.ts @@ -636,7 +636,7 @@ describe('PortfolioCalculator', () => { hasErrors: false, currentValue: new Big('657.62'), grossPerformance: new Big('-61.84'), - grossPerformancePercentage: new Big('-0.08456342256692519389'), + grossPerformancePercentage: new Big('-0.08595335390431712673'), positions: [ { averagePrice: new Big('719.46'), @@ -674,7 +674,7 @@ describe('PortfolioCalculator', () => { hasErrors: false, currentValue: new Big('657.62'), grossPerformance: new Big('-61.84'), - grossPerformancePercentage: new Big('-0.08456342256692519389'), + grossPerformancePercentage: new Big('-0.08595335390431712673'), positions: [ { averagePrice: new Big('719.46'), @@ -712,7 +712,7 @@ describe('PortfolioCalculator', () => { hasErrors: false, currentValue: new Big('657.62'), grossPerformance: new Big('-9.04'), - grossPerformancePercentage: new Big('-0.01206012060120601206'), + grossPerformancePercentage: new Big('-0.01356013560135601356'), positions: [ { averagePrice: new Big('719.46'), @@ -750,7 +750,7 @@ describe('PortfolioCalculator', () => { hasErrors: false, currentValue: new Big('4871.5'), grossPerformance: new Big('240.4'), - grossPerformancePercentage: new Big('0.08908669575467971768'), + grossPerformancePercentage: new Big('0.08839407904876477102'), positions: [ { averagePrice: new Big('178.438'), @@ -830,7 +830,7 @@ describe('PortfolioCalculator', () => { hasErrors: false, currentValue: new Big('3897.2'), grossPerformance: new Big('303.2'), - grossPerformancePercentage: new Big('0.2759628350186678759'), + grossPerformancePercentage: new Big('0.27537838148272398344'), positions: [ { averagePrice: new Big('146.185'), @@ -903,7 +903,7 @@ describe('PortfolioCalculator', () => { hasErrors: false, currentValue: new Big('1192327.999656600298238721'), grossPerformance: new Big('92327.999656600898394721'), - grossPerformancePercentage: new Big('0.09788598099999947809'), + grossPerformancePercentage: new Big('0.09788498099999947809'), positions: [ { averagePrice: new Big('1.01287018290924923237'), // 1'100'000 / 1'086'022.689344542 @@ -989,9 +989,9 @@ describe('PortfolioCalculator', () => { spy.mockRestore(); expect(currentPositions).toEqual({ - currentValue: '517', - grossPerformance: '17', // 517 - 500 - grossPerformancePercentage: '0.034', // ((200 * 2.5) + (300 * 4)) / (200 + 300) = 3.4% + currentValue: new Big('517'), + grossPerformance: new Big('17'), // 517 - 500 + grossPerformancePercentage: new Big('0.034'), // ((200 * 0.025) + (300 * 0.04)) / (200 + 300) = 3.4% hasErrors: false, positions: [ { diff --git a/apps/api/src/app/core/portfolio-calculator.ts b/apps/api/src/app/core/portfolio-calculator.ts index 558e0f773..375819beb 100644 --- a/apps/api/src/app/core/portfolio-calculator.ts +++ b/apps/api/src/app/core/portfolio-calculator.ts @@ -297,48 +297,15 @@ export class PortfolioCalculator { transactionCount: item.transactionCount }); } - - let currentValue = new Big(0); - let overallGrossPerformance = new Big(0); - let grossPerformancePercentage = new Big(1); - let completeInitialValue = new Big(0); - for (const currentPosition of positions) { - currentValue = currentValue.add( - new Big(currentPosition.marketPrice).mul(currentPosition.quantity) - ); - if (currentPosition.grossPerformance) { - overallGrossPerformance = overallGrossPerformance.plus( - currentPosition.grossPerformance - ); - } else { - hasErrors = true; - } - if ( - currentPosition.grossPerformancePercentage && - initialValues[currentPosition.symbol] - ) { - const currentInitialValue = initialValues[currentPosition.symbol]; - completeInitialValue = completeInitialValue.plus(currentInitialValue); - grossPerformancePercentage = grossPerformancePercentage.plus( - currentPosition.grossPerformancePercentage.mul(currentInitialValue) - ); - } else { - console.log(initialValues); - console.error( - 'initial value is missing for symbol', - currentPosition.symbol - ); - hasErrors = true; - } - } + const overall = this.calculateOverallGrossPerformance( + positions, + initialValues + ); return { - hasErrors, - positions, - grossPerformance: overallGrossPerformance, - grossPerformancePercentage: - grossPerformancePercentage.div(completeInitialValue), - currentValue + ...overall, + hasErrors: hasErrors || overall.hasErrors, + positions }; } @@ -404,6 +371,53 @@ export class PortfolioCalculator { return flatten(timelinePeriods); } + private calculateOverallGrossPerformance( + positions: TimelinePosition[], + initialValues: { [p: string]: Big } + ) { + let hasErrors = false; + let currentValue = new Big(0); + let grossPerformance = new Big(0); + let grossPerformancePercentage = new Big(0); + let completeInitialValue = new Big(0); + for (const currentPosition of positions) { + currentValue = currentValue.add( + new Big(currentPosition.marketPrice).mul(currentPosition.quantity) + ); + if (currentPosition.grossPerformance) { + grossPerformance = grossPerformance.plus( + currentPosition.grossPerformance + ); + } else { + hasErrors = true; + } + + if ( + currentPosition.grossPerformancePercentage && + initialValues[currentPosition.symbol] + ) { + const currentInitialValue = initialValues[currentPosition.symbol]; + completeInitialValue = completeInitialValue.plus(currentInitialValue); + grossPerformancePercentage = grossPerformancePercentage.plus( + currentPosition.grossPerformancePercentage.mul(currentInitialValue) + ); + } else { + console.error( + 'initial value is missing for symbol', + currentPosition.symbol + ); + hasErrors = true; + } + } + return { + currentValue, + grossPerformance, + grossPerformancePercentage: + grossPerformancePercentage.div(completeInitialValue), + hasErrors + }; + } + private async getTimePeriodForDate( j: number, startDate: Date,