From dced06ebb54becf48c35815ba17e89ffd3deb830 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 19 Feb 2022 18:41:12 +0100 Subject: [PATCH] Bugfix/improve allocations (#710) * Fix allocations by account for non-unique account names * Refactor calculations with big.js * Update changelog --- CHANGELOG.md | 4 ++ .../allocations/allocations-page.component.ts | 8 +++- .../allocations/allocations-page.html | 2 +- .../portfolio-proportion-chart.component.ts | 42 +++++++++++-------- 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5efe84cd..8be92b28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Moved the countries and sectors charts in the position detail dialog - Restructured the server modules +### Fixed + +- Fixed the allocations by account for non-unique account names + ## 1.116.0 - 16.02.2022 ### Added diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts index f170a541..5cf55504 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts @@ -14,7 +14,7 @@ import { } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { ToggleOption } from '@ghostfolio/common/types'; -import { AssetClass, DataSource } from '@prisma/client'; +import { Account, AssetClass, DataSource } from '@prisma/client'; import { DeviceDetectorService } from 'ngx-device-detector'; import { Subject, Subscription } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; @@ -27,7 +27,10 @@ import { takeUntil } from 'rxjs/operators'; }) export class AllocationsPageComponent implements OnDestroy, OnInit { public accounts: { - [symbol: string]: Pick & { value: number }; + [id: string]: Pick & { + id: string; + value: number; + }; }; public continents: { [code: string]: { name: string; value: number }; @@ -171,6 +174,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit { this.portfolioDetails.accounts )) { this.accounts[id] = { + id, name, value: aPeriod === 'original' ? original : current }; diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.html b/apps/client/src/app/pages/portfolio/allocations/allocations-page.html index a210c4cd..21b5618d 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.html +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.html @@ -20,7 +20,7 @@ diff --git a/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts b/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts index ca0475d6..75593a16 100644 --- a/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts +++ b/libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts @@ -11,6 +11,7 @@ import { import { UNKNOWN_KEY } from '@ghostfolio/common/config'; import { getTextColor } from '@ghostfolio/common/helper'; import { PortfolioPosition } from '@ghostfolio/common/interfaces'; +import Big from 'big.js'; import { Tooltip } from 'chart.js'; import { LinearScale } from 'chart.js'; import { ArcElement } from 'chart.js'; @@ -78,16 +79,17 @@ export class PortfolioProportionChartComponent [symbol: string]: { color?: string; name: string; - subCategory: { [symbol: string]: { value: number } }; - value: number; + subCategory: { [symbol: string]: { value: Big } }; + value: Big; }; } = {}; Object.keys(this.positions).forEach((symbol) => { if (this.positions[symbol][this.keys[0]]) { if (chartData[this.positions[symbol][this.keys[0]]]) { - chartData[this.positions[symbol][this.keys[0]]].value += - this.positions[symbol].value; + chartData[this.positions[symbol][this.keys[0]]].value = chartData[ + this.positions[symbol][this.keys[0]] + ].value.plus(this.positions[symbol].value); if ( chartData[this.positions[symbol][this.keys[0]]].subCategory[ @@ -96,37 +98,43 @@ export class PortfolioProportionChartComponent ) { chartData[this.positions[symbol][this.keys[0]]].subCategory[ this.positions[symbol][this.keys[1]] - ].value += this.positions[symbol].value; + ].value = chartData[ + this.positions[symbol][this.keys[0]] + ].subCategory[this.positions[symbol][this.keys[1]]].value.plus( + this.positions[symbol].value + ); } else { chartData[this.positions[symbol][this.keys[0]]].subCategory[ this.positions[symbol][this.keys[1]] ?? UNKNOWN_KEY - ] = { value: this.positions[symbol].value }; + ] = { value: new Big(this.positions[symbol].value) }; } } else { chartData[this.positions[symbol][this.keys[0]]] = { name: this.positions[symbol].name, subCategory: {}, - value: this.positions[symbol].value + value: new Big(this.positions[symbol].value) }; if (this.positions[symbol][this.keys[1]]) { chartData[this.positions[symbol][this.keys[0]]].subCategory = { [this.positions[symbol][this.keys[1]]]: { - value: this.positions[symbol].value + value: new Big(this.positions[symbol].value) } }; } } } else { if (chartData[UNKNOWN_KEY]) { - chartData[UNKNOWN_KEY].value += this.positions[symbol].value; + chartData[UNKNOWN_KEY].value = chartData[UNKNOWN_KEY].value.plus( + this.positions[symbol].value + ); } else { chartData[UNKNOWN_KEY] = { name: this.positions[symbol].name, subCategory: this.keys[1] - ? { [this.keys[1]]: { value: 0 } } + ? { [this.keys[1]]: { value: new Big(0) } } : undefined, - value: this.positions[symbol].value + value: new Big(this.positions[symbol].value) }; } } @@ -134,7 +142,7 @@ export class PortfolioProportionChartComponent let chartDataSorted = Object.entries(chartData) .sort((a, b) => { - return a[1].value - b[1].value; + return a[1].value.minus(b[1].value).toNumber(); }) .reverse(); @@ -152,7 +160,7 @@ export class PortfolioProportionChartComponent if (!unknownItem) { chartDataSorted.push([ UNKNOWN_KEY, - { name: UNKNOWN_KEY, subCategory: {}, value: 0 } + { name: UNKNOWN_KEY, subCategory: {}, value: new Big(0) } ]); unknownItem = chartDataSorted[chartDataSorted.length - 1]; } @@ -162,7 +170,7 @@ export class PortfolioProportionChartComponent unknownItem[1] = { name: UNKNOWN_KEY, subCategory: {}, - value: unknownItem[1].value + restItem[1].value + value: unknownItem[1].value.plus(restItem[1].value) }; } }); @@ -170,7 +178,7 @@ export class PortfolioProportionChartComponent // Sort data again chartDataSorted = chartDataSorted .sort((a, b) => { - return a[1].value - b[1].value; + return a[1].value.minus(b[1].value).toNumber(); }) .reverse(); } @@ -201,7 +209,7 @@ export class PortfolioProportionChartComponent backgroundColorSubCategory.push( Color(item.color).lighten(lightnessRatio).hex() ); - dataSubCategory.push(item.subCategory[subCategory].value); + dataSubCategory.push(item.subCategory[subCategory].value.toNumber()); labelSubCategory.push(subCategory); lightnessRatio += 0.1; @@ -215,7 +223,7 @@ export class PortfolioProportionChartComponent }), borderWidth: 0, data: chartDataSorted.map(([, item]) => { - return item.value; + return item.value.toNumber(); }) } ];