166 lines
6.7 KiB
Python
166 lines
6.7 KiB
Python
from .base_sync import BaseSync
|
|
from loguru import logger
|
|
from typing import List, Dict
|
|
import json
|
|
import time
|
|
from datetime import datetime, timedelta
|
|
|
|
class OrderSync(BaseSync):
|
|
"""订单数据同步器"""
|
|
|
|
async def sync(self):
|
|
"""同步订单数据"""
|
|
try:
|
|
# 获取所有账号
|
|
accounts = self.get_accounts_from_redis()
|
|
|
|
for k_id_str, account_info in accounts.items():
|
|
try:
|
|
k_id = int(k_id_str)
|
|
st_id = account_info.get('st_id', 0)
|
|
exchange_id = account_info['exchange_id']
|
|
|
|
if k_id <= 0 or st_id <= 0:
|
|
continue
|
|
|
|
# 从Redis获取最近N天的订单数据
|
|
orders = await self._get_recent_orders_from_redis(k_id, exchange_id)
|
|
|
|
# 同步到数据库
|
|
if orders:
|
|
success = self._sync_orders_to_db(k_id, st_id, orders)
|
|
if success:
|
|
logger.debug(f"订单同步成功: k_id={k_id}, 订单数={len(orders)}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"同步账号 {k_id_str} 订单失败: {e}")
|
|
continue
|
|
|
|
logger.info("订单数据同步完成")
|
|
|
|
except Exception as e:
|
|
logger.error(f"订单同步失败: {e}")
|
|
|
|
async def _get_recent_orders_from_redis(self, k_id: int, exchange_id: str) -> List[Dict]:
|
|
"""从Redis获取最近N天的订单数据"""
|
|
try:
|
|
redis_key = f"{exchange_id}:orders:{k_id}"
|
|
|
|
# 计算最近N天的日期
|
|
from config.settings import SYNC_CONFIG
|
|
recent_days = SYNC_CONFIG['recent_days']
|
|
|
|
today = datetime.now()
|
|
recent_dates = []
|
|
for i in range(recent_days):
|
|
date = today - timedelta(days=i)
|
|
date_format = date.strftime('%Y-%m-%d')
|
|
recent_dates.append(date_format)
|
|
|
|
# 获取所有key
|
|
all_keys = self.redis_client.client.hkeys(redis_key)
|
|
|
|
orders_list = []
|
|
for key in all_keys:
|
|
key_str = key.decode('utf-8') if isinstance(key, bytes) else key
|
|
|
|
if key_str == 'positions':
|
|
continue
|
|
|
|
# 检查是否以最近N天的日期开头
|
|
for date_format in recent_dates:
|
|
if key_str.startswith(date_format + '_'):
|
|
try:
|
|
order_json = self.redis_client.client.hget(redis_key, key_str)
|
|
if order_json:
|
|
order = json.loads(order_json)
|
|
|
|
# 验证时间
|
|
order_time = order.get('time', 0)
|
|
if order_time >= int(time.time()) - recent_days * 24 * 3600:
|
|
orders_list.append(order)
|
|
|
|
break
|
|
except:
|
|
break
|
|
|
|
return orders_list
|
|
|
|
except Exception as e:
|
|
logger.error(f"获取Redis订单数据失败: k_id={k_id}, error={e}")
|
|
return []
|
|
|
|
def _sync_orders_to_db(self, k_id: int, st_id: int, orders_data: List[Dict]) -> bool:
|
|
"""同步订单数据到数据库"""
|
|
session = self.db_manager.get_session()
|
|
try:
|
|
# 准备批量数据
|
|
insert_data = []
|
|
for order_data in orders_data:
|
|
try:
|
|
order_dict = self._convert_order_data(order_data)
|
|
|
|
# 检查完整性
|
|
required_fields = ['order_id', 'symbol', 'side', 'time']
|
|
if not all(order_dict.get(field) for field in required_fields):
|
|
continue
|
|
|
|
insert_data.append(order_dict)
|
|
|
|
except Exception as e:
|
|
logger.error(f"转换订单数据失败: {order_data}, error={e}")
|
|
continue
|
|
|
|
if not insert_data:
|
|
return True
|
|
|
|
with session.begin():
|
|
# 使用参数化批量插入
|
|
sql = """
|
|
INSERT INTO deh_strategy_order_new
|
|
(st_id, k_id, asset, order_id, symbol, side, price, time,
|
|
order_qty, last_qty, avg_price, exchange_id)
|
|
VALUES
|
|
(:st_id, :k_id, :asset, :order_id, :symbol, :side, :price, :time,
|
|
:order_qty, :last_qty, :avg_price, :exchange_id)
|
|
ON DUPLICATE KEY UPDATE
|
|
side = VALUES(side),
|
|
price = VALUES(price),
|
|
time = VALUES(time),
|
|
order_qty = VALUES(order_qty),
|
|
last_qty = VALUES(last_qty),
|
|
avg_price = VALUES(avg_price)
|
|
"""
|
|
|
|
# 分块执行
|
|
from config.settings import SYNC_CONFIG
|
|
chunk_size = SYNC_CONFIG['chunk_size']
|
|
|
|
for i in range(0, len(insert_data), chunk_size):
|
|
chunk = insert_data[i:i + chunk_size]
|
|
session.execute(text(sql), chunk)
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
logger.error(f"同步订单到数据库失败: k_id={k_id}, error={e}")
|
|
return False
|
|
finally:
|
|
session.close()
|
|
|
|
def _convert_order_data(self, data: Dict) -> Dict:
|
|
"""转换订单数据格式"""
|
|
return {
|
|
'st_id': int(data.get('st_id', 0)),
|
|
'k_id': int(data.get('k_id', 0)),
|
|
'asset': 'USDT',
|
|
'order_id': str(data.get('order_id', '')),
|
|
'symbol': data.get('symbol', ''),
|
|
'side': data.get('side', ''),
|
|
'price': float(data.get('price', 0)) if data.get('price') is not None else None,
|
|
'time': int(data.get('time', 0)) if data.get('time') is not None else None,
|
|
'order_qty': float(data.get('order_qty', 0)) if data.get('order_qty') is not None else None,
|
|
'last_qty': float(data.get('last_qty', 0)) if data.get('last_qty') is not None else None,
|
|
'avg_price': float(data.get('avg_price', 0)) if data.get('avg_price') is not None else None,
|
|
'exchange_id': None # 忽略该字段
|
|
} |