Files
chanlun_1/data/data_fetcher.py
T
2025-05-23 19:09:55 +08:00

160 lines
4.9 KiB
Python

"""
数据获取模块:使用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