""" 数据获取模块:使用ccxt库拉取数字货币市场数据 """ import ccxt import pandas as pd import numpy as np from datetime import datetime, timedelta import time from typing import List, Dict, Optional, Tuple import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class DataFetcher: """数据获取器:负责从交易所获取K线数据""" def __init__(self, exchange_name: str = 'binance'): """ 初始化数据获取器 Args: exchange_name: 交易所名称,默认为binance """ self.exchange_name = exchange_name self.exchange = self._init_exchange() def _init_exchange(self) -> ccxt.Exchange: """初始化交易所连接""" try: exchange_class = getattr(ccxt, self.exchange_name) exchange = exchange_class({ 'apiKey': '', # 对于公开数据不需要API密钥 'secret': '', 'timeout': 30000, 'enableRateLimit': True, }) return exchange except Exception as e: logger.error(f"初始化交易所失败: {e}") raise def fetch_klines(self, symbol: str, timeframe: str = '1h', limit: int = 1000, since: Optional[int] = None) -> pd.DataFrame: """ 获取K线数据 Args: symbol: 交易对符号,如'BTC/USDT' timeframe: 时间周期,如'1h', '4h', '1d' limit: 获取的K线数量 since: 开始时间戳(毫秒) Returns: 包含K线数据的DataFrame """ try: logger.info(f"正在获取 {symbol} {timeframe} 数据,数量: {limit}") # 获取原始数据 ohlcv = self.exchange.fetch_ohlcv( symbol=symbol, timeframe=timeframe, limit=limit, since=since ) if not ohlcv: raise ValueError("未获取到数据") # 转换为DataFrame df = pd.DataFrame(ohlcv, columns=[ 'timestamp', 'open', 'high', 'low', 'close', 'volume' ]) # 转换时间戳为datetime df['datetime'] = pd.to_datetime(df['timestamp'], unit='ms') df.set_index('datetime', inplace=True) # 确保数据类型正确 price_columns = ['open', 'high', 'low', 'close'] df[price_columns] = df[price_columns].astype(float) df['volume'] = df['volume'].astype(float) logger.info(f"成功获取 {len(df)} 条K线数据") return df except Exception as e: logger.error(f"获取K线数据失败: {e}") raise def fetch_multiple_timeframes(self, symbol: str, timeframes: List[str], limit: int = 1000) -> Dict[str, pd.DataFrame]: """ 获取多个时间周期的数据 Args: symbol: 交易对符号 timeframes: 时间周期列表 limit: 每个周期获取的数量 Returns: 字典,键为时间周期,值为对应的DataFrame """ result = {} for timeframe in timeframes: try: df = self.fetch_klines(symbol, timeframe, limit) result[timeframe] = df # 避免请求过于频繁 time.sleep(self.exchange.rateLimit / 1000) except Exception as e: logger.error(f"获取 {timeframe} 数据失败: {e}") continue return result def get_latest_price(self, symbol: str) -> float: """ 获取最新价格 Args: symbol: 交易对符号 Returns: 最新价格 """ try: ticker = self.exchange.fetch_ticker(symbol) return float(ticker['last']) except Exception as e: logger.error(f"获取最新价格失败: {e}") raise def validate_symbol(self, symbol: str) -> bool: """ 验证交易对是否有效 Args: symbol: 交易对符号 Returns: 是否有效 """ try: markets = self.exchange.load_markets() return symbol in markets except Exception as e: logger.error(f"验证交易对失败: {e}") return False