fix(api): 修复时光机引擎本金未折算汇率 bug,重建历史财务快照

This commit is contained in:
2026-05-02 22:33:29 +08:00
parent 89b40a72bb
commit 189266c5e3
2 changed files with 33 additions and 7 deletions
+26 -7
View File
@@ -32,13 +32,8 @@ export async function recordDailySnapshot() {
new Big(0)
).toString();
// 推导真实投入本金 CNY = 市值 - 累计盈亏
const totalCostCny = positions.reduce(
(sum, pos) => {
const mv = new Big(pos.marketValueCny || '0');
const ap = new Big(pos.accumulatedPnlCny || '0');
return sum.plus(mv.minus(ap));
},
(sum, pos) => sum.plus(new Big(pos.totalCostCny || '0')),
new Big(0)
).toString();
@@ -357,6 +352,7 @@ export async function reconstructPortfolioHistory() {
quantity: transactions.quantity,
price: transactions.price,
fee: transactions.fee,
exchangeRate: transactions.exchangeRate,
})
.from(transactions)
.where(lte(transactions.executedAt, currentDate))
@@ -399,7 +395,30 @@ export async function reconstructPortfolioHistory() {
const metrics = calculateAssetMetrics(assetTxs, priceStrForMetrics);
const posValueCny = new Big(metrics.marketValue).times(snapshotFxRate);
const posCostCny = new Big(metrics.accumulatedCost || '0');
// 使用交易时的真实汇率计算法币本金,而非直接用 metrics.accumulatedCost
let calculatedFiatCost = new Big(0);
const rawTxs = historicalTx.filter(t => t.assetId === assetId && (t.txType === 'BUY' || t.txType === 'SELL' || t.txType === 'DIVIDEND'));
let currentQty = new Big(0);
for (const tx of rawTxs) {
const qty = new Big(tx.quantity);
const fx = new Big(tx.exchangeRate || '1');
const price = new Big(tx.price);
if (tx.txType === 'BUY') {
currentQty = currentQty.plus(qty);
calculatedFiatCost = calculatedFiatCost.plus(qty.times(price).times(fx));
} else if (tx.txType === 'SELL') {
let avgFiatCostPerUnit = new Big(0);
if (currentQty.gt(0)) {
avgFiatCostPerUnit = calculatedFiatCost.div(currentQty);
}
calculatedFiatCost = calculatedFiatCost.minus(avgFiatCostPerUnit.times(qty));
currentQty = currentQty.minus(qty);
}
}
const posCostCny = calculatedFiatCost.gt(0) ? calculatedFiatCost : new Big(0);
totalValueCny = totalValueCny.plus(posValueCny);
totalCostCny = totalCostCny.plus(posCostCny);