diff --git a/app/dashboard/assets/page.tsx b/app/dashboard/assets/page.tsx
index 27a3c06..fca5edb 100644
--- a/app/dashboard/assets/page.tsx
+++ b/app/dashboard/assets/page.tsx
@@ -10,6 +10,7 @@ import {
TableHeader,
TableRow,
} from '@/components/ui/table';
+import Big from 'big.js';
export default async function AssetsPage() {
const assets = await getAssets();
@@ -53,14 +54,14 @@ export default async function AssetsPage() {
{asset.symbol}
{typeLabels[asset.type] || asset.type}
{asset.baseCurrency}
- {asset.latestPrice}
+ {asset.latestPrice ? new Big(asset.latestPrice).toString() : '-'}
{asset.createdAt
? new Date(asset.createdAt).toLocaleString('zh-CN')
: '-'}
-
+
))
diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx
index d97dd54..b30ec1d 100644
--- a/app/dashboard/page.tsx
+++ b/app/dashboard/page.tsx
@@ -90,21 +90,33 @@ export default async function DashboardPage() {
{pos.baseCurrency}
- CNY 估值
-
- ¥{formatAmount(pos.cnyValue)}
+ 持仓成本 ({pos.baseCurrency})
+
+ {formatAmount(pos.totalCostNative)}
-
+ {(() => {
+ const posPnlNative = new Big(pos.pnlNative);
+ const posPnlNativePositive = posPnlNative.gte(0);
+ return (
+
+ 当前盈亏 ({pos.baseCurrency})
+
+ {posPnlNativePositive ? '+' : ''}{formatAmount(pos.pnlNative)}
+
+
+ );
+ })()}
+
成本 (CNY)
¥{formatAmount(pos.totalCostCny)}
-
-
盈亏
+
+ 盈亏 (CNY)
- {posPnlPositive ? '+' : ''}{formattedPosPnl}
+ {posPnlPositive ? '+' : ''}{formatAmount(pos.pnlCny)}
diff --git a/src/actions/portfolio.ts b/src/actions/portfolio.ts
index 0279a82..7cc9741 100644
--- a/src/actions/portfolio.ts
+++ b/src/actions/portfolio.ts
@@ -14,6 +14,8 @@ interface Position {
cnyValue: string;
totalCostCny: string;
pnlCny: string;
+ totalCostNative: string;
+ pnlNative: string;
}
interface RawRate {
@@ -95,6 +97,7 @@ export async function getPortfolioPositions(): Promise
{
baseCurrency: string;
latestPrice: string;
totalCostCny: Big;
+ totalCostNative: Big;
}>();
for (const tx of allTransactions) {
@@ -110,6 +113,7 @@ export async function getPortfolioPositions(): Promise {
baseCurrency: tx.assetBaseCurrency || '',
latestPrice: tx.assetLatestPrice || '0',
totalCostCny: new Big('0'),
+ totalCostNative: new Big('0'),
});
}
@@ -118,10 +122,15 @@ export async function getPortfolioPositions(): Promise {
if (tx.txType === 'BUY') {
holding.quantity = holding.quantity.plus(new Big(tx.quantity));
const costPerUnit = new Big(tx.quantity).times(new Big(tx.price));
+ holding.totalCostNative = holding.totalCostNative.plus(costPerUnit);
const costCny = costPerUnit.times(new Big(tx.exchangeRate || '1'));
holding.totalCostCny = holding.totalCostCny.plus(costCny);
} else if (tx.txType === 'SELL') {
holding.quantity = holding.quantity.minus(new Big(tx.quantity));
+ const sellCostPerUnit = new Big(tx.quantity).times(new Big(tx.price));
+ holding.totalCostNative = holding.totalCostNative.minus(sellCostPerUnit);
+ const sellCostCny = sellCostPerUnit.times(new Big(tx.exchangeRate || '1'));
+ holding.totalCostCny = holding.totalCostCny.minus(sellCostCny);
} else if (tx.txType === 'AIRDROP') {
holding.quantity = holding.quantity.plus(new Big(tx.quantity));
} else if (tx.txType === 'DIVIDEND') {
@@ -160,6 +169,9 @@ export async function getPortfolioPositions(): Promise {
const pnlCny = cnyValue.minus(holding.totalCostCny);
totalPnlCny = totalPnlCny.plus(pnlCny);
+ const currentNativeValue = new Big(holding.latestPrice).times(holding.quantity);
+ const pnlNative = currentNativeValue.minus(holding.totalCostNative);
+
result.push({
assetId: holding.assetId,
symbol: holding.symbol,
@@ -169,6 +181,8 @@ export async function getPortfolioPositions(): Promise {
cnyValue: cnyValue.toString(),
totalCostCny: holding.totalCostCny.toString(),
pnlCny: pnlCny.toString(),
+ totalCostNative: holding.totalCostNative.toString(),
+ pnlNative: pnlNative.toString(),
});
}
diff --git a/src/components/transactions/add-transaction-dialog.tsx b/src/components/transactions/add-transaction-dialog.tsx
index 44a960f..99dbe86 100644
--- a/src/components/transactions/add-transaction-dialog.tsx
+++ b/src/components/transactions/add-transaction-dialog.tsx
@@ -218,9 +218,18 @@ export function AddTransactionDialog({ assets }: AddTransactionDialogProps) {
render={({ field }) => (
交易币种
-
-
-
+
)}