4. 金融数据采集与预处理:数据源介绍、数据清洗、数据标准化
做量化投资,最怕什么?
不是策略失效,而是数据造假。我见过太多团队,模型跑得飞起,结果一查底层数据全是错的。嗯,今天我们就来聊聊金融数据的源头活水,以及怎么把这些「脏水」过滤成能喝的「纯净水」。
4.1 三大核心数据源:财报、新闻、公告
我个人习惯把金融数据分成三类:结构化数据(财报)、半结构化数据(公告)、非结构化数据(新闻)。这三类数据,缺一不可。
4.1.1 财报数据
财报是量化投资的「地基」。你想想看,没有准确的营收、利润、现金流,你的估值模型就是空中楼阁。
- 来源:巨潮资讯网、上交所/深交所官网、Wind、Choice
- 频率:季报(4月底前)、中报(8月底前)、年报(次年4月底前)
- 关键字段:营业收入、净利润、每股收益、净资产收益率、经营活动现金流
⚠️ 避坑指南
我曾经在回测中发现某公司连续5年ROE都超过20%,结果一查,原来是「出售子公司」带来的非经常性损益。所以,我建议你一定要区分「扣非净利润」和「归母净利润」。
4.1.2 新闻数据
新闻数据是「情绪指标」。说白了,市场有时候是非理性的。一条负面新闻能让股价跌停,一条利好能拉涨停。
- 来源:东方财富、新浪财经、财联社、Reuters、Bloomberg
- 特点:高频、海量、噪音大
- 处理难点:情感分析、实体识别、事件抽取
💡 我的经验
做新闻舆情因子时,别只看标题。正文里的「但是」、「然而」这类转折词,往往藏着真正的市场态度。我习惯用BERT模型做细粒度情感分析,准确率能到85%以上。
4.1.3 公告数据
公告是「事件驱动」的核心。分红、配股、重组、减持、质押……每一个动作都可能引发股价波动。
- 来源:交易所官网、上市公司公告
- 类型:定期公告、临时公告、澄清公告
- 关键事件:业绩预告、股权激励、限售股解禁、股东增减持
4.2 数据清洗:把脏数据「洗白」
数据清洗,说白了就是「去伪存真」。我接手过一个项目,原始数据里居然有「2023年2月30日」这种日期。你想想看,这种数据不洗掉,模型能准吗?
4.2.1 常见脏数据类型
| 类型 | 示例 | 处理方法 |
|---|---|---|
| 缺失值 | 某季度财报缺失 | 前向填充、插值、删除 |
| 异常值 | 市盈率突然变成-9999 | 3σ原则、IQR方法 |
| 重复值 | 同一条新闻被爬取3次 | 去重(基于MD5或SimHash) |
| 格式错误 | 日期格式不统一 | 正则表达式统一格式化 |
4.2.2 清洗实战代码
我习惯用Pandas做数据清洗,效率很高。给你看一段我常用的代码:
import pandas as pd
import numpy as np
# 加载原始财报数据
df = pd.read_csv('financial_data.csv')
# 1. 处理缺失值:前向填充
df['revenue'] = df['revenue'].fillna(method='ffill')
# 2. 处理异常值:剔除超过3个标准差的
z_scores = np.abs((df['pe_ratio'] - df['pe_ratio'].mean()) / df['pe_ratio'].std())
df = df[z_scores < 3]
# 3. 去重:基于股票代码和报告期
df = df.drop_duplicates(subset=['stock_code', 'report_date'])
# 4. 日期格式化
df['report_date'] = pd.to_datetime(df['report_date'], format='%Y-%m-%d')
print(f"清洗后数据量:{len(df)} 条")
⚠️ 注意
我曾经犯过一个错误:直接用均值填充缺失的营收数据。结果导致某家ST公司的「营收」被高估,模型误判为优质股。后来我改用「行业均值+公司历史趋势」的方式填充,效果好了很多。
4.3 数据标准化:让不同量纲的数据「对齐」
数据标准化,说白了就是让「茅台」和「工商银行」的股价能放在一起比较。你想想看,茅台股价1800元,工行股价5元,直接做回归分析,工行的权重几乎被忽略。
4.3.1 常用标准化方法
| 方法 | 公式 | 适用场景 |
|---|---|---|
| Z-score标准化 | (x - μ) / σ | 数据近似正态分布 |
| Min-Max标准化 | (x - min) / (max - min) | 数据有明确边界 |
| 对数变换 | log(x) | 数据偏态分布(如市值) |
| 排名标准化 | rank(x) / N | 异常值较多时 |
4.3.2 标准化代码示例
from sklearn.preprocessing import StandardScaler, MinMaxScaler
import numpy as np
# 假设我们有市值数据
market_cap = np.array([100, 500, 1000, 5000, 10000]).reshape(-1, 1)
# Z-score标准化
scaler = StandardScaler()
z_score_data = scaler.fit_transform(market_cap)
# Min-Max标准化
minmax_scaler = MinMaxScaler()
minmax_data = minmax_scaler.fit_transform(market_cap)
# 对数变换(处理偏态)
log_data = np.log(market_cap)
print("原始数据:", market_cap.flatten())
print("Z-score:", z_score_data.flatten().round(2))
print("Min-Max:", minmax_data.flatten().round(2))
print("对数变换:", log_data.flatten().round(2))
💡 我的建议
做多因子模型时,我习惯用「排名标准化」。为什么?因为金融数据里异常值太多了——比如某天股价突然跌了90%,Z-score会把这个异常值放大,而排名标准化能很好地抑制这种影响。
4.4 知识图谱视角下的数据预处理
作为知识图谱专家,我想强调一点:数据预处理不只是「清洗」和「标准化」,更重要的是「实体对齐」和「关系抽取」。
- 实体对齐:同一家公司,财报里叫「贵州茅台」,新闻里叫「茅台」,公告里叫「600519.SH」。这三者必须映射到同一个实体节点。
- 关系抽取:从新闻中提取「公司A」与「公司B」的「合作」关系,或者「股东C」对「公司D」的「减持」动作。
- 时间对齐:财报是季度数据,新闻是分钟级数据。如何把不同频率的数据对齐到同一个时间轴?我通常用「事件窗口法」——以财报发布日为T日,向前向后各取30天。
⚠️ 避坑指南
我曾经在构建知识图谱时,把「阿里巴巴」和「阿里健康」当成同一个实体。结果导致关系推理完全错误。所以,实体消歧这一步,千万别偷懒。
4.5 本章知识体系图
好了,这一章的内容就到这里。数据预处理是量化投资的「脏活累活」,但也是最重要的环节。记住一句话:垃圾进,垃圾出。把数据搞干净了,你的模型才能跑得稳。