feat(trades): 优化从币安同步历史订单的逻辑
更新 `sync_trades_from_binance` 接口,新增 `account_id` 参数以支持多账户同步。改进了订单同步逻辑,仅对数据库中有记录的交易对进行拉取,避免全市场请求,提升效率。同时,增强了异常处理和日志记录,确保同步过程的稳定性和可追溯性。
This commit is contained in:
parent
c6126a42c9
commit
ec5c76c546
|
|
@ -391,13 +391,13 @@ async def get_trade_stats(
|
|||
|
||||
@router.post("/sync-binance")
|
||||
async def sync_trades_from_binance(
|
||||
days: int = Query(7, ge=1, le=30, description="同步最近N天的订单")
|
||||
account_id: int = Depends(get_account_id),
|
||||
days: int = Query(7, ge=1, le=30, description="同步最近N天的订单"),
|
||||
):
|
||||
"""
|
||||
从币安同步历史订单,确保数据库与币安一致
|
||||
|
||||
Args:
|
||||
days: 同步最近N天的订单(默认7天)
|
||||
从币安同步历史订单,补全 DB 中缺失的 exit_order_id / 平仓信息。
|
||||
**WS 已接入后**:开仓/平仓订单号主要由 User Data Stream 回写,此接口仅作**冷启动或补漏**,建议降低调用频率。
|
||||
仅对「DB 中近期有记录的 symbol」拉取订单,避免全市场逐 symbol 请求。
|
||||
"""
|
||||
try:
|
||||
logger.info(f"开始从币安同步历史订单(最近{days}天)...")
|
||||
|
|
@ -416,7 +416,45 @@ async def sync_trades_from_binance(
|
|||
|
||||
from binance_client import BinanceClient
|
||||
import config
|
||||
|
||||
from database.models import DEFAULT_ACCOUNT_ID
|
||||
|
||||
# 计算时间范围(秒,供 DB 查询)
|
||||
end_time_ms = int(time.time() * 1000)
|
||||
start_time_ms = int((datetime.now() - timedelta(days=days)).timestamp() * 1000)
|
||||
start_ts_sec = start_time_ms // 1000
|
||||
end_ts_sec = end_time_ms // 1000
|
||||
|
||||
# 仅对 DB 中在时间范围内有 open/closed 记录的 symbol 拉取订单(WS 已回写订单号,大幅减少请求)
|
||||
symbol_list = []
|
||||
try:
|
||||
trades_in_range = Trade.get_all(
|
||||
start_timestamp=start_ts_sec,
|
||||
end_timestamp=end_ts_sec,
|
||||
account_id=account_id or DEFAULT_ACCOUNT_ID,
|
||||
)
|
||||
symbol_list = list({t.get("symbol") for t in (trades_in_range or []) if t.get("symbol")})
|
||||
except Exception as e:
|
||||
logger.warning(f"从 DB 获取 symbol 列表失败,将跳过同步: {e}")
|
||||
return {
|
||||
"success": True,
|
||||
"message": "未获取到需同步的交易对,跳过(WS 正常时订单号已由推送回写)",
|
||||
"total_orders": 0,
|
||||
"updated_trades": 0,
|
||||
"close_orders": 0,
|
||||
"open_orders": 0,
|
||||
}
|
||||
|
||||
if not symbol_list:
|
||||
logger.info("DB 内在时间范围内无交易记录,跳过全量拉取订单(WS 为主时无需频繁同步)")
|
||||
return {
|
||||
"success": True,
|
||||
"message": "近期无交易记录,未请求币安订单;WS 正常时订单号已由推送回写",
|
||||
"total_orders": 0,
|
||||
"updated_trades": 0,
|
||||
"close_orders": 0,
|
||||
"open_orders": 0,
|
||||
}
|
||||
|
||||
# 初始化客户端
|
||||
client = BinanceClient(
|
||||
api_key=config.BINANCE_API_KEY,
|
||||
|
|
@ -427,42 +465,23 @@ async def sync_trades_from_binance(
|
|||
await client.connect()
|
||||
|
||||
try:
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# 计算时间范围
|
||||
end_time = int(time.time() * 1000) # 当前时间(毫秒)
|
||||
start_time = int((datetime.now() - timedelta(days=days)).timestamp() * 1000)
|
||||
|
||||
# 获取所有已成交的订单(包括开仓和平仓)
|
||||
# 仅对上述 symbol 拉取订单
|
||||
all_orders = []
|
||||
try:
|
||||
# 获取所有交易对的订单
|
||||
# 注意:币安API可能需要分交易对查询,这里先获取所有交易对
|
||||
symbols = await client.client.futures_exchange_info()
|
||||
symbol_list = [s['symbol'] for s in symbols.get('symbols', []) if s.get('contractType') == 'PERPETUAL']
|
||||
|
||||
logger.info(f"开始同步 {len(symbol_list)} 个交易对的订单...")
|
||||
|
||||
logger.info(f"仅对 {len(symbol_list)} 个有 DB 记录的 symbol 拉取订单(已跳过全市场请求)")
|
||||
for symbol in symbol_list:
|
||||
try:
|
||||
# 获取该交易对的历史订单
|
||||
orders = await client.client.futures_get_all_orders(
|
||||
symbol=symbol,
|
||||
startTime=start_time,
|
||||
endTime=end_time
|
||||
startTime=start_time_ms,
|
||||
endTime=end_time_ms
|
||||
)
|
||||
|
||||
# 只保留已成交的订单
|
||||
filled_orders = [o for o in orders if o.get('status') == 'FILLED']
|
||||
all_orders.extend(filled_orders)
|
||||
|
||||
# 避免请求过快
|
||||
await asyncio.sleep(0.1)
|
||||
except Exception as e:
|
||||
logger.debug(f"获取 {symbol} 订单失败: {e}")
|
||||
continue
|
||||
|
||||
logger.info(f"从币安获取到 {len(all_orders)} 个已成交订单")
|
||||
except Exception as e:
|
||||
logger.error(f"获取币安订单失败: {e}")
|
||||
|
|
@ -504,8 +523,8 @@ async def sync_trades_from_binance(
|
|||
logger.debug(f"订单 {order_id} 已同步过且 exit_reason={existing_trade.get('exit_reason')},跳过")
|
||||
continue
|
||||
|
||||
# 查找数据库中该交易对的open状态记录(仅当前账号)
|
||||
open_trades = Trade.get_by_symbol(symbol, status='open', account_id=None)
|
||||
# 查找数据库中该交易对的 open 状态记录(仅当前账号)
|
||||
open_trades = Trade.get_by_symbol(symbol, status='open', account_id=account_id or DEFAULT_ACCOUNT_ID)
|
||||
if existing_trade or open_trades:
|
||||
# 找到匹配的交易记录(通过symbol匹配,如果有多个则取最近的)
|
||||
trade = existing_trade or open_trades[0] # 取第一个
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user