From 0c0b3e60237b890f2ad25f4fa55a901a986e64f5 Mon Sep 17 00:00:00 2001
From: Sebastian Legarraga <64795732+slegarraga@users.noreply.github.com>
Date: Fri, 28 Aug 2026 15:13:26 -0400
Subject: [PATCH] fix: preserve cryptocurrency quantity precision
---
.../holdings-table.component.html | 2 +-
.../holdings-table.component.ts | 5 +++
.../holdings-table/quantity-precision.spec.ts | 44 +++++++++++++++++++
.../lib/holdings-table/quantity-precision.ts | 17 +++++++
4 files changed, 67 insertions(+), 1 deletion(-)
create mode 100644 libs/ui/src/lib/holdings-table/quantity-precision.spec.ts
create mode 100644 libs/ui/src/lib/holdings-table/quantity-precision.ts
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;
+}