diff --git a/docs/订单与统计一致性说明.md b/docs/订单与统计一致性说明.md index 825e50d..6f0ec7c 100644 --- a/docs/订单与统计一致性说明.md +++ b/docs/订单与统计一致性说明.md @@ -58,3 +58,28 @@ - **订单记录与币安可对账**:可以,`entry_order_id` / `exit_order_id` 与防重复逻辑已保证一一对应、不重复。 - **统计准确性**:在「同一笔平仓只被记录一次」和「按净盈亏汇总」上已保证;**手续费与实际盈亏**已在所有关仓路径补全: - 系统/仪表板平仓、持仓同步、订单同步 均会按 `exit_order_id` 拉取成交并写入 commission/realized_pnl,统计与币安对齐。 + +--- + +## 四、下单路径与「意外订单」排查 + +### 1. 会向币安下单的入口(汇总) + +| 类型 | 入口 | 触发条件 | 是否可能「意外」开仓 | +|------|------|----------|----------------------| +| **开仓** | `trading_system/position_manager.open_position` | 仅由策略在「通过风控 + 有信号」后调用;`risk_manager.should_trade` 会检查:持仓数 ≥ MAX_OPEN_POSITIONS 则 return False,且检查该 symbol 是否已有持仓 | 否。持仓数/已有仓检查均基于币安 `get_open_positions()`,到上限或已有该 symbol 即跳过,不会下单。 | +| **开仓** | `backend/api/routes/account.py` 限价下单接口 | 用户在前端/API 主动发起的「手动限价开仓」 | 否,需显式调用。 | +| **平仓** | `position_manager.close_position` | 仅对 `active_positions` 中存在的 symbol 调用(止损/止盈/手动);`check_stop_loss_take_profit` 只遍历 `active_positions` | 否,只平我们监控的仓。 | +| **平仓** | backend 平仓/一键平仓 | 用户主动平仓 | 否,需显式调用。 | +| **止盈/止损单** | `position_manager._ensure_exchange_sltp_orders` | 仅在两处调用:(1) 开仓成功后为该 symbol 挂 SL/TP;(2) 补建「仅币安有、DB 无」的持仓时,若开启 SYNC_CREATE_MANUAL_ENTRY_RECORD,为补建记录补挂 SL/TP。挂前会先取消该 symbol 下同类型 Algo 单(STOP_MARKET/TAKE_PROFIT_MARKET),再下新单 | 不会产生「开仓」;可能覆盖用户在该 symbol 上已有的同类型保护单(属预期:补建后统一用系统计算的 SL/TP)。 | + +结论:**没有逻辑会在「不该开仓」时自动下开仓单**;止盈/止损挂单仅对「我们已纳入监控的持仓」补挂或覆盖,不会对「仅币安有、且未补建」的持仓主动挂单(因未进 `active_positions` 不会走到 `_ensure_exchange_sltp_orders`)。 + +### 2. 日志里「总是想下一些单」是否正常? + +- **策略扫描日志**(如 `处理交易对: SIRENUSDT (UP 31.32%, 市场状态: ranging)`、`SIRENUSDT 4H趋势中性,信号质量可能降低`、`SIRENUSDT 持仓数量已达上限:16/16,跳过开仓`) + 表示:每轮扫描会**评估**各交易对并可能尝试开仓,但 **`持仓数量已达上限:16/16,跳过开仓` 时 `risk_manager.should_trade` 已 return False**,**不会调用 `open_position`,也不会向币安下任何单**。这是正常、预期行为。 +- **挂止盈/止损相关日志**(如「已挂币安保护单」「挂止盈单失败」等) + 表示:仅对 **当前已在 `active_positions` 中且具备 SL/TP 价格的持仓** 在交易所侧挂或更新保护单;每次挂前会先取消同类型旧单再挂新单,不会重复堆积同一 symbol 的多组 SL/TP。 + +若希望减少「想下单」类日志的干扰,可将「跳过开仓」类日志级别调低(如改为 debug),或仅在有实际下单时再打 info。 diff --git a/trading_system/risk_manager.py b/trading_system/risk_manager.py index c8b1030..6bcc917 100644 --- a/trading_system/risk_manager.py +++ b/trading_system/risk_manager.py @@ -792,7 +792,7 @@ class RiskManager: except Exception: max_open = 0 if max_open > 0 and len(positions) >= max_open: - logger.info(f"{symbol} 持仓数量已达上限:{len(positions)}/{max_open},跳过开仓") + logger.debug(f"{symbol} 持仓数量已达上限:{len(positions)}/{max_open},跳过开仓") return False existing_position = next(