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 # 忽略该字段 }