From 4a5406c7e8140aa30449eef72bb3f37d82e4f240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Sat, 28 Feb 2026 19:01:59 +0800 Subject: [PATCH] feat(position_manager): Enhance stop-loss logic for short positions and implement automatic SL/TP order synchronization Updated the stop-loss calculation for short positions to ensure it locks in profits effectively. Added logic to automatically synchronize stop-loss and take-profit orders for positions without existing SL/TP on the exchange. This improves risk management and ensures positions are adequately protected. Enhanced logging for better tracking of stop-loss updates and synchronization events. --- docs/position_analysis_2026-02-28.md | 99 +++++++++++++++++++++ docs/trade_analysis_2026-02-28.md | 127 +++++++++++++++++++++++++++ trading_system/position_manager.py | 63 ++++++++----- 3 files changed, 268 insertions(+), 21 deletions(-) create mode 100644 docs/position_analysis_2026-02-28.md create mode 100644 docs/trade_analysis_2026-02-28.md diff --git a/docs/position_analysis_2026-02-28.md b/docs/position_analysis_2026-02-28.md new file mode 100644 index 0000000..5374ef7 --- /dev/null +++ b/docs/position_analysis_2026-02-28.md @@ -0,0 +1,99 @@ +# 持仓分析:持仓记录_2026-02-28T10-43-05.json + +## 一、20% 以上盈利的持仓(共 3 个) + +| 交易对 | 方向 | 盈亏% | 入场价 | 标记价 | 止损 | 止盈 | 交易所 SL/TP | +|--------|------|-------|--------|--------|------|------|--------------| +| **WIFUSDT** | SELL | **40.3%** | 0.2051 | 0.1863 | **无** | **无** | **无** | +| **ZECUSDT** | SELL | **26.3%** | 221.44 | 207.78 | **无** | **无** | **无** | +| **BCHUSDT** | SELL | **23.7%** | 470.74 | 444.40 | 479.05 | 436.04 | 有 | + +### 止损问题诊断 + +1. **WIF、ZEC:完全没有止损/止盈** + - 两笔已浮盈 40%、26%,但交易所无任何 SL/TP 挂单,一旦反转会全部回吐甚至变亏。 + - 可能原因:非本系统开仓(手动/别处)、或开仓时未成功挂出 SL/TP、或同步/补建时未补挂。 + - **建议**:尽快在交易所或通过系统对这两笔**至少挂上保本/锁利止损**(例如锁住一半利润或 5%~10% 利润)。 + +2. **BCH:有 SL/TP,但止损未上移锁利** + - 空头:入场 470.74,当前 444.40,止损仍在 **479.05**(开仓时的初始止损,高于入场价)。 + - 正确做法:盈利 23.7% 后,**做空的移动止损应下移**(例如从 479 移到 455~460 一带),锁住部分利润;否则价格反弹到 479 才触发,会几乎回吐全部盈利。 + - 可能原因: + - 该持仓不在本系统 `active_positions` 内(例如由同步/补建得到),未参与定时检查的移动止损逻辑; + - 或做空方向的移动止损更新条件/方向在代码中有误(见下文「策略执行」)。 + +--- + +## 二、全部 13 笔持仓汇总 + +| 交易对 | 方向 | 盈亏% | 止损 | 止盈 | 交易所有 SL/TP | +|--------|------|-------|------|------|----------------| +| WIFUSDT | SELL | 40.3 | 无 | 无 | 无 | +| ZECUSDT | SELL | 26.3 | 无 | 无 | 无 | +| BCHUSDT | SELL | 23.7 | 479.05 | 436.04 | 有 | +| VVVUSDT | BUY | 15.1 | 无 | 无 | 无 | +| PUMPUSDT | SELL | 7.8 | 0.001813 | 0.001651 | 有 | +| ZROUSDT | SELL | 4.7 | 1.5763 | 1.4348 | 有 | +| SAHARAUSDT | BUY | 2.5 | 0.01829 | 0.02356 | 有 | +| ASTERUSDT | SELL | -0.0 | 0.7152 | 0.651 | 有 | +| MYXUSDT | SELL | -0.5 | 无 | 无 | 无 | +| FARTCOINUSDT | SELL | -0.8 | 无 | 无 | 无 | +| HYPEUSDT | SELL | -3.8 | 无 | 无 | 无 | +| VIRTUALUSDT | BUY | -9.5 | 无 | 无 | 无 | +| **ICPUSDT** | **BUY** | **-24.5** | **无** | **无** | **无** | + +- **无任何止损/止盈的共 7 笔**:VIRTUAL, ZEC, HYPE, FARTCOIN, VVV, ICP, WIF, MYX。其中 **ICP 已亏 24.5%**,若无止损会继续放大亏损。 + +--- + +## 三、策略执行问题分析 + +### 1. 为何大量持仓「无止损/无止盈」? + +- 若这些仓位是**本系统开仓**:开仓后应调用 `_ensure_exchange_sltp_orders` 在交易所挂 SL/TP;若仍无挂单,可能是: + - 开仓流程中未成功挂单(网络/权限/参数错误)且未重试或告警; + - 或仓位来自**同步/补建**(币安有仓、DB 无记录),补建时若未同时挂 SL/TP,就会一直处于「无保护」状态。 +- **建议**: + - 对「有持仓但无 SL/TP」的 symbol,在同步/健康检查中**自动补挂**(至少止损,止盈可按配置或保守价); + - 开仓后若挂单失败,要有重试与日志/告警,便于排查。 + +### 2. 做空(SELL)移动止损方向是否正确? + +- 做空盈利时,应**下移止损价**(从高位往当前价方向移)才能锁利;当前 BCH 空头止损仍在 479,未下移。 +- 代码中做空分支(`position_manager` 定时检查)有: + - `new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity` + - `new_stop_loss = min(new_stop_loss, breakeven)`,再判断 `new_stop_loss > current_sl` 才更新。 +- 做空时 `pnl_amount = (entry - current)*q > 0`,`entry + (pnl - protect)/q` 可能**大于**初始止损 479,导致条件 `new_stop_loss > current_sl` 不成立,从而从不更新;即便更新,也是把止损往**更上方**移(更宽松),而不是往下锁利。这与「盈利后锁利」的目标相反。 +- **建议**:复查做空移动止损公式与更新条件,确保「盈利后新止损比当前止损更靠近当前价」(空头即新止损 < 当前止损),并只在「锁利方向」上更新。 + +### 3. 亏损单 ICP -24.5% 且无止损 + +- 单笔已亏 24.5%,若无止损会继续暴露风险。 +- **建议**:立即对该仓设止损(或减仓/平仓);并检查为何该仓从未挂上止损(是否补建、是否开仓失败挂单等)。 + +### 4. 多账号/多数据源一致性 + +- 持仓记录中 `id`、`entry_time`、`created_at` 多为 null,说明可能来自**交易所快照 + 部分本地合并**,而非全部来自本系统 DB。要确保: + - 凡在交易所存在的仓位,只要被本系统「认领」或展示,就应纳入监控并在缺失时补挂 SL/TP; + - 移动止损/滞涨早止盈等逻辑应对**所有被监控仓位**生效,包括同步/补建进来的。 + +--- + +## 四、建议汇总 + +| 优先级 | 建议 | +|--------|------| +| **P0** | **WIF、ZEC**:立即在交易所或通过系统挂上止损(至少保本或锁 5%~10% 利润),避免 40%/26% 盈利回吐。 | +| **P0** | **ICP**:已亏 24.5% 且无止损,立即设止损或减仓/平仓,并排查为何无 SL。 | +| **P1** | **BCH**:检查该仓是否在 `active_positions`、是否参与移动止损;若在,复查做空移动止损公式与更新条件,确保盈利后下移止损锁利。 | +| **P1** | 对所有「有仓但无 SL/TP」的持仓(含同步/补建)在同步或健康检查中**自动补挂止损**(止盈可选)。 | +| **P2** | 开仓后 SL/TP 挂单失败时增加重试与告警;移动止损(尤其做空)逻辑做代码审查与单测。 | +| **P2** | 滞涨早止盈:若已开启,确认对 20%+ 盈利的仓位在「长时间不创新高」时能触发分批减仓+抬止损。 | + +--- + +## 五、小结 + +- **3 笔 20%+ 盈利**:2 笔(WIF、ZEC)**完全没有止损**,1 笔(BCH)有止损但**未随盈利下移锁利**,整体「止损不对」的观感成立。 +- **7 笔无任何 SL/TP**,其中 1 笔已亏 24.5%(ICP),风险突出。 +- 策略执行上需:**补挂缺失 SL/TP**、**修正做空移动止损方向与条件**、**保证同步/补建仓位也纳入监控并补挂保护单**。 diff --git a/docs/trade_analysis_2026-02-28.md b/docs/trade_analysis_2026-02-28.md new file mode 100644 index 0000000..b560b8d --- /dev/null +++ b/docs/trade_analysis_2026-02-28.md @@ -0,0 +1,127 @@ +# 交易复盘分析:binance_trades_2_2026-02-28(近一日) + +## 一、整体表现 + +| 指标 | 数值 | +|------|------| +| 总成交笔数 | 83(开仓相关 47 + 平仓相关 36) | +| 盈利次数 / 亏损次数 | 7 / 29 | +| **胜率** | **19.4%** | +| 总已实现盈亏 | -2.10 USDT | +| 总手续费 | 0.60 USDT | +| **净盈亏** | **-2.70 USDT** | +| 总成交额(quote) | 1810.26 USDT | +| 手续费率 | ≈0.033% | + +**结论**:胜率明显偏低,亏损单数量约为盈利单的 4 倍,单笔平均亏损虽被止损控制,但累积亏损 + 手续费导致净损。需要从**入场质量、止损止盈平衡、同一交易对重复交易、时段/币种过滤**等多环节优化。 + +--- + +## 二、按交易对表现 + +### 亏损集中(建议重点关注或加入黑名单/降权) + +| 交易对 | 盈亏(USDT) | 胜/负 | 说明 | +|--------|------------|-------|------| +| PENGUUSDT | -1.75 | 0/2 | 连续 2 笔亏损 | +| AAVEUSDT | -1.73 | 0/1 | 单笔大亏 | +| HYPEUSDT | -1.43 | 0/1 | 单笔大亏 | +| WIFUSDT | -1.34 | 0/3 | **同一天 3 笔亏损**,重复交易严重 | +| ENAUSDT | -1.11 | 0/1 | 单笔大亏 | +| PUMPUSDT | -1.10 | 0/3 | **同一天 3 笔亏损** | +| SIRENUSDT | -0.71 | 0/3 | **同一天 3 笔亏损** | +| RIVERUSDT | -0.66 | 0/2 | 连续 2 笔亏损 | +| WLDUSDT | -0.51 | 0/3 | **同一天 3 笔亏损** | + +### 盈利交易对(可作白名单或维持当前逻辑) + +| 交易对 | 盈亏(USDT) | 胜/负 | +|--------|------------|-------| +| ARUSDT | +3.47 | 1/0 | +| ZECUSDT | +2.19 | 1/0 | +| TAOUSDT | +1.13 | 2/3(有盈有亏,整体小正) | +| VVVUSDT | +1.83 | 1/0 | +| 1000LUNCUSDT | +1.41 | 2/0 | + +**问题**:WIF、PUMP、SIREN、WLD 等同一天内多次亏损,说明要么**冷却时间不足**,要么**同一交易对当日开仓次数**未做上限,导致在弱势品种上反复试错。 + +--- + +## 三、按时段表现 + +- **亏损集中时段**:0 时(-1.43)、1 时(-1.64)、7 时(-0.42)、8 时(-1.02)、17 时(-0.97)、19 时(-1.74)、20 时(-1.34)、21 时(-1.75)。 +- **盈利集中时段**:5 时(+1.41)、6 时(+3.41)、10 时(+0.73)、12 时(+0.85)、22 时(+2.19)。 +- **按星期**:周五 48 笔、-2.42 USDT;周六 35 笔、+0.31 USDT。 + +**结论**:凌晨 0–1 时、早 7–8 时、晚 17–21 时表现较差,可与「按小时统计过滤/黑名单」结合,在这些时段对部分品种降权或减少开仓。 + +--- + +## 四、策略环节诊断与优化建议 + +### 1. 入场与信号质量 + +- **现象**:胜率 19.4%,多数单子被止损打掉,说明**假突破或逆势入场**较多。 +- **建议**: + - 将 **MIN_SIGNAL_STRENGTH** 从 7 提高到 **8**,减少弱信号开仓。 + - 确认 **LOW_VOLATILITY_MIN_SIGNAL_STRENGTH**(当前 9)在低波动期已生效。 + - 对近期统计中**连续亏损或胜率极低的交易对**使用黑名单(硬/软)或降权,避免在 PENGU、WIF、PUMP、SIREN、WLD 等上重复开仓。 + +### 2. 同一交易对重复交易与冷却 + +- **现象**:WIF、PUMP、SIREN、WLD 同一天内 3 笔亏损,说明冷却或「同一 symbol 当日次数」未充分限制。 +- **建议**: + - **SYMBOL_LOSS_COOLDOWN_SEC** 从 3600 提高到 **7200(2 小时)** 或更长,观察同一 symbol 亏损后是否仍频繁再开。 + - 增加「**同一交易对每日最大开仓次数**」(如 2 次),超过则当日不再开该 symbol。 + - 若已有基于 `trade_stats` 的黑名单/降权,确保这些近期大亏或连亏的 symbol 被纳入并生效。 + +### 3. 止损与止盈平衡 + +- **现象**:亏损单多、盈利单少,但单笔亏损被止损控制在约 -0.2~-1.7 USDT,说明止损在执行;盈利单如 AR、ZEC、TAO、VVV 能拿住一部分利润。 +- **建议**: + - 当前 **STOP_LOSS_PERCENT** 5%、**TAKE_PROFIT_1_PERCENT** 12%、**TAKE_PROFIT_PERCENT** 25%:若多数单在未到第一目标就被止损,可考虑: + - **略放宽止损**(如 ATR 倍数从 2.0 调到 2.2)或 **MIN_STOP_LOSS_PRICE_PCT** 略增,减少「刚入场就被震荡扫损」; + - 或**提高入场门槛**(提高 MIN_SIGNAL_STRENGTH),从源头减少劣质单,而不是一味放宽止损。 + - **滞涨早止盈**(STAGNATION_EARLY_EXIT):若已开启,可观察是否在「曾涨到约 10% 后长时间不创新高」时锁利,减少由盈转亏。 + +### 4. 手续费与频率 + +- **现象**:83 笔、手续费 0.60 USDT、费率约 0.033%,单笔平均约 0.007 USDT,占比不高,但**交易频率偏高**会放大亏损和手续费。 +- **建议**: + - 在提高信号门槛、冷却和 symbol 限制后,**自然降低开仓频率**,优先质量而非数量。 + - 若使用市价单较多,可评估在能接受延迟的前提下部分改用限价单以降低 taker 费率。 + +### 5. 时段与品种过滤(统计过滤) + +- **现象**:0–1 时、7–8 时、17–21 时亏损集中;PENGU、WIF、PUMP、SIREN、WLD、AAVE、HYPE、ENA 等明显偏弱。 +- **建议**: + - 使用现有 **trade_stats 按 symbol / 按小时** 的统计:对**亏损集中时段**做降权或禁止开仓,对**近期连亏/大亏的 symbol** 加入黑名单或软黑名单(降权)。 + - 白名单可考虑优先 AR、ZEC、TAO、VVV、1000LUNC 等近期有盈利记录的品种(需结合更长周期再确认)。 + +### 6. 风控与仓位 + +- **现象**:单笔亏损多在 -0.2~-1.7 USDT,未出现单笔爆仓式亏损,说明**单笔风险**受控。 +- **建议**: + - 保持 **MAX_OPEN_POSITIONS**、**FIXED_RISK_PERCENT** 等不变,重点放在**减少开仓次数、提高单笔质量**上,而非加大仓位。 + +--- + +## 五、优化项汇总(按优先级) + +| 优先级 | 优化项 | 说明 | +|--------|--------|------| +| P0 | 提高 MIN_SIGNAL_STRENGTH 到 8 | 减少弱信号开仓,提升胜率 | +| P0 | 延长 SYMBOL_LOSS_COOLDOWN_SEC 到 7200 | 降低同一 symbol 连续亏损次数 | +| P1 | 同一交易对每日最大开仓次数上限 | 避免 WIF/PUMP/SIREN/WLD 类重复试错 | +| P1 | 基于统计的黑名单/时段降权 | 对近期连亏 symbol、亏损集中时段过滤或降权 | +| P2 | 评估略放宽止损(ATR 或 MIN_STOP) | 在提高入场质量前提下,减少震荡扫损 | +| P2 | 滞涨早止盈观察与调参 | 确认 STAGNATION_* 是否在「涨后横盘」时锁利 | +| P3 | 盈利品种白名单/优先 | 结合更长周期后,对稳定盈利的 symbol 做优先或白名单 | + +--- + +## 六、结论 + +- **主要问题**:胜率低(19.4%)、同一交易对同一天多次亏损、部分时段和品种持续贡献亏损。 +- **策略环节**:入场信号偏松、同一 symbol 冷却与次数限制不足、缺少基于近期统计的 symbol/时段过滤,是当前最值得改动的环节;止损执行正常,可先通过「提高质量、减少次数」再考虑是否微调止损/止盈。 +- **建议执行顺序**:先做 P0(信号门槛 + 冷却),观察 1~2 天;再上 P1(每日同 symbol 上限 + 统计黑名单/时段),最后按需微调止损与滞涨早止盈(P2/P3)。 diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index bca07ba..e984d38 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -2254,13 +2254,15 @@ class PositionManager: exc_info=False, ) else: - new_stop_loss = entry_price + (remaining_pnl - protect_amount) / remaining_quantity - new_stop_loss = min(new_stop_loss, self._breakeven_stop_price(entry_price, 'SELL')) + # 做空锁利:止损下移,锁住 protect_amount 利润。(entry - stop)*q = protect → stop = entry - protect/q + new_stop_loss = entry_price - protect_amount / remaining_quantity + new_stop_loss = max(new_stop_loss, self._breakeven_stop_price(entry_price, 'SELL')) current_sl = float(position_info['stopLoss']) if position_info.get('stopLoss') is not None else None - if current_sl is not None and new_stop_loss > current_sl and remaining_pnl > 0: + # 仅当新止损低于当前止损(下移锁利)且高于市价(锁住的是利润)时更新 + if (current_sl is None or new_stop_loss < current_sl) and new_stop_loss > current_price and remaining_pnl > 0: position_info['stopLoss'] = new_stop_loss logger.info( - f"{symbol} 移动止损更新(剩余仓位): {new_stop_loss:.4f} " + f"{symbol} 移动止损更新(剩余仓位-做空锁利): {new_stop_loss:.4f} " f"(保护{trailing_protect*100:.1f}% of remaining margin = {protect_amount:.4f} USDT, " f"剩余数量: {remaining_quantity:.4f})" ) @@ -2300,17 +2302,15 @@ class PositionManager: exc_info=False, ) else: - # 做空:止损价 = 开仓价 + (当前盈亏 - 保护金额) / 数量 - # 注意:对于做空,止损价应该高于开仓价,所以用加法 - # 当盈利时(pnl_amount > 0),止损价应该往上移(更宽松) - # 当亏损时(pnl_amount < 0),不应该移动止损(保持初始止损) - new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity - new_stop_loss = min(new_stop_loss, self._breakeven_stop_price(entry_price, 'SELL')) + # 做空锁利:止损下移(从初始高位往市价方向移),锁住 protect_amount。(entry - stop)*q = protect → stop = entry - protect/q + new_stop_loss = entry_price - protect_amount / quantity + new_stop_loss = max(new_stop_loss, self._breakeven_stop_price(entry_price, 'SELL')) current_sl = float(position_info['stopLoss']) if position_info.get('stopLoss') is not None else None - if current_sl is not None and new_stop_loss > current_sl and pnl_amount > 0: + # 仅当新止损低于当前止损(下移锁利)且高于市价(锁住的是利润)时更新 + if (current_sl is None or new_stop_loss < current_sl) and new_stop_loss > current_price and pnl_amount > 0: position_info['stopLoss'] = new_stop_loss logger.info( - f"{symbol} 移动止损更新: {new_stop_loss:.4f} " + f"{symbol} 移动止损更新(做空锁利): {new_stop_loss:.4f} " f"(保护{trailing_protect*100:.1f}% of margin = {protect_amount:.4f} USDT)" ) _log_trailing_stop_event(self.account_id, symbol, "trailing_update", new_stop_loss=new_stop_loss, source="定时检查") @@ -2820,6 +2820,24 @@ class PositionManager: except Exception as e: logger.debug(f"{symbol} 载入 active_positions 失败: {e}") + # 2.6 对「有仓但交易所无 SL/TP」的持仓自动补挂止损止盈(含仅在本系统 active 的仓) + for symbol in list(self.active_positions.keys()): + if symbol not in binance_symbols: + continue + position_info = self.active_positions[symbol] + if not position_info.get('stopLoss') and not position_info.get('takeProfit'): + continue + try: + sl_from_ex, tp_from_ex = await self._get_sltp_from_exchange(symbol, position_info['side']) + if sl_from_ex is not None and tp_from_ex is not None: + continue + ticker = await self.client.get_ticker_24h(symbol) + current_price = float(ticker.get('price', 0) or position_info.get('entryPrice', 0)) + await self._ensure_exchange_sltp_orders(symbol, position_info, current_price=current_price) + logger.info(f"[账号{self.account_id}] {symbol} [同步] 检测到交易所无止损/止盈,已补挂 SL/TP") + except Exception as e: + logger.warning(f"[账号{self.account_id}] {symbol} [同步] 补挂 SL/TP 失败: {e}", exc_info=False) + # 3. 找出在数据库中open但在币安已不存在的持仓 missing_in_binance = db_open_symbols - binance_symbols @@ -4412,10 +4430,10 @@ class PositionManager: new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity breakeven = self._breakeven_stop_price(entry_price, 'BUY') new_stop_loss = max(new_stop_loss, breakeven) - else: # SELL - new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity + else: # SELL 做空锁利:止损下移,锁住 protect_amount。(entry - stop)*q = protect → stop = entry - protect/q + new_stop_loss = entry_price - protect_amount / quantity breakeven = self._breakeven_stop_price(entry_price, 'SELL') - new_stop_loss = min(new_stop_loss, breakeven) + new_stop_loss = max(new_stop_loss, breakeven) position_info['stopLoss'] = new_stop_loss logger.info( @@ -4448,7 +4466,8 @@ class PositionManager: if position_info['side'] == 'BUY': new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity new_stop_loss = max(new_stop_loss, self._breakeven_stop_price(entry_price, 'BUY')) - if new_stop_loss > position_info['stopLoss']: + current_sl_buy = position_info.get('stopLoss') + if current_sl_buy is None or new_stop_loss > current_sl_buy: position_info['stopLoss'] = new_stop_loss logger.info( f"[账号{self.account_id}] {symbol} [实时监控] 移动止损更新: {new_stop_loss:.4f} " @@ -4465,13 +4484,15 @@ class PositionManager: f"[账号{self.account_id}] {symbol} [实时监控] 同步移动止损至交易所失败: {type(sync_e).__name__}: {sync_e}", exc_info=False, ) - else: # SELL - new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity - new_stop_loss = min(new_stop_loss, self._breakeven_stop_price(entry_price, 'SELL')) - if new_stop_loss > position_info['stopLoss'] and pnl_amount > 0: + else: # SELL 做空锁利:止损下移,锁住 protect_amount。(entry - stop)*q = protect → stop = entry - protect/q + new_stop_loss = entry_price - protect_amount / quantity + new_stop_loss = max(new_stop_loss, self._breakeven_stop_price(entry_price, 'SELL')) + current_sl = position_info.get('stopLoss') + # 仅当新止损低于当前止损(下移锁利)且高于市价时更新 + if (current_sl is None or new_stop_loss < current_sl) and new_stop_loss > current_price_float and pnl_amount > 0: position_info['stopLoss'] = new_stop_loss logger.info( - f"[账号{self.account_id}] {symbol} [实时监控] 移动止损更新: {new_stop_loss:.4f} " + f"[账号{self.account_id}] {symbol} [实时监控] 移动止损更新(做空锁利): {new_stop_loss:.4f} " f"(保护{trailing_protect*100:.1f}% of margin = {protect_amount:.4f} USDT)" ) _log_trailing_stop_event(self.account_id, symbol, "trailing_update", new_stop_loss=new_stop_loss, source="实时监控")