diff --git a/backend/app/services/paper_trading_service.py b/backend/app/services/paper_trading_service.py index 12db623..13a579c 100644 --- a/backend/app/services/paper_trading_service.py +++ b/backend/app/services/paper_trading_service.py @@ -354,12 +354,13 @@ class PaperTradingService: def _calculate_dynamic_position(self, position_size: str, symbol: str) -> tuple: """ - 根据 LLM 建议的仓位大小计算实际保证金和持仓价值(复利策略) + 根据 LLM 建议的仓位大小计算实际保证金和持仓价值 计算逻辑: - - 可用保证金 = 余额 - (持仓 + 挂单占用保证金) - - 根据 position_size 按可用保证金的百分比分配 - - 持仓价值 = 保证金 × 杠杆 + - 根据可用保证金的倍数确定持仓价值 + - micro: 0.8x, light: 1.2x, medium: 2.0x, heavy: 3.0x + - 累计持仓价值不超过可用保证金的 15 倍 + - 保证金 = 持仓价值 / 杠杆 Args: position_size: 'heavy' / 'medium' / 'light' / 'micro' @@ -372,44 +373,57 @@ class PaperTradingService: account = self.get_account_status() balance = account['current_balance'] used_margin = account['used_margin'] # 已用保证金(持仓+挂单) + total_position_value = account['total_position_value'] # 累计持仓价值 - # 计算可用保证金(复利核心) - available_margin = balance - used_margin + # 计算可用保证金 + available_margin = max(0, balance - used_margin) - if available_margin <= 0: - logger.warning(f"可用保证金不足,无法开仓(余额: ${balance:.2f}, 已用: ${used_margin:.2f})") + # 根据 position_size 确定倍数(相对于可用保证金) + position_multiplier = { + 'micro': 0.8, + 'light': 1.2, + 'medium': 2.0, + 'heavy': 3.0 + }.get(position_size, 1.2) + + # 最大累计持仓价值倍数 + max_total_multiplier = 15.0 + + # 计算目标持仓价值 = 可用保证金 × 倍数 + target_position_value = available_margin * position_multiplier + + # 计算最大允许的累计持仓价值 = 可用保证金 × 15 + max_total_position_value = available_margin * max_total_multiplier + + # 可用的剩余持仓价值额度 + available_position_value = max(0, max_total_position_value - total_position_value) + + # 检查是否超过可用额度 + if target_position_value > available_position_value: + logger.warning(f"目标持仓价值 ${target_position_value:.2f} 超过可用额度 ${available_position_value:.2f},调整为可用额度") + target_position_value = available_position_value + + if target_position_value < 50: + logger.warning(f"可用持仓价值不足(${available_position_value:.2f}),无法开仓") return 0, 0 - # 根据 position_size 确定保证金比例(按可用保证金百分比) - # micro: 5%, light: 10%, medium: 15%, heavy: 20% - size_ratio = { - 'micro': 0.05, - 'light': 0.10, - 'medium': 0.15, - 'heavy': 0.20 - }.get(position_size, 0.10) + # 计算保证金 = 持仓价值 / 杠杆 + margin = target_position_value / self.leverage - # 计算目标保证金(直接使用可用保证金的百分比) - target_margin = available_margin * size_ratio - - # 设置最小和最大保证金限制 - min_margin = 50 # 最小保证金 50 USDT(对应 1000 USDT 持仓价值) - max_single_margin = balance * 0.25 # 单笔最大不超过余额的 25% - - margin = max(min_margin, min(target_margin, max_single_margin)) - - # 确保不超过可用保证金 - margin = min(margin, available_margin) + # 确保不超过可用保证金(理论上不会超过,因为 position_value = available_margin × multiplier) + if margin > available_margin: + logger.warning(f"计算保证金 ${margin:.2f} 超过可用保证金 ${available_margin:.2f},调整为可用保证金") + margin = available_margin + # 重新计算持仓价值 + target_position_value = margin * self.leverage # 修正浮点数精度问题,保留 2 位小数 margin = round(margin, 2) + position_value = round(target_position_value, 2) - # 计算持仓价值(保证金 × 杠杆) - position_value = round(margin * self.leverage, 2) - - logger.info(f"动态仓位计算: {position_size} | 余额: ${balance:.2f} | 已用保证金: ${used_margin:.2f} | " - f"可用保证金: ${available_margin:.2f} | 目标保证金: ${margin:.2f} ({size_ratio*100:.0f}%) | " - f"持仓价值: ${position_value:.2f}") + logger.info(f"动态仓位计算: {position_size} | 可用保证金: ${available_margin:.2f} | " + f"累计持仓: ${total_position_value:.2f}/${max_total_position_value:.2f} | " + f"目标保证金: ${margin:.2f} | 持仓价值: ${position_value:.2f} ({position_multiplier}x, {self.leverage}x杠杆)") return margin, position_value