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 e66dac725..6ffeb8442 100644
--- a/libs/ui/src/lib/holdings-table/holdings-table.component.html
+++ b/libs/ui/src/lib/holdings-table/holdings-table.component.html
@@ -80,9 +80,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 7fe21720e..8dd46b3e7 100644
--- a/libs/ui/src/lib/holdings-table/holdings-table.component.ts
+++ b/libs/ui/src/lib/holdings-table/holdings-table.component.ts
@@ -28,6 +28,7 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { GfEntityLogoComponent } from '../entity-logo/entity-logo.component';
import { GfValueComponent } from '../value/value.component';
+import { getHoldingQuantityPrecision } from './quantity-precision';
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
@@ -103,6 +104,10 @@ export class GfHoldingsTableComponent {
return this.hasPermissionToOpenDetails() && canOpenHoldingDetail(holding);
}
+ protected getQuantityPrecision(holding: PortfolioPosition): 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 000000000..f2ab31327
--- /dev/null
+++ b/libs/ui/src/lib/holdings-table/quantity-precision.spec.ts
@@ -0,0 +1,44 @@
+import { PortfolioPosition } from '@ghostfolio/common/interfaces';
+
+import { AssetSubClass } from '@prisma/client';
+
+import { getHoldingQuantityPrecision } from './quantity-precision';
+
+function createHolding(
+ quantity: number,
+ assetSubClass: AssetSubClass
+): Pick {
+ return {
+ assetProfile: { assetSubClass } as PortfolioPosition['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);
+ });
+});
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 000000000..42bc37ee0
--- /dev/null
+++ b/libs/ui/src/lib/holdings-table/quantity-precision.ts
@@ -0,0 +1,17 @@
+import { PortfolioPosition } from '@ghostfolio/common/interfaces';
+
+import { AssetSubClass } from '@prisma/client';
+
+export function getHoldingQuantityPrecision(
+ holding: Pick
+): number {
+ if (Number.isInteger(holding.quantity)) {
+ return 0;
+ }
+
+ if (holding.assetProfile.assetSubClass === AssetSubClass.CRYPTOCURRENCY) {
+ return 8;
+ }
+
+ return 2;
+}