feat(订单推送/通知): 按实际成交价与 size_matched 展示价格与数量

- 实际成交价公式: original_size * price / size_matched,数量展示用 size_matched
- OrderPushService/OrderStatusUpdateService/CryptoTail: 用公式计算 avgFilledPrice,移除 getTrades 依赖
- TelegramNotificationService: 有 avgFilledPrice 时展示数量用 filled,ORDER_SUCCESS/CRYPTO_TAIL 一致
- 前端订单推送: 有成交时展示 size_matched;无 orderDetail 时用 WebSocket 数据计算价格与数量
- OrderDetailDto 增加 avgFilledPrice;PolymarketClobService 移除 getAvgFilledPriceFromTradeIds

Made-with: Cursor
This commit is contained in:
WrBug
2026-03-02 23:05:15 +08:00
parent b8e10f340c
commit 561ebf0ce3
11 changed files with 194 additions and 48 deletions
+20 -11
View File
@@ -117,28 +117,37 @@ function App() {
}
}
// 优先使用订单详情中的数据,如果没有则使用 WebSocket 消息中的数据
const price = orderDetail ? parseFloat(orderDetail.price).toFixed(4) : parseFloat(order.price).toFixed(4)
const size = orderDetail ? parseFloat(orderDetail.size).toFixed(2) : parseFloat(order.original_size).toFixed(2)
const filled = orderDetail ? parseFloat(orderDetail.filled).toFixed(2) : parseFloat(order.size_matched).toFixed(2)
// 实际成交价 = original_size*price/size_matched;有成交时数量用 size_matched
const size = orderDetail ? orderDetail.size : order.original_size
const filled = orderDetail ? orderDetail.filled : order.size_matched
const sizeNum = parseFloat(size).toFixed(2)
const filledNum = parseFloat(filled).toFixed(2)
const hasFilled = parseFloat(filled) > 0
const price = orderDetail
? (orderDetail.avgFilledPrice ?? orderDetail.price)
: (hasFilled
? (parseFloat(order.original_size) * parseFloat(order.price) / parseFloat(order.size_matched)).toString()
: order.price)
const priceStr = parseFloat(price).toFixed(4)
const status = orderDetail?.status || 'UNKNOWN'
// 有成交时展示数量用 size_matchedfilled),否则用 original_size
const displaySize = (orderDetail?.avgFilledPrice || (orderDetail == null && hasFilled)) ? filledNum : sizeNum
// 构建描述信息
let description = `${t('order.market')}: ${marketName}\n${sideText} ${size} @ ${price}`
let description = `${t('order.market')}: ${marketName}\n${sideText} ${displaySize} @ ${priceStr}`
// 如果有订单详情,显示更详细的信息
if (orderDetail) {
description += `\n${t('order.status')}: ${status}`
if (parseFloat(filled) > 0) {
description += ` | ${t('order.filled')}: ${filled}`
if (parseFloat(filledNum) > 0) {
description += ` | ${t('order.filled')}: ${filledNum}`
}
const remaining = (parseFloat(size) - parseFloat(filled)).toFixed(2)
const remaining = (parseFloat(sizeNum) - parseFloat(filledNum)).toFixed(2)
if (parseFloat(remaining) > 0) {
description += ` | ${t('order.remaining')}: ${remaining}`
}
} else if (order.type === 'UPDATE' && parseFloat(order.size_matched) > 0) {
// 如果没有订单详情,使用 WebSocket 消息中的已成交数量
description += `\n${t('order.filled')}: ${filled}`
description += `\n${t('order.filled')}: ${filledNum}`
}
// 根据订单类型选择通知类型
+3 -1
View File
@@ -580,12 +580,13 @@ export interface OrderMessage {
/**
* 订单详情(通过 API 获取)
* price 为订单限价,avgFilledPrice 为平均成交价(有成交时优先用于展示)
*/
export interface OrderDetail {
id: string // 订单 ID
market: string // 市场 ID (condition ID)
side: string // BUY/SELL
price: string // 价
price: string // 订单限
size: string // 订单大小
filled: string // 已成交数量
status: string // 订单状态
@@ -593,6 +594,7 @@ export interface OrderDetail {
marketName?: string // 市场名称
marketSlug?: string // 市场 slug
marketIcon?: string // 市场图标
avgFilledPrice?: string // 平均成交价(有成交时优先展示)
}
/**