From ff3775eadaf1356c12e3c5a284f68612e30ce3da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Sat, 17 Jan 2026 11:34:19 +0800 Subject: [PATCH] a --- backend/config_manager.py | 21 ++-- backend/database/init.sql | 21 ++-- trading_system/config.py | 21 ++-- trading_system/position_manager.py | 13 ++ trading_system/risk_manager.py | 190 ++++++++++++++++++----------- 5 files changed, 168 insertions(+), 98 deletions(-) diff --git a/backend/config_manager.py b/backend/config_manager.py index bdd9c80..f3beab3 100644 --- a/backend/config_manager.py +++ b/backend/config_manager.py @@ -109,20 +109,23 @@ class ConfigManager: """获取交易配置字典(兼容原有config.py的TRADING_CONFIG)""" return { # 仓位控制 - 'MAX_POSITION_PERCENT': self.get('MAX_POSITION_PERCENT', 0.05), - 'MAX_TOTAL_POSITION_PERCENT': self.get('MAX_TOTAL_POSITION_PERCENT', 0.30), - 'MIN_POSITION_PERCENT': self.get('MIN_POSITION_PERCENT', 0.01), - 'MIN_MARGIN_USDT': self.get('MIN_MARGIN_USDT', 0.5), # 最小保证金要求(USDT) + 'MAX_POSITION_PERCENT': self.get('MAX_POSITION_PERCENT', 0.08), # 提高单笔仓位到8% + 'MAX_TOTAL_POSITION_PERCENT': self.get('MAX_TOTAL_POSITION_PERCENT', 0.40), # 提高总仓位到40% + 'MIN_POSITION_PERCENT': self.get('MIN_POSITION_PERCENT', 0.02), # 提高最小仓位到2% + 'MIN_MARGIN_USDT': self.get('MIN_MARGIN_USDT', 5.0), # 提高最小保证金到5美元 # 涨跌幅阈值 'MIN_CHANGE_PERCENT': self.get('MIN_CHANGE_PERCENT', 2.0), 'TOP_N_SYMBOLS': self.get('TOP_N_SYMBOLS', 10), # 风险控制 - 'STOP_LOSS_PERCENT': self.get('STOP_LOSS_PERCENT', 0.10), # 默认10%(更宽松,避免被小幅波动触发) - 'TAKE_PROFIT_PERCENT': self.get('TAKE_PROFIT_PERCENT', 0.20), # 默认20%(提高盈亏比) + 'STOP_LOSS_PERCENT': self.get('STOP_LOSS_PERCENT', 0.10), # 默认10% + 'TAKE_PROFIT_PERCENT': self.get('TAKE_PROFIT_PERCENT', 0.30), # 默认30%(盈亏比3:1) 'MIN_STOP_LOSS_PRICE_PCT': self.get('MIN_STOP_LOSS_PRICE_PCT', 0.02), # 默认2% 'MIN_TAKE_PROFIT_PRICE_PCT': self.get('MIN_TAKE_PROFIT_PRICE_PCT', 0.03), # 默认3% + 'USE_ATR_STOP_LOSS': self.get('USE_ATR_STOP_LOSS', True), # 是否使用ATR动态止损 + 'ATR_STOP_LOSS_MULTIPLIER': self.get('ATR_STOP_LOSS_MULTIPLIER', 1.8), # ATR止损倍数 + 'ATR_TAKE_PROFIT_MULTIPLIER': self.get('ATR_TAKE_PROFIT_MULTIPLIER', 3.0), # ATR止盈倍数 # 市场扫描(1小时主周期) 'SCAN_INTERVAL': self.get('SCAN_INTERVAL', 3600), # 1小时 @@ -141,10 +144,10 @@ class ConfigManager: 'MIN_SIGNAL_STRENGTH': self.get('MIN_SIGNAL_STRENGTH', 5), 'LEVERAGE': self.get('LEVERAGE', 10), 'USE_DYNAMIC_LEVERAGE': self.get('USE_DYNAMIC_LEVERAGE', True), - 'MAX_LEVERAGE': self.get('MAX_LEVERAGE', 20), + 'MAX_LEVERAGE': self.get('MAX_LEVERAGE', 15), # 降低到15,更保守,配合更大的保证金 'USE_TRAILING_STOP': self.get('USE_TRAILING_STOP', True), - 'TRAILING_STOP_ACTIVATION': self.get('TRAILING_STOP_ACTIVATION', 0.05), # 默认5%(避免过早触发) - 'TRAILING_STOP_PROTECT': self.get('TRAILING_STOP_PROTECT', 0.03), # 默认3%(更合理) + 'TRAILING_STOP_ACTIVATION': self.get('TRAILING_STOP_ACTIVATION', 0.10), # 默认10%(给趋势更多空间) + 'TRAILING_STOP_PROTECT': self.get('TRAILING_STOP_PROTECT', 0.05), # 默认5%(保护更多利润) } diff --git a/backend/database/init.sql b/backend/database/init.sql index bcc6eb6..eb0b7e9 100644 --- a/backend/database/init.sql +++ b/backend/database/init.sql @@ -130,10 +130,10 @@ CREATE TABLE IF NOT EXISTS `trade_recommendations` ( -- 初始化默认配置 INSERT INTO `trading_config` (`config_key`, `config_value`, `config_type`, `category`, `description`) VALUES -- 仓位控制 -('MAX_POSITION_PERCENT', '0.05', 'number', 'position', '单笔最大仓位:账户余额的5%'), -('MAX_TOTAL_POSITION_PERCENT', '0.30', 'number', 'position', '总仓位上限:账户余额的30%'), -('MIN_POSITION_PERCENT', '0.01', 'number', 'position', '单笔最小仓位:账户余额的1%'), -('MIN_MARGIN_USDT', '0.5', 'number', 'position', '最小保证金要求:0.5 USDT(避免手续费侵蚀收益)'), +('MAX_POSITION_PERCENT', '0.08', 'number', 'position', '单笔最大仓位:账户余额的8%(提高收益)'), +('MAX_TOTAL_POSITION_PERCENT', '0.40', 'number', 'position', '总仓位上限:账户余额的40%(允许更多持仓)'), +('MIN_POSITION_PERCENT', '0.02', 'number', 'position', '单笔最小仓位:账户余额的2%(避免过小仓位)'), +('MIN_MARGIN_USDT', '5.0', 'number', 'position', '最小保证金要求:5 USDT(提高收益)'), -- 涨跌幅阈值 ('MIN_CHANGE_PERCENT', '2.0', 'number', 'scan', '最小涨跌幅阈值:2%'), @@ -141,10 +141,13 @@ INSERT INTO `trading_config` (`config_key`, `config_value`, `config_type`, `cate ('MAX_SCAN_SYMBOLS', '500', 'number', 'scan', '扫描的最大交易对数量(0表示扫描所有,建议100-500)'), -- 风险控制 -('STOP_LOSS_PERCENT', '0.10', 'number', 'risk', '止损:10%(相对于保证金,更宽松避免被小幅波动触发)'), -('TAKE_PROFIT_PERCENT', '0.20', 'number', 'risk', '止盈:20%(相对于保证金,提高盈亏比)'), +('STOP_LOSS_PERCENT', '0.10', 'number', 'risk', '止损:10%(相对于保证金)'), +('TAKE_PROFIT_PERCENT', '0.30', 'number', 'risk', '止盈:30%(相对于保证金,盈亏比3:1)'), ('MIN_STOP_LOSS_PRICE_PCT', '0.02', 'number', 'risk', '最小止损价格变动:2%(防止止损过紧)'), ('MIN_TAKE_PROFIT_PRICE_PCT', '0.03', 'number', 'risk', '最小止盈价格变动:3%(防止止盈过紧)'), +('USE_ATR_STOP_LOSS', 'true', 'boolean', 'risk', '是否使用ATR动态止损(优先于固定百分比)'), +('ATR_STOP_LOSS_MULTIPLIER', '1.8', 'number', 'risk', 'ATR止损倍数(1.5-2倍ATR,默认1.8)'), +('ATR_TAKE_PROFIT_MULTIPLIER', '3.0', 'number', 'risk', 'ATR止盈倍数(3倍ATR,对应3:1盈亏比)'), -- 市场扫描(1小时主周期) ('SCAN_INTERVAL', '3600', 'number', 'scan', '扫描间隔:1小时(秒)'), @@ -161,10 +164,10 @@ INSERT INTO `trading_config` (`config_key`, `config_value`, `config_type`, `cate ('MIN_SIGNAL_STRENGTH', '7', 'number', 'strategy', '最小信号强度(0-10),已提升至7以提高入场质量'), ('LEVERAGE', '10', 'number', 'strategy', '基础杠杆倍数'), ('USE_DYNAMIC_LEVERAGE', 'true', 'boolean', 'strategy', '是否启用动态杠杆(根据信号强度调整杠杆倍数)'), -('MAX_LEVERAGE', '20', 'number', 'strategy', '最大杠杆倍数(动态杠杆上限)'), +('MAX_LEVERAGE', '15', 'number', 'strategy', '最大杠杆倍数(动态杠杆上限,降低到15更保守)'), ('USE_TRAILING_STOP', 'true', 'boolean', 'strategy', '是否使用移动止损'), -('TRAILING_STOP_ACTIVATION', '0.05', 'number', 'strategy', '移动止损激活阈值(盈利5%后激活,避免过早触发)'), -('TRAILING_STOP_PROTECT', '0.03', 'number', 'strategy', '移动止损保护利润(保护3%利润,更合理)'), +('TRAILING_STOP_ACTIVATION', '0.10', 'number', 'strategy', '移动止损激活阈值(盈利10%后激活,给趋势更多空间)'), +('TRAILING_STOP_PROTECT', '0.05', 'number', 'strategy', '移动止损保护利润(保护5%利润,更合理)'), -- 持仓同步 ('POSITION_SYNC_INTERVAL', '300', 'number', 'scan', '持仓状态同步间隔(秒),默认5分钟,用于同步币安实际持仓与数据库状态'), diff --git a/trading_system/config.py b/trading_system/config.py index f04aa85..abebb6f 100644 --- a/trading_system/config.py +++ b/trading_system/config.py @@ -161,17 +161,20 @@ def _get_trading_config(): return _config_manager.get_trading_config() # 回退到默认配置 return { - 'MAX_POSITION_PERCENT': 0.05, - 'MAX_TOTAL_POSITION_PERCENT': 0.30, - 'MIN_POSITION_PERCENT': 0.01, - 'MIN_MARGIN_USDT': 0.5, # 最小保证金要求(USDT),如果保证金小于此值,自动调整到0.5U保证金 + 'MAX_POSITION_PERCENT': 0.08, # 提高单笔仓位到8%(原来5%),增加收益 + 'MAX_TOTAL_POSITION_PERCENT': 0.40, # 提高总仓位到40%(原来30%),允许更多持仓 + 'MIN_POSITION_PERCENT': 0.02, # 提高最小仓位到2%(原来1%),避免过小仓位 + 'MIN_MARGIN_USDT': 5.0, # 提高最小保证金到5美元(原来0.5U),确保收益可观 'MIN_CHANGE_PERCENT': 0.5, # 降低到0.5%以获取更多推荐(推荐系统可以更宽松) 'TOP_N_SYMBOLS': 50, # 每次扫描后处理的交易对数量(增加到50以获取更多推荐) 'MAX_SCAN_SYMBOLS': 500, # 扫描的最大交易对数量(0表示扫描所有) - 'STOP_LOSS_PERCENT': 0.10, # 止损百分比(相对于保证金),默认10%(更宽松,避免被小幅波动触发) - 'TAKE_PROFIT_PERCENT': 0.20, # 止盈百分比(相对于保证金),默认20%(提高盈亏比) + 'STOP_LOSS_PERCENT': 0.10, # 止损百分比(相对于保证金),默认10% + 'TAKE_PROFIT_PERCENT': 0.30, # 止盈百分比(相对于保证金),默认30%(盈亏比3:1) 'MIN_STOP_LOSS_PRICE_PCT': 0.02, # 最小止损价格变动百分比(如0.02表示2%),防止止损过紧,默认2% 'MIN_TAKE_PROFIT_PRICE_PCT': 0.03, # 最小止盈价格变动百分比(如0.03表示3%),防止止盈过紧,默认3% + 'USE_ATR_STOP_LOSS': True, # 是否使用ATR动态止损(优先于固定百分比) + 'ATR_STOP_LOSS_MULTIPLIER': 1.8, # ATR止损倍数(1.5-2倍ATR,默认1.8) + 'ATR_TAKE_PROFIT_MULTIPLIER': 3.0, # ATR止盈倍数(3倍ATR,对应3:1盈亏比) 'SCAN_INTERVAL': 3600, 'KLINE_INTERVAL': '1h', 'PRIMARY_INTERVAL': '1h', @@ -182,10 +185,10 @@ def _get_trading_config(): 'MIN_SIGNAL_STRENGTH': 7, # 提高至7,只交易高质量信号(简化策略后) 'LEVERAGE': 10, # 基础杠杆倍数 'USE_DYNAMIC_LEVERAGE': True, # 是否启用动态杠杆(根据信号强度调整) - 'MAX_LEVERAGE': 20, # 最大杠杆倍数(动态杠杆上限) + 'MAX_LEVERAGE': 15, # 最大杠杆倍数(降低到15,更保守,配合更大的保证金) 'USE_TRAILING_STOP': True, - 'TRAILING_STOP_ACTIVATION': 0.05, # 移动止损激活从1%改为5%(避免过早触发) - 'TRAILING_STOP_PROTECT': 0.03, # 保护利润从1%提高到3%(更合理) + 'TRAILING_STOP_ACTIVATION': 0.10, # 移动止损激活提高到10%(盈利10%后激活,给趋势更多空间) + 'TRAILING_STOP_PROTECT': 0.05, # 保护利润提高到5%(保护5%利润,更合理) 'POSITION_SYNC_INTERVAL': 300, # 持仓状态同步间隔(秒),默认5分钟 } diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index f1445f7..2f89048 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -163,6 +163,7 @@ class PositionManager: atr=atr ) +<<<<<<< Current (Your changes) # 计算止盈(基于保证金) # 优先使用配置的止盈百分比,如果没有配置则使用止损的2倍 take_profit_pct_margin = self.risk_manager.config.get('TAKE_PROFIT_PERCENT', 0.15) @@ -172,6 +173,18 @@ class PositionManager: take_profit_price = self.risk_manager.get_take_profit_price( entry_price, side, quantity, leverage, take_profit_pct=take_profit_pct_margin +======= + # 计算止盈(基于保证金,支持ATR动态止盈) + # 优先使用配置的止盈百分比,如果没有配置则使用止损的3倍(盈亏比3:1) + take_profit_pct_margin = self.risk_manager.config.get('TAKE_PROFIT_PERCENT', 0.30) + # 如果配置中没有设置止盈,则使用止损的3倍作为默认(盈亏比3:1) + if take_profit_pct_margin is None or take_profit_pct_margin == 0: + take_profit_pct_margin = stop_loss_pct_margin * 3.0 + take_profit_price = self.risk_manager.get_take_profit_price( + entry_price, side, quantity, leverage, + take_profit_pct=take_profit_pct_margin, + atr=atr # 传递ATR用于动态止盈 +>>>>>>> Incoming (Background Agent changes) ) # 下单 diff --git a/trading_system/risk_manager.py b/trading_system/risk_manager.py index bf9358d..90b4570 100644 --- a/trading_system/risk_manager.py +++ b/trading_system/risk_manager.py @@ -426,6 +426,28 @@ class RiskManager: position_value = entry_price * quantity margin = position_value / leverage if leverage > 0 else position_value + # 优先使用ATR动态止损(如果启用且ATR可用) + use_atr_stop = self.config.get('USE_ATR_STOP_LOSS', True) + atr_multiplier = self.config.get('ATR_STOP_LOSS_MULTIPLIER', 1.8) + + if use_atr_stop and atr is not None and atr > 0: + # 基于ATR的动态止损 + atr_stop_distance = atr * atr_multiplier + + if side == 'BUY': # 做多,止损价低于入场价 + stop_loss_price_atr = entry_price - atr_stop_distance + else: # 做空,止损价高于入场价 + stop_loss_price_atr = entry_price + atr_stop_distance + + logger.info( + f"ATR动态止损计算 ({side}): ATR={atr:.4f}, 倍数={atr_multiplier}, " + f"止损距离={atr_stop_distance:.4f}, ATR止损价={stop_loss_price_atr:.4f}" + ) + else: + stop_loss_price_atr = None + if use_atr_stop and (atr is None or atr <= 0): + logger.debug(f"ATR不可用,使用固定百分比止损") + # 获取止损百分比(相对于保证金) stop_loss_percent = stop_loss_pct or self.config['STOP_LOSS_PERCENT'] @@ -449,23 +471,27 @@ class RiskManager: stop_loss_price_price = entry_price * (1 - min_price_change_pct) else: stop_loss_price_price = entry_price * (1 + min_price_change_pct) - - # 取更宽松的止损价(对做多取更大的值,对做空取更小的值) - if side == 'BUY': - stop_loss_price = max(stop_loss_price_margin, stop_loss_price_price) - else: - stop_loss_price = min(stop_loss_price_margin, stop_loss_price_price) - - logger.info( - f"止损计算 ({side}): 基于保证金={stop_loss_price_margin:.4f}, " - f"基于价格={stop_loss_price_price:.4f}, " - f"最终止损={stop_loss_price:.4f} (取更宽松)" - ) else: - # 没有配置最小价格变动,直接使用基于保证金的止损价 - stop_loss_price = stop_loss_price_margin + stop_loss_price_price = None - # 如果提供了技术分析数据,可以调整止损价(但不能超过基于保证金的止损范围) + # 选择最终的止损价:优先ATR,其次保证金,最后价格百分比(取更宽松的) + candidate_prices = [] + if stop_loss_price_atr is not None: + candidate_prices.append(('ATR', stop_loss_price_atr)) + candidate_prices.append(('保证金', stop_loss_price_margin)) + if stop_loss_price_price is not None: + candidate_prices.append(('价格百分比', stop_loss_price_price)) + + # 对做多取最大的值(最宽松),对做空取最小的值(最宽松) + if side == 'BUY': + stop_loss_price = max(p[1] for p in candidate_prices) + selected_method = [p[0] for p in candidate_prices if p[1] == stop_loss_price][0] + else: + stop_loss_price = min(p[1] for p in candidate_prices) + selected_method = [p[0] for p in candidate_prices if p[1] == stop_loss_price][0] + + # 如果提供了技术分析数据,计算技术止损(允许更紧的止损,但需要在保证金止损范围内) + technical_stop = None if klines and len(klines) >= 10: # 计算支撑/阻力位 low_prices = [float(k[3]) for k in klines[-20:]] # 最近20根K线的最低价 @@ -483,22 +509,14 @@ class RiskManager: bollinger_stop = bollinger['lower'] * 0.995 # 布林带下轨下方0.5% technical_stop = max(technical_stop, bollinger_stop) - # 使用技术止损,但不能超过基于保证金的止损范围(允许更紧的止损) - # 如果技术止损更紧(价格更低),使用技术止损;否则使用基于保证金的止损 - if technical_stop < stop_loss_price: - # 技术止损更紧,使用技术止损 - logger.info( - f"动态止损计算 (BUY): 使用技术止损 {technical_stop:.4f} " - f"(基于保证金的止损: {stop_loss_price:.4f}, 止损金额: {stop_loss_amount:.2f} USDT)" + # 技术止损更紧,但需要确保在保证金止损范围内(不能超过保证金止损) + if technical_stop < stop_loss_price and technical_stop >= stop_loss_price_margin: + # 技术止损在合理范围内,可以考虑使用 + candidate_prices.append(('技术分析', technical_stop)) + logger.debug( + f"技术止损 (BUY): {technical_stop:.4f} " + f"(在保证金止损范围内)" ) - return technical_stop - else: - logger.info( - f"动态止损计算 (BUY): 使用基于保证金的止损 {stop_loss_price:.4f} " - f"(技术止损: {technical_stop:.4f}, 止损金额: {stop_loss_amount:.2f} USDT, " - f"止损比例: {stop_loss_percent*100:.1f}% of margin)" - ) - return stop_loss_price else: # 做空,止损放在阻力位上方 # 找到近期波段高点 recent_high = max(high_prices) @@ -511,31 +529,32 @@ class RiskManager: bollinger_stop = bollinger['upper'] * 1.005 # 布林带上轨上方0.5% technical_stop = min(technical_stop, bollinger_stop) - # 使用技术止损,但不能超过基于保证金的止损范围(允许更紧的止损) - # 如果技术止损更紧(价格更高),使用技术止损;否则使用基于保证金的止损 - if technical_stop > stop_loss_price: - # 技术止损更紧,使用技术止损 - logger.info( - f"动态止损计算 (SELL): 使用技术止损 {technical_stop:.4f} " - f"(基于保证金的止损: {stop_loss_price:.4f}, 止损金额: {stop_loss_amount:.2f} USDT)" + # 技术止损更紧,但需要确保在保证金止损范围内(不能超过保证金止损) + if technical_stop > stop_loss_price and technical_stop <= stop_loss_price_margin: + # 技术止损在合理范围内,可以考虑使用 + candidate_prices.append(('技术分析', technical_stop)) + logger.debug( + f"技术止损 (SELL): {technical_stop:.4f} " + f"(在保证金止损范围内)" ) - return technical_stop - else: - logger.info( - f"动态止损计算 (SELL): 使用基于保证金的止损 {stop_loss_price:.4f} " - f"(技术止损: {technical_stop:.4f}, 止损金额: {stop_loss_amount:.2f} USDT, " - f"止损比例: {stop_loss_percent*100:.1f}% of margin)" - ) - return stop_loss_price - # 没有技术分析数据,直接使用基于保证金的止损 + # 重新选择最终的止损价(包括技术止损) + if side == 'BUY': + final_stop_loss = max(p[1] for p in candidate_prices) + selected_method = [p[0] for p in candidate_prices if p[1] == final_stop_loss][0] + else: + final_stop_loss = min(p[1] for p in candidate_prices) + selected_method = [p[0] for p in candidate_prices if p[1] == final_stop_loss][0] + logger.info( - f"止损计算 ({side}): 入场价={entry_price:.4f}, 数量={quantity:.4f}, " - f"杠杆={leverage}x, 保证金={margin:.4f} USDT, " - f"止损金额={stop_loss_amount:.4f} USDT ({stop_loss_percent*100:.1f}% of margin), " - f"止损价={stop_loss_price:.4f}" + f"最终止损 ({side}): {final_stop_loss:.4f} (使用{selected_method}), " + + (f"ATR={stop_loss_price_atr:.4f}, " if stop_loss_price_atr else "") + + f"保证金={stop_loss_price_margin:.4f}, " + + (f"价格={stop_loss_price_price:.4f}, " if stop_loss_price_price else "") + + (f"技术={technical_stop:.4f}, " if technical_stop else "") + + f"止损金额={stop_loss_amount:.2f} USDT ({stop_loss_percent*100:.1f}% of margin)" ) - return stop_loss_price + return final_stop_loss def get_take_profit_price( self, @@ -543,10 +562,11 @@ class RiskManager: side: str, quantity: float, leverage: int, - take_profit_pct: Optional[float] = None + take_profit_pct: Optional[float] = None, + atr: Optional[float] = None ) -> float: """ - 计算止盈价格(基于保证金的盈亏金额) + 计算止盈价格(基于保证金的盈亏金额,支持ATR动态止盈) Args: entry_price: 入场价格 @@ -554,6 +574,7 @@ class RiskManager: quantity: 持仓数量 leverage: 杠杆倍数 take_profit_pct: 止盈百分比(相对于保证金),如果为None则使用配置值 + atr: 平均真实波幅,用于计算动态止盈(可选) Returns: 止盈价格 @@ -562,6 +583,28 @@ class RiskManager: position_value = entry_price * quantity margin = position_value / leverage if leverage > 0 else position_value + # 优先使用ATR动态止盈(如果启用且ATR可用) + use_atr_stop = self.config.get('USE_ATR_STOP_LOSS', True) + atr_tp_multiplier = self.config.get('ATR_TAKE_PROFIT_MULTIPLIER', 3.0) + + if use_atr_stop and atr is not None and atr > 0: + # 基于ATR的动态止盈(对应3:1盈亏比) + atr_tp_distance = atr * atr_tp_multiplier + + if side == 'BUY': # 做多,止盈价高于入场价 + take_profit_price_atr = entry_price + atr_tp_distance + else: # 做空,止盈价低于入场价 + take_profit_price_atr = entry_price - atr_tp_distance + + logger.info( + f"ATR动态止盈计算 ({side}): ATR={atr:.4f}, 倍数={atr_tp_multiplier}, " + f"止盈距离={atr_tp_distance:.4f}, ATR止盈价={take_profit_price_atr:.4f}" + ) + else: + take_profit_price_atr = None + if use_atr_stop and (atr is None or atr <= 0): + logger.debug(f"ATR不可用,使用固定百分比止盈") + # 获取止盈百分比(相对于保证金) take_profit_percent = take_profit_pct or self.config['TAKE_PROFIT_PERCENT'] @@ -585,27 +628,32 @@ class RiskManager: take_profit_price_price = entry_price * (1 + min_price_change_pct) else: take_profit_price_price = entry_price * (1 - min_price_change_pct) - - # 取更宽松的止盈价(对做多取更大的值,对做空取更小的值) - if side == 'BUY': - take_profit_price = max(take_profit_price_margin, take_profit_price_price) - else: - take_profit_price = min(take_profit_price_margin, take_profit_price_price) - - logger.info( - f"止盈计算 ({side}): 基于保证金={take_profit_price_margin:.4f}, " - f"基于价格={take_profit_price_price:.4f}, " - f"最终止盈={take_profit_price:.4f} (取更宽松)" - ) else: - # 没有配置最小价格变动,直接使用基于保证金的止盈价 - take_profit_price = take_profit_price_margin + take_profit_price_price = None + + # 选择最终的止盈价:优先ATR,其次保证金,最后价格百分比(取更宽松的) + candidate_prices = [] + if take_profit_price_atr is not None: + candidate_prices.append(('ATR', take_profit_price_atr)) + candidate_prices.append(('保证金', take_profit_price_margin)) + if take_profit_price_price is not None: + candidate_prices.append(('价格百分比', take_profit_price_price)) + + # 对做多取最大的值(更宽松),对做空取最小的值(更宽松) + if side == 'BUY': + take_profit_price = max(p[1] for p in candidate_prices) + selected_method = [p[0] for p in candidate_prices if p[1] == take_profit_price][0] + else: + take_profit_price = min(p[1] for p in candidate_prices) + selected_method = [p[0] for p in candidate_prices if p[1] == take_profit_price][0] logger.info( - f"止盈计算 ({side}): 入场价={entry_price:.4f}, 数量={quantity:.4f}, " - f"杠杆={leverage}x, 保证金={margin:.4f} USDT, " - f"止盈金额={take_profit_amount:.4f} USDT ({take_profit_percent*100:.1f}% of margin), " - f"止盈价={take_profit_price:.4f}" + f"止盈计算 ({side}): " + + (f"ATR={take_profit_price_atr:.4f}, " if take_profit_price_atr else "") + + f"基于保证金={take_profit_price_margin:.4f}, " + + (f"基于价格={take_profit_price_price:.4f}, " if take_profit_price_price else "") + + f"最终止盈={take_profit_price:.4f} (使用{selected_method}, 取更宽松), " + + f"止盈金额={take_profit_amount:.4f} USDT ({take_profit_percent*100:.1f}% of margin)" ) return take_profit_price