diff --git a/backend/api/routes/account.py b/backend/api/routes/account.py index 40e4529..ccde550 100644 --- a/backend/api/routes/account.py +++ b/backend/api/routes/account.py @@ -1629,8 +1629,8 @@ async def sync_positions(account_id: int = Depends(get_account_id)): except Exception: latest_close_order = None - # 获取该交易对的所有open记录 - open_trades = Trade.get_by_symbol(symbol, status='open') + # 获取该交易对的 open 记录(仅当前账号,避免误更新其他账号) + open_trades = Trade.get_by_symbol(symbol, status='open', account_id=account_id) for trade in open_trades: trade_id = trade['id'] diff --git a/trading_system/binance_client.py b/trading_system/binance_client.py index d0d1ae3..b753dcc 100644 --- a/trading_system/binance_client.py +++ b/trading_system/binance_client.py @@ -759,18 +759,25 @@ class BinanceClient: try: # 增加 recvWindow 以避免 -1021 错误 positions = await self.client.futures_position_information(recvWindow=20000) - open_positions = [ - { + # 只保留真实持仓:非零且名义价值 >= 1 USDT,避免灰尘持仓被当成“有仓”导致同步时批量创建假 manual_entry + min_notional = 1.0 + open_positions = [] + for pos in positions: + amt = float(pos['positionAmt']) + if amt == 0: + continue + entry_price = float(pos['entryPrice']) + notional = abs(amt) * entry_price + if notional < min_notional: + continue + open_positions.append({ 'symbol': pos['symbol'], - 'positionAmt': float(pos['positionAmt']), - 'entryPrice': float(pos['entryPrice']), + 'positionAmt': amt, + 'entryPrice': entry_price, 'markPrice': float(pos.get('markPrice', 0)), 'unRealizedProfit': float(pos['unRealizedProfit']), 'leverage': int(pos['leverage']) - } - for pos in positions - if float(pos['positionAmt']) != 0 - ] + }) return open_positions except (asyncio.TimeoutError, BinanceAPIException) as e: last_error = e diff --git a/trading_system/position_manager.py b/trading_system/position_manager.py index cf7a7a6..c88012e 100644 --- a/trading_system/position_manager.py +++ b/trading_system/position_manager.py @@ -2799,12 +2799,15 @@ class PositionManager: quantity = abs(position_amt) side = 'BUY' if position_amt > 0 else 'SELL' + notional = (float(entry_price) * float(quantity)) if entry_price and quantity else 0 + if notional < 1.0: + logger.debug(f"{symbol} [状态同步] 跳过灰尘持仓 (名义 {notional:.4f} USDT < 1),不创建记录") + continue logger.info( f"{symbol} [状态同步] 检测到手动开仓,创建数据库记录... " f"({side} {quantity:.4f} @ {entry_price:.4f})" ) - - # 创建数据库记录 + # 创建数据库记录(显式传入 account_id,避免多账号混用) trade_id = Trade.create( symbol=symbol, side=side, @@ -2812,9 +2815,9 @@ class PositionManager: entry_price=entry_price, leverage=binance_position.get('leverage', 10), entry_reason='manual_entry', # 标记为手动开仓 - # 手动开仓无法拿到策略侧ATR/分步止盈,这里尽量补齐“规模字段” - notional_usdt=(float(entry_price) * float(quantity)) if entry_price and quantity else None, - margin_usdt=((float(entry_price) * float(quantity)) / float(binance_position.get('leverage', 10))) if entry_price and quantity and float(binance_position.get('leverage', 10) or 0) > 0 else None, + notional_usdt=notional, + margin_usdt=(notional / float(binance_position.get('leverage', 10) or 10)) if float(binance_position.get('leverage', 10) or 0) > 0 else None, + account_id=self.account_id, ) logger.info(f"{symbol} [状态同步] ✓ 数据库记录已创建 (ID: {trade_id})")