From 8980a169eda53da76b29be089e28053cce122d91 Mon Sep 17 00:00:00 2001 From: hailin Date: Tue, 3 Feb 2026 05:56:12 -0800 Subject: [PATCH] =?UTF-8?q?fix(trading):=20=E4=BF=AE=E5=A4=8D=E5=81=9A?= =?UTF-8?q?=E5=B8=82=E5=95=86=E5=90=83=E5=8D=95=E6=89=A3=E6=AC=BE=E9=87=91?= =?UTF-8?q?=E9=A2=9D=E9=94=99=E8=AF=AF=EF=BC=88=E4=BD=BF=E7=94=A8=E4=BA=A4?= =?UTF-8?q?=E6=98=93=E6=80=BB=E9=A2=9D=E8=80=8C=E9=9D=9E=E5=8E=9F=E5=A7=8B?= =?UTF-8?q?=E6=95=B0=E9=87=8F=C3=97=E4=BB=B7=E6=A0=BC=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 问题: 做市商吃单时,buyerPayAmount = tradeQuantity × price(原始数量×价格), 未计入销毁倍数。例如:卖出 697.81 积分股,销毁倍数 5000.88, 交易总额 = 17,615.96 积分值,但做市商只被扣了 697.81 × 0.005 = 3.49。 10% 手续费(1,761.60)反而大于做市商支出,导致做市商不减反增。 修复: - 做市商吃单时:actualBuyerCost = sellerGrossAmount(含销毁倍数的交易总额) - 普通用户买入时:actualBuyerCost = buyerPayAmount(原始数量×价格,不变) - frozenCash 仍释放下单时冻结的原始金额(buyerPayAmount) - 做市商交易流水记录 assetType=CASH + 实际支付金额 做市商吃单扣款计算(修复后): MM 支出 = sellerGrossAmount(交易总额) MM 手续费收入 = tradeFee(10%) MM 净支出 = sellerReceiveAmount = 交易总额 × 90% Co-Authored-By: Claude Opus 4.5 --- .../src/application/services/order.service.ts | 61 +++++++++++++------ 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/backend/services/trading-service/src/application/services/order.service.ts b/backend/services/trading-service/src/application/services/order.service.ts index debffd1b..4fac6d9b 100644 --- a/backend/services/trading-service/src/application/services/order.service.ts +++ b/backend/services/trading-service/src/application/services/order.service.ts @@ -254,15 +254,22 @@ export class OrderService { }, }); - // 4. 更新买方账户(扣除冻结现金) - // 做市商吃单时:积分股不进做市商账户,只进流通池(事务外处理) - // 普通用户买入时:积分股直接进入买方账户 + // 4. 更新买方账户 + // 做市商吃单时: + // - 支付 sellerGrossAmount(含销毁倍数的交易总额),不是仅原始数量×价格 + // - 积分股不进做市商账户,只进流通池 + // 普通用户买入时: + // - 支付 buyerPayAmount(原始数量×价格) + // - 积分股直接进入买方账户 const buyerAccountRecord = await tx.tradingAccount.findUnique({ where: { accountSequence: match.buyOrder.accountSequence }, }); if (buyerAccountRecord) { + // 做市商实际支付 = 交易总额(含销毁倍数);普通用户支付 = 原始数量×价格 + const actualBuyerCost = isBuyerMarketMaker ? sellerGrossAmount : buyerPayAmount; + // frozenCash 释放的是下单时冻结的原始金额 const newFrozenCash = Number(buyerAccountRecord.frozenCash) - buyerPayAmount.value.toNumber(); - const newCashBalance = Number(buyerAccountRecord.cashBalance) - buyerPayAmount.value.toNumber(); + const newCashBalance = Number(buyerAccountRecord.cashBalance) - actualBuyerCost.value.toNumber(); const newShareBalance = isBuyerMarketMaker ? Number(buyerAccountRecord.shareBalance) : Number(buyerAccountRecord.shareBalance) + tradeQuantity.value.toNumber(); @@ -279,21 +286,37 @@ export class OrderService { }); // 记录买方交易流水 - await tx.tradingTransaction.create({ - data: { - accountSequence: match.buyOrder.accountSequence, - type: 'BUY', - assetType: 'SHARE', - amount: tradeQuantity.value, - balanceBefore: buyerAccountRecord.shareBalance, - balanceAfter: newShareBalance, - referenceId: match.trade.tradeNo, - referenceType: 'TRADE', - description: isBuyerMarketMaker - ? '做市商吃单(积分股→流通池)' - : '买入成交', - }, - }); + if (isBuyerMarketMaker) { + // 做市商:记录现金支出(交易总额) + await tx.tradingTransaction.create({ + data: { + accountSequence: match.buyOrder.accountSequence, + type: 'BUY', + assetType: 'CASH', + amount: actualBuyerCost.value, + balanceBefore: buyerAccountRecord.cashBalance, + balanceAfter: newCashBalance, + referenceId: match.trade.tradeNo, + referenceType: 'TRADE', + description: `做市商吃单(积分股→流通池), 交易总额${sellerGrossAmount.toFixed(4)}`, + }, + }); + } else { + // 普通用户:记录积分股收入 + await tx.tradingTransaction.create({ + data: { + accountSequence: match.buyOrder.accountSequence, + type: 'BUY', + assetType: 'SHARE', + amount: tradeQuantity.value, + balanceBefore: buyerAccountRecord.shareBalance, + balanceAfter: newShareBalance, + referenceId: match.trade.tradeNo, + referenceType: 'TRADE', + description: '买入成交', + }, + }); + } } // 5. 更新卖方账户(扣除冻结积分股,增加现金)