订单跟踪系统BUG31
订单跟踪系统严重 Bug 分析报告
审计范围:
websocket_order_manager.py、executor.py、position_manager.py、orchestrator.py、realtime_kline_service_base.py日期: 2026-02-22
Bug 1: 平仓冷却机制阻止止损执行(严重度:危急)
位置: position_manager.py:295-306
cooldown_until = self._close_cooldown.get(key)
if cooldown_until is not None:
if time.time() < cooldown_until:
return None # ← 止损也被拒绝
问题: close_position() 失败后会设置 30 秒冷却期(line 335, 645)。在此期间,所有 平仓请求都被拒绝——包括止损监控线程发起的紧急止损。
影响路径:
- 信号触发平仓 → 交易所 API 异常 → 设置 30s 冷却
- 在这 30s 内,市场剧烈波动触发止损
_close_with_retry调用close_position→ 被冷却拒绝 → 返回None- 重试 3 次(1s + 2s + 4s = 7s),全部在冷却期内 → 全部失败
- 止损监控放弃,等下一个监控周期(默认间隔 + 30s 冷却)
- 结果: 仓位在极端行情下暴露长达 30+ 秒无保护
修复建议: close_position 应区分冷却原因,对 force_market=True 的止损请求跳过冷却检查:
if cooldown_until is not None and not force_market:
...
Bug 2: 单 WebSocket 架构导致 Testnet 订单事件完全丢失(严重度:高)
位置: config.py:104 + enhanced_ws_manager.py:275 + realtime_kline_service_base.py:443-457
# config.py - WS 地址硬编码为主网
WS_URL = "wss://api.hyperliquid.xyz/ws"
# enhanced_ws_manager.py - 所有 WS 订阅都走这一个连接
self.ws_url = WS_URL # 永远是主网
# realtime_kline_service_base.py - 订单订阅也加到同一个 WS
subscriptions.extend([
{"type": "orderUpdates", "user": user_address},
{"type": "userFills", "user": user_address},
])
问题: 系统只有一个 WebSocket 连接(主网),但交易可能在测试网执行。当 TRADING_NETWORK=testnet 时:
- 订单通过测试网 HTTP API 提交
- 但
orderUpdates/userFills订阅在主网 WS 上 - 主网 WS 不会推送测试网的订单事件
影响:
- 所有限价单的 WS 实时追踪完全失效
_on_order_update和_on_user_fill永远不会被触发- 每笔限价单必须等待完整 timeout(默认 600s)+ HTTP 兜底
- 系统降级为纯 HTTP 轮询模式,延迟从毫秒级退化到秒级
- 虽然 docs 中有"双WebSocket架构设计"文档,但未实际实现
Bug 3: userFills 部分到达时的过早解析(严重度:中高)
位置: websocket_order_manager.py:416-421
# _on_user_fill 中
if tracking._ws_status is not None: # orderUpdates 已先到
should_resolve = True # ← 只收到1笔fill就立即resolve
resolve_tracking = tracking
问题: 一笔订单可能被分成多笔 partial fills。当 orderUpdates 的 "filled" 先到达后,第一笔 userFill 到达就触发立即解析。如果订单有 3 笔 partial fills,只有第 1 笔被计入加权均价。
竞态时序:
T=0: orderUpdates "filled" → _ws_status=FILLED, 启动5s grace timer
T=1: userFill #1 (200 PURR @ $0.01) → has_fill_price=True + _ws_status≠None → 立即resolve!
T=2: userFill #2 (300 PURR @ $0.012) → oid已从_tracking移除,丢弃
T=3: userFill #3 (500 PURR @ $0.011) → oid已从_tracking移除,丢弃
影响: avg_price 只反映第 1 笔 fill 的价格,而非全部 fills 的加权均价。
缓解因素: _verify_fill_completeness (executor.py:713) 会通过 HTTP 对比校验并修正。但:
- 如果 HTTP 查询失败,错误价格将被持久化
- 开仓时的
alt_entry_price可能不准确,影响后续 PnL 计算和止损判断
Bug 4: 幽灵仓位清理时 PnL 数据失真(严重度:中)
位置: position_manager.py:1159
# sync_with_exchange 中
ghost_pnl = pos.unrealized_pnl or 0.0 # ← 使用上一次sync的unrealizedPnl
pos.status = PositionStatus.CLOSED
问题: 当 sync_with_exchange 发现交易所已无某仓位(幽灵仓位),使用 pos.unrealized_pnl(上一个 sync 周期的值)作为 realized_pnl 写入 DB。
影响场景:
- 仓位被交易所强制平仓(清算/自动减仓)
- 上一次 sync 时 unrealizedPnl = -$5
- 实际清算价格导致 realized_pnl = -$50
- DB 记录的 PnL = -$5,严重失真
RiskManager.update_daily_pnl接收错误值 → 日亏损统计不准 → 风控决策基础数据错误
修复建议: 使用当前市场价格重新计算 PnL,或至少标记为"估算值":
mid = all_mids.get(coin, 0.0) if all_mids else 0.0
if mid > 0 and pos.alt_entry_price > 0:
ghost_pnl = (mid - pos.alt_entry_price) * pos.alt_size * (1 if pos.alt_side == "buy" else -1)
Bug 5: base 腿消失后的强制平仓与冷却冲突(严重度:中)
位置: position_manager.py:1255-1261
# sync_with_exchange 锁外处理
for lost_key in _base_lost_pairs:
close_result = self.close_position(
lost_symbol, lost_base, reason="base_leg_lost", force_market=True
)
问题: 与 Bug 1 相关。当 base 腿在交易所消失(对冲保护失效),系统尝试强制平仓 alt 腿。但如果该配对之前有平仓失败记录(处于 30s 冷却中),close_position 会因冷却而拒绝此紧急请求。
影响: alt 腿失去对冲保护后,在冷却期内无法被平仓,直到:
- 冷却到期(最长 30s)
- 或下一个 sync 周期再次检测到 base 缺失
叠加风险: 如果 base 腿被清算是因为剧烈波动,alt 腿在同样的波动中也可能亏损,但无法及时退出。
Bug 6: 平仓 DB 更新失败后的数据不一致窗口(严重度:中低)
位置: position_manager.py:605-629
try:
self._repo.update_position_status(...) # DB更新
self._repo.save_order(...)
except Exception as e:
logger.error(f"平仓 DB 更新失败: {position.position_id} | {e}")
问题: 平仓已在交易所执行成功,但 DB 更新失败。此时:
- 内存状态:已移除仓位(line 602:
self._positions.pop(key, None)) - 交易所:仓位已平
- DB:仓位仍为
OPEN
影响: 系统重启后 recover_positions_from_db 会从 DB 加载该仓位,发现交易所无持仓后标记为 CLOSED(幽灵清理)。但在重启前:
- 日 PnL 统计可能缺失这笔已平仓的收益/亏损
- 如果
save_order也失败,订单记录永久丢失
缓解因素: risk_manager.update_daily_pnl(realized_pnl) 在 DB 写入之后执行(line 632),且不受 DB 异常影响。重启后有自动修复机制。
总结风险矩阵
| Bug | 严重度 | 触发条件 | 影响范围 | 现有缓解 |
|---|---|---|---|---|
| #1 止损冷却冲突 | 危急 | 平仓失败+极端行情 | 资金损失 | 无 |
| #2 Testnet WS 失效 | 高 | TRADING_NETWORK=testnet | 性能严重退化 | HTTP 兜底 |
| #3 Fill 过早解析 | 中高 | 多笔 partial fills | 价格数据不准 | HTTP 校验 |
| #4 幽灵 PnL 失真 | 中 | 仓位被交易所清算 | 风控统计错误 | 无 |
| #5 Base 消失+冷却 | 中 | 对冲腿被清算+近期平仓失败 | 资金暴露 | 下个 sync 周期 |
| #6 DB 更新失败 | 中低 | 数据库异常 | 数据不一致 | 重启自动修复 |
优先修复顺序: Bug #1 > Bug #3 > Bug #4 > Bug #5 > Bug #2 > Bug #6