2. Tick数据获取与存储:常见数据源介绍
做量化交易的朋友都知道,Tick数据是订单流分析的命根子。没有高质量的数据,再牛的策略也是空中楼阁。今天我就把这块内容掰开了讲,从数据源到存储,一条龙说清楚。
2.1 常见数据源介绍
数据源这块,说白了就两条路:要么直接对接交易所,要么找第三方数据商。我两种都折腾过,各有各的坑。
2.1.1 交易所API
直接连交易所,听起来很酷对吧?但这里面的门道不少。
- 实时数据:WebSocket接口,延迟低,适合高频策略
- 历史数据:REST接口,但通常有长度限制
- 费用:大部分免费,但有些交易所要收数据费
注意:交易所API的限频策略很严格。我曾经在回测时没注意,一口气拉了3年的数据,结果IP被ban了整整24小时。嗯,那天的复盘计划全泡汤了。
举个例子,用Binance的API拉取BTC/USDT的Tick数据:
import requests
import json
# 获取最近1000条成交记录
url = "https://api.binance.com/api/v3/trades"
params = {
"symbol": "BTCUSDT",
"limit": 1000
}
response = requests.get(url, params=params)
trades = response.json()
# 看看数据结构
print(trades[0])
# 输出:{'id': 123456, 'price': '50000.00', 'qty': '0.01',
# 'time': 1623456789000, 'isBuyerMaker': True}
2.1.2 第三方数据商
如果你不想自己折腾交易所API,第三方数据商是个省心的选择。我个人的习惯是,小规模回测用免费数据,实盘或大规模研究才买付费数据。
| 数据商 | 覆盖范围 | 数据质量 | 价格 |
|---|---|---|---|
| QuantConnect | 美股、期货、加密货币 | 高 | 免费/付费 |
| Polygon.io | 美股为主 | 高 | 月费制 |
| Kaiko | 加密货币 | 极高 | 企业级定价 |
| CoinAPI | 多交易所加密货币 | 高 | 按量计费 |
我的建议:刚开始做研究,先用免费数据跑通流程。等策略有眉目了,再考虑买付费数据。别一上来就花大钱,我见过太多人数据买了,策略却没跑出来。
2.2 数据存储格式选择
数据拿到手了,存哪里?怎么存?这问题看似简单,但选错了后面会非常痛苦。你想想看,几千万条Tick数据,如果存成CSV,加载一次就要等半天。
2.2.1 CSV格式
CSV是最通用的格式,但也是最慢的。适合小规模数据或临时分析。
import pandas as pd
# 保存为CSV
df.to_csv('tick_data.csv', index=False)
# 读取CSV
df = pd.read_csv('tick_data.csv', parse_dates=['timestamp'])
避坑指南:我曾经用CSV存了3个月的Tick数据,文件大小超过10GB。每次读取都要等5分钟,而且经常内存溢出。后来我果断换成了Parquet,读取时间从5分钟降到了10秒。
2.2.2 Parquet格式
Parquet是列式存储格式,压缩率高,读取快。我个人强烈推荐用于Tick数据存储。
# 保存为Parquet
df.to_parquet('tick_data.parquet', compression='snappy')
# 读取Parquet
df = pd.read_parquet('tick_data.parquet')
# 按日期分区存储,查询更快
df['date'] = df['timestamp'].dt.date
df.to_parquet('tick_data_partitioned.parquet',
partition_cols=['date'])
2.2.3 HDF5格式
HDF5适合存储大规模科学数据,支持多维数组。但说实话,在量化领域用得不多。
# 保存为HDF5
df.to_hdf('tick_data.h5', key='trades', mode='w')
# 读取HDF5
df = pd.read_hdf('tick_data.h5', key='trades')
2.3 本地数据库搭建
当数据量达到TB级别时,文件存储就不够用了。这时候需要上数据库。我建议从小规模开始,用SQLite就够了。
2.3.1 SQLite
SQLite是轻量级数据库,零配置,适合单机使用。对于个人研究来说,完全够用。
import sqlite3
import pandas as pd
# 创建数据库连接
conn = sqlite3.connect('tick_data.db')
# 创建表
conn.execute('''
CREATE TABLE IF NOT EXISTS trades (
id INTEGER PRIMARY KEY,
symbol TEXT,
price REAL,
volume REAL,
timestamp INTEGER,
side TEXT
)
''')
# 批量插入数据
df.to_sql('trades', conn, if_exists='append', index=False)
# 查询数据
query = '''
SELECT * FROM trades
WHERE symbol = 'BTCUSDT'
AND timestamp BETWEEN 1623456789000 AND 1623456889000
'''
result = pd.read_sql(query, conn)
小技巧:给timestamp字段加索引,查询速度能提升10倍以上。我刚开始没加索引,查一次数据要等30秒,加了索引后秒出结果。
2.3.2 InfluxDB
如果你做的是高频交易,时间序列数据量特别大,InfluxDB是更好的选择。它是专门为时序数据设计的数据库。
from influxdb import InfluxDBClient
import pandas as pd
# 连接InfluxDB
client = InfluxDBClient(host='localhost', port=8086)
client.create_database('tick_data')
client.switch_database('tick_data')
# 构造数据点
json_body = [
{
"measurement": "trades",
"tags": {
"symbol": "BTCUSDT"
},
"time": "2023-01-01T00:00:00Z",
"fields": {
"price": 50000.00,
"volume": 0.01,
"side": "buy"
}
}
]
# 写入数据
client.write_points(json_body)
# 查询数据
results = client.query('SELECT * FROM trades WHERE symbol = \'BTCUSDT\'')
df = pd.DataFrame(results.get_points())
核心要点:选择存储方案时,记住这个原则——
- 数据量 < 1GB:CSV或SQLite
- 数据量 1GB-100GB:Parquet
- 数据量 > 100GB:InfluxDB或分布式存储
- 数据量 < 1GB:CSV或SQLite
- 数据量 1GB-100GB:Parquet
- 数据量 > 100GB:InfluxDB或分布式存储
好了,数据源和存储这块就讲到这里。记住,数据是量化交易的基石,花时间把这块做好,后面会省很多事。我个人踩过的坑,都写在上面了,希望能帮你少走弯路。