diff --git a/CHANGELOG.md b/CHANGELOG.md index 5de9cac071..49a372ebac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved the style of the close button in the dialog header component - Upgraded `prettier` from version `3.9.9` to `3.9.10` +### Fixed + +- Fixed the precision of cryptocurrency quantities in the holdings table + ## 3.90.0 - 2026-10-21 ### Changed diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.html b/libs/ui/src/lib/holdings-table/holdings-table.component.html index 025be8a723..68fe6b077a 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.html +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html @@ -101,9 +101,9 @@ >
diff --git a/libs/ui/src/lib/holdings-table/holdings-table.component.ts b/libs/ui/src/lib/holdings-table/holdings-table.component.ts index 3181cc1347..53755bfa9e 100644 --- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts +++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts @@ -29,6 +29,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { GfEntityLogoComponent } from '../entity-logo/entity-logo.component'; import { GfValueComponent } from '../value/value.component'; import { HoldingsTableItem } from './interfaces/interfaces'; +import { getHoldingQuantityPrecision } from './quantity-precision'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -144,6 +145,10 @@ export class GfHoldingsTableComponent { : ''; } + protected getQuantityPrecision(holding: HoldingsTableItem): number { + return getHoldingQuantityPrecision(holding); + } + protected onOpenHoldingDialog({ dataSource, symbol diff --git a/libs/ui/src/lib/holdings-table/quantity-precision.spec.ts b/libs/ui/src/lib/holdings-table/quantity-precision.spec.ts new file mode 100644 index 0000000000..7199c5a8ec --- /dev/null +++ b/libs/ui/src/lib/holdings-table/quantity-precision.spec.ts @@ -0,0 +1,51 @@ +import { AssetSubClass } from '@ghostfolio/prisma/enums'; + +import { HoldingsTableItem } from './interfaces/interfaces'; +import { getHoldingQuantityPrecision } from './quantity-precision'; + +function createHolding( + quantity: number | undefined, + assetSubClass: AssetSubClass +): Pick { + return { + assetProfile: { assetSubClass } as HoldingsTableItem['assetProfile'], + quantity + }; +} + +describe('getHoldingQuantityPrecision', () => { + it('preserves satoshi precision for fractional cryptocurrency quantities', () => { + expect( + getHoldingQuantityPrecision( + createHolding(0.01525217, AssetSubClass.CRYPTOCURRENCY) + ) + ).toBe(8); + expect( + getHoldingQuantityPrecision( + createHolding(10.12345678, AssetSubClass.CRYPTOCURRENCY) + ) + ).toBe(8); + }); + + it('does not add decimal places to integer cryptocurrency quantities', () => { + expect( + getHoldingQuantityPrecision( + createHolding(12, AssetSubClass.CRYPTOCURRENCY) + ) + ).toBe(0); + }); + + it('keeps the existing precision for non-cryptocurrency quantities', () => { + expect( + getHoldingQuantityPrecision(createHolding(12.3456, AssetSubClass.STOCK)) + ).toBe(2); + }); + + it('does not add decimal places when the quantity is not available', () => { + expect( + getHoldingQuantityPrecision( + createHolding(undefined, AssetSubClass.CRYPTOCURRENCY) + ) + ).toBe(0); + }); +}); diff --git a/libs/ui/src/lib/holdings-table/quantity-precision.ts b/libs/ui/src/lib/holdings-table/quantity-precision.ts new file mode 100644 index 0000000000..a51d1a60a7 --- /dev/null +++ b/libs/ui/src/lib/holdings-table/quantity-precision.ts @@ -0,0 +1,18 @@ +import { AssetSubClass } from '@ghostfolio/prisma/enums'; + +import { HoldingsTableItem } from './interfaces/interfaces'; + +export function getHoldingQuantityPrecision({ + assetProfile, + quantity +}: Pick): number { + if (quantity === undefined || Number.isInteger(quantity)) { + return 0; + } + + if (assetProfile.assetSubClass === AssetSubClass.CRYPTOCURRENCY) { + return 8; + } + + return 2; +}