From 5c854290eb1dc4cf83aff4cf4ceb8fbba3824dae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Wed, 25 Feb 2026 14:58:13 +0800 Subject: [PATCH] =?UTF-8?q?feat(position=5Fmanager):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=8C=81=E4=BB=93=E8=8E=B7=E5=8F=96=E9=80=BB=E8=BE=91=E4=BB=A5?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A4=9A=E8=B4=A6=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在持仓管理中,更新了 `_get_open_positions` 方法,增加了 `force_rest` 参数以支持强制从 REST 获取持仓数据,确保在多账号情况下能够正确读取对应的缓存。同时,增强了异常处理逻辑,确保在拉取持仓失败时记录调试信息。这一改动旨在提升系统的稳定性与用户友好性,确保持仓数据的准确性与一致性。 --- trading_system/position_manager.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index 19e667a..28a7056 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -144,12 +144,12 @@ class PositionManager: self._last_auto_close_attempt_ms: Dict[str, int] = {} self._last_auto_close_fail_log_ms: Dict[str, int] = {} - async def _get_open_positions(self) -> List[Dict]: - """优先使用 User Data Stream 持仓缓存(Redis),无缓存或未启动时走 REST。""" - if get_stream_instance() is not None: + async def _get_open_positions(self, force_rest: bool = False) -> List[Dict]: + """优先使用 User Data Stream 持仓缓存(Redis),无缓存或未启动时走 REST。多账号时必须传 account_id 读对应缓存。""" + if not force_rest and get_stream_instance() is not None: min_notional = float(getattr(config, "POSITION_MIN_NOTIONAL_USDT", 1.0) or 1.0) redis_cache = getattr(self.client, "redis_cache", None) - cached = await get_positions_from_cache(min_notional, redis_cache) + cached = await get_positions_from_cache(min_notional, redis_cache, account_id=self.account_id) if cached is not None: return cached return await self.client.get_open_positions() @@ -3552,9 +3552,19 @@ class PositionManager: return # 获取当前所有持仓(与 sync 一致:仅本系统关心的持仓会进 active_positions) + # 多账号时必须用 account_id 读缓存;若缓存返回数量少于本地记录则强制 REST 一次,避免误判「持仓已不存在」 positions = await self._get_open_positions() binance_symbols = {p['symbol'] for p in positions} active_symbols = set(self.active_positions.keys()) + if active_symbols and len(binance_symbols) < len(active_symbols): + try: + rest_positions = await self.client.get_open_positions() + if rest_positions and len(rest_positions) > len(positions): + positions = rest_positions + binance_symbols = {p['symbol'] for p in positions} + logger.info(f"[账号{self.account_id}] 缓存持仓数少于本地记录,已用 REST 拉取完整持仓: {len(binance_symbols)} 个") + except Exception as e: + logger.debug(f"[账号{self.account_id}] REST 拉取完整持仓失败: {e}") sync_create_manual = config.TRADING_CONFIG.get("SYNC_CREATE_MANUAL_ENTRY_RECORD", False) logger.info(f"[账号{self.account_id}] 币安持仓: {len(binance_symbols)} 个 ({', '.join(binance_symbols) if binance_symbols else '无'})")