This commit is contained in:
薇薇安 2026-01-20 10:28:04 +08:00
parent 8d5ea39bd4
commit d23ed2252c

View File

@ -72,6 +72,9 @@ class PositionManager:
self._monitoring_enabled = True # 是否启用实时监控 self._monitoring_enabled = True # 是否启用实时监控
self._pending_entry_orders: Dict[str, Dict] = {} # 未成交的入场订单(避免重复挂单) self._pending_entry_orders: Dict[str, Dict] = {} # 未成交的入场订单(避免重复挂单)
self._last_entry_attempt_ms: Dict[str, int] = {} # 每个symbol的最近一次尝试冷却/去抖) self._last_entry_attempt_ms: Dict[str, int] = {} # 每个symbol的最近一次尝试冷却/去抖)
# 自动平仓去抖/限流(避免止损触发后反复下单/刷屏)
self._last_auto_close_attempt_ms: Dict[str, int] = {}
self._last_auto_close_fail_log_ms: Dict[str, int] = {}
@staticmethod @staticmethod
def _pct_like_to_ratio(v: float) -> float: def _pct_like_to_ratio(v: float) -> float:
@ -2456,6 +2459,20 @@ class PositionManager:
# 如果触发止损止盈,执行平仓 # 如果触发止损止盈,执行平仓
if should_close: if should_close:
# 自动平仓限流:避免同一 symbol 短时间内反复触发平仓请求WebSocket 高频推送下很常见)
try:
now_ms = int(time.time() * 1000)
except Exception:
now_ms = None
if now_ms is not None:
cooldown_sec = int(config.TRADING_CONFIG.get("AUTO_CLOSE_COOLDOWN_SEC", 20) or 0)
last_ms = self._last_auto_close_attempt_ms.get(symbol)
if last_ms and cooldown_sec > 0 and now_ms - last_ms < cooldown_sec * 1000:
# 不重复刷屏:仅 debug
logger.debug(f"{symbol} [自动平仓] 冷却中({cooldown_sec}s跳过重复平仓尝试")
return
self._last_auto_close_attempt_ms[symbol] = now_ms
logger.info( logger.info(
f"{symbol} [自动平仓] 开始执行平仓操作 | " f"{symbol} [自动平仓] 开始执行平仓操作 | "
f"原因: {exit_reason} | " f"原因: {exit_reason} | "
@ -2478,7 +2495,37 @@ class PositionManager:
except Exception as sync_error: except Exception as sync_error:
logger.warning(f"{symbol} [自动平仓] 状态同步失败: {sync_error}") logger.warning(f"{symbol} [自动平仓] 状态同步失败: {sync_error}")
else: else:
logger.error(f"{symbol} [自动平仓] ❌ 平仓失败") # 平仓失败:先二次核对币安是否已无仓位(常见于竞态/网络抖动/幂等场景)
live_amt = None
try:
live_amt = await self._get_live_position_amt(symbol, position_side=None)
except Exception:
live_amt = None
if live_amt is not None and abs(live_amt) <= 0:
logger.warning(f"{symbol} [自动平仓] 平仓返回失败但币安持仓已为0按已平仓处理避免误报")
# 尝试同步一次让DB与界面尽快一致失败也不刷屏
try:
await self.sync_positions_with_binance()
except Exception:
pass
return
# 仍有仓位:减少刷屏(按时间窗口合并/限流)
should_log = True
if now_ms is not None:
log_cd = int(config.TRADING_CONFIG.get("AUTO_CLOSE_FAIL_LOG_COOLDOWN_SEC", 600) or 0)
last_log = self._last_auto_close_fail_log_ms.get(symbol)
if last_log and log_cd > 0 and now_ms - last_log < log_cd * 1000:
should_log = False
else:
self._last_auto_close_fail_log_ms[symbol] = now_ms
if should_log:
logger.error(f"{symbol} [自动平仓] ❌ 平仓失败(币安持仓仍存在: {live_amt}")
else:
logger.warning(f"{symbol} [自动平仓] 平仓仍失败(已在短时间内记录,暂不重复输出)")
# 即使平仓失败,也尝试同步状态(可能币安已经平仓了) # 即使平仓失败,也尝试同步状态(可能币安已经平仓了)
try: try:
await self.sync_positions_with_binance() await self.sync_positions_with_binance()