diff --git a/trading_system/binance_client.py b/trading_system/binance_client.py index d392bbc..92f8ce9 100644 --- a/trading_system/binance_client.py +++ b/trading_system/binance_client.py @@ -360,28 +360,63 @@ class BinanceClient: await self.client.close_connection() logger.info("币安客户端已断开连接") - async def get_all_usdt_pairs(self) -> List[str]: + async def get_all_usdt_pairs(self, max_retries: int = 3, timeout: int = 30) -> List[str]: """ 获取所有USDT交易对 + 添加超时处理和重试机制,避免推荐系统因网络超时中断 + + Args: + max_retries: 最大重试次数(默认3次) + timeout: 单次请求超时时间(秒,默认30秒) Returns: - USDT交易对列表 + USDT交易对列表(失败时返回空列表) """ - try: - # 获取合约市场信息 - exchange_info = await self.client.futures_exchange_info() - usdt_pairs = [ - symbol['symbol'] - for symbol in exchange_info['symbols'] - if symbol['symbol'].endswith('USDT') - and symbol['status'] == 'TRADING' - and symbol.get('contractType') == 'PERPETUAL' # U本位永续合约 - ] - logger.info(f"获取到 {len(usdt_pairs)} 个USDT永续合约交易对") - return usdt_pairs - except BinanceAPIException as e: - logger.error(f"获取交易对失败: {e}") - return [] + for attempt in range(1, max_retries + 1): + try: + # 使用 _rate_limited_request 包装请求,添加速率限制 + # 同时使用 asyncio.wait_for 添加超时处理 + exchange_info = await asyncio.wait_for( + self._rate_limited_request( + 'futures_exchange_info', + self.client.futures_exchange_info() + ), + timeout=timeout + ) + + usdt_pairs = [ + symbol['symbol'] + for symbol in exchange_info['symbols'] + if symbol['symbol'].endswith('USDT') + and symbol['status'] == 'TRADING' + and symbol.get('contractType') == 'PERPETUAL' # U本位永续合约 + ] + logger.info(f"获取到 {len(usdt_pairs)} 个USDT永续合约交易对") + return usdt_pairs + + except asyncio.TimeoutError: + if attempt < max_retries: + wait_time = attempt * 2 # 递增等待时间:2秒、4秒、6秒 + logger.warning(f"获取交易对超时({timeout}秒),{wait_time}秒后重试 ({attempt}/{max_retries})") + await asyncio.sleep(wait_time) + else: + logger.error(f"获取交易对失败:{max_retries}次重试后仍然超时") + return [] + + except BinanceAPIException as e: + logger.error(f"获取交易对失败(API错误): {e}") + return [] + + except Exception as e: + if attempt < max_retries: + wait_time = attempt * 2 + logger.warning(f"获取交易对出错: {e},{wait_time}秒后重试 ({attempt}/{max_retries})") + await asyncio.sleep(wait_time) + else: + logger.error(f"获取交易对失败(未知错误): {e}") + return [] + + return [] # 所有重试都失败,返回空列表 async def _rate_limited_request(self, endpoint: str, coro): """