一、波动率基础:什么是波动率?
各位同学,咱们今天聊聊波动率。说实话,我刚入行那会儿,觉得波动率就是个数字——涨涨跌跌嘛,算个标准差就完事了。后来在实盘里吃过亏,才明白这东西没那么简单。
波动率,说白了就是资产价格变动的剧烈程度。你想想看,一只股票今天涨5%,明天跌4%,后天又涨3%——这种上蹿下跳的走势,波动率就高。反过来,像国债那样每天波动不到0.1%,波动率就低。
核心定义:波动率是金融资产收益率的标准差,衡量价格的不确定性或风险程度。
1.1 波动率的金融意义
为什么我们要花一整章来讲波动率?因为它太重要了。我个人习惯把波动率比作金融市场的「心跳」——太快了说明市场恐慌,太慢了说明市场死气沉沉。
具体来说,波动率有这几个关键作用:
- 风险度量:波动率越高,资产风险越大。我在做风控模型时,第一件事就是看波动率曲线。
- 定价核心:期权定价公式里,波动率是唯一需要估计的变量。没有波动率,期权就没法定价。
- 市场情绪指标:VIX指数(恐慌指数)就是基于期权隐含波动率编制的。我记得2020年3月,VIX飙到80多,那真是市场最恐慌的时候。
- 资产配置依据:不同波动率的资产要搭配着来,不能全押在高波动品种上。
我的经验:做量化交易时,波动率不仅用来算风险,还能用来做择时。波动率低的时候往往酝酿着大行情,波动率极高的时候反而可能是反转信号。这个规律我验证过很多次。
1.2 波动率的数学定义
数学上,波动率就是收益率的标准差。假设我们有n个收益率数据 r₁, r₂, ..., rₙ,那么:
# 波动率的数学定义
# 收益率序列:r = [r₁, r₂, ..., rₙ]
# 均值:μ = (1/n) * Σrᵢ
# 方差:σ² = (1/(n-1)) * Σ(rᵢ - μ)²
# 波动率:σ = √σ²
这里要注意,我们通常用样本标准差(分母是n-1)而不是总体标准差。为什么?因为样本数据有限,用n-1能给出无偏估计。嗯,这个细节在实盘里挺重要的。
另外,波动率通常要年化。日波动率乘以√252(一年约252个交易日),周波动率乘以√52,月波动率乘以√12。我曾经犯过一个低级错误——直接用日波动率去对比年化波动率,结果差了一个数量级,被领导批评了一顿。
1.3 波动率的三种主要类型
实际工作中,我们主要接触三种波动率。它们各有各的用途,千万别搞混了。
| 类型 | 英文名 | 计算方式 | 主要用途 |
|---|---|---|---|
| 历史波动率 | Historical Volatility (HV) | 基于历史价格数据计算 | 回测、风险评估 |
| 隐含波动率 | Implied Volatility (IV) | 从期权市场价格反推 | 期权定价、市场情绪判断 |
| 已实现波动率 | Realized Volatility (RV) | 基于高频数据计算 | 高频交易、波动率预测 |
1.3.1 历史波动率
历史波动率是最基础的。就是用过去一段时间的价格数据,算个标准差。比如你想知道过去30天某只股票的波动率,那就取过去30天的日收益率,算标准差,再年化。
import numpy as np
import pandas as pd
def historical_volatility(prices, window=30, trading_days=252):
"""
计算历史波动率
prices: 价格序列
window: 滚动窗口大小
trading_days: 年化天数
"""
# 计算对数收益率
log_returns = np.log(prices / prices.shift(1))
# 滚动计算标准差并年化
hv = log_returns.rolling(window=window).std() * np.sqrt(trading_days)
return hv
这段代码我用了很多年。注意我用的对数收益率而不是简单收益率——对数收益率在时间上可加,数学性质更好。这是做量化的人都知道的小技巧。
避坑指南:我曾经用简单收益率算波动率,结果在回测里表现很好,实盘却对不上。后来发现是对数收益率和简单收益率在波动率计算上的差异导致的。建议统一用对数收益率。
1.3.2 隐含波动率
隐含波动率就有点意思了。它不是算出来的,而是从期权市场价格「反推」出来的。你想想看,期权价格里已经包含了市场对未来波动率的预期,我们把这个预期提取出来,就是隐含波动率。
具体做法是:把期权价格代入Black-Scholes公式,反解出波动率。因为BS公式里除了波动率,其他参数都是已知的(标的价格、行权价、到期时间、无风险利率)。
from scipy.optimize import brentq
from scipy.stats import norm
def implied_volatility(option_price, S, K, T, r, option_type='call'):
"""
计算隐含波动率
option_price: 期权市场价格
S: 标的价格
K: 行权价
T: 到期时间(年)
r: 无风险利率
"""
def bs_price(sigma):
d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
d2 = d1 - sigma*np.sqrt(T)
if option_type == 'call':
price = S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)
else:
price = K*np.exp(-r*T)*norm.cdf(-d2) - S*norm.cdf(-d1)
return price - option_price
# 用二分法求解
try:
iv = brentq(bs_price, 0.001, 5.0)
except:
iv = np.nan
return iv
这段代码里用了brentq算法来求解。为什么不用牛顿法?因为BS公式对波动率的导数在某些边界条件下不稳定,brentq更鲁棒。这是我踩过坑之后换的。
关键认知:隐含波动率反映的是市场对未来波动率的「预期」,而不是「历史」。所以它天然具有前瞻性,是预测波动率的重要参考指标。
1.3.3 已实现波动率
已实现波动率是高频交易领域的概念。它用日内的高频数据(比如5分钟、1分钟甚至逐笔数据)来度量当天的波动率。公式是:
# 已实现波动率(RV)的计算
# 假设一天内有m个等间隔的收益率数据
# RV = Σ(rᵢ²) 其中rᵢ是第i个区间的收益率
def realized_volatility(intraday_returns):
"""
计算已实现波动率
intraday_returns: 日内收益率序列
"""
rv = np.sum(intraday_returns**2)
return np.sqrt(rv)
已实现波动率的好处是,它比历史波动率更精确。历史波动率用日数据,一天只有一个点;已实现波动率用高频数据,一天可能有几十上百个点。信息量完全不一样。
我在做波动率预测模型时,最喜欢用已实现波动率作为「真实值」来训练模型。因为它的精度高,能捕捉到日内波动的细节。
我的建议:如果你刚开始做波动率研究,先别碰高频数据。从历史波动率入手,把基础概念搞扎实了,再逐步过渡到已实现波动率和隐含波动率。一步一个脚印,别贪快。
1.4 三种波动率的关系
这三种波动率不是孤立的。它们之间有关系,而且这个关系是波动率预测的核心逻辑。
这张图我画了很多遍。核心逻辑是:历史波动率提供「过去」的信息,隐含波动率提供「市场预期」的信息,已实现波动率提供「当前真实」的信息。一个好的预测模型,需要把这三种信息融合起来。
举个例子。假设某只股票的历史波动率是20%,隐含波动率是30%,已实现波动率是25%。这说明什么?市场预期未来波动会加大(IV > HV),而且当前确实在加大(RV > HV)。这时候你如果做空波动率,可能就要小心了。
总结一下:波动率不是玄学,它是可以用数学精确度量的金融变量。理解这三种波动率的定义、计算方法和用途,是构建波动率预测模型的第一步。后面的章节,我们会一步步深入。
公众号:蓝海资料掘金营,微信deep3321