第三章 数据获取与处理:量化交易的“原材料”
做量化交易,说白了就是跟数据打交道。没有数据,再牛的策略也是空中楼阁。我个人习惯把数据获取比作做饭——米都没下锅,你谈什么厨艺?这一章,我们就来聊聊怎么拿到干净、可用的行情数据。
3.1 用CCXT获取行情数据
CCXT这个库,我用了快五年了。它最大的好处是统一了上百家交易所的API接口。你想想看,不用为每个交易所单独写一套代码,多省心。
安装很简单:
pip install ccxt
获取实时行情,几行代码就搞定:
import ccxt
# 初始化交易所对象
exchange = ccxt.binance()
# 获取BTC/USDT的最新ticker
ticker = exchange.fetch_ticker('BTC/USDT')
print(f"最新价: {ticker['last']}")
print(f"24h涨跌: {ticker['percentage']}%")
嗯,这里要注意。不同交易所的交易对命名规则不一样。币安是BTC/USDT,有些交易所可能是BTC-USDT或者btcusdt。CCXT会自动帮你处理这些差异,但初始化时最好指定一下参数:
exchange = ccxt.binance({
'rateLimit': 1200, # 控制请求频率
'enableRateLimit': True, # 自动限速
})
避坑指南:我曾经在实盘交易中忘记设置rateLimit,结果被交易所封了IP半小时。那半小时里策略完全停摆,亏了不少钱。记住,交易所的API都有频率限制,别贪快。
3.2 K线数据结构
K线数据是量化策略的基石。CCXT获取K线的方法很直观:
# 获取BTC/USDT的1小时K线,最近100根
ohlcv = exchange.fetch_ohlcv('BTC/USDT', '1h', limit=100)
# 返回的数据结构是这样的:
# [
# [timestamp, open, high, low, close, volume],
# [1625097600000, 35000, 35200, 34800, 35100, 1234.5],
# ...
# ]
返回的是列表嵌套列表。每个元素依次是:时间戳(毫秒)、开盘价、最高价、最低价、收盘价、成交量。我个人习惯第一时间把它转成pandas DataFrame:
import pandas as pd
df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
df.set_index('timestamp', inplace=True)
print(df.head())
为什么转成DataFrame?因为后续的数据清洗、特征工程、回测,pandas都是标配。你想想看,用原生列表做计算,效率低不说,代码还难看。
3.3 数据清洗与预处理
拿到的原始数据,很少是完美的。我在项目中遇到过好几次,交易所返回的数据里突然出现一个空值,或者时间戳错乱。这时候就需要清洗。
常见的清洗步骤:
- 处理缺失值:用前向填充或插值
- 去除重复数据:网络波动可能导致重复请求
- 检查时间连续性:K线应该是等间隔的
- 异常值检测:比如价格突然跳变100倍
# 缺失值处理
df.fillna(method='ffill', inplace=True) # 用前一个值填充
# 去除重复行
df.drop_duplicates(inplace=True)
# 检查时间间隔是否一致
time_diff = df.index.to_series().diff()
print(f"最大时间间隔: {time_diff.max()}")
print(f"最小时间间隔: {time_diff.min()}")
小技巧:如果发现时间间隔不一致,可以用resample重新采样。比如把5分钟K线重采样成15分钟:df.resample('15min').agg({'open': 'first', 'high': 'max', 'low': 'min', 'close': 'last', 'volume': 'sum'})
3.4 数据存储:CSV还是数据库?
数据清洗完了,得存起来。这里我分两种情况讨论。
3.4.1 CSV存储
适合小规模数据、个人研究。简单直接:
df.to_csv('btc_usdt_1h.csv', index=True)
# 读取也很方便
df = pd.read_csv('btc_usdt_1h.csv', index_col=0, parse_dates=True)
但CSV有个问题——数据量大了以后,读写速度会变慢。我试过存3年的1分钟K线,文件大小接近1GB,每次读取都要等好几秒。
3.4.2 数据库存储
生产环境我强烈建议用数据库。SQLite轻量级,适合单机;PostgreSQL适合团队协作。
import sqlite3
# 连接数据库
conn = sqlite3.connect('crypto_data.db')
# 写入数据
df.to_sql('btc_usdt_1h', conn, if_exists='append', index=True)
# 读取数据
df = pd.read_sql("SELECT * FROM btc_usdt_1h WHERE timestamp >= '2024-01-01'", conn, index_col='timestamp', parse_dates=['timestamp'])
conn.close()
数据库的好处是支持条件查询、增量更新。你想想看,每天只需要插入新数据,不用每次都全量覆盖。
| 存储方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| CSV | 简单、通用、可读性强 | 大文件慢、不支持并发 | 个人研究、小数据量 |
| SQLite | 轻量、无需服务器、支持SQL | 并发写入差 | 单机策略、回测 |
| PostgreSQL | 高性能、支持并发、功能丰富 | 需要部署维护 | 团队协作、生产环境 |
核心要点:数据获取只是第一步,清洗和存储同样重要。我见过太多人花大量时间优化策略,结果数据本身就有问题。记住一句话:垃圾进,垃圾出(Garbage In, Garbage Out)。
3.5 知识体系总览
下面这张图,是我对本章知识结构的总结。你可以把它当作一个检查清单:
这张图展示了数据从获取到存储的完整链路。每个环节都有坑,但只要你按部就班地处理好,后面的策略开发就会顺畅很多。