1
This commit is contained in:
parent
7bc384a58f
commit
1e55365d43
|
|
@ -12,7 +12,7 @@ const TradeList = () => {
|
|||
const [showStatsTable, setShowStatsTable] = useState(false) // 控制详细统计表格折叠
|
||||
|
||||
// 筛选状态
|
||||
const [period, setPeriod] = useState('today') // '1d', '7d', '30d', 'today', 'week', 'month', null
|
||||
const [period, setPeriod] = useState('7d') // 默认最近7天,与 3 小时同步节奏匹配,易看到数据
|
||||
const [startDate, setStartDate] = useState('')
|
||||
const [endDate, setEndDate] = useState('')
|
||||
const [symbol, setSymbol] = useState('')
|
||||
|
|
@ -20,17 +20,12 @@ const TradeList = () => {
|
|||
const [useCustomDate, setUseCustomDate] = useState(false)
|
||||
const [tradeType, setTradeType] = useState('')
|
||||
const [exitReason, setExitReason] = useState('')
|
||||
const [reconciledOnly, setReconciledOnly] = useState(true) // 默认仅可对账,与币安一致
|
||||
const [timeFilter, setTimeFilter] = useState('exit') // 'exit' 按平仓时间(今天=今天平掉的单), 'entry' 按开仓时间
|
||||
const [syncing, setSyncing] = useState(false) // 同步订单状态
|
||||
const [syncResult, setSyncResult] = useState(null) // 同步结果
|
||||
const [syncDays, setSyncDays] = useState(7) // 同步天数
|
||||
const [syncAllSymbols, setSyncAllSymbols] = useState(false) // 是否同步所有交易对的订单
|
||||
const [dataSource, setDataSource] = useState('binance') // 'binance' | 'local',默认币安成交更可靠
|
||||
const [timeFilter, setTimeFilter] = useState('exit')
|
||||
const [dataSource, setDataSource] = useState('binance') // 'binance' | 'local'
|
||||
|
||||
useEffect(() => {
|
||||
loadData()
|
||||
}, [accountId, dataSource, reconciledOnly, timeFilter, period, useCustomDate, startDate, endDate, symbol, status, tradeType, exitReason])
|
||||
}, [accountId, dataSource, timeFilter, period, useCustomDate, startDate, endDate, symbol, status, tradeType, exitReason])
|
||||
|
||||
const loadData = async () => {
|
||||
setLoading(true)
|
||||
|
|
@ -55,7 +50,7 @@ const TradeList = () => {
|
|||
if (status) params.status = status
|
||||
if (tradeType) params.trade_type = tradeType
|
||||
if (exitReason) params.exit_reason = exitReason
|
||||
params.reconciled_only = reconciledOnly
|
||||
params.reconciled_only = false
|
||||
params.time_filter = timeFilter || 'exit'
|
||||
}
|
||||
|
||||
|
|
@ -101,58 +96,15 @@ const TradeList = () => {
|
|||
}
|
||||
|
||||
const handleReset = () => {
|
||||
setPeriod(null)
|
||||
setPeriod('7d')
|
||||
setStartDate('')
|
||||
setEndDate('')
|
||||
setSymbol('')
|
||||
setStatus('')
|
||||
setUseCustomDate(false)
|
||||
setReconciledOnly(true)
|
||||
}
|
||||
|
||||
// 同步订单:从币安同步历史订单,补全缺失的订单号
|
||||
const handleSyncOrders = async () => {
|
||||
if (syncing) {
|
||||
return // 防止重复点击
|
||||
}
|
||||
|
||||
const confirmMsg = syncAllSymbols
|
||||
? `确定要同步最近 ${syncDays} 天的所有交易对订单吗?\n这将从币安拉取所有交易对的历史订单,并创建缺失的交易记录。\n⚠️ 注意:这会请求大量数据,可能需要较长时间。`
|
||||
: `确定要同步最近 ${syncDays} 天的订单吗?\n这将从币安拉取历史订单并补全缺失的订单号(仅限数据库中已有的交易对)。`
|
||||
|
||||
if (!window.confirm(confirmMsg)) {
|
||||
return
|
||||
}
|
||||
|
||||
setSyncing(true)
|
||||
setSyncResult(null)
|
||||
|
||||
try {
|
||||
const result = await api.syncTradesFromBinance(syncDays, syncAllSymbols)
|
||||
const backfillHint = (result.entry_order_id_filled || result.exit_order_id_filled)
|
||||
? `,补全开仓订单号 ${result.entry_order_id_filled || 0} 个、平仓订单号 ${result.exit_order_id_filled || 0} 个(勾选「仅可对账」后可见)`
|
||||
: ''
|
||||
setSyncResult({
|
||||
success: true,
|
||||
message: `同步完成:共处理 ${result.total_orders || 0} 个订单,更新 ${result.updated_trades || 0} 条记录${result.created_trades ? `,创建 ${result.created_trades} 条新记录` : ''}${backfillHint}`,
|
||||
details: result
|
||||
})
|
||||
// 同步成功后自动刷新数据
|
||||
setTimeout(() => {
|
||||
loadData()
|
||||
}, 1000)
|
||||
} catch (error) {
|
||||
setSyncResult({
|
||||
success: false,
|
||||
message: `同步失败:${error.message || '未知错误'}`,
|
||||
details: null
|
||||
})
|
||||
} finally {
|
||||
setSyncing(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 导出当前订单数据(含入场/离场原因、入场思路等完整字段,便于后续分析)
|
||||
// 导出当前订单数据
|
||||
// type: 'csv' | 'json'
|
||||
const handleExport = (type = 'csv') => {
|
||||
if (trades.length === 0) {
|
||||
|
|
@ -390,70 +342,14 @@ const TradeList = () => {
|
|||
|
||||
return (
|
||||
<div className="trade-list">
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '10px' }}>
|
||||
<div>
|
||||
<div style={{ marginBottom: '10px' }}>
|
||||
<h2 style={{ margin: 0 }}>交易记录</h2>
|
||||
<p style={{ color: '#666', fontSize: '14px', marginTop: '5px', marginBottom: '0' }}>
|
||||
{dataSource === 'binance'
|
||||
? '数据源:币安成交(binance_trades 表,与交易所一致)。由定时任务每 3 小时的第 0 分钟同步,存在一定延时(最多约 3 小时);需先在服务器运行 scripts/sync_binance_orders.py。'
|
||||
: '说明:每条记录代表一笔完整的交易(开仓+平仓),统计总盈亏时每条记录只计算一次。默认「仅可对账」:只显示有开仓/平仓订单号的记录,统计与币安一致。时间依据:按平仓时间=今日平仓+今日开仓未平仓;按开仓时间=实际入场时间,适合策略分析;按创建时间=记录写入 DB 时间。'}
|
||||
? '数据源:币安成交(binance_trades 表,与交易所一致)。由定时任务每 3 小时同步;默认显示最近 7 天。'
|
||||
: '数据源:本地 trades 表(开仓/平仓回合)。时间依据:按平仓时间 / 开仓时间 / 创建时间。'}
|
||||
</p>
|
||||
</div>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '8px',
|
||||
alignItems: 'flex-end',
|
||||
padding: '10px',
|
||||
backgroundColor: '#f5f5f5',
|
||||
borderRadius: '4px',
|
||||
border: '1px solid #ddd'
|
||||
}}>
|
||||
<div style={{ fontSize: '12px', fontWeight: 'bold', color: '#666', marginBottom: '4px' }}>订单同步</div>
|
||||
<p style={{ fontSize: '11px', color: '#888', margin: '0 0 6px 0' }}>
|
||||
同步的是当前选中账号的币安订单。若系统里几乎没有记录,请勾选「全量同步」并选 7 天或 30 天。
|
||||
</p>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }}>
|
||||
<select
|
||||
value={syncDays}
|
||||
onChange={(e) => setSyncDays(Number(e.target.value))}
|
||||
disabled={syncing}
|
||||
style={{ padding: '4px 8px', fontSize: '12px', width: '70px' }}
|
||||
>
|
||||
<option value={3}>3天</option>
|
||||
<option value={7}>7天</option>
|
||||
<option value={14}>14天</option>
|
||||
<option value={30}>30天</option>
|
||||
</select>
|
||||
<label style={{ display: 'flex', alignItems: 'center', gap: '4px', fontSize: '12px', cursor: 'pointer' }}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={syncAllSymbols}
|
||||
onChange={(e) => setSyncAllSymbols(e.target.checked)}
|
||||
disabled={syncing}
|
||||
style={{ cursor: 'pointer' }}
|
||||
/>
|
||||
<span title="勾选后将同步所有交易对的订单(不限于数据库中的),用于补全缺失的交易记录">全量同步</span>
|
||||
</label>
|
||||
<button
|
||||
onClick={handleSyncOrders}
|
||||
disabled={syncing}
|
||||
style={{
|
||||
backgroundColor: syncing ? '#ccc' : '#4CAF50',
|
||||
color: 'white',
|
||||
border: 'none',
|
||||
padding: '6px 12px',
|
||||
fontSize: '12px',
|
||||
borderRadius: '4px',
|
||||
cursor: syncing ? 'not-allowed' : 'pointer'
|
||||
}}
|
||||
title={syncAllSymbols ? "从币安同步所有交易对的历史订单,并创建缺失的交易记录(会请求大量数据)" : "从币安同步历史订单,补全缺失的订单号(仅限数据库中已有的交易对,不会重复同步)"}
|
||||
>
|
||||
{syncing ? '同步中...' : '同步订单'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 筛选面板 */}
|
||||
<div className="filter-panel">
|
||||
|
|
@ -636,17 +532,6 @@ const TradeList = () => {
|
|||
</select>
|
||||
</div>
|
||||
|
||||
<div className="filter-section">
|
||||
<label title="只显示有开仓/平仓订单号的记录,统计与币安一致,避免系统盈利而币安亏损的偏差">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={reconciledOnly}
|
||||
onChange={(e) => setReconciledOnly(e.target.checked)}
|
||||
/>
|
||||
仅可对账(与币安一致)
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="filter-actions">
|
||||
<button className="btn-primary" onClick={loadData}>
|
||||
查询
|
||||
|
|
@ -665,42 +550,6 @@ const TradeList = () => {
|
|||
</>
|
||||
)}
|
||||
</div>
|
||||
{syncResult && (
|
||||
<div style={{
|
||||
marginTop: '10px',
|
||||
padding: '10px',
|
||||
backgroundColor: syncResult.success ? '#e8f5e9' : '#ffebee',
|
||||
border: `1px solid ${syncResult.success ? '#4CAF50' : '#f44336'}`,
|
||||
borderRadius: '4px',
|
||||
fontSize: '13px',
|
||||
color: syncResult.success ? '#2e7d32' : '#c62828'
|
||||
}}>
|
||||
{syncResult.message}
|
||||
{syncResult.details && syncResult.success && (
|
||||
<div style={{ marginTop: '8px', fontSize: '12px', color: '#666' }}>
|
||||
开仓订单:{syncResult.details.open_orders || 0} |
|
||||
平仓订单:{syncResult.details.close_orders || 0} |
|
||||
更新记录:{syncResult.details.updated_trades || 0}
|
||||
{syncResult.details.created_trades ? ` | 新建记录:${syncResult.details.created_trades}` : ''}
|
||||
{syncResult.details.entry_order_id_filled ? ` | 补全开仓订单号:${syncResult.details.entry_order_id_filled}` : ''}
|
||||
{syncResult.details.exit_order_id_filled ? ` | 补全平仓订单号:${syncResult.details.exit_order_id_filled}` : ''}
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setSyncResult(null)}
|
||||
style={{
|
||||
float: 'right',
|
||||
background: 'none',
|
||||
border: 'none',
|
||||
color: '#666',
|
||||
cursor: 'pointer',
|
||||
fontSize: '16px'
|
||||
}}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{
|
||||
|
|
@ -883,12 +732,12 @@ const TradeList = () => {
|
|||
<div>暂无交易记录</div>
|
||||
{dataSource === 'binance' && (
|
||||
<p style={{ marginTop: '10px', fontSize: '13px', color: '#666', maxWidth: '480px' }}>
|
||||
暂无已同步的币安成交记录。数据由定时任务每 3 小时同步(存在一定延时)。请先在服务器运行 scripts/sync_binance_orders.py 或稍后刷新,也可切换为「本地记录」查看本系统 trades 表。
|
||||
暂无已同步的币安成交记录。数据由定时任务每 3 小时同步;请稍后刷新或切换为「本地记录」。
|
||||
</p>
|
||||
)}
|
||||
{dataSource === 'local' && reconciledOnly && (
|
||||
{dataSource === 'local' && (
|
||||
<p style={{ marginTop: '10px', fontSize: '13px', color: '#666', maxWidth: '420px' }}>
|
||||
若币安今日有订单但此处为空,可先点击右上角「同步订单」补全开仓/平仓订单号,或取消勾选「仅可对账」查看全部记录。
|
||||
暂无本地 trades 表记录。
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user