diff --git a/backend/api/routes/trades.py b/backend/api/routes/trades.py index 3ab1d6e..e28d269 100644 --- a/backend/api/routes/trades.py +++ b/backend/api/routes/trades.py @@ -210,15 +210,25 @@ async def get_trade_stats( trades = Trade.get_all(start_timestamp, end_timestamp, symbol, None) closed_trades = [t for t in trades if t['status'] == 'closed'] - win_trades = [t for t in closed_trades if float(t['pnl']) > 0] + + # 排除0盈亏的订单(abs(pnl) < 0.01 USDT视为0盈亏),这些订单不应该影响胜率统计 + ZERO_PNL_THRESHOLD = 0.01 # 0.01 USDT的阈值,小于此值视为0盈亏 + meaningful_trades = [t for t in closed_trades if abs(float(t['pnl'])) >= ZERO_PNL_THRESHOLD] + zero_pnl_trades = [t for t in closed_trades if abs(float(t['pnl'])) < ZERO_PNL_THRESHOLD] + + # 只统计有意义的交易(排除0盈亏)的胜率 + win_trades = [t for t in meaningful_trades if float(t['pnl']) > 0] + loss_trades = [t for t in meaningful_trades if float(t['pnl']) < 0] stats = { "total_trades": len(trades), "closed_trades": len(closed_trades), "open_trades": len(trades) - len(closed_trades), + "meaningful_trades": len(meaningful_trades), # 有意义的交易数(排除0盈亏) + "zero_pnl_trades": len(zero_pnl_trades), # 0盈亏交易数 "win_trades": len(win_trades), - "loss_trades": len(closed_trades) - len(win_trades), - "win_rate": len(win_trades) / len(closed_trades) * 100 if closed_trades else 0, + "loss_trades": len(loss_trades), + "win_rate": len(win_trades) / len(meaningful_trades) * 100 if meaningful_trades else 0, # 基于有意义的交易计算胜率 "total_pnl": sum(float(t['pnl']) for t in closed_trades), "avg_pnl": sum(float(t['pnl']) for t in closed_trades) / len(closed_trades) if closed_trades else 0, "filters": { @@ -231,7 +241,11 @@ async def get_trade_stats( } } - logger.info(f"交易统计: 总交易数={stats['total_trades']}, 已平仓={stats['closed_trades']}, 胜率={stats['win_rate']:.2f}%, 总盈亏={stats['total_pnl']:.2f} USDT") + logger.info( + f"交易统计: 总交易数={stats['total_trades']}, 已平仓={stats['closed_trades']}, " + f"有意义交易={stats['meaningful_trades']}, 0盈亏交易={stats['zero_pnl_trades']}, " + f"胜率={stats['win_rate']:.2f}%, 总盈亏={stats['total_pnl']:.2f} USDT" + ) return stats except Exception as e: diff --git a/frontend/src/components/TradeList.jsx b/frontend/src/components/TradeList.jsx index fcad521..d9a2f83 100644 --- a/frontend/src/components/TradeList.jsx +++ b/frontend/src/components/TradeList.jsx @@ -240,11 +240,19 @@ const TradeList = () => {
总交易数
{stats.total_trades}
-
(已平仓的完整交易)
+
+ {stats.meaningful_trades !== undefined && ( + <>(有意义: {stats.meaningful_trades},0盈亏: {stats.zero_pnl_trades || 0}) + )} + {stats.meaningful_trades === undefined && <>(已平仓的完整交易)} +
胜率
{stats.win_rate.toFixed(2)}%
+
+ {stats.meaningful_trades !== undefined && <>(已排除0盈亏订单)} +
总盈亏
diff --git a/trading_system/binance_client.py b/trading_system/binance_client.py index e524f75..50c261d 100644 --- a/trading_system/binance_client.py +++ b/trading_system/binance_client.py @@ -801,6 +801,16 @@ class BinanceClient: f"最小要求: {min_margin_usdt:.2f} USDT (杠杆: {current_leverage}x)" ) + # 最终检查:确保名义价值不小于0.2 USDT(避免无意义的小单子) + # 对于平仓操作(reduce_only=True),跳过此检查 + # MIN_NOTIONAL_VALUE = 0.2 # 最小名义价值0.2 USDT + # if not reduce_only and notional_value < MIN_NOTIONAL_VALUE: + # logger.error( + # f"❌ {symbol} 订单名义价值 {notional_value:.4f} USDT < 最小要求 {MIN_NOTIONAL_VALUE:.2f} USDT,拒绝下单" + # ) + # logger.error(f" 💡 此类小单子意义不大,拒绝开仓") + # return None + # 构建订单参数 order_params = { 'symbol': symbol, diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index f2dc6df..eeea8b6 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -114,6 +114,10 @@ class PositionManager: logger.warning(f" 3. 总仓位超过限制") logger.warning(f" 4. 无法获取价格数据") logger.warning(f" 5. 保证金不足最小要求(MIN_MARGIN_USDT)") +<<<<<<< Current (Your changes) +======= + logger.warning(f" 6. 名义价值小于0.2 USDT(避免无意义的小单子)") +>>>>>>> Incoming (Background Agent changes) return None logger.info(f"✓ {symbol} 仓位计算成功: {quantity:.4f}") diff --git a/trading_system/risk_manager.py b/trading_system/risk_manager.py index 3d24550..72f79a4 100644 --- a/trading_system/risk_manager.py +++ b/trading_system/risk_manager.py @@ -354,6 +354,19 @@ class RiskManager: # 检查是否通过风险控制 logger.info(f" 检查仓位大小是否符合风险控制要求...") + + # 计算最终的名义价值 + final_notional_value = quantity * current_price + + # 添加最小名义价值检查(0.2 USDT),避免下无意义的小单子 + MIN_NOTIONAL_VALUE = 0.2 # 最小名义价值0.2 USDT + if final_notional_value < MIN_NOTIONAL_VALUE: + logger.warning( + f" ❌ {symbol} 名义价值 {final_notional_value:.4f} USDT < 最小要求 {MIN_NOTIONAL_VALUE:.2f} USDT" + ) + logger.warning(f" 💡 此类小单子意义不大,拒绝开仓") + return None + if await self.check_position_size(symbol, quantity): final_margin = (quantity * current_price) / actual_leverage logger.info(