第三章:数据基础设施——数据源选择、数据库选型与ETL设计
做量化策略研发,说白了就是跟数据打交道。我见过太多人策略逻辑写得天花乱坠,结果一上实盘就崩——十有八九是数据基础设施没搭好。这一章,咱们就把数据这块地基夯实了。
3.1 数据源选择:你的“米”从哪来?
量化交易里,数据就是米。没有米,再好的厨子也做不出饭。我个人习惯把数据源分成三类:金融终端类、开源Python库类、以及量化平台类。
3.1.1 Wind(万得)
Wind是机构标配。数据全、质量高、更新快。但贵,一年几万到几十万不等。我个人建议:如果你在机构工作,或者资金量上千万,直接上Wind。省心。
3.1.2 Tushare
Tushare是国内开源数据接口的鼻祖。免费版够用,但有限制(比如每分钟请求次数)。Pro版需要积分,其实也不贵。
我比较喜欢Tushare的地方:数据结构清晰,文档全。适合个人研究和小团队。
3.1.3 AkShare
AkShare是后起之秀,完全免费。它其实是个爬虫集合,从各大财经网站抓数据。好处是数据源广,连期货、期权、宏观经济数据都有。
3.1.4 聚宽(JoinQuant)
聚宽是个量化平台,也提供数据API。它的数据经过清洗,质量不错。如果你用聚宽的回测系统,直接用它的数据最方便。
怎么选?我列个表,你一看就明白:
| 数据源 | 费用 | 数据质量 | 适合场景 |
|---|---|---|---|
| Wind | 高(万元级) | ★★★★★ | 机构、大资金 |
| Tushare | 低(免费/积分) | ★★★★ | 个人研究、小团队 |
| AkShare | 免费 | ★★★ | 辅助数据、研究 |
| 聚宽 | 免费/付费 | ★★★★ | 平台内回测 |
3.2 数据库选型:你的“米缸”怎么选?
数据拿到手,得存起来。选数据库这事,我踩过不少坑。说白了,没有最好的数据库,只有最合适的。
3.2.1 MySQL / PostgreSQL
这两兄弟是关系型数据库的代表。适合存结构化数据,比如日线行情、财务数据。
我个人更倾向PostgreSQL。为什么?因为它支持数组、JSON等数据类型,做量化时很方便。比如存一个股票的5分钟K线,我可以直接把一天的数据存成一个数组,查询效率高很多。
3.2.2 ClickHouse
ClickHouse是列式存储数据库,专门为分析场景设计。如果你做高频策略,或者需要秒级查询上亿条数据,ClickHouse是首选。
3.2.3 InfluxDB
InfluxDB是时序数据库,专门处理带时间戳的数据。如果你做Tick级别的高频交易,或者存传感器数据(比如服务器监控),用InfluxDB最合适。
怎么选?看你的数据量和查询频率:
- 日线级别、数据量小(百万级):PostgreSQL就够了
- 分钟级别、数据量大(亿级):ClickHouse
- Tick级别、实时写入:InfluxDB
3.3 数据存储结构设计
结构设计这事,我刚开始做的时候也犯过傻。把所有数据塞一张表里,结果查询慢得要死。后来学乖了,按“频率+类型”分表。
举个例子,股票日线行情表:
CREATE TABLE stock_daily (
ts_code VARCHAR(20), -- 股票代码
trade_date DATE, -- 交易日期
open DECIMAL(10,2), -- 开盘价
high DECIMAL(10,2), -- 最高价
low DECIMAL(10,2), -- 最低价
close DECIMAL(10,2), -- 收盘价
volume BIGINT, -- 成交量
amount DECIMAL(20,2), -- 成交额
PRIMARY KEY (ts_code, trade_date)
);
注意这里用了联合主键(股票代码+日期)。为什么?因为查询时最常用的条件就是“某只股票某段时间的数据”。这样设计,查询效率最高。
3.4 数据ETL流程设计
ETL就是:抽取(Extract)、转换(Transform)、加载(Load)。说白了,就是把原始数据洗成你能用的样子。
3.4.1 抽取(Extract)
从数据源拉数据。我一般用Python写个定时任务,每天收盘后自动跑。
import tushare as ts
import pandas as pd
pro = ts.pro_api('your_token')
df = pro.daily(ts_code='000001.SZ', start_date='20240101', end_date='20240131')
df.to_csv('raw_data.csv', index=False)
3.4.2 转换(Transform)
这一步最花时间。原始数据可能有缺失值、异常值、复权问题等。
我举个例子:股票分红后,价格会跳空。如果你直接用原始价格算收益率,结果会失真。所以要做复权处理。
# 前复权处理示例
df['adj_close'] = df['close'] * (df['adj_factor'] / df['adj_factor'].iloc[-1])
3.4.3 加载(Load)
把清洗好的数据写入数据库。我建议用批量插入,别一条一条插,太慢了。
from sqlalchemy import create_engine
engine = create_engine('postgresql://user:pass@localhost:5432/quant')
df.to_sql('stock_daily', engine, if_exists='append', index=False, method='multi')
3.5 整体架构图
下面这张图,是我自己搭建数据流水线的标准架构。你照着搭,基本不会出大问题。
这张图从左到右,从上到下,就是数据从源头到应用的完整流程。你想想看,如果没有这一套基础设施,你的策略就像建在沙滩上的城堡——看着漂亮,一涨潮就没了。
公众号:蓝海数据掘金营,微信deep3321