数据准备与清洗:打好VaR计算的地基

说实话,做投资组合VaR计算,最让我头疼的往往不是模型本身,而是数据。我见过太多人一上来就调参数、跑模型,结果数据源里一堆坑——缺失值、异常值、复权没处理好……最后算出来的VaR,你敢信吗?

我个人习惯,花在数据清洗上的时间,至少占整个项目的40%。别嫌多,这很值。今天我们就聊聊这块硬骨头怎么啃。

获取金融时间序列数据

数据源的选择,直接决定了后续工作的质量。我常用的几个渠道:

  • 免费数据源:Yahoo Finance、Quandl(部分免费)、Tushare(国内股票)
  • 商业数据源:Wind、Bloomberg、Reuters——贵,但数据质量有保障
  • 自建数据仓库:公司内部ETL,我最推荐的方式,可控性最强

举个例子,用Python从Yahoo拉数据,代码很简单:

import yfinance as yf
import pandas as pd

# 获取股票数据
tickers = ['AAPL', 'MSFT', 'GOOGL']
data = yf.download(tickers, start='2020-01-01', end='2023-12-31')
prices = data['Adj Close']  # 用复权价格

嗯,这里要注意。我建议始终使用复权价格。为什么?因为分红、拆股会影响价格连续性。我曾经有个项目,直接用原始价格算收益率,结果VaR低估了将近15%——就是因为没处理分红除权。

⚠️ 避坑指南:我曾经遇到过某只股票在2018年有一次1:10的拆股,原始价格直接从1000跌到100。如果不做复权处理,那天的收益率就是-90%,VaR直接炸了。

处理缺失值与异常值

金融数据里,缺失值太常见了。停牌、节假日、数据源故障……你想想看,如果直接dropna,可能会丢掉很多信息。

我的处理策略分三步:

  1. 识别缺失模式:是随机缺失,还是结构性缺失?
  2. 选择填充方法:前向填充、插值、还是用行业均值?
  3. 验证填充效果:填充后分布有没有明显偏移?

代码实现:

# 前向填充(最常用)
prices.fillna(method='ffill', inplace=True)

# 线性插值(适合短期缺失)
prices.interpolate(method='linear', inplace=True)

# 检查缺失比例
missing_ratio = prices.isnull().sum() / len(prices)
print(f"缺失比例: {missing_ratio}")

至于异常值,我一般用两种方法:

  • Z-score法:超过3倍标准差,标记为异常
  • IQR法:低于Q1-1.5*IQR或高于Q3+1.5*IQR,视为异常
💡 个人经验:别一看到异常值就删。有一次我发现某只股票连续3天涨跌幅超过10%,以为是数据错误,结果一查——是公司发布了重大并购公告。所以,先查原因,再决定处理方式。

收益率计算:简单收益率 vs 对数收益率

这是VaR计算的核心环节。两种收益率,各有各的适用场景。

类型 公式 优点 缺点
简单收益率 R_t = (P_t - P_{t-1}) / P_{t-1} 直观,容易理解 不可加性,多期计算麻烦
对数收益率 r_t = ln(P_t / P_{t-1}) 可加性,近似正态分布 小收益率时近似相等

我个人习惯,做VaR计算时首选对数收益率。原因很简单:对数收益率在时间上可加,而且更接近正态分布——这对VaR的假设很重要。

代码实现:

# 简单收益率
simple_returns = prices.pct_change().dropna()

# 对数收益率
log_returns = np.log(prices / prices.shift(1)).dropna()

# 对比一下分布
print(f"简单收益率偏度: {simple_returns.skew().mean():.4f}")
print(f"对数收益率偏度: {log_returns.skew().mean():.4f}")

你看,对数收益率的偏度通常更接近0,也就是更对称。这对VaR建模来说,是个好消息。

数据可视化与初步分析

数据清洗完了,别急着建模。先画图看看,心里有个底。

我一般会做三张图:

  • 价格走势图:看整体趋势和波动
  • 收益率分布直方图:看是否正态,有没有厚尾
  • 相关性热力图:看资产之间的联动关系

代码示例:

import matplotlib.pyplot as plt
import seaborn as sns

# 1. 价格走势
prices.plot(figsize=(12, 6), title='资产价格走势')
plt.show()

# 2. 收益率分布
log_returns.hist(bins=50, figsize=(12, 6), alpha=0.7)
plt.title('对数收益率分布')
plt.show()

# 3. 相关性热力图
corr_matrix = log_returns.corr()
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm')
plt.title('资产收益率相关性')
plt.show()
🔑 核心要点:数据可视化不是走过场。我曾在一次项目中,通过热力图发现两只“看起来不相关”的股票,相关系数竟然高达0.85——后来一查,它们同属一个供应链。这个发现直接改变了我的分散化策略。

知识体系总览

下面这张图,是我自己梳理的数据准备与清洗流程。你看一眼,心里就有谱了。

数据准备与清洗流程 数据获取 Yahoo / Wind / 自建 缺失值处理 前向填充 / 插值 异常值检测 Z-score / IQR 收益率计算 简单 vs 对数收益率 可视化分析 走势图 / 分布 / 相关性 ✅ 干净数据输出 关键检查点 ✓ 复权价格处理 ✓ 缺失比例 < 5% ✓ 异常值原因排查 ✓ 收益率分布检验

这张图把整个流程串起来了。你从数据获取开始,一步步往下走,最后拿到干净的数据。每一步都有对应的处理方法和检查点。

📌 我的小习惯:每次做完数据清洗,我都会保存一份清洗日志。记录哪些数据被填充了、哪些异常值被处理了、处理方式是什么。这样万一结果有问题,我能快速回溯。说白了,就是给自己留条后路。

好了,数据准备这块就聊到这儿。记住一句话:垃圾进,垃圾出。数据质量不过关,再牛的VaR模型也是白搭。


公众号:蓝海资料掘金营,微信deep3321