auto_trade_sys/trading_system/pending_reconcile.py
薇薇安 e4e6e64608 feat(trade, binance_client, position_manager, user_data_stream): 增强待处理记录对账逻辑
在 `models.py` 中新增 `get_pending_recent` 方法,用于获取最近的待处理交易记录。`binance_client.py` 中添加 `get_order_by_client_order_id` 方法,以支持按 `client_order_id` 查询订单。`position_manager.py` 中实现 `_reconcile_pending_with_binance` 方法,增强对待处理记录的对账能力。`user_data_stream.py` 中在重连前执行待处理记录对账,确保系统在断线期间的交易状态得到及时更新。这些改进提升了系统的稳定性与交易记录的准确性。
2026-02-21 11:09:01 +08:00

86 lines
3.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
正向流程加固pending 对账模块
供 sync_positions_with_binance 和 UserDataStream 重连后调用,补齐因 WS 断线/进程重启漏掉的 pending→open。
"""
import logging
logger = logging.getLogger(__name__)
DB_AVAILABLE = False
Trade = None
try:
import sys
from pathlib import Path
project_root = Path(__file__).parent.parent
backend_path = project_root / "backend"
if backend_path.exists():
sys.path.insert(0, str(backend_path))
from database.models import Trade
DB_AVAILABLE = True
except Exception:
pass
async def reconcile_pending_with_binance(client, account_id: int, limit: int = 50, max_age_sec: int = 86400) -> int:
"""
对 status=pending 记录查币安订单,若已 FILLED 则更新为 open。
返回成功对账数量。
"""
if not DB_AVAILABLE or not Trade:
return 0
try:
pending_list = Trade.get_pending_recent(account_id, limit=limit, max_age_sec=max_age_sec)
if not pending_list:
return 0
reconciled = 0
for row in pending_list:
try:
symbol = (row.get("symbol") or "").strip()
client_order_id = (row.get("client_order_id") or "").strip() or None
entry_order_id = row.get("entry_order_id")
if not symbol:
continue
order_info = None
if client_order_id and hasattr(client, "get_order_by_client_order_id"):
order_info = await client.get_order_by_client_order_id(symbol, client_order_id)
if not order_info and entry_order_id:
try:
oid = int(entry_order_id)
order_info = await client.client.futures_get_order(
symbol=symbol, orderId=oid, recvWindow=20000
)
except Exception:
pass
if not order_info or str(order_info.get("status")).upper() != "FILLED":
continue
ap = order_info.get("avgPrice") or order_info.get("price") or 0
z = order_info.get("executedQty") or 0
try:
ap_f = float(ap)
z_f = float(z)
except (TypeError, ValueError):
continue
if ap_f <= 0 or z_f <= 0:
continue
order_id = order_info.get("orderId")
if client_order_id:
ok = Trade.update_pending_to_filled(
client_order_id, account_id, order_id, ap_f, z_f
)
else:
ok = Trade.update_pending_by_entry_order_id(
symbol, account_id, order_id, ap_f, z_f
)
if ok:
reconciled += 1
logger.info(
f"[账号{account_id}] pending 对账: {symbol} client_order_id={client_order_id!r} "
f"已完善为 open (orderId={order_id} 成交价={ap_f:.4f} 数量={z_f:.4f})"
)
except Exception as e:
logger.debug(f"[账号{account_id}] pending 对账单条失败: {e}")
return reconciled
except Exception as e:
logger.debug(f"[账号{account_id}] pending 对账失败: {e}")
return 0