第二章:数据采集与存储
2.1 数据采集——从API到本地
做市商这行,数据就是命根子。我见过太多团队,策略模型再漂亮,数据源一塌糊涂,最后全白搭。今天咱们就从最基础的API数据获取讲起。
我个人习惯用 ccxt 这个库,它统一了上百家交易所的接口。说白了,你写一套代码,就能对接币安、OKX、火币这些主流平台。省心。
核心要点:API数据获取的关键不是“能连上”,而是“连得稳”。
先看一个最简单的例子,获取BTC/USD的实时报价:
import ccxt
import pandas as pd
from datetime import datetime
# 初始化交易所连接
exchange = ccxt.binance({
'rateLimit': 1200, # 币安的限制是1200次/分钟
'enableRateLimit': True, # 自动限速,别把自己封了
})
# 获取ticker数据
ticker = exchange.fetch_ticker('BTC/USDT')
print(f"时间: {datetime.now()}, 买一价: {ticker['bid']}, 卖一价: {ticker['ask']}")
嗯,这里要注意。很多新手直接写死API Key,这是大忌。我曾经有个同事,把Key硬编码在代码里,结果不小心提交到了GitHub公开仓库...那叫一个惨。建议用环境变量或者配置文件来管理。
我的小技巧:写个config.yaml文件,把API Key、Secret、交易所名称都放进去。代码里用 yaml.safe_load() 读取,既安全又灵活。
2.2 数据清洗——拿到手先别急着用
数据从API下来,你以为就能直接建模了?太天真了。我做了这么多年,遇到的坑能写本书。
常见问题有哪些?
- 缺失值:网络波动、交易所维护,数据就断了
- 异常值:比如价格突然跳了100倍,明显是数据错误
- 时间戳不一致:不同交易所的时钟不同步,差个几毫秒很正常
- 重复数据:重连后可能收到重复的tick
我曾经在回测一个高频策略时,发现收益曲线漂亮得不像话。后来一查,原来是数据里有重复的tick,导致策略“预知未来”。嗯,从那以后,我每次清洗数据都会加一步去重检查。
清洗代码示例:
def clean_tick_data(df):
# 1. 去重:按时间戳去重,保留第一条
df = df.drop_duplicates(subset='timestamp', keep='first')
# 2. 处理缺失值:用前向填充,别用均值填充
df = df.fillna(method='ffill')
# 3. 异常值过滤:价格超过3个标准差就剔除
mean_price = df['price'].mean()
std_price = df['price'].std()
df = df[(df['price'] > mean_price - 3*std_price) &
(df['price'] < mean_price + 3*std_price)]
return df
避坑指南:我曾经用均值填充缺失值,结果把策略搞崩了。外汇数据有很强的自相关性,用前向填充(ffill)更合理。你想想看,下一秒的价格,跟上一秒的关系,肯定比跟整体均值的关系大得多。
2.3 存储方案——CSV、Parquet还是数据库?
数据清洗完了,存哪?这是个好问题。我根据不同场景,一般有三种选择。
| 存储方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| CSV | 简单、通用、人类可读 | 慢、占空间、不支持压缩 | 小数据量、临时分析 |
| Parquet | 快、压缩率高、列式存储 | 二进制、不易直接查看 | 大数据量、机器学习 |
| 数据库 | 支持查询、并发、事务 | 需要维护、有学习成本 | 生产环境、团队协作 |
我个人习惯:开发阶段用CSV,回测用Parquet,生产用数据库。为什么?
CSV方便调试,你打开Excel就能看。但如果你有上亿条tick数据,CSV能把你硬盘撑爆。Parquet的压缩率能达到10:1,而且读取速度是CSV的几十倍。我回测一个5年的欧元兑美元数据,CSV要读30秒,Parquet只要1秒。
数据库的话,我推荐 TimescaleDB,它是基于PostgreSQL的时序数据库。专门为金融数据优化过。你想想看,做市商每秒可能产生几千条数据,普通数据库根本扛不住。
存储代码示例:
import pandas as pd
# CSV存储
df.to_csv('eur_usd_2024.csv', index=False)
# Parquet存储
df.to_parquet('eur_usd_2024.parquet', compression='snappy')
# 数据库存储(以SQLite为例,生产用TimescaleDB)
import sqlite3
conn = sqlite3.connect('forex_data.db')
df.to_sql('tick_data', conn, if_exists='append', index=False)
conn.close()
我的经验:Parquet的压缩算法选snappy,速度快,压缩率也不错。gzip压缩率更高,但写入慢。做市商数据讲究实时性,snappy是平衡之选。
2.4 知识体系总览
说了这么多,咱们用一张图把整个流程串起来。从数据源到最终存储,每一步都有讲究。
2.5 实战建议
最后,给你几个实在的建议:
- 别把所有鸡蛋放一个篮子里。 我建议同时用CSV和数据库存两份。CSV用于快速调试,数据库用于正式回测。
- 数据版本控制。 每次清洗完,加个版本号。我吃过亏,改完清洗逻辑后,旧数据找不回来了。
- 监控数据质量。 写个定时脚本,每天检查数据有没有断点、异常值。做市商的数据一天断个几分钟,策略可能就亏几万美金。
- 压缩是王道。 尤其是高频数据,一天就能产生几个GB。Parquet + snappy,能帮你省下80%的存储成本。
记住:数据采集和存储是整个做市系统的地基。地基不稳,上面盖多高的楼都没用。我见过太多团队,策略模型花里胡哨,结果数据源一换,全崩了。稳扎稳打,先把数据管好。