Files
crpto_predictor/data/fetcher.py
T
crypto_predictorandClaude Sonnet 4.5 9bbdc8d42b Initial commit: BTC 1h prediction model (53.10% accuracy)
🎯 项目成果:
- 准确率: 53.10% (2026年测试集)
- 任务类型: 二分类 (预测涨/跌)
- 特征: OHLCV + RSI + MACD (9个特征)
- 训练数据: 2020-2025年BTC小时数据 (52,351序列)
- 测试数据: 2026年1-29日 (484序列)

📊 性能指标:
- 精确率: 51.79%
- 召回率: 49.36%
- F1分数: 0.5054
- 预测分布: 非常平衡 (偏差仅-11个)

🔬 实验历史:
- 尝试了5种方案 (回归/分类, 不同数据划分)
- 分类任务优于回归任务 (53.10% vs 49.5%)
- 全量训练避免了过拟合问题

📦 主要模型文件:
- models/checkpoints/dlinear_classification_2026/
  - best_model.pt (最佳模型)
  - preprocessor.pkl (预处理器)
  - test_2026_results.json (测试结果)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-29 21:27:15 +08:00

192 lines
6.1 KiB
Python

"""从Binance获取加密货币OHLCV数据"""
import os
from datetime import datetime, timedelta
from pathlib import Path
from typing import Optional, Literal
import pandas as pd
from binance.client import Client
import pytz
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
class BinanceDataFetcher:
"""从Binance公开API获取和缓存OHLCV数据"""
INTERVALS = {
'1h': Client.KLINE_INTERVAL_1HOUR,
'15m': Client.KLINE_INTERVAL_15MINUTE,
}
def __init__(self, cache_dir: str = "./data/cache"):
"""初始化Binance客户端和缓存目录
Args:
cache_dir: 缓存下载数据的目录
"""
# 配置代理
proxies = None
use_proxy = os.getenv('USE_PROXY', 'false').lower() == 'true'
if use_proxy:
socks5_proxy = os.getenv('SOCKS5_PROXY', 'socks5://127.0.0.1:7890')
proxies = {
'http': socks5_proxy,
'https': socks5_proxy
}
print(f"✓ 使用SOCKS5代理: {socks5_proxy}")
try:
# 初始化Binance客户端(带代理)
if proxies:
self.client = Client(requests_params={'proxies': proxies})
else:
self.client = Client()
# 测试连接
self.client.ping()
print("✓ 已成功连接到Binance API")
except Exception as e:
print(f"⚠ Binance API连接失败: {e}")
print("提示:")
print(" 1. 检查代理设置 (.env文件)")
print(" 2. 确保代理服务正在运行")
print(" 3. 或者使用已缓存的数据")
self.client = None
self.cache_dir = Path(cache_dir)
self.cache_dir.mkdir(parents=True, exist_ok=True)
def fetch_ohlcv(
self,
symbol: Literal['BTC', 'ETH', 'SOL'],
timeframe: Literal['1h', '15m'],
start_date: Optional[str] = None,
end_date: Optional[str] = None,
use_cache: bool = True
) -> pd.DataFrame:
"""获取加密货币对的OHLCV数据
Args:
symbol: 加密货币符号 (BTC, ETH, SOL)
timeframe: 时间框架间隔 (1h 或 15m)
start_date: 开始日期,格式:'YYYY-MM-DD' (默认: 1年前)
end_date: 结束日期,格式:'YYYY-MM-DD' (默认: 现在)
use_cache: 是否使用缓存数据
Returns:
包含以下列的DataFrame: timestamp, open, high, low, close, volume
"""
# 生成缓存文件名
cache_file = self._get_cache_filename(symbol, timeframe, start_date, end_date)
# 检查缓存
if use_cache and cache_file.exists():
print(f"从缓存加载数据:{cache_file}")
return pd.read_csv(cache_file, parse_dates=['timestamp'])
# 检查客户端是否可用
if self.client is None:
raise ConnectionError(
"Binance客户端不可用。请使用VPN或使用已缓存的数据。"
)
# 设置默认日期
if end_date is None:
end_dt = datetime.now(pytz.UTC)
else:
end_dt = datetime.strptime(end_date, '%Y-%m-%d').replace(tzinfo=pytz.UTC)
if start_date is None:
start_dt = end_dt - timedelta(days=365) # 1年前
else:
start_dt = datetime.strptime(start_date, '%Y-%m-%d').replace(tzinfo=pytz.UTC)
# Binance使用USDT交易对
pair = f"{symbol}USDT"
interval = self.INTERVALS[timeframe]
print(f"获取 {symbol} {timeframe} 数据,时间范围:{start_dt.date()} 至 {end_dt.date()}...")
# 获取K线数据
klines = self.client.get_historical_klines(
symbol=pair,
interval=interval,
start_str=str(int(start_dt.timestamp() * 1000)),
end_str=str(int(end_dt.timestamp() * 1000))
)
if not klines:
raise ValueError(f"未获取到 {symbol} {timeframe} 的数据")
# 转换为DataFrame
df = pd.DataFrame(klines, columns=[
'timestamp', 'open', 'high', 'low', 'close', 'volume',
'close_time', 'quote_volume', 'trades', 'taker_buy_base',
'taker_buy_quote', 'ignore'
])
# 选择并转换列
df = df[['timestamp', 'open', 'high', 'low', 'close', 'volume']].copy()
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
for col in ['open', 'high', 'low', 'close', 'volume']:
df[col] = df[col].astype(float)
# 按时间排序
df = df.sort_values('timestamp').reset_index(drop=True)
print(f"已获取 {len(df)} 行数据,时间范围:{df['timestamp'].min()} 至 {df['timestamp'].max()}")
# 保存到缓存
df.to_csv(cache_file, index=False)
print(f"已缓存数据至:{cache_file}")
return df
def _get_cache_filename(
self,
symbol: str,
timeframe: str,
start_date: Optional[str],
end_date: Optional[str]
) -> Path:
"""根据参数生成缓存文件名"""
start = start_date or "1y"
end = end_date or "now"
filename = f"{symbol}_{timeframe}_{start}_{end}.csv"
return self.cache_dir / filename
def get_latest_price(self, symbol: Literal['BTC', 'ETH', 'SOL']) -> float:
"""获取符号的当前价格
Args:
symbol: 加密货币符号
Returns:
当前USDT价格
"""
pair = f"{symbol}USDT"
ticker = self.client.get_symbol_ticker(symbol=pair)
return float(ticker['price'])
if __name__ == "__main__":
# 测试数据获取器
fetcher = BinanceDataFetcher()
# 获取BTC 1小时数据(1年)
df = fetcher.fetch_ohlcv('BTC', '1h')
print("\nBTC 1小时数据:")
print(df.head())
print(f"\n形状:{df.shape}")
print(f"日期范围:{df['timestamp'].min()} 至 {df['timestamp'].max()}")
# 获取当前价格
current_price = fetcher.get_latest_price('BTC')
print(f"\n当前BTC价格:${current_price:,.2f}")