from abc import ABC, abstractmethod from loguru import logger from typing import List, Dict, Any import json from utils.redis_client import RedisClient from utils.database_manager import DatabaseManager class BaseSync(ABC): """同步基类""" def __init__(self): self.redis_client = RedisClient() self.db_manager = DatabaseManager() self.computer_name = None # 从配置读取 @abstractmethod async def sync(self): """执行同步""" pass def get_accounts_from_redis(self) -> Dict[str, Dict]: """从Redis获取账号配置""" try: if self.computer_name is None: from config.settings import COMPUTER_NAME self.computer_name = COMPUTER_NAME # 从Redis获取数据 result = self.redis_client.client.hgetall(f"{self.computer_name}_strategy_api") if not result: logger.warning(f"未找到 {self.computer_name} 的策略API配置") return {} accounts_dict = {} for exchange_name, accounts_json in result.items(): try: accounts = json.loads(accounts_json) if not accounts: continue # 格式化交易所ID exchange_id = self.format_exchange_id(exchange_name) for account_id, account_info in accounts.items(): parsed_account = self.parse_account(exchange_id, account_id, account_info) if parsed_account: accounts_dict[account_id] = parsed_account except json.JSONDecodeError as e: logger.error(f"解析交易所 {exchange_name} 的JSON数据失败: {e}") continue return accounts_dict except Exception as e: logger.error(f"获取账户信息失败: {e}") return {} def format_exchange_id(self, key: str) -> str: """格式化交易所ID""" key = key.lower().strip() # 交易所名称映射 exchange_mapping = { 'metatrader': 'mt5', 'binance_spot_test': 'binance', 'binance_spot': 'binance', 'binance': 'binance', 'gate_spot': 'gate', 'okex': 'okx' } return exchange_mapping.get(key, key) def parse_account(self, exchange_id: str, account_id: str, account_info: str) -> Dict: """解析账号信息""" try: source_account_info = json.loads(account_info) account_data = { 'exchange_id': exchange_id, 'k_id': account_id, 'st_id': int(source_account_info.get('st_id', 0)), 'add_time': int(source_account_info.get('add_time', 0)) } return {**source_account_info, **account_data} except json.JSONDecodeError as e: logger.error(f"解析账号 {account_id} 数据失败: {e}") return {}