quant-ai / frontend /src /components /LedgerTable.tsx
Ypeng12's picture
feat: Implement Historical Replay Simulator, Intraday Trade Inspector, and typography bugfixes
c1bdf7c
Raw
History Blame Contribute Delete
3.24 kB
// frontend/src/components/LedgerTable.tsx
import React from 'react';
export interface LedgerItem {
timestamp: string;
action: 'BUY' | 'SELL';
ticker: string;
shares: number;
market_price: number;
execution_price: number;
commission: number;
total_value: number;
total_cost?: number;
revenue?: number;
realized_pnl?: number;
cash_remaining: number;
}
interface LedgerTableProps {
ledger: LedgerItem[];
onRowClick?: (item: LedgerItem) => void;
}
export const LedgerTable: React.FC<LedgerTableProps> = ({ ledger, onRowClick }) => {
const formatTime = (timeStr: string) => {
// 简化时间显示,只保留 "YYYY-MM-DD HH:MM"
try {
const parts = timeStr.split(' ');
if (parts.length >= 2) {
return `${parts[0]} ${parts[1].substring(0, 5)}`;
}
} catch (e) {}
return timeStr;
};
return (
<div className="card" style={{ overflowX: 'auto' }}>
<h3 className="card-title">交易流水账单 (Transaction Ledger)</h3>
{ledger.length === 0 ? (
<p style={{ color: 'var(--color-text-secondary)', margin: 0 }}>
回测期间系统保持空仓防守,未触发交易信号。
</p>
) : (
<table className="ledger-table">
<thead>
<tr>
<th>交易时间</th>
<th>操作</th>
<th>代码</th>
<th>股数</th>
<th>成交均价</th>
<th>( 盘面价格 )</th>
<th>交易手续费</th>
<th style={{ textAlign: 'right' }}>净收益 PnL</th>
</tr>
</thead>
<tbody>
{[...ledger].reverse().map((item, index) => {
const pnl = item.realized_pnl;
const hasPnl = pnl !== undefined && item.action === 'SELL';
const pnlColor = hasPnl ? (pnl >= 0 ? 'var(--color-green)' : 'var(--color-red)') : 'inherit';
const pnlText = hasPnl ? `${pnl >= 0 ? '+' : ''}$${pnl.toFixed(2)}` : '--';
return (
<tr
key={index}
onClick={() => onRowClick && onRowClick(item)}
style={{ cursor: onRowClick ? 'pointer' : 'default' }}
>
<td>{formatTime(item.timestamp)}</td>
<td>
<span className={`action-badge ${item.action.toLowerCase()}`}>
{item.action === 'BUY' ? 'BUY / 买入' : 'SELL / 平仓'}
</span>
</td>
<td style={{ fontWeight: 700 }}>{item.ticker}</td>
<td>{item.shares}</td>
<td>${item.execution_price.toFixed(2)}</td>
<td style={{ color: 'var(--color-text-secondary)', fontSize: '0.85rem' }}>
${item.market_price.toFixed(2)}
</td>
<td style={{ color: 'var(--color-red)' }}>${item.commission.toFixed(2)}</td>
<td style={{ textAlign: 'right', fontWeight: 700, color: pnlColor }}>
{pnlText}
</td>
</tr>
);
})}
</tbody>
</table>
)}
</div>
);
};