1
This commit is contained in:
parent
16cf4f2157
commit
a52b8c4738
|
|
@ -1750,17 +1750,66 @@ async def sync_positions(account_id: int = Depends(get_account_id)):
|
|||
else:
|
||||
logger.info("✓ 数据库与币安状态一致,无需更新")
|
||||
|
||||
# 4. 检查币安有但数据库没有记录的持仓
|
||||
# 4. 币安有仓但数据库无记录:从币安成交里取 orderId 并补建交易记录,便于在「订单记录」和统计中展示(含系统挂单/条件单)
|
||||
missing_in_db = binance_symbols - db_open_symbols
|
||||
recovered_count = 0
|
||||
if missing_in_db:
|
||||
logger.info(f"发现 {len(missing_in_db)} 个持仓在币安存在但数据库中没有记录: {', '.join(missing_in_db)}")
|
||||
logger.info(" 这些持仓可能是手动开仓的,建议手动处理")
|
||||
for symbol in missing_in_db:
|
||||
try:
|
||||
pos = next((p for p in binance_positions if p.get('symbol') == symbol), None)
|
||||
if not pos or float(pos.get('positionAmt', 0)) == 0:
|
||||
continue
|
||||
position_amt = float(pos['positionAmt'])
|
||||
quantity = abs(position_amt)
|
||||
side = 'BUY' if position_amt > 0 else 'SELL'
|
||||
entry_price = float(pos.get('entryPrice', 0))
|
||||
leverage = int(pos.get('leverage', 10)) or 10
|
||||
notional = quantity * entry_price
|
||||
if notional < 1.0:
|
||||
continue
|
||||
entry_order_id = None
|
||||
try:
|
||||
trades = await client.get_recent_trades(symbol, limit=30)
|
||||
if trades:
|
||||
same_side = [t for t in trades if str(t.get('side', '')).upper() == side]
|
||||
if same_side:
|
||||
same_side.sort(key=lambda x: int(x.get('time', 0)), reverse=True)
|
||||
entry_order_id = same_side[0].get('orderId')
|
||||
except Exception as e:
|
||||
logger.debug(f"获取 {symbol} 成交记录失败: {e}")
|
||||
if entry_order_id and hasattr(Trade, 'get_by_entry_order_id'):
|
||||
try:
|
||||
existing = Trade.get_by_entry_order_id(entry_order_id)
|
||||
if existing:
|
||||
continue
|
||||
except Exception:
|
||||
pass
|
||||
trade_id = Trade.create(
|
||||
symbol=symbol,
|
||||
side=side,
|
||||
quantity=quantity,
|
||||
entry_price=entry_price,
|
||||
leverage=leverage,
|
||||
entry_reason='sync_recovered',
|
||||
entry_order_id=entry_order_id,
|
||||
notional_usdt=notional,
|
||||
margin_usdt=(notional / leverage) if leverage > 0 else None,
|
||||
account_id=account_id,
|
||||
)
|
||||
recovered_count += 1
|
||||
logger.info(f" ✓ {symbol} 已补建交易记录 (ID: {trade_id}, orderId: {entry_order_id or '-'})")
|
||||
except Exception as e:
|
||||
logger.warning(f" ✗ {symbol} 补建记录失败: {e}")
|
||||
if recovered_count > 0:
|
||||
logger.info(f"共补建 {recovered_count} 条交易记录,将在订单记录与统计中展示")
|
||||
|
||||
result = {
|
||||
"message": "持仓状态同步完成",
|
||||
"binance_positions": len(binance_symbols),
|
||||
"db_open_positions": len(db_open_symbols),
|
||||
"updated_to_closed": updated_count,
|
||||
"recovered_count": recovered_count,
|
||||
"missing_in_binance": list(missing_in_binance),
|
||||
"missing_in_db": list(missing_in_db)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,7 +234,10 @@ const StatsDashboard = () => {
|
|||
if (result.updated_to_closed > 0) {
|
||||
message += `,已更新 ${result.updated_to_closed} 条记录为已平仓`
|
||||
}
|
||||
if (result.missing_in_db && result.missing_in_db.length > 0) {
|
||||
if (result.recovered_count > 0) {
|
||||
message += `,已为 ${result.recovered_count} 个持仓补建交易记录(将出现在订单记录与统计中)`
|
||||
}
|
||||
if (result.missing_in_db && result.missing_in_db.length > 0 && (result.recovered_count || 0) === 0) {
|
||||
message += `,发现 ${result.missing_in_db.length} 个币安持仓在数据库中没有记录`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2818,6 +2818,17 @@ class PositionManager:
|
|||
f"{symbol} [状态同步] 检测到手动开仓,创建数据库记录... "
|
||||
f"({side} {quantity:.4f} @ {entry_price:.4f})"
|
||||
)
|
||||
# 尽量从币安成交取 entry_order_id,便于订单记录/统计对账
|
||||
entry_order_id = None
|
||||
try:
|
||||
recent = await self.client.get_recent_trades(symbol, limit=30)
|
||||
if recent:
|
||||
same_side = [t for t in recent if str(t.get('side', '')).upper() == side]
|
||||
if same_side:
|
||||
same_side.sort(key=lambda x: int(x.get('time', 0)), reverse=True)
|
||||
entry_order_id = same_side[0].get('orderId')
|
||||
except Exception:
|
||||
pass
|
||||
# 创建数据库记录(显式传入 account_id,避免多账号混用)
|
||||
trade_id = Trade.create(
|
||||
symbol=symbol,
|
||||
|
|
@ -2826,6 +2837,7 @@ class PositionManager:
|
|||
entry_price=entry_price,
|
||||
leverage=binance_position.get('leverage', 10),
|
||||
entry_reason='manual_entry', # 标记为手动开仓
|
||||
entry_order_id=entry_order_id,
|
||||
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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user