优化推荐模块

This commit is contained in:
薇薇安 2026-02-04 16:07:25 +08:00
parent f8eca1ed59
commit 9be1c5777d
2 changed files with 94 additions and 51 deletions

View File

@ -228,6 +228,69 @@ class RiskManager:
logger.error(f"检查总仓位失败: {e}", exc_info=True) logger.error(f"检查总仓位失败: {e}", exc_info=True)
return False return False
async def calculate_dynamic_leverage(self, symbol: str, entry_price: float, stop_loss_price: Optional[float] = None, atr: Optional[float] = None, side: Optional[str] = None) -> int:
"""
计算动态杠杆
Args:
symbol: 交易对
entry_price: 入场价格
stop_loss_price: 止损价格
atr: ATR值
side: 交易方向
Returns:
建议杠杆倍数
"""
# 默认使用配置杠杆
default_leverage = config.TRADING_CONFIG.get('LEVERAGE', 10)
if not config.TRADING_CONFIG.get('USE_DYNAMIC_LEVERAGE', False):
return default_leverage
# 尝试获取止损价格(如果没有传入,尝试估算)
target_stop_loss = stop_loss_price
# 如果没有传入止损价尝试使用ATR估算仅用于计算杠杆建议
if target_stop_loss is None and atr and atr > 0 and entry_price:
atr_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 2.5)
if side == 'BUY':
target_stop_loss = entry_price - (atr * atr_multiplier)
elif side == 'SELL':
target_stop_loss = entry_price + (atr * atr_multiplier)
if target_stop_loss and entry_price:
# 计算止损宽度比例
stop_loss_width = abs(entry_price - target_stop_loss) / entry_price
if stop_loss_width > 0:
# 获取最大单笔亏损率限制 (默认20%)
max_loss_pct = config.TRADING_CONFIG.get('MAX_SINGLE_TRADE_LOSS_PERCENT', 20.0) / 100.0
# 计算建议杠杆
# 理论杠杆 = 最大允许亏损比例 / 止损宽度比例
theoretical_leverage = max_loss_pct / stop_loss_width
# 向下取整
suggested_leverage = int(theoretical_leverage)
# 限制在最大杠杆范围内
max_config_leverage = config.TRADING_CONFIG.get('MAX_LEVERAGE', 10)
final_dynamic_leverage = min(suggested_leverage, max_config_leverage)
# 至少为1倍
final_dynamic_leverage = max(1, final_dynamic_leverage)
logger.info(f" ⚖️ 动态杠杆计算 ({symbol}):")
logger.info(f" 止损价格: {target_stop_loss:.4f} (宽度: {stop_loss_width*100:.2f}%)")
logger.info(f" 最大单笔亏损限制: {max_loss_pct*100:.1f}%")
logger.info(f" 理论最大杠杆: {theoretical_leverage:.2f}x")
logger.info(f" -> 最终建议杠杆: {final_dynamic_leverage}x")
return final_dynamic_leverage
return default_leverage
async def calculate_position_size( async def calculate_position_size(
self, self,
symbol: str, symbol: str,
@ -283,53 +346,15 @@ class RiskManager:
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# 动态杠杆计算逻辑 (针对 ZROUSDT 亏损案例优化) # 动态杠杆计算逻辑 (针对 ZROUSDT 亏损案例优化)
# ------------------------------------------------------------------------- # -------------------------------------------------------------------------
# 如果启用了动态杠杆,根据止损宽度自动调整杠杆
# 公式: 建议杠杆 = 目标最大单单亏损率 / 止损宽度
# 例如: 目标亏损20%止损宽度10%,则建议杠杆 = 20% / 10% = 2倍
# -------------------------------------------------------------------------
calculated_leverage = None calculated_leverage = None
if config.TRADING_CONFIG.get('USE_DYNAMIC_LEVERAGE', False): if config.TRADING_CONFIG.get('USE_DYNAMIC_LEVERAGE', False):
# 尝试获取止损价格(如果没有传入,尝试估算) calculated_leverage = await self.calculate_dynamic_leverage(
target_stop_loss = stop_loss_price symbol=symbol,
entry_price=entry_price if entry_price else current_price,
# 如果没有传入止损价尝试使用ATR估算仅用于计算杠杆建议 stop_loss_price=stop_loss_price,
if target_stop_loss is None and atr and atr > 0 and entry_price: atr=atr,
atr_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 2.5) side=side
if side == 'BUY': )
target_stop_loss = entry_price - (atr * atr_multiplier)
else:
target_stop_loss = entry_price + (atr * atr_multiplier)
if target_stop_loss and entry_price:
# 计算止损宽度比例
stop_loss_width = abs(entry_price - target_stop_loss) / entry_price
if stop_loss_width > 0:
# 获取最大单笔亏损率限制 (默认20%)
max_loss_pct = config.TRADING_CONFIG.get('MAX_SINGLE_TRADE_LOSS_PERCENT', 20.0) / 100.0
# 计算建议杠杆
# 理论杠杆 = 最大允许亏损比例 / 止损宽度比例
theoretical_leverage = max_loss_pct / stop_loss_width
# 向下取整
suggested_leverage = int(theoretical_leverage)
# 限制在最大杠杆范围内
max_config_leverage = config.TRADING_CONFIG.get('MAX_LEVERAGE', 10)
final_dynamic_leverage = min(suggested_leverage, max_config_leverage)
# 至少为1倍
final_dynamic_leverage = max(1, final_dynamic_leverage)
logger.info(f" ⚖️ 动态杠杆计算:")
logger.info(f" 止损价格: {target_stop_loss:.4f} (宽度: {stop_loss_width*100:.2f}%)")
logger.info(f" 最大单笔亏损限制: {max_loss_pct*100:.1f}%")
logger.info(f" 理论最大杠杆: {theoretical_leverage:.2f}x")
logger.info(f" 配置最大杠杆: {max_config_leverage}x")
logger.info(f" -> 最终建议杠杆: {final_dynamic_leverage}x")
calculated_leverage = final_dynamic_leverage
# 确定最终使用的杠杆 # 确定最终使用的杠杆
# 优先级: 动态计算杠杆 > 传入的leverage参数 > 配置的默认LEVERAGE # 优先级: 动态计算杠杆 > 传入的leverage参数 > 配置的默认LEVERAGE

View File

@ -489,14 +489,23 @@ class TradeRecommender:
entry_price = suggested_limit_price entry_price = suggested_limit_price
# 估算仓位数量和杠杆(用于计算止损止盈) # 估算仓位数量和杠杆(用于计算止损止盈)
# 1. 优先计算动态杠杆(基于波动率和风险)
atr = symbol_info.get('atr')
leverage = await self.risk_manager.calculate_dynamic_leverage(
symbol,
entry_price,
stop_loss_price=None, # 让内部使用ATR自动估算止损来计算杠杆
atr=atr,
side=direction
)
# 重要语义suggested_position_pct 表示“保证金占用比例” # 重要语义suggested_position_pct 表示“保证金占用比例”
account_balance = symbol_info.get('account_balance', 1000) # 使用传入的 account_balance (默认为1000用于展示)
suggested_position_pct = symbol_info.get('suggested_position_pct', 0.05) suggested_position_pct = symbol_info.get('suggested_position_pct', 0.05)
leverage = config.TRADING_CONFIG.get('LEVERAGE', 10)
# 估算保证金与名义价值 # 估算保证金与名义价值
estimated_margin = account_balance * suggested_position_pct estimated_margin = account_balance * suggested_position_pct
estimated_notional = estimated_margin * leverage if leverage and leverage > 0 else estimated_margin estimated_notional = estimated_margin * leverage
estimated_quantity = estimated_notional / entry_price if entry_price > 0 else 0 estimated_quantity = estimated_notional / entry_price if entry_price > 0 else 0
# 计算基于保证金的止损止盈 # 计算基于保证金的止损止盈
@ -593,7 +602,8 @@ class TradeRecommender:
# 生成用户指南(人话版计划) # 生成用户指南(人话版计划)
user_guide = self._generate_user_guide( user_guide = self._generate_user_guide(
symbol, direction, suggested_limit_price, stop_loss_price, take_profit_1, take_profit_2, symbol, direction, suggested_limit_price, stop_loss_price, take_profit_1, take_profit_2,
simple_reason, expected_hold_time, risk_warning, recommendation_category, current_price simple_reason, expected_hold_time, risk_warning, recommendation_category, current_price,
leverage, suggested_position_pct
) )
# 基础推荐数据 # 基础推荐数据
@ -626,7 +636,7 @@ class TradeRecommender:
# 计划入场价(限价挂单价)作为止损/止盈计算基准 # 计划入场价(限价挂单价)作为止损/止盈计算基准
'planned_entry_price': entry_price, 'planned_entry_price': entry_price,
'suggested_position_percent': suggested_position_pct, 'suggested_position_percent': suggested_position_pct,
'suggested_leverage': config.TRADING_CONFIG.get('LEVERAGE', 10), 'suggested_leverage': leverage,
'volume_24h': symbol_info.get('volume24h'), 'volume_24h': symbol_info.get('volume24h'),
'volatility': symbol_info.get('volatility'), 'volatility': symbol_info.get('volatility'),
'estimated_win_rate': round(estimated_win_rate, 1), 'estimated_win_rate': round(estimated_win_rate, 1),
@ -869,7 +879,9 @@ class TradeRecommender:
expected_hold_time: str, expected_hold_time: str,
risk_warning: str, risk_warning: str,
category: str, category: str,
current_price: float current_price: float,
leverage: int,
position_pct: float
) -> str: ) -> str:
""" """
生成用户指南人话版计划 生成用户指南人话版计划
@ -886,6 +898,8 @@ class TradeRecommender:
risk_warning: 风险警告 risk_warning: 风险警告
category: 推荐分类 category: 推荐分类
current_price: 当前价格用于计算反向波动 current_price: 当前价格用于计算反向波动
leverage: 建议杠杆
position_pct: 建议仓位保证金比例
Returns: Returns:
用户指南文本 用户指南文本
@ -910,6 +924,10 @@ class TradeRecommender:
明确的入场价 明确的入场价
建议在 {limit_price:.4f} USDT 附近{direction_action} 建议在 {limit_price:.4f} USDT 附近{direction_action}
资金管理
建议杠杆: {leverage}x
建议仓位: 保证金占用总资金的 {position_pct*100:.1f}%
具体点位 具体点位
建议挂单价: {limit_price:.4f} USDT 建议挂单价: {limit_price:.4f} USDT
止损价: {stop_loss:.4f} USDT 止损价: {stop_loss:.4f} USDT