3. 因子数据源接入:股票行情数据、财务数据、另类数据(舆情、新闻)的接入与清洗

因子数据源是量化因子库的“原材料”。不同数据源在接入方式、更新频率、数据质量上差异显著。本章聚焦三类核心数据源——股票行情数据、财务数据、另类数据(舆情/新闻),讲解其接入架构、清洗流程与质量校验方法。

3.1 数据源接入架构总览

一个稳健的因子库需要统一的数据接入层。下图展示了从原始数据到因子计算引擎的标准化接入流程。

因子数据源接入架构 股票行情数据 日/分钟/ Tick 财务数据 季报/年报/快报 另类数据 舆情/新闻/社交 统一数据接入层(API / FTP / 数据库直连) 定时调度 + 增量/全量同步 数据清洗与质量校验 去重 / 缺失处理 / 异常值 / 复权 / 对齐 因子库存储(Parquet / ClickHouse / HDF5)
架构要点:行情数据通常通过量化数据供应商 API 获取;财务数据依赖定期财报披露,需处理报告期与发布日期的时间差;另类数据非结构化程度高,需先做文本解析再进入清洗流程。

3.2 股票行情数据接入与清洗

3.2.1 接入方式

数据粒度 典型来源 接入协议 更新频率
日线 Wind / Tushare / AKShare HTTP API / SDK 每日盘后
分钟线 聚宽 / 米筐 / 掘金 WebSocket / REST 实时或盘后批量
Tick 级 交易所 Level-2 / 量化平台 TCP / 文件推送 实时流式

3.2.2 清洗核心步骤

  1. 复权处理:前复权与后复权选择。因子计算通常使用后复权价格,避免未来函数。
  2. 缺失值处理:停牌日填充前收盘价,新股上市首日特殊标记。
  3. 异常值过滤:涨跌幅超过阈值(如 ±20%)需人工复核或剔除。
  4. 时间对齐:不同交易所(沪深/北交所)交易日历统一,非交易日数据置空。
# 行情数据清洗示例(Python)
import pandas as pd

def clean_market_data(df: pd.DataFrame) -> pd.DataFrame:
    # 1. 复权调整(假设已获取复权因子)
    df['adj_close'] = df['close'] * df['adj_factor']
    # 2. 停牌填充
    df['adj_close'] = df['adj_close'].fillna(method='ffill')
    # 3. 异常涨跌幅过滤
    df['pct_chg'] = df['adj_close'].pct_change()
    df.loc[df['pct_chg'].abs() > 0.2, 'adj_close'] = None
    # 4. 按交易日对齐
    df = df[df['is_trading_day'] == True]
    return df.reset_index(drop=True)

3.3 财务数据接入与清洗

3.3.1 数据特点与接入难点

财务数据具有低频、滞后、跨表关联的特点。主要难点在于:

  • 报告期与发布日期不一致:季报通常在季度结束后 1 个月内发布,年报最长可延至 4 月底。
  • 会计准则差异:新旧准则(如新金融工具准则)导致科目名称和口径变化。
  • 合并报表与母公司报表:因子计算需明确使用哪个口径。

3.3.2 清洗流程

步骤 操作 说明
1 科目标准化 将不同来源的科目名映射到统一字典
2 时间戳对齐 使用报告期(fiscal_period)而非发布日期
3 TTM 计算 滚动十二个月数据,用于估值类因子
4 异常值检测 营收/利润突变超过 5 倍标准差需标记
5 行业中性化 财务指标按行业做标准化处理
# 财务数据 TTM 计算示例
def calc_ttm(fin_df: pd.DataFrame, current_q: str) -> dict:
    """
    计算指定报告期的 TTM 值
    current_q: 当前报告期,如 '2024Q3'
    """
    # 获取最近四个季度数据
    quarters = get_last_4_quarters(current_q)
    ttm_data = {}
    for col in ['revenue', 'net_profit']:
        ttm_data[col] = fin_df.loc[fin_df['quarter'].isin(quarters), col].sum()
    return ttm_data
避坑提示:财务数据中的“净利润”需区分“归母净利润”与“净利润总额”。多数估值因子(如 PE)使用归母口径。务必在清洗阶段明确标注口径来源。

3.4 另类数据(舆情/新闻)接入与清洗

3.4.1 数据源分类

  • 新闻数据:财经门户(东方财富、新浪财经)、专业金融终端(Bloomberg、Reuters)
  • 舆情数据:社交媒体(微博、雪球、股吧)、研报摘要
  • 另类结构化数据:卫星图像、电商数据、供应链数据(需专业供应商)

3.4.2 接入与清洗流程

另类数据清洗的核心是从非结构化文本中提取情感分数和实体关联。

另类数据清洗流程 原始文本采集 API / 爬虫 / RSS 文本预处理 分词 / 去停用词 / 实体识别 情感分析 NLP 模型 / 词典打分 因子化 情感分数 清洗要点 去重(相同新闻多源转发)→ 时间戳归一化(精确到秒)→ 股票代码关联(实体链接)

3.4.3 情感分数计算示例

# 基于词典的舆情情感打分(简化版)
import re

positive_words = ['利好', '增长', '突破', '盈利', '超预期']
negative_words = ['利空', '下跌', '亏损', '风险', '不及预期']

def sentiment_score(text: str) -> float:
    pos_count = sum(1 for w in positive_words if w in text)
    neg_count = sum(1 for w in negative_words if w in text)
    total = pos_count + neg_count
    if total == 0:
        return 0.0  # 中性
    return (pos_count - neg_count) / total  # 范围 [-1, 1]

# 示例
news = "公司三季度盈利超预期,营收增长突破历史新高"
print(f"情感分数: {sentiment_score(news):.2f}")  # 输出: 0.60

3.5 数据质量校验清单

无论哪种数据源,接入后必须通过以下质量校验:

校验项 行情数据 财务数据 另类数据
完整性 交易日无缺失 报告期连续 时间戳完整
一致性 OHLC 关系校验(H≥L, C≥L) 资产负债表平衡 同一新闻去重
时效性 盘后 30 分钟内更新 财报发布后 24h 入库 实时流延迟 < 5s
异常值 涨跌幅 > 20% 标记 营收突变 > 5σ 标记 情感分数超出 [-1,1] 剔除
最佳实践:建立数据质量监控看板,每日自动运行校验脚本,异常数据通过邮件/钉钉告警。因子库的可靠性取决于数据清洗的严谨程度,而非因子数量。