第三章:因子数据获取——用Python搞定行情、财务与宏观数据
做因子投资,最头疼的事是什么?
我个人觉得,不是策略设计,也不是回测优化,而是——数据。数据拿不到、拿不全、拿不准,后面全是白搭。我在2018年刚开始做多因子模型时,就吃过这个亏。当时从某数据商买来的财务数据,居然有30%的缺失值,回测结果漂亮得不像话,实盘却一塌糊涂。
嗯,从那以后,我对数据获取这件事,再也不敢马虎。
3.1 行情数据:最基础也最讲究
行情数据,说白了就是价格和成交量。但这里有个坑:你拿到的复权价格,到底对不对?
我个人习惯用 akshare 和 tushare 两个库。前者免费,后者部分数据需要积分。给你看个例子:
import akshare as ak
import pandas as pd
# 获取沪深300成分股日线数据(后复权)
def get_stock_daily(symbol="000300", start="2020-01-01", end="2023-12-31"):
df = ak.stock_zh_index_daily(symbol=f"sh{symbol}")
df = df[(df['date'] >= start) & (df['date'] <= end)]
df['returns'] = df['close'].pct_change()
return df
# 获取个股行情
def get_individual_stock(symbol="000001", start="2020-01-01", end="2023-12-31"):
df = ak.stock_zh_a_hist(symbol=symbol, period="daily",
start_date=start, end_date=end, adjust="qfq")
return df
这里有个小技巧:我一般会同时拉取复权因子,自己算后复权价格。这样数据更可控。
3.2 财务数据:因子挖掘的富矿
财务数据是基本面因子的核心来源。市盈率、市净率、ROE、毛利率……这些因子都来自财务报表。
但财务数据有个特点:发布滞后。一季报在4月底才出完,年报可能拖到次年4月。如果你用最新财报数据做因子,其实已经过时了。
我建议的做法是:
- 用
tushare的financial接口获取原始报表数据 - 自己计算财务指标,而不是直接用别人算好的
- 做「财报日期对齐」,确保因子值用的是当时可获取的数据
import tushare as ts
# 初始化(需要token)
pro = ts.pro_api('your_token_here')
# 获取利润表
def get_income_data(ts_code="000001.SZ", start_date="20200101", end_date="20231231"):
df = pro.income(ts_code=ts_code, start_date=start_date, end_date=end_date)
# 计算毛利率
df['gross_margin'] = (df['revenue'] - df['cost_of_sales']) / df['revenue']
return df
# 获取资产负债表
def get_balance_data(ts_code="000001.SZ", start_date="20200101", end_date="20231231"):
df = pro.balancesheet(ts_code=ts_code, start_date=start_date, end_date=end_date)
# 计算资产负债率
df['debt_ratio'] = df['total_liability'] / df['total_assets']
return df
3.3 宏观经济数据:把握大方向
宏观数据对宽基指数增强特别重要。GDP增速、CPI、PMI、社融数据……这些会影响整个市场的估值中枢。
我常用的宏观数据来源:
- 国家统计局:官方数据,最权威但更新慢
- akshare的macro模块:整合了多个来源,方便快捷
- FRED(美联储经济数据库):做全球宏观时必用
# 获取宏观经济数据
def get_macro_data():
# PMI数据
pmi = ak.macro_china_pmi()
# CPI数据
cpi = ak.macro_china_cpi_monthly()
# 社融数据
social_financing = ak.macro_china_social_financing()
return {
'pmi': pmi,
'cpi': cpi,
'social_financing': social_financing
}
你想想看,宏观数据对因子有什么影响?举个例子:当PMI连续3个月低于50时,周期股的盈利因子就会走弱。这时候如果你还在用高盈利因子选股,大概率会亏钱。
3.4 数据清洗与对齐:真正的功夫在这里
数据拿到手,只是第一步。真正的难点在于:如何把不同频率、不同来源的数据对齐到同一个时间轴上。
行情数据是日频,财务数据是季频,宏观数据可能是月频。你要把它们全部对齐到每个交易日。
我常用的方法:
- 向前填充:财务数据在发布日之后,一直沿用直到下一期发布
- 线性插值:对于宏观数据,可以用前后值做线性插值
- 滚动窗口:计算过去N天的均值,平滑噪声
# 数据对齐示例
def align_data(price_df, financial_df, macro_df):
# 财务数据向前填充
financial_aligned = financial_df.reindex(price_df.index, method='ffill')
# 宏观数据线性插值
macro_aligned = macro_df.reindex(price_df.index).interpolate(method='linear')
# 合并
combined = pd.concat([price_df, financial_aligned, macro_aligned], axis=1)
return combined.dropna()
3.5 本章知识体系
下面这张图,是我做数据获取时的整体思路。你可以把它当成一个检查清单:
这张图的核心逻辑是:三大数据源各自获取后,统一进入「数据清洗与对齐」环节,最后才能用于因子计算。跳过这一步,你的因子就是垃圾。
3.6 我的数据获取工作流
最后,分享一个我目前在用的工作流。不一定适合所有人,但你可以参考:
| 步骤 | 内容 | 频率 | 工具 |
|---|---|---|---|
| 1 | 拉取全市场日线行情 | 每日收盘后 | akshare |
| 2 | 更新财务数据(季报/年报) | 财报发布日 | tushare pro |
| 3 | 获取宏观数据 | 每月/每周 | akshare macro |
| 4 | 数据对齐与清洗 | 每次更新后 | pandas |
| 5 | 存储到本地数据库 | 每次更新后 | SQLite / Parquet |
这个流程我跑了快两年,基本没出过问题。当然,数据源偶尔会变,接口偶尔会挂——这时候就需要你灵活应对了。
好了,数据获取这部分就讲到这里。记住:数据质量决定了因子上限。花80%的时间在数据上,20%的时间在策略上——这个比例,我觉得刚刚好。