-
- {trade.symbol}
-
- {trade.side === 'BUY' ? '买入' : '卖出'} · {trade.status === 'open' ? '持仓中' : trade.status === 'closed' ? '已平仓' : '已取消'}
-
-
-
-
- 数量
- {parseFloat(trade.quantity).toFixed(4)}
-
-
- 入场价
- {parseFloat(trade.entry_price).toFixed(4)}
-
-
- 出场价
- {trade.exit_price ? parseFloat(trade.exit_price).toFixed(4) : '-'}
-
-
-
盈亏
-
= 0 ? 'positive' : 'negative'}`}>
- {parseFloat(trade.pnl).toFixed(2)} USDT
+ {trades.map(trade => {
+ // 计算保证金和盈亏比例
+ const entryValue = trade.entry_value_usdt !== undefined
+ ? parseFloat(trade.entry_value_usdt)
+ : (parseFloat(trade.quantity || 0) * parseFloat(trade.entry_price || 0))
+ const leverage = parseFloat(trade.leverage || 10)
+ const margin = leverage > 0 ? entryValue / leverage : 0
+ const pnl = parseFloat(trade.pnl || 0)
+ const pnlPercent = margin > 0 ? (pnl / margin) * 100 : 0
+
+ // 格式化时间为北京时间
+ const formatTime = (timeStr) => {
+ if (!timeStr) return '-'
+ try {
+ const date = new Date(timeStr)
+ if (isNaN(date.getTime())) return timeStr
+ return date.toLocaleString('zh-CN', {
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ timeZone: 'Asia/Shanghai'
+ })
+ } catch (e) {
+ return timeStr
+ }
+ }
+
+ return (
+
+
+ {trade.symbol}
+
+ {trade.side === 'BUY' ? '买入' : '卖出'} · {trade.status === 'open' ? '持仓中' : trade.status === 'closed' ? '已平仓' : '已取消'}
- {trade.exit_reason_display && (
+
- 平仓类型
- {trade.exit_reason_display}
+ 数量
+ {parseFloat(trade.quantity).toFixed(4)}
- )}
+
+ 保证金
+ {margin.toFixed(2)} USDT
+
+
+ 入场价
+ {parseFloat(trade.entry_price).toFixed(4)}
+
+
+ 出场价
+ {trade.exit_price ? parseFloat(trade.exit_price).toFixed(4) : '-'}
+
+
+ 盈亏
+ = 0 ? 'positive' : 'negative'}`}>
+ {pnl.toFixed(2)} USDT
+
+
+
+ 盈亏比例
+ = 0 ? 'positive' : 'negative'}`}>
+ {pnlPercent >= 0 ? '+' : ''}{pnlPercent.toFixed(2)}%
+
+
+ {trade.exit_reason_display && (
+
+ 平仓类型
+ {trade.exit_reason_display}
+
+ )}
+
+
+ {formatTime(trade.entry_time)}
+ {trade.exit_time && (
+ 平仓: {formatTime(trade.exit_time)}
+ )}
+
-
- {new Date(trade.entry_time).toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })}
- {trade.exit_time && (
- 平仓: {new Date(trade.exit_time).toLocaleString('zh-CN', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' })}
- )}
-
-
- ))}
+ )
+ })}
>
)}
diff --git a/recommendations-viewer/src/components/RecommendationsViewer.jsx b/recommendations-viewer/src/components/RecommendationsViewer.jsx
index 433a690..fef5e2b 100644
--- a/recommendations-viewer/src/components/RecommendationsViewer.jsx
+++ b/recommendations-viewer/src/components/RecommendationsViewer.jsx
@@ -104,6 +104,24 @@ function RecommendationsViewer() {
};
const formatTime = (timeStr) => {
+ if (!timeStr) return '-'
+ try {
+ const date = new Date(timeStr)
+ if (isNaN(date.getTime())) return timeStr
+ // 使用北京时间格式化
+ return date.toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+ timeZone: 'Asia/Shanghai' // 明确使用北京时间
+ })
+ } catch (e) {
+ return timeStr
+ }
+ }
if (!timeStr) return '-';
try {
const date = new Date(timeStr);