This commit is contained in:
aaron 2026-03-13 23:47:44 +08:00
parent ae762c94cb
commit 9fceadcb27
3 changed files with 72 additions and 5 deletions

View File

@ -130,7 +130,8 @@ class Settings(BaseSettings):
# 模拟交易配置
paper_trading_enabled: bool = True # 是否启用模拟交易
paper_trading_initial_balance: float = 10000 # 初始本金 (USDT)
paper_trading_leverage: int = 20 # 杠杆倍数(全仓模式下的最大杠杆)
paper_trading_leverage: int = 20 # 单笔订单杠杆倍数
paper_trading_max_total_leverage: float = 10 # 总杠杆上限(持仓+挂单,倍数)
paper_trading_margin_per_order: float = 1000 # 每单保证金 (USDT)
paper_trading_max_orders: int = 10 # 最大持仓+挂单总数
paper_trading_auto_close_opposite: bool = False # 是否自动平掉反向持仓(智能策略)

View File

@ -27,6 +27,7 @@ class PaperTradingService:
self.max_orders = self.settings.paper_trading_max_orders # 最大订单数
self.auto_close_opposite = self.settings.paper_trading_auto_close_opposite # 是否自动平掉反向持仓
self.breakeven_threshold = self.settings.paper_trading_breakeven_threshold # 保本止损触发阈值
self.max_total_leverage = self.settings.paper_trading_max_total_leverage # 总杠杆上限
# 移动止损配置
self.trailing_stop_enabled = self.settings.paper_trading_trailing_stop_enabled
@ -48,7 +49,8 @@ class PaperTradingService:
# 加载活跃订单到内存
self._load_active_orders()
logger.info(f"交易服务初始化完成(自动平反向持仓: {'启用' if self.auto_close_opposite else '禁用'}"
logger.info(f"交易服务初始化完成(单笔杠杆: {self.leverage}x总杠杆上限: {self.max_total_leverage}x"
f"自动平反向持仓: {'启用' if self.auto_close_opposite else '禁用'}"
f"保本止损阈值: {self.breakeven_threshold}%"
f"移动止损: {'启用' if self.trailing_stop_enabled else '禁用'}"
f"触发倍数: {self.trailing_stop_threshold_multiplier}x"
@ -265,6 +267,46 @@ class PaperTradingService:
result['message'] = msg
return result
# === 检查总杠杆是否超限 ===
# 计算当前已用保证金(持仓+挂单)
current_used_margin = len(self.active_orders) * self.margin_per_order
# 新订单增加的保证金
new_margin = margin
# 新订单的总持仓价值 = 保证金 × 杠杆
new_position_value = new_margin * self.leverage
# 新增后的总持仓价值
new_total_position_value = (current_used_margin * self.leverage) + new_position_value
# 获取当前账户余额
db = db_service.get_session()
try:
closed_orders = db.query(PaperOrder).filter(
PaperOrder.status.in_([
OrderStatus.CLOSED_TP,
OrderStatus.CLOSED_SL,
OrderStatus.CLOSED_BE,
OrderStatus.CLOSED_TS,
OrderStatus.CLOSED_MANUAL
])
).all()
realized_pnl = sum(o.pnl_amount for o in closed_orders)
finally:
db.close()
current_balance = self.initial_balance + realized_pnl
# 计算新订单后的总杠杆
new_total_leverage = new_total_position_value / current_balance if current_balance > 0 else 0
if new_total_leverage > self.max_total_leverage:
msg = f"总杠杆超限!当前 {new_total_leverage:.1f}x上限 {self.max_total_leverage}x"
logger.info(f"{msg}: {symbol} | 当前持仓价值: ${current_used_margin * self.leverage:,.0f} | "
f"新订单持仓价值: ${new_position_value:,.0f} | 总持仓价值: ${new_total_position_value:,.0f} | "
f"账户余额: ${current_balance:,.0f}")
result['message'] = msg
return result
logger.debug(f"总杠杆检查通过: {new_total_leverage:.1f}x / {self.max_total_leverage}x")
quantity = round(position_value, 2) # 确保持仓价值保留2位小数
# 确定入场类型
@ -1769,6 +1811,10 @@ class PaperTradingService:
# 计算当前余额
current_balance = self.initial_balance + realized_pnl
# 计算当前总杠杆(持仓价值 / 账户余额)
total_position_value = used_margin * self.leverage
current_total_leverage = total_position_value / current_balance if current_balance > 0 else 0
# 计算可用保证金
available_margin = current_balance - used_margin
@ -1782,12 +1828,14 @@ class PaperTradingService:
'used_margin': round(used_margin, 2),
'available': round(available_margin, 2), # 添加 available 字段,兼容性
'available_margin': round(available_margin, 2),
'leverage': self.leverage,
'leverage': self.leverage, # 单笔订单杠杆
'max_total_leverage': self.max_total_leverage, # 总杠杆上限
'current_total_leverage': round(current_total_leverage, 2), # 当前总杠杆
'margin_per_order': self.margin_per_order,
'active_orders': active_count,
'max_orders': self.max_orders,
'available_orders': available_orders,
'total_position_value': round(used_margin * self.leverage, 2),
'total_position_value': round(total_position_value, 2),
'margin_ratio': round((used_margin / current_balance * 100), 2) if current_balance > 0 else 0,
'max_drawdown': round(account_max_drawdown, 2), # 账户最大回撤百分比
'max_drawdown_amount': round(account_max_drawdown * self.initial_balance / 100, 2) if account_max_drawdown != 0 else 0, # 账户最大回撤金额

View File

@ -135,6 +135,10 @@
color: #ef4444;
}
.stat-value.warning {
color: #f59e0b; /* 橙色警告 */
}
/* 统计卡片内的正值/负值样式 */
.grade-card-stats .positive {
color: var(--accent);
@ -1200,6 +1204,18 @@
${{ account.current_balance?.toFixed(2) || '0.00' }}
</div>
</div>
<div class="stat-card">
<div class="stat-label">总仓位价值</div>
<div class="stat-value">
${{ account.total_position_value?.toFixed(2) || '0.00' }}
</div>
</div>
<div class="stat-card">
<div class="stat-label">总杠杆率</div>
<div class="stat-value" :class="account.current_total_leverage > account.max_total_leverage * 0.8 ? 'warning' : ''">
{{ account.current_total_leverage?.toFixed(1) || '0.0' }}x / {{ account.max_total_leverage }}x
</div>
</div>
<div class="stat-card">
<div class="stat-label">收益率</div>
<div class="stat-value" :class="account.current_balance >= account.initial_balance ? 'positive' : 'negative'">
@ -1701,7 +1717,9 @@
available_orders: 10,
total_position_value: 0,
margin_ratio: 0,
realized_pnl: 0
realized_pnl: 0,
current_total_leverage: 0, // 当前总杠杆率
max_total_leverage: 10 // 总杠杆上限
},
monitorRunning: false,
latestPrices: {},