diff --git a/backend/config_manager.py b/backend/config_manager.py index 94fbc85..78222c7 100644 --- a/backend/config_manager.py +++ b/backend/config_manager.py @@ -724,12 +724,40 @@ class ConfigManager: """ # API key/secret/testnet 永远按账号读取(在 get() 内部已处理) if key in RISK_KNOBS_KEYS: - return self.get(key, default) - # 从全局配置表读取 - try: - return global_config_mgr.get(key, default) - except Exception: - return self.get(key, default) + value = self.get(key, default) + else: + # 从全局配置表读取 + try: + value = global_config_mgr.get(key, default) + except Exception: + value = self.get(key, default) + + # ⚠️ 关键修复:百分比配置值格式转换 + # 如果配置值是百分比形式(>1),转换为比例形式(除以100) + # 兼容数据库中存储的百分比形式(如30表示30%)和比例形式(如0.30表示30%) + if isinstance(value, (int, float)) and value is not None: + # 需要转换的百分比配置项 + percent_keys = [ + 'TRAILING_STOP_ACTIVATION', + 'TRAILING_STOP_PROTECT', + 'MIN_VOLATILITY', + 'TAKE_PROFIT_PERCENT', + 'STOP_LOSS_PERCENT', + 'MIN_STOP_LOSS_PRICE_PCT', + 'MIN_TAKE_PROFIT_PRICE_PCT', + 'FIXED_RISK_PERCENT', + 'MAX_POSITION_PERCENT', + 'MAX_TOTAL_POSITION_PERCENT', + 'MIN_POSITION_PERCENT', + ] + + if key in percent_keys: + # 如果值>1,认为是百分比形式,转换为比例形式 + if value > 1: + value = value / 100.0 + logger.debug(f"配置值格式转换: {key} = {value*100:.2f}% (从百分比形式转换为比例形式)") + + return value return { # 仓位控制 diff --git a/trading_system/main.py b/trading_system/main.py index ddfb551..dceadb7 100644 --- a/trading_system/main.py +++ b/trading_system/main.py @@ -343,8 +343,16 @@ async def main(): logger.info(f" 每笔风险: {config.TRADING_CONFIG.get('FIXED_RISK_PERCENT', 0.02)*100:.1f}%") logger.info(f" 移动止损: {'开启' if config.TRADING_CONFIG.get('USE_TRAILING_STOP') else '关闭'}") if config.TRADING_CONFIG.get('USE_TRAILING_STOP'): - logger.info(f" 激活条件: 盈利{config.TRADING_CONFIG.get('TRAILING_STOP_ACTIVATION', 0.1)*100:.0f}%") - logger.info(f" 保护利润: {config.TRADING_CONFIG.get('TRAILING_STOP_PROTECT', 0.05)*100:.0f}%") + # 修复:配置值已经是比例形式,直接乘以100显示 + trailing_activation = config.TRADING_CONFIG.get('TRAILING_STOP_ACTIVATION', 0.1) + trailing_protect = config.TRADING_CONFIG.get('TRAILING_STOP_PROTECT', 0.05) + # 如果值>1,说明可能还是百分比形式,需要转换;否则直接使用 + if trailing_activation > 1: + trailing_activation = trailing_activation / 100.0 + if trailing_protect > 1: + trailing_protect = trailing_protect / 100.0 + logger.info(f" 激活条件: 盈利{trailing_activation*100:.0f}%") + logger.info(f" 保护利润: {trailing_protect*100:.0f}%") logger.info(f" 最小持仓时间: {config.TRADING_CONFIG.get('MIN_HOLD_TIME_SEC', 0)} 秒") logger.info("") logger.info("【市场扫描】") @@ -352,7 +360,11 @@ async def main(): logger.info(f" 扫描交易对数量: {config.TRADING_CONFIG.get('MAX_SCAN_SYMBOLS', 500)}") logger.info(f" 处理交易对数量: {config.TRADING_CONFIG['TOP_N_SYMBOLS']} 个") logger.info(f" 最小24H成交额: ${config.TRADING_CONFIG.get('MIN_VOLUME_24H', 0)/1000000:.0f}M") - logger.info(f" 最小波动率: {config.TRADING_CONFIG.get('MIN_VOLATILITY', 0.02)*100:.1f}%") + # 修复:配置值格式转换 + min_volatility = config.TRADING_CONFIG.get('MIN_VOLATILITY', 0.02) + if min_volatility > 1: + min_volatility = min_volatility / 100.0 + logger.info(f" 最小波动率: {min_volatility*100:.1f}%") logger.info(f" 最小信号强度: {config.TRADING_CONFIG.get('MIN_SIGNAL_STRENGTH', 5)}") logger.info(f" 最小涨跌幅: {config.TRADING_CONFIG['MIN_CHANGE_PERCENT']:.1f}%") logger.info("") diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index c96bece..551f868 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -490,6 +490,9 @@ class PositionManager: # ===== 成交后基于“实际成交价/数量”重新计算止损止盈(修复限价/滑点导致的偏差)===== stop_loss_pct_margin = config.TRADING_CONFIG.get('STOP_LOSS_PERCENT', 0.03) + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + if stop_loss_pct_margin is not None and stop_loss_pct_margin > 1: + stop_loss_pct_margin = stop_loss_pct_margin / 100.0 stop_loss_price = self.risk_manager.get_stop_loss_price( entry_price, side, quantity, leverage, stop_loss_pct=stop_loss_pct_margin, @@ -510,6 +513,9 @@ class PositionManager: stop_distance_for_tp = entry_price * atr_percent * atr_multiplier take_profit_pct_margin = config.TRADING_CONFIG.get('TAKE_PROFIT_PERCENT', 0.30) + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + if take_profit_pct_margin is not None and take_profit_pct_margin > 1: + take_profit_pct_margin = take_profit_pct_margin / 100.0 if take_profit_pct_margin is None or take_profit_pct_margin == 0: take_profit_pct_margin = float(stop_loss_pct_margin or 0) * 3.0 take_profit_price = self.risk_manager.get_take_profit_price( @@ -1442,6 +1448,13 @@ class PositionManager: trailing_activation = config.TRADING_CONFIG.get('TRAILING_STOP_ACTIVATION', 0.01) # 相对于保证金 trailing_protect = config.TRADING_CONFIG.get('TRAILING_STOP_PROTECT', 0.01) # 相对于保证金 + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + # 如果值>1,认为是百分比形式,转换为比例形式 + if trailing_activation > 1: + trailing_activation = trailing_activation / 100.0 + if trailing_protect > 1: + trailing_protect = trailing_protect / 100.0 + if not position_info.get('trailingStopActivated', False): # 盈利超过阈值后(相对于保证金),激活移动止损 if pnl_percent_margin > trailing_activation * 100: @@ -2346,7 +2359,13 @@ class PositionManager: # 计算止损止盈(基于保证金) leverage = binance_position.get('leverage', 10) stop_loss_pct_margin = config.TRADING_CONFIG.get('STOP_LOSS_PERCENT', 0.08) + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + if stop_loss_pct_margin is not None and stop_loss_pct_margin > 1: + stop_loss_pct_margin = stop_loss_pct_margin / 100.0 take_profit_pct_margin = config.TRADING_CONFIG.get('TAKE_PROFIT_PERCENT', 0.15) + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + if take_profit_pct_margin is not None and take_profit_pct_margin > 1: + take_profit_pct_margin = take_profit_pct_margin / 100.0 # 如果配置中没有设置止盈,则使用止损的2倍作为默认 if take_profit_pct_margin is None or take_profit_pct_margin == 0: take_profit_pct_margin = stop_loss_pct_margin * 2.0 @@ -2441,7 +2460,13 @@ class PositionManager: # 计算止损止盈(基于保证金) leverage = position.get('leverage', 10) stop_loss_pct_margin = config.TRADING_CONFIG.get('STOP_LOSS_PERCENT', 0.08) + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + if stop_loss_pct_margin is not None and stop_loss_pct_margin > 1: + stop_loss_pct_margin = stop_loss_pct_margin / 100.0 take_profit_pct_margin = config.TRADING_CONFIG.get('TAKE_PROFIT_PERCENT', 0.15) + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + if take_profit_pct_margin is not None and take_profit_pct_margin > 1: + take_profit_pct_margin = take_profit_pct_margin / 100.0 # 如果配置中没有设置止盈,则使用止损的2倍作为默认 if take_profit_pct_margin is None or take_profit_pct_margin == 0: take_profit_pct_margin = stop_loss_pct_margin * 2.0 @@ -2702,34 +2727,41 @@ class PositionManager: f"(盈利: {pnl_percent_margin:.2f}% of margin)" ) else: - # 盈利超过阈值后,止损移至保护利润位(基于保证金) - # 计算需要保护的利润金额 - protect_amount = margin * trailing_protect - # 计算对应的止损价 - if position_info['side'] == 'BUY': - # 保护利润:当前盈亏 - 保护金额 = (止损价 - 开仓价) × 数量 - # 所以:止损价 = 开仓价 + (当前盈亏 - 保护金额) / 数量 - new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity - if new_stop_loss > position_info['stopLoss']: - position_info['stopLoss'] = new_stop_loss - logger.info( - f"{symbol} [实时监控] 移动止损更新: {new_stop_loss:.4f} " - f"(保护{trailing_protect*100:.1f}% of margin = {protect_amount:.4f} USDT)" - ) - else: # SELL - # 做空:止损价 = 开仓价 + (当前盈亏 - 保护金额) / 数量 - # 注意:对于做空,止损价应该高于开仓价,所以用加法 - # 当盈利时(pnl_amount > 0),止损价应该往上移(更宽松) - # 当亏损时(pnl_amount < 0),不应该移动止损(保持初始止损) - new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity - # 对于做空,止损价应该越来越高(更宽松),所以检查 new_stop_loss > 当前止损 - # 同时,移动止损只应该在盈利时激活,不应该在亏损时把止损往下移 - if new_stop_loss > position_info['stopLoss'] and pnl_amount > 0: - position_info['stopLoss'] = new_stop_loss - logger.info( - f"{symbol} [实时监控] 移动止损更新: {new_stop_loss:.4f} " - f"(保护{trailing_protect*100:.1f}% of margin = {protect_amount:.4f} USDT)" - ) + # ⚠️ 优化:如果分步止盈第一目标已触发,移动止损不再更新剩余仓位的止损价 + # 原因:分步止盈第一目标触发后,剩余50%仓位止损已移至成本价(保本),等待第二目标 + # 移动止损不应该覆盖分步止盈设置的止损价 + if position_info.get('partialProfitTaken', False): + # 分步止盈第一目标已触发,移动止损不再更新 + logger.debug(f"{symbol} [实时监控-移动止损] 分步止盈第一目标已触发,移动止损不再更新剩余仓位止损价") + else: + # 盈利超过阈值后,止损移至保护利润位(基于保证金) + # 计算需要保护的利润金额 + protect_amount = margin * trailing_protect + # 计算对应的止损价 + if position_info['side'] == 'BUY': + # 保护利润:当前盈亏 - 保护金额 = (止损价 - 开仓价) × 数量 + # 所以:止损价 = 开仓价 + (当前盈亏 - 保护金额) / 数量 + new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity + if new_stop_loss > position_info['stopLoss']: + position_info['stopLoss'] = new_stop_loss + logger.info( + f"{symbol} [实时监控] 移动止损更新: {new_stop_loss:.4f} " + f"(保护{trailing_protect*100:.1f}% of margin = {protect_amount:.4f} USDT)" + ) + else: # SELL + # 做空:止损价 = 开仓价 + (当前盈亏 - 保护金额) / 数量 + # 注意:对于做空,止损价应该高于开仓价,所以用加法 + # 当盈利时(pnl_amount > 0),止损价应该往上移(更宽松) + # 当亏损时(pnl_amount < 0),不应该移动止损(保持初始止损) + new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity + # 对于做空,止损价应该越来越高(更宽松),所以检查 new_stop_loss > 当前止损 + # 同时,移动止损只应该在盈利时激活,不应该在亏损时把止损往下移 + if new_stop_loss > position_info['stopLoss'] and pnl_amount > 0: + position_info['stopLoss'] = new_stop_loss + logger.info( + f"{symbol} [实时监控] 移动止损更新: {new_stop_loss:.4f} " + f"(保护{trailing_protect*100:.1f}% of margin = {protect_amount:.4f} USDT)" + ) # 检查止损(基于保证金收益比) # ⚠️ 重要:止损检查应该在时间锁之前,止损必须立即执行 diff --git a/trading_system/risk_manager.py b/trading_system/risk_manager.py index 98e5f34..a262f15 100644 --- a/trading_system/risk_manager.py +++ b/trading_system/risk_manager.py @@ -650,6 +650,11 @@ class RiskManager: # 获取止损百分比(相对于保证金) stop_loss_percent = stop_loss_pct or config.TRADING_CONFIG['STOP_LOSS_PERCENT'] + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + # 如果值>1,认为是百分比形式,转换为比例形式 + if stop_loss_percent > 1: + stop_loss_percent = stop_loss_percent / 100.0 + # 计算止损金额(相对于保证金) stop_loss_amount = margin * stop_loss_percent @@ -813,6 +818,11 @@ class RiskManager: # 获取止盈百分比(相对于保证金) take_profit_percent = take_profit_pct or config.TRADING_CONFIG['TAKE_PROFIT_PERCENT'] + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + # 如果值>1,认为是百分比形式,转换为比例形式 + if take_profit_percent > 1: + take_profit_percent = take_profit_percent / 100.0 + # 计算止盈金额(相对于保证金) take_profit_amount = margin * take_profit_percent diff --git a/trading_system/trade_recommender.py b/trading_system/trade_recommender.py index 9b9b0c3..b245c5c 100644 --- a/trading_system/trade_recommender.py +++ b/trading_system/trade_recommender.py @@ -432,7 +432,13 @@ class TradeRecommender: # 计算基于保证金的止损止盈 stop_loss_pct_margin = config.TRADING_CONFIG.get('STOP_LOSS_PERCENT', 0.08) + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + if stop_loss_pct_margin is not None and stop_loss_pct_margin > 1: + stop_loss_pct_margin = stop_loss_pct_margin / 100.0 take_profit_pct_margin = config.TRADING_CONFIG.get('TAKE_PROFIT_PERCENT', 0.15) + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + if take_profit_pct_margin is not None and take_profit_pct_margin > 1: + take_profit_pct_margin = take_profit_pct_margin / 100.0 stop_loss_price = self.risk_manager.get_stop_loss_price( entry_price, @@ -454,6 +460,9 @@ class TradeRecommender: # 第一目标:30%固定止盈(基于保证金),保证拿到30%盈利,然后留一部分去追求更高利润 take_profit_1_pct_margin = config.TRADING_CONFIG.get('TAKE_PROFIT_PERCENT', 0.30) # 30%固定止盈 + # ⚠️ 关键修复:配置值格式转换(兼容百分比形式和比例形式) + if take_profit_1_pct_margin > 1: + take_profit_1_pct_margin = take_profit_1_pct_margin / 100.0 take_profit_1 = self.risk_manager.get_take_profit_price( entry_price, direction, estimated_quantity, leverage, take_profit_pct=take_profit_1_pct_margin