This commit is contained in:
薇薇安 2026-02-15 00:08:12 +08:00
parent d985b94161
commit 99df066101
2 changed files with 26 additions and 1 deletions

View File

@ -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。

View File

@ -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(