a
This commit is contained in:
parent
54430a0e06
commit
209a5cd376
|
|
@ -50,6 +50,8 @@ async def get_trades(
|
||||||
end_date: Optional[str] = Query(None, description="结束日期 (YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS)"),
|
end_date: Optional[str] = Query(None, description="结束日期 (YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS)"),
|
||||||
period: Optional[str] = Query(None, description="快速时间段筛选: '1d'(最近1天), '7d'(最近7天), '30d'(最近30天)"),
|
period: Optional[str] = Query(None, description="快速时间段筛选: '1d'(最近1天), '7d'(最近7天), '30d'(最近30天)"),
|
||||||
symbol: Optional[str] = Query(None, description="交易对筛选"),
|
symbol: Optional[str] = Query(None, description="交易对筛选"),
|
||||||
|
trade_type: Optional[str] = Query(None, description="交易类型筛选: 'buy', 'sell'"),
|
||||||
|
exit_reason: Optional[str] = Query(None, description="平仓原因筛选: 'stop_loss', 'take_profit', 'trailing_stop', 'manual', 'sync'"),
|
||||||
status: Optional[str] = Query(None, description="状态筛选: 'open', 'closed', 'cancelled'"),
|
status: Optional[str] = Query(None, description="状态筛选: 'open', 'closed', 'cancelled'"),
|
||||||
limit: int = Query(100, ge=1, le=1000, description="返回记录数限制")
|
limit: int = Query(100, ge=1, le=1000, description="返回记录数限制")
|
||||||
):
|
):
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ class Trade:
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all(start_date=None, end_date=None, symbol=None, status=None):
|
def get_all(start_date=None, end_date=None, symbol=None, status=None, trade_type=None, exit_reason=None):
|
||||||
"""获取交易记录"""
|
"""获取交易记录"""
|
||||||
query = "SELECT * FROM trades WHERE 1=1"
|
query = "SELECT * FROM trades WHERE 1=1"
|
||||||
params = []
|
params = []
|
||||||
|
|
@ -129,6 +129,12 @@ class Trade:
|
||||||
if status:
|
if status:
|
||||||
query += " AND status = %s"
|
query += " AND status = %s"
|
||||||
params.append(status)
|
params.append(status)
|
||||||
|
if trade_type:
|
||||||
|
query += " AND side = %s"
|
||||||
|
params.append(trade_type)
|
||||||
|
if exit_reason:
|
||||||
|
query += " AND exit_reason = %s"
|
||||||
|
params.append(exit_reason)
|
||||||
|
|
||||||
query += " ORDER BY entry_time DESC"
|
query += " ORDER BY entry_time DESC"
|
||||||
return db.execute_query(query, params)
|
return db.execute_query(query, params)
|
||||||
|
|
|
||||||
|
|
@ -30,12 +30,12 @@
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
/* @media (min-width: 768px) {
|
||||||
.dashboard-grid {
|
.dashboard-grid {
|
||||||
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
|
|
||||||
.dashboard-card {
|
.dashboard-card {
|
||||||
background: #f8f9fa;
|
background: #f8f9fa;
|
||||||
|
|
@ -128,6 +128,8 @@
|
||||||
border: 1px solid #e9ecef;
|
border: 1px solid #e9ecef;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
.trade-item {
|
.trade-item {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,10 @@ const StatsDashboard = () => {
|
||||||
</div>
|
</div>
|
||||||
<div className="trade-info">
|
<div className="trade-info">
|
||||||
<div>数量: {parseFloat(trade.quantity || 0).toFixed(4)}</div>
|
<div>数量: {parseFloat(trade.quantity || 0).toFixed(4)}</div>
|
||||||
|
<div>保证金: {margin.toFixed(2)} USDT</div>
|
||||||
|
{trade.entry_time && (
|
||||||
|
<div className="entry-time">开仓时间: {formatEntryTime(trade.entry_time)}</div>
|
||||||
|
)}
|
||||||
<div>入场价: {parseFloat(trade.entry_price || 0).toFixed(4)}</div>
|
<div>入场价: {parseFloat(trade.entry_price || 0).toFixed(4)}</div>
|
||||||
{trade.mark_price && (
|
{trade.mark_price && (
|
||||||
<div>标记价: {parseFloat(trade.mark_price).toFixed(4)}</div>
|
<div>标记价: {parseFloat(trade.mark_price).toFixed(4)}</div>
|
||||||
|
|
@ -152,10 +156,6 @@ const StatsDashboard = () => {
|
||||||
{trade.leverage && (
|
{trade.leverage && (
|
||||||
<div>杠杆: {trade.leverage}x</div>
|
<div>杠杆: {trade.leverage}x</div>
|
||||||
)}
|
)}
|
||||||
<div>保证金: {margin.toFixed(2)} USDT</div>
|
|
||||||
{trade.entry_time && (
|
|
||||||
<div className="entry-time">开仓时间: {formatEntryTime(trade.entry_time)}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="trade-actions">
|
<div className="trade-actions">
|
||||||
<div className={`trade-pnl ${parseFloat(trade.pnl || 0) >= 0 ? 'positive' : 'negative'}`}>
|
<div className={`trade-pnl ${parseFloat(trade.pnl || 0) >= 0 ? 'positive' : 'negative'}`}>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ const TradeList = () => {
|
||||||
const [symbol, setSymbol] = useState('')
|
const [symbol, setSymbol] = useState('')
|
||||||
const [status, setStatus] = useState('')
|
const [status, setStatus] = useState('')
|
||||||
const [useCustomDate, setUseCustomDate] = useState(false)
|
const [useCustomDate, setUseCustomDate] = useState(false)
|
||||||
|
const [tradeType, setTradeType] = useState('')
|
||||||
|
const [exitReason, setExitReason] = useState('')
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadData()
|
loadData()
|
||||||
|
|
@ -37,6 +39,8 @@ const TradeList = () => {
|
||||||
|
|
||||||
if (symbol) params.symbol = symbol
|
if (symbol) params.symbol = symbol
|
||||||
if (status) params.status = status
|
if (status) params.status = status
|
||||||
|
if (tradeType) params.trade_type = tradeType
|
||||||
|
if (exitReason) params.exit_reason = exitReason
|
||||||
|
|
||||||
const [tradesData, statsData] = await Promise.all([
|
const [tradesData, statsData] = await Promise.all([
|
||||||
api.getTrades(params),
|
api.getTrades(params),
|
||||||
|
|
@ -151,6 +155,33 @@ const TradeList = () => {
|
||||||
style={{ width: '150px' }}
|
style={{ width: '150px' }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="filter-section">
|
||||||
|
<label>交易类型:</label>
|
||||||
|
<select
|
||||||
|
value={tradeType}
|
||||||
|
onChange={(e) => setTradeType(e.target.value)}
|
||||||
|
style={{ width: '120px' }}
|
||||||
|
>
|
||||||
|
<option value="">全部</option>
|
||||||
|
<option value="buy">买入</option>
|
||||||
|
<option value="sell">卖出</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="filter-section">
|
||||||
|
<label>平仓原因:</label>
|
||||||
|
<select
|
||||||
|
value={exitReason}
|
||||||
|
onChange={(e) => setExitReason(e.target.value)}
|
||||||
|
style={{ width: '120px' }}
|
||||||
|
>
|
||||||
|
<option value="">全部</option>
|
||||||
|
<option value="stop_loss">止损</option>
|
||||||
|
<option value="take_profit">止盈</option>
|
||||||
|
<option value="trailing_stop">移动止损</option>
|
||||||
|
<option value="manual">手动平仓</option>
|
||||||
|
<option value="sync">同步平仓</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="filter-section">
|
<div className="filter-section">
|
||||||
<label>状态:</label>
|
<label>状态:</label>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user