数据准备与清洗:打好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,可能会丢掉很多信息。
我的处理策略分三步:
- 识别缺失模式:是随机缺失,还是结构性缺失?
- 选择填充方法:前向填充、插值、还是用行业均值?
- 验证填充效果:填充后分布有没有明显偏移?
代码实现:
# 前向填充(最常用)
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——后来一查,它们同属一个供应链。这个发现直接改变了我的分散化策略。
知识体系总览
下面这张图,是我自己梳理的数据准备与清洗流程。你看一眼,心里就有谱了。
这张图把整个流程串起来了。你从数据获取开始,一步步往下走,最后拿到干净的数据。每一步都有对应的处理方法和检查点。
📌 我的小习惯:每次做完数据清洗,我都会保存一份清洗日志。记录哪些数据被填充了、哪些异常值被处理了、处理方式是什么。这样万一结果有问题,我能快速回溯。说白了,就是给自己留条后路。
好了,数据准备这块就聊到这儿。记住一句话:垃圾进,垃圾出。数据质量不过关,再牛的VaR模型也是白搭。
公众号:蓝海资料掘金营,微信deep3321