第三章:因子数据获取——用Python搞定行情、财务与宏观数据

做因子投资,最头疼的事是什么?

我个人觉得,不是策略设计,也不是回测优化,而是——数据。数据拿不到、拿不全、拿不准,后面全是白搭。我在2018年刚开始做多因子模型时,就吃过这个亏。当时从某数据商买来的财务数据,居然有30%的缺失值,回测结果漂亮得不像话,实盘却一塌糊涂。

嗯,从那以后,我对数据获取这件事,再也不敢马虎。

3.1 行情数据:最基础也最讲究

行情数据,说白了就是价格和成交量。但这里有个坑:你拿到的复权价格,到底对不对?

注意: 大部分免费接口提供的是前复权数据。前复权适合看历史走势,但做因子计算时,我建议用后复权或不复权数据。为什么?前复权会改变历史价格,导致你的因子值失真。

我个人习惯用 aksharetushare 两个库。前者免费,后者部分数据需要积分。给你看个例子:

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

这里有个小技巧:我一般会同时拉取复权因子,自己算后复权价格。这样数据更可控。

我的经验: 行情数据最好每天增量更新,别一次性拉全量。我曾经一次性拉5年数据,结果被接口封了IP。现在我的做法是:每天收盘后跑一次增量更新脚本,只拉当天的数据。

3.2 财务数据:因子挖掘的富矿

财务数据是基本面因子的核心来源。市盈率、市净率、ROE、毛利率……这些因子都来自财务报表。

但财务数据有个特点:发布滞后。一季报在4月底才出完,年报可能拖到次年4月。如果你用最新财报数据做因子,其实已经过时了。

我建议的做法是:

  • tusharefinancial 接口获取原始报表数据
  • 自己计算财务指标,而不是直接用别人算好的
  • 做「财报日期对齐」,确保因子值用的是当时可获取的数据
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
核心要点: 财务数据一定要做「前瞻性调整」。比如你在2023年5月计算因子,应该用2023年一季报的数据,而不是2022年年报。很多新手在这里犯错,导致因子失效。

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 数据清洗与对齐:真正的功夫在这里

数据拿到手,只是第一步。真正的难点在于:如何把不同频率、不同来源的数据对齐到同一个时间轴上

行情数据是日频,财务数据是季频,宏观数据可能是月频。你要把它们全部对齐到每个交易日。

我常用的方法:

  1. 向前填充:财务数据在发布日之后,一直沿用直到下一期发布
  2. 线性插值:对于宏观数据,可以用前后值做线性插值
  3. 滚动窗口:计算过去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 本章知识体系

下面这张图,是我做数据获取时的整体思路。你可以把它当成一个检查清单:

因子数据获取体系 行情数据 财务数据 宏观数据 akshare / tushare 东方财富 / 新浪 复权处理 tushare financial Wind / 聚宽 财报日期对齐 国家统计局 akshare macro FRED数据库 数据清洗与对齐 因子计算就绪

这张图的核心逻辑是:三大数据源各自获取后,统一进入「数据清洗与对齐」环节,最后才能用于因子计算。跳过这一步,你的因子就是垃圾。

3.6 我的数据获取工作流

最后,分享一个我目前在用的工作流。不一定适合所有人,但你可以参考:

步骤 内容 频率 工具
1 拉取全市场日线行情 每日收盘后 akshare
2 更新财务数据(季报/年报) 财报发布日 tushare pro
3 获取宏观数据 每月/每周 akshare macro
4 数据对齐与清洗 每次更新后 pandas
5 存储到本地数据库 每次更新后 SQLite / Parquet

这个流程我跑了快两年,基本没出过问题。当然,数据源偶尔会变,接口偶尔会挂——这时候就需要你灵活应对了。

一个小建议: 别把所有鸡蛋放在一个篮子里。我通常会同时用2-3个数据源做交叉验证。如果某个数据源的数据和其他两个对不上,我就知道有问题了。

好了,数据获取这部分就讲到这里。记住:数据质量决定了因子上限。花80%的时间在数据上,20%的时间在策略上——这个比例,我觉得刚刚好。

专注资料整理