This commit is contained in:
薇薇安 2026-01-22 18:51:26 +08:00
parent 244ef6f4ba
commit 06272b6922

View File

@ -6,7 +6,7 @@ const TradeList = () => {
const [trades, setTrades] = useState([])
const [stats, setStats] = useState(null)
const [loading, setLoading] = useState(true)
//
const [period, setPeriod] = useState('today') // '1d', '7d', '30d', 'today', 'week', 'month', null
const [startDate, setStartDate] = useState('')
@ -19,13 +19,13 @@ const TradeList = () => {
useEffect(() => {
loadData()
//
const handleAccountChange = () => {
loadData()
}
window.addEventListener('ats:account:changed', handleAccountChange)
return () => {
window.removeEventListener('ats:account:changed', handleAccountChange)
}
@ -37,7 +37,7 @@ const TradeList = () => {
const params = {
limit: 100
}
// 使
if (!useCustomDate && period) {
params.period = period
@ -46,12 +46,12 @@ const TradeList = () => {
if (startDate) params.start_date = startDate
if (endDate) params.end_date = endDate
}
if (symbol) params.symbol = symbol
if (status) params.status = status
if (tradeType) params.trade_type = tradeType
if (exitReason) params.exit_reason = exitReason
const [tradesData, statsData] = await Promise.all([
api.getTrades(params),
api.getTradeStats(params)
@ -96,49 +96,49 @@ const TradeList = () => {
<p style={{ color: '#666', fontSize: '14px', marginTop: '-10px', marginBottom: '20px' }}>
说明每条记录代表一笔完整的交易开仓+平仓统计总盈亏时每条记录只计算一次
</p>
{/* 筛选面板 */}
<div className="filter-panel">
<div className="filter-section">
<label>快速筛选</label>
<div className="period-buttons">
<button
<button
className={period === 'today' ? 'active' : ''}
onClick={() => handlePeriodChange('today')}
>
今天
</button>
<button
<button
className={period === 'week' ? 'active' : ''}
onClick={() => handlePeriodChange('week')}
>
本周
</button>
<button
<button
className={period === 'month' ? 'active' : ''}
onClick={() => handlePeriodChange('month')}
>
本月
</button>
<button
<button
className={period === '1d' ? 'active' : ''}
onClick={() => handlePeriodChange('1d')}
>
最近1天
</button>
<button
<button
className={period === '7d' ? 'active' : ''}
onClick={() => handlePeriodChange('7d')}
>
最近7天
</button>
<button
<button
className={period === '30d' ? 'active' : ''}
onClick={() => handlePeriodChange('30d')}
>
最近30天
</button>
<button
<button
className={period === null && !useCustomDate ? 'active' : ''}
onClick={() => handlePeriodChange(null)}
>
@ -149,8 +149,8 @@ const TradeList = () => {
<div className="filter-section">
<label>
<input
type="checkbox"
<input
type="checkbox"
checked={useCustomDate}
onChange={handleCustomDateToggle}
/>
@ -248,14 +248,34 @@ const TradeList = () => {
<div className="stat-value">总盈亏{stats.total_pnl.toFixed(2)} USDT</div>
<div className="stat-value">平均盈亏{stats.avg_pnl.toFixed(2)} USDT</div>
<div className="stat-value">平均持仓时长分钟{Number(stats.avg_duration_minutes || 0).toFixed(0)}</div>
<div className="stat-value">平仓原因有意义交易{stats.exit_reason_counts.join(' / ')}</div>
<div className="stat-value">平仓原因有意义交易
<div className="stat-value" style={{ fontSize: '1.1rem' }}>
{(() => {
const m = stats.exit_reason_counts || {}
const stopLoss = Number(m.stop_loss || 0)
const takeProfit = Number(m.take_profit || 0)
const trailing = Number(m.trailing_stop || 0)
const manual = Number(m.manual || 0)
const sync = Number(m.sync || 0)
const other = Number(m.unknown || 0)
const parts = []
if (stopLoss) parts.push(`止损 ${stopLoss}`)
if (takeProfit) parts.push(`止盈 ${takeProfit}`)
if (trailing) parts.push(`移动止损 ${trailing}`)
if (manual) parts.push(`手动 ${manual}`)
if (sync) parts.push(`同步 ${sync}`)
if (other) parts.push(`其他 ${other}`)
return parts.length ? parts.join(' / ') : '—'
})()}
</div>
</div>
<div className="stat-value">平均盈利 / 平均亏损期望 3:1{stats.avg_win_loss_ratio.toFixed(2)} : 1</div>
<div className="stat-value">总交易量名义{stats.total_notional_usdt.toFixed(2)} USDT</div>
</div>
</div>
)
}
{stats && (
<div className="stats-summary">
<div className="stat-card">
@ -324,9 +344,8 @@ const TradeList = () => {
<div className="stat-card">
<div className="stat-label">平均盈利 / 平均亏损期望 3:1</div>
<div
className={`stat-value ${
typeof stats.avg_win_loss_ratio === 'number' && stats.avg_win_loss_ratio >= 3 ? 'positive' : ''
}`}
className={`stat-value ${typeof stats.avg_win_loss_ratio === 'number' && stats.avg_win_loss_ratio >= 3 ? 'positive' : ''
}`}
>
{typeof stats.avg_win_loss_ratio === 'number'
? `${stats.avg_win_loss_ratio.toFixed(2)} : 1`
@ -380,19 +399,19 @@ const TradeList = () => {
const notional = trade.notional_usdt !== undefined && trade.notional_usdt !== null
? parseFloat(trade.notional_usdt)
: (
trade.entry_value_usdt !== undefined && trade.entry_value_usdt !== null
? parseFloat(trade.entry_value_usdt)
: (parseFloat(trade.quantity || 0) * parseFloat(trade.entry_price || 0))
)
trade.entry_value_usdt !== undefined && trade.entry_value_usdt !== null
? parseFloat(trade.entry_value_usdt)
: (parseFloat(trade.quantity || 0) * parseFloat(trade.entry_price || 0))
)
const leverage = parseFloat(trade.leverage || 10)
const margin = trade.margin_usdt !== undefined && trade.margin_usdt !== null
? parseFloat(trade.margin_usdt)
: (leverage > 0 ? notional / leverage : 0)
// /
const pnl = parseFloat(trade.pnl || 0)
const pnlPercent = margin > 0 ? (pnl / margin) * 100 : 0
//
// Unix
const formatTime = (timeValue) => {
@ -418,7 +437,7 @@ const TradeList = () => {
return String(timeValue)
}
}
//
const formatOrderIds = () => {
const entry = trade.entry_order_id || '-'
@ -429,7 +448,7 @@ const TradeList = () => {
}
return entry !== '-' ? `开仓: ${entry}` : `平仓: ${exit}`
}
return (
<tr key={trade.id}>
<td style={{ fontSize: '12px', color: '#999' }}>#{trade.id}</td>
@ -458,7 +477,7 @@ const TradeList = () => {
})}
</tbody>
</table>
{/* 移动端卡片 */}
<div className="trades-cards">
{trades.map(trade => {
@ -466,17 +485,17 @@ const TradeList = () => {
const notional = trade.notional_usdt !== undefined && trade.notional_usdt !== null
? parseFloat(trade.notional_usdt)
: (
trade.entry_value_usdt !== undefined && trade.entry_value_usdt !== null
? parseFloat(trade.entry_value_usdt)
: (parseFloat(trade.quantity || 0) * parseFloat(trade.entry_price || 0))
)
trade.entry_value_usdt !== undefined && trade.entry_value_usdt !== null
? parseFloat(trade.entry_value_usdt)
: (parseFloat(trade.quantity || 0) * parseFloat(trade.entry_price || 0))
)
const leverage = parseFloat(trade.leverage || 10)
const margin = trade.margin_usdt !== undefined && trade.margin_usdt !== null
? parseFloat(trade.margin_usdt)
: (leverage > 0 ? notional / leverage : 0)
const pnl = parseFloat(trade.pnl || 0)
const pnlPercent = margin > 0 ? (pnl / margin) * 100 : 0
//
// Unix
const formatTime = (timeValue) => {
@ -501,7 +520,7 @@ const TradeList = () => {
return String(timeValue)
}
}
return (
<div key={trade.id} className="trade-card">
<div className="trade-card-header">
@ -562,17 +581,17 @@ const TradeList = () => {
)}
</div>
<div className="trade-card-footer">
<div className="trade-time-item">
<span className="time-label">入场:</span>
<span>{formatTime(trade.entry_time)}</span>
</div>
{trade.exit_time && (
<div className="trade-time-item">
<span className="time-label">平仓:</span>
<span>{formatTime(trade.exit_time)}</span>
<span className="time-label">入场:</span>
<span>{formatTime(trade.entry_time)}</span>
</div>
)}
</div>
{trade.exit_time && (
<div className="trade-time-item">
<span className="time-label">平仓:</span>
<span>{formatTime(trade.exit_time)}</span>
</div>
)}
</div>
</div>
)
})}