大家可能都听说过:“富贵险中求”,“高风险高收益”,这些说法虽不太严谨,但也表述了一个基本原理——获取高收益的背后必然需要承担相应的风险。
收益容易理解,该如何定义和衡量风险呢?
诺贝尔经济学奖获得者马科维茨在20世纪50年代提出了一个经典的“现代资产组合理论”,其中以资产收益率的方差或标准差来代表风险(在统计学中,方差、标准差用来计算一组数据跟平均值之间的偏离程度,比如统计一只股票近1年收盘价的方差,价格振幅越大方差值就越大)。这一经典理论从此打开了量化投资的大门,被金融行业沿用至今。
在此基础上,又有其他大神发明了更多衡量“风险——收益”均衡程度的考核指标,比如夏普比率、索提诺比率等等。老基民应该都知道买基金不能只看收益率,还要看夏普比率,同类型基金中夏普比率越高者持仓体验越好。
长期来看,低波动资产通常会有比高波动资产更高的风险调整后回报(即夏普比率或卡玛比率),量化术语叫做低波动性异象(Low Volatility Anomaly),这一现象违反了传统的金融理论的说法;高风险应当伴随高回报。低波动性异象的存在有几个可能的原因:
-
投资者行为偏差:许多投资者对于风险的追求导致他们偏爱那些具有高波动性的资产,因为这些资产被公认为有更大的获利潜力。这种追求高风险、高回报的心理可能导致低波动性股票被低估,从而在长期内提供了超出其风险水平的回报。
-
限制性投资政策:一些机构投资者,如养老基金和保险公司,可能受到投资政策的限制,使得他们不能投资于波动性较低的股票。此外,追求绝对回报的基金可能更偏好使用杠杆来提高高波动性股票的回报,从而忽略了低波动性股票。
-
信息不对称:低波动性股票往往是那些不太被市场关注的股票。较少的分析和媒体报道可能意味着这些股票的信息不对称程度较高,因此它们可能被市场低估。
-
流动性差异:低波动性股票可能具有较低的交易量和流动性,这意味着大型投资者可能难以在没有影响价格的情况下买入或卖出这些股票。因此,这些股票可能因为流动性折扣而被低估。
综上所述,低波动性异象的存在可能是多种因素综合作用的结果,包括投资者行为的非理性因素、市场和机构的结构性限制以及金融模型的局限性等。
以下是一些常用的波动性因子指标:
-
Beta系数 (β):Beta系数衡量的是一个资产相对于整个市场(通常是一个广泛的市场指数,如S&P500)的波动性。Beta值大于1表示资产的价格波动性高于市场平均水平;小于1表示低于市场平均水平。
-
历史波动率:根据过去的价格变动来计算的波动性指标,通常是通过计算一定时间窗口内的日收益率的标准差来得出。
-
隐含波动率:从期权价格中反推出来的预期波动率,它反映了市场参与者对未来资产价格波动性的预期。隐含波动率通常通过布莱克-斯科尔斯模型或其他期权定价模型计算得出。
下面详细介绍一下最常用的历史波动率指标计算:
import akshare as ak
import pandas as pd
import numpy as np
# 获取沪深300指数近5年的日收盘价数据
index_code = "sh000300" # 沪深300指数的代码
# 使用akshare获取指数日线数据
index_daily_df = ak.stock_zh_index_daily_tx(symbol=index_code)
# 计算日收益率
index_daily_df['return'] = index_daily_df['close'].pct_change()
# 过滤上面df中date列范围
end_date = pd.Timestamp.now() # 当前日期
start_date = end_date - pd.DateOffset(years=1) # 1年前的日期
y1_index_daily_df = index_daily_df[
(index_daily_df['date'] >= start_date) & (index_daily_df['date'] <= end_date)]
# 计算近1年日收益率的标准差(波动率)
daily_volatility = y1_index_daily_df['return'].std() * 100
# 年化波动率
annualized_volatility = daily_volatility * np.sqrt(252)
print(f"沪深300指数近1年的日波动率为: {daily_volatility}%")
print(f"沪深300指数近1年的年化波动率为: {annualized_volatility}%")
如果认为日内最高价、最低价比仅仅使用收盘价更能反映市场的波动性,可以进一步使用Parkinson波动率公式来计算:
def calculate_parkinson_volatility(df):
# 计算每日波动率
daily_volatility = np.sqrt((1 / (4 * np.log(2))) * np.mean(np.log(df['high'] / df['low']) ** 2))
# 年化波动率
annualized_volatility = daily_volatility * np.sqrt(252) * 100
return annualized_volatility
# 调用函数计算parkinson年化波动率
annualized_vol = calculate_parkinson_volatility(y1_index_daily_df)
print(f"年化Parkinson波动率为: {annualized_vol}%")
计算每天的近1年滚动年化波动率,并用折线图展示:
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei'] #用来在图中正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来在图中正常显示负号
# 计算每天的近1年波动率
rolling_window = 252
index_daily_df['vix'] = index_daily_df['return'].rolling(window=rolling_window).std() * np.sqrt(rolling_window)
# 绘制波动率的折线图
plt.figure(figsize=(14, 7))
plt.plot(index_daily_df['date'], index_daily_df['vix'])
plt.title('沪深300指数每日滚动年化波动率')
# index_daily_df['vix'].plot(title='沪深300指数近1年每天的波动率')
plt.xlabel('日期')
plt.ylabel('年化波动率')
plt.grid(True)
plt.show()