第二章:数据获取与处理——金融数据源的实战选择
做量化交易,第一步就是搞数据。没有数据,再牛的策略也是空中楼阁。今天咱们聊聊金融数据源怎么选、数据怎么洗、存到哪儿最合适。
我个人习惯把数据获取分成两个阶段:研究阶段和实盘阶段。研究阶段追求免费、方便、数据全;实盘阶段追求稳定、低延迟、合规。今天主要讲研究阶段,因为这是大家入门最关心的。
2.1 金融数据源介绍
国内做量化,绕不开两个库:Tushare 和 AKShare。我两个都用过,各有千秋。
2.1.1 Tushare
Tushare 是老牌数据源了。我2018年刚开始做量化时就在用。它最大的特点是数据规范、文档清晰。但有个门槛——需要积分。免费用户能拿到的数据有限,想拿全得充值。
举个例子,获取股票日线数据:
import tushare as ts
# 设置token(需要去官网注册获取)
ts.set_token('你的token')
pro = ts.pro_api()
# 获取平安银行2024年1月日线数据
df = pro.daily(ts_code='000001.SZ', start_date='20240101', end_date='20240131')
print(df.head())
输出结果长这样:
| ts_code | trade_date | open | high | low | close | vol |
|---|---|---|---|---|---|---|
| 000001.SZ | 20240131 | 9.12 | 9.35 | 9.08 | 9.22 | 1234567 |
| 000001.SZ | 20240130 | 9.30 | 9.38 | 9.10 | 9.15 | 987654 |
2.1.2 AKShare
AKShare 是后起之秀,完全免费。它的数据源来自各大财经网站,覆盖面很广。但有个问题——数据格式不太统一,不同接口返回的列名可能不一样。
我去年做一个期货策略时,AKShare 帮了大忙。它连南华期货指数这种冷门数据都有:
import akshare as ak
# 获取南华商品指数
index_df = ak.futures_nh_index(symbol="南华商品指数", start_date="20240101", end_date="20240131")
print(index_df.head())
2.1.3 怎么选?
我的建议很简单:
- 做股票策略:优先 Tushare,数据规范,省心
- 做期货/期权:AKShare 免费且数据全
- 做回测:两个都备着,互相校验
为什么会这样?因为股票数据对复权、除权处理要求高,Tushare 做得更专业。期货数据嘛,AKShare 的覆盖面确实广。
2.2 数据清洗与预处理
拿到原始数据后,千万别直接扔进策略。我见过太多人,数据没洗干净,策略跑出来漂亮得很,实盘一跑就亏。为什么?前视偏差和幸存者偏差在作怪。
2.2.1 常见问题
金融数据常见的坑,我列几个:
- 缺失值:停牌日、节假日,数据是空的
- 异常值:比如某天涨幅1000%,明显是数据错误
- 复权问题:不处理复权,回测结果全是错的
- 未来数据:用当天的数据预测当天,这是作弊
2.2.2 清洗实战
拿 Tushare 的日线数据举例,我一般这么洗:
import pandas as pd
import numpy as np
# 假设 df 是原始数据
def clean_stock_data(df):
# 1. 排序:按时间升序
df = df.sort_values('trade_date')
# 2. 处理缺失值:前向填充
df = df.fillna(method='ffill')
# 3. 处理异常值:涨跌幅超过20%的,用前一日数据替换
df['pct_chg'] = df['close'].pct_change()
abnormal = df['pct_chg'].abs() > 0.2
df.loc[abnormal, 'close'] = df['close'].shift(1)
# 4. 复权处理(这里用后复权)
df['adj_close'] = df['close'] * df['adj_factor']
return df
# 使用
df_clean = clean_stock_data(df)
2.2.3 避坑指南
我曾经犯过一个低级错误:用当天的收盘价计算均线,然后预测当天的涨跌。回测结果年化收益50%,实盘直接腰斩。后来才发现,回测时用了未来数据。
正确的做法是:计算技术指标时,只用历史数据。比如计算5日均线,只能用前5天的数据,不能用当天。
2.3 数据存储
数据洗好了,存哪儿?我试过三种方式:CSV、SQLite、MySQL。各有适用场景。
2.3.1 CSV 存储
最简单的方式。研究阶段,数据量不大,CSV 完全够用。
# 保存
df_clean.to_csv('stock_data.csv', index=False)
# 读取
df = pd.read_csv('stock_data.csv', parse_dates=['trade_date'])
但 CSV 有个问题:不支持增量更新。每次更新数据,都得全量重写。数据量大了之后,效率很低。
2.3.2 数据库存储
我建议用 SQLite 做研究阶段的数据存储。它不需要安装服务器,一个文件搞定,而且支持 SQL 查询。
import sqlite3
# 连接数据库(文件不存在会自动创建)
conn = sqlite3.connect('quant_data.db')
# 写入数据
df_clean.to_sql('stock_daily', conn, if_exists='replace', index=False)
# 查询数据
query = "SELECT * FROM stock_daily WHERE trade_date >= '2024-01-01'"
df = pd.read_sql(query, conn)
conn.close()
如果数据量特别大(比如全市场分钟级数据),可以考虑 MySQL 或 PostgreSQL。但说实话,个人研究阶段,SQLite 完全够用。
2.3.3 存储方案对比
| 存储方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| CSV | 简单、通用 | 不支持增量、查询慢 | 小数据量、一次性分析 |
| SQLite | 轻量、支持SQL | 并发差 | 个人研究、中小规模 |
| MySQL | 并发好、功能强 | 需要安装维护 | 团队协作、生产环境 |
2.4 本章知识体系
说了这么多,咱们用一张图总结一下数据获取与处理的完整流程:
嗯,数据这块就聊到这儿。记住一句话:数据质量决定策略上限。数据没处理好,后面再牛的模型也白搭。我见过太多人花90%时间写策略,10%时间搞数据,结果策略一跑就崩。反过来,花70%时间搞数据,30%时间写策略,反而更容易出成果。
你想想看,是不是这个理?