This commit is contained in:
薇薇安 2026-01-18 09:47:18 +08:00
parent 61af631e46
commit 6aca7f9f73
5 changed files with 54 additions and 5 deletions

View File

@ -210,15 +210,25 @@ async def get_trade_stats(
trades = Trade.get_all(start_timestamp, end_timestamp, symbol, None) trades = Trade.get_all(start_timestamp, end_timestamp, symbol, None)
closed_trades = [t for t in trades if t['status'] == 'closed'] 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 = { stats = {
"total_trades": len(trades), "total_trades": len(trades),
"closed_trades": len(closed_trades), "closed_trades": len(closed_trades),
"open_trades": len(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), "win_trades": len(win_trades),
"loss_trades": len(closed_trades) - len(win_trades), "loss_trades": len(loss_trades),
"win_rate": len(win_trades) / len(closed_trades) * 100 if closed_trades else 0, "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), "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, "avg_pnl": sum(float(t['pnl']) for t in closed_trades) / len(closed_trades) if closed_trades else 0,
"filters": { "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 return stats
except Exception as e: except Exception as e:

View File

@ -240,11 +240,19 @@ const TradeList = () => {
<div className="stat-card"> <div className="stat-card">
<div className="stat-label">总交易数</div> <div className="stat-label">总交易数</div>
<div className="stat-value">{stats.total_trades}</div> <div className="stat-value">{stats.total_trades}</div>
<div style={{ fontSize: '12px', color: '#999', marginTop: '4px' }}>已平仓的完整交易</div> <div style={{ fontSize: '12px', color: '#999', marginTop: '4px' }}>
{stats.meaningful_trades !== undefined && (
<>有意义: {stats.meaningful_trades}0盈亏: {stats.zero_pnl_trades || 0}</>
)}
{stats.meaningful_trades === undefined && <>已平仓的完整交易</>}
</div>
</div> </div>
<div className="stat-card"> <div className="stat-card">
<div className="stat-label">胜率</div> <div className="stat-label">胜率</div>
<div className="stat-value">{stats.win_rate.toFixed(2)}%</div> <div className="stat-value">{stats.win_rate.toFixed(2)}%</div>
<div style={{ fontSize: '12px', color: '#999', marginTop: '4px' }}>
{stats.meaningful_trades !== undefined && <>已排除0盈亏订单</>}
</div>
</div> </div>
<div className="stat-card"> <div className="stat-card">
<div className="stat-label">总盈亏</div> <div className="stat-label">总盈亏</div>

View File

@ -801,6 +801,16 @@ class BinanceClient:
f"最小要求: {min_margin_usdt:.2f} USDT (杠杆: {current_leverage}x)" 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 = { order_params = {
'symbol': symbol, 'symbol': symbol,

View File

@ -114,6 +114,10 @@ class PositionManager:
logger.warning(f" 3. 总仓位超过限制") logger.warning(f" 3. 总仓位超过限制")
logger.warning(f" 4. 无法获取价格数据") logger.warning(f" 4. 无法获取价格数据")
logger.warning(f" 5. 保证金不足最小要求MIN_MARGIN_USDT") logger.warning(f" 5. 保证金不足最小要求MIN_MARGIN_USDT")
<<<<<<< Current (Your changes)
=======
logger.warning(f" 6. 名义价值小于0.2 USDT避免无意义的小单子")
>>>>>>> Incoming (Background Agent changes)
return None return None
logger.info(f"{symbol} 仓位计算成功: {quantity:.4f}") logger.info(f"{symbol} 仓位计算成功: {quantity:.4f}")

View File

@ -354,6 +354,19 @@ class RiskManager:
# 检查是否通过风险控制 # 检查是否通过风险控制
logger.info(f" 检查仓位大小是否符合风险控制要求...") 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): if await self.check_position_size(symbol, quantity):
final_margin = (quantity * current_price) / actual_leverage final_margin = (quantity * current_price) / actual_leverage
logger.info( logger.info(