3、因子数据获取:用Python搞定三大数据源
做因子投资,数据就是你的弹药。没有数据,再牛的策略也是空中楼阁。
我个人习惯把数据源分成三类:行情数据、财务数据、以及因子计算所需的辅助数据。这三类数据,获取方式完全不同,坑也各不相同。今天我就带你一个个过一遍。
3.1 行情数据获取:从K线到复权
行情数据是最基础的。说白了就是开盘价、收盘价、最高价、最低价、成交量这些。
我常用的数据源是 Tushare 和 AKShare。前者是老牌,后者是后起之秀。我个人更偏爱 AKShare,因为它免费且更新快。
核心要点:获取行情数据时,一定要搞清楚「复权」问题。前复权、后复权、不复权,三种数据算出来的因子可能天差地别。
举个例子,获取贵州茅台近一年的日线数据:
import akshare as ak
# 获取前复权数据
stock_zh_a_hist_df = ak.stock_zh_a_hist(
symbol="600519",
period="daily",
start_date="20240101",
end_date="20241231",
adjust="qfq" # qfq=前复权, hfq=后复权
)
print(stock_zh_a_hist_df.head())
嗯,这里要注意。前复权适合做回测,因为它保持了历史价格的连续性。但如果你要计算分红相关的因子,就得用不复权数据。
我曾经踩过一个坑:用前复权数据计算股息率,结果算出来全是负数。后来才发现,前复权已经把分红从价格里扣掉了。从那以后,我养成了一个习惯——同时拉三份数据:前复权、后复权、不复权。
3.2 财务数据获取:从财报到TTM
财务数据比行情数据麻烦得多。为什么?因为财报有季节性,而且发布时间滞后。
我建议你重点关注这几个指标:
- 营业收入:看公司卖了多少东西
- 净利润:看公司赚了多少钱
- 净资产:算PB的基础
- 经营活动现金流:防止财务造假的关键
获取财务数据,我一般用 Tushare 的 pro 接口:
import tushare as ts
# 初始化
pro = ts.pro_api('你的token')
# 获取利润表
df = pro.income(
ts_code='600519.SH',
start_date='20240101',
end_date='20241231',
fields='ts_code,ann_date,f_ann_date,end_date,revenue,n_income'
)
print(df.head())
小技巧:财务数据有「公告日期」和「实际截止日期」之分。做回测时,一定要用公告日期来判断数据是否可用。否则你会用到未来数据,回测结果全是假的。
你想想看,一家公司2024年一季报可能在4月底才公布。如果你在回测中用了3月份的数据,那就相当于提前知道了未来信息。这种错误,我见过太多人犯了。
3.3 因子计算所需数据源:不止是价格和财报
很多因子需要特殊数据。比如:
| 因子类型 | 所需数据 | 数据来源 |
|---|---|---|
| 动量因子 | 过去N日收益率 | 行情数据 |
| 价值因子 | PE、PB、PS | 财务数据 + 行情数据 |
| 质量因子 | ROE、毛利率 | 财务数据 |
| 情绪因子 | 换手率、波动率 | 行情数据 |
| 成长因子 | 营收增长率、利润增长率 | 财务数据(需TTM计算) |
这里我要特别说一下TTM(Trailing Twelve Months)的计算。很多新手直接用单季度数据,但这样会漏掉季节性因素。
我的做法是:
# 计算TTM净利润
# 假设我们有四个季度的净利润数据
q1_net = 100 # 2024Q1
q2_net = 120 # 2024Q2
q3_net = 110 # 2024Q3
q4_net = 130 # 2024Q4
# TTM = 最近四个季度之和
ttm_net = q1_net + q2_net + q3_net + q4_net
# 如果当前是2024年10月,最新完整季度是Q3
# 那么TTM = 2023Q4 + 2024Q1 + 2024Q2 + 2024Q3
# 注意:2023Q4的数据要从上一年的年报中取
警告:千万不要直接用「最新财报」的数据来计算TTM。比如现在是10月,最新完整财报是三季报。如果你直接用三季报的累计数据,那算出来的是前三季度总和,不是TTM。正确的做法是:用三季报的累计数据减去半年报的累计数据,得到单季度数据,再往前推三个季度。
3.4 数据清洗与对齐:最容易被忽视的环节
数据拿到了,但能用吗?不一定。
我遇到过这些问题:
- 停牌日期的数据是空的
- ST股票的数据还在,但应该剔除
- 新股上市前几天的数据波动太大
- 财务数据有缺失值
我的处理流程是这样的:
import pandas as pd
def clean_data(df):
# 1. 剔除ST股票
df = df[~df['name'].str.contains('ST')]
# 2. 剔除上市不满60天的股票
df = df[df['list_days'] >= 60]
# 3. 处理缺失值
df = df.fillna(method='ffill') # 前向填充
# 4. 剔除极端值(比如涨跌幅超过20%的)
df = df[(df['pct_chg'] > -0.2) & (df['pct_chg'] < 0.2)]
return df
说白了,数据清洗就是「去伪存真」的过程。你想想看,如果数据里混着ST股票,算出来的因子值能准吗?
3.5 数据存储:别每次都重新拉
我刚开始做量化的时候,每次跑策略都重新拉数据。结果发现,光下载数据就要花半小时。后来我学乖了,把数据存到本地。
我的存储方案:
- 日线数据:存到CSV文件,按股票代码分文件
- 财务数据:存到SQLite数据库,方便查询
- 因子数据:存到Parquet格式,压缩率高、读取快
举个例子,把日线数据存到CSV:
# 保存数据
stock_data.to_csv(f'data/{stock_code}_daily.csv', index=False)
# 读取数据
stock_data = pd.read_csv(f'data/{stock_code}_daily.csv', parse_dates=['date'])
建议:每天收盘后,跑一个定时任务,自动更新数据。这样你第二天起来,数据就已经准备好了。我用的是Windows的任务计划程序,配合Python脚本,已经稳定跑了两年多。
3.6 本章知识体系
下面这张图,是我对本章内容的总结。你可以把它当作一个检查清单:
这张图把整个数据获取流程串起来了。从三大数据源出发,经过清洗对齐,最终得到可用的因子数据。每一步都有坑,但只要你按这个流程走,基本不会出大问题。
最后说一句:数据获取是因子投资中最枯燥、但也是最重要的一环。我见过太多人花90%的时间写策略,结果数据是错的,白忙一场。记住:垃圾进,垃圾出。数据质量决定了你策略的天花板。