auto_trade_sys/docs/正向流程漏洞分析与加固方案.md
薇薇安 e4e6e64608 feat(trade, binance_client, position_manager, user_data_stream): 增强待处理记录对账逻辑
在 `models.py` 中新增 `get_pending_recent` 方法,用于获取最近的待处理交易记录。`binance_client.py` 中添加 `get_order_by_client_order_id` 方法,以支持按 `client_order_id` 查询订单。`position_manager.py` 中实现 `_reconcile_pending_with_binance` 方法,增强对待处理记录的对账能力。`user_data_stream.py` 中在重连前执行待处理记录对账,确保系统在断线期间的交易状态得到及时更新。这些改进提升了系统的稳定性与交易记录的准确性。
2026-02-21 11:09:01 +08:00

6.6 KiB
Raw Permalink Blame History

正向流程漏洞分析与加固方案

目标弄清楚正常流程为什么会出现「币安有持仓、DB 无 open 记录」,并完善正向流程,使正常流程掌控全局。

一、正常流程梳理

1.1 开仓链路(简化)

strategy.open_position()
  → 创建 pending 记录 (DB, client_order_id)
  → place_order 下单币安
  → _wait_for_order_filled() REST 轮询
     → 若 FILLEDupdate_pending_to_filled()update_open_fields()
     → 若超时/CANCELED撤单返回 None

1.2 两条更新路径

路径 触发点 说明
REST 路径 open_position_wait_for_order_filled 返回 ok 进程存活、未超时
WS 路径 UserDataStream._on_order_trade_update 收到 ORDER_TRADE_UPDATE 需 listenKey 连接正常

正常情况下REST 和 WS 都会尝试更新;update_pending_to_filled 幂等,重复更新无害。


二、遗漏场景分析

2.1 进程崩溃 / 重启(最主要)

场景

  • 创建 pending下单币安进入 _wait_for_order_filled 轮询
  • 进程在轮询过程中崩溃OOM、kill、异常退出
  • 订单在币安成交
  • 重启后:
    • REST 路径不会再执行(open_position 已结束)
    • WS 不会重放历史推送,ORDER_TRADE_UPDATE 已丢失

结果pending 长期残留币安有持仓DB 无 open。

2.2 WS 断线期间成交

场景

  • listenKey 失效 / 网络抖动WS 断开
  • 在断开期间订单成交,未收到 ORDER_TRADE_UPDATE
  • REST 路径:若 open_position 仍在运行,轮询会拿到 FILLED可以更新若已超时返回则不会更新

结论只有在「WS 断线 + REST 已超时返回」时,才会出现漏记。open_position 中限价单超时后会撤单,一般不留下持仓;但若存在「撤单与成交」的竞态,仍可能漏记。

2.3 listenKey 失效

  • 60 分钟无 keepalive 会失效
  • 文档建议 24 小时主动重连
  • 失效期间新连接不会重放历史事件

效果同 2.2。

2.4 重连空窗期

  • 断线 → 60s 后重连 → 新 listenKey
  • 空窗期内的成交事件永久丢失
  • 若该期间 REST 也未完成轮询(例如进程崩溃),则必然漏记

2.5 update_pending_to_filled 异常

  • Trade.update_pending_to_filled 抛异常,_on_order_trade_update 会 catch 并打日志pending 保持
  • REST 路径若在调用前崩溃,则完全依赖 WSWS 路径若异常,则完全依赖 REST
  • 任一路径失败且另一路径也失败,则漏记

2.6 竞态:撤单 vs 成交

  • 限价单超时,调用 cancel_order
  • 若撤单请求发出时订单刚好成交,撤单可能失败
  • 当前逻辑:超时则 return Nonepending 保留,不会执行 update_pending_to_filled
  • 结果pending 残留 + 币安已成交,属于漏记

三、当前 sync_positions_with_binance 的覆盖范围

情况 是否处理
DB open、币安无 更新 DB 为 closed
DB open、币安有 加载到 active_positions
币安有、DB 无 open 不处理(依赖 SYNC_RECOVER_MISSING_POSITIONS
DB pending、币安订单已 FILLED 不处理

当前同步逻辑不包含「pending 对账」:不会主动查币安订单状态,也不会把已成交的 pending 转为 open。


四、正向流程加固方案

4.1 思路

不依赖补建SYNC_RECOVER_MISSING_POSITIONS在正向流程中补齐「pending 对账」能力,使:

  • 有 pending 且有 client_order_id / entry_order_id 时,主动查币安订单状态
  • 若已 FILLED则执行 update_pending_to_filled,将 pending 转为 open

4.2 加固点 1WS 重连后 pending 对账(推荐)

位置user_data_stream.py_run_ws 重连成功后

逻辑

  • 重连成功后,查询当前账号下 status=pending 且有 client_order_id 的记录(可限制如 24h 内)
  • 对每条记录调用币安 RESTfutures_get_order(symbol, orderId) 或按 client_order_id 查
  • 若 status=FILLED调用 Trade.update_pending_to_filled

意义:补齐 WS 断线期间丢失的 ORDER_TRADE_UPDATE。

4.3 加固点 2sync_positions_with_binance 中增加 pending 对账(推荐)

位置position_manager.sync_positions_with_binance

逻辑

  • 在现有「DB open vs 币安持仓」同步之外,增加:
    • 查询 Trade.get_pending_recent(account_id, limit=50, max_age_sec=86400)(需在 models 中新增)
    • 对每条 pending若存在 client_order_id 或 entry_order_id查币安订单
    • 若 FILLEDupdate_pending_to_filledupdate_pending_by_entry_order_id

意义周期性兜底覆盖进程重启、WS 漏推等场景。

4.4 加固点 3撤单后校验是否已成交可选

位置position_manager.open_position,在 cancel_order 之后

逻辑

  • 撤单后(或撤单异常时),再查一次订单状态
  • 若 status=FILLED则按 REST 路径正常执行 update_pending_to_filled,避免竞态漏记

意义:消除「撤单与成交」竞态导致的漏记。

4.5 加固点 4update_pending_to_filled robustness

  • 保持幂等(当前已满足)
  • 异常时记录清晰日志,便于排查
  • 可选:对瞬时 DB 异常做有限次重试

五、实现优先级建议

优先级 加固点 影响 复杂度
P0 sync_positions_with_binance 中 pending 对账 覆盖进程重启、WS 漏推等主要漏记
P0 WS 重连后 pending 对账 覆盖断线期间的漏推
P1 撤单后校验是否已成交 消除竞态漏记
P2 update_pending_to_filled 重试与日志 提升可靠性

六、需要的 DB / API 支持

  1. Trade 模型

    • get_pending_recent(account_id, limit, max_age_sec):返回指定时间范围内的 pending 记录,用于对账
  2. 币安 API

    • clientOrderId 查询:futures_get_all_orders(symbol, limit) 过滤,或使用支持 origClientOrderId 的接口(如有)
    • orderId 查询:futures_get_order(symbol, orderId)(已有)
  3. 多账号:以上逻辑需按 account_id 隔离,保证对账时使用对应账号的 client / API。


七、小结

  • 主要漏记来自:进程崩溃 + 订单已成交,以及 WS 断线期间的成交
  • 正向流程目前缺少「pending 对账」:不会主动用币安订单状态修正 pending。
  • 加固方向:在 WS 重连后sync_positions_with_binance 中加入 pending 对账,使正常流程在运行中即可发现并修正漏记,而不依赖单独的补建逻辑。