import Big from 'big.js'; // 定义流水参数结构 export interface TxRecord { date: string | Date; txType: 'BUY' | 'SELL' | 'DIVIDEND' | string; quantity: string | number; price: string | number; fee: string | number; totalValue?: string | number; } export function calculateAssetMetrics(transactions: TxRecord[], currentPrice: string | number) { let holdings = new Big(0); let totalInvested = new Big(0); let totalRealized = new Big(0); let averageCost = new Big(0); const sortedTx = [...transactions].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()); for (const tx of sortedTx) { const qty = new Big(tx.quantity || 0); const price = new Big(tx.price || 0); const fee = new Big(tx.fee || 0); if (tx.txType === 'BUY') { const cost = qty.times(price).plus(fee); totalInvested = totalInvested.plus(cost); if (holdings.plus(qty).gt(0)) { const oldTotalValue = holdings.times(averageCost); averageCost = oldTotalValue.plus(cost).div(holdings.plus(qty)); } holdings = holdings.plus(qty); } else if (tx.txType === 'SELL') { const revenue = qty.times(price).minus(fee); totalRealized = totalRealized.plus(revenue); holdings = holdings.minus(qty); if (holdings.lte(0)) { holdings = new Big(0); averageCost = new Big(0); } } else if (tx.txType === 'DIVIDEND') { totalRealized = totalRealized.plus(tx.totalValue || 0); } } const currentMarketValue = holdings.times(new Big(currentPrice)); const accumulatedPnl = currentMarketValue.plus(totalRealized).minus(totalInvested); const floatingPnl = holdings.gt(0) ? new Big(currentPrice).minus(averageCost).times(holdings) : new Big(0); const dilutedCost = holdings.gt(0) ? totalInvested.minus(totalRealized).div(holdings) : new Big(0); return { holdings: holdings.toString(), averageCost: averageCost.toString(), dilutedCost: dilutedCost.toString(), floatingPnl: floatingPnl.toString(), accumulatedPnl: accumulatedPnl.toString(), marketValue: currentMarketValue.toString() }; }