股票/期货/期权历史波动率测算方法汇总


文章仅分享了波动率测算代码实例,尚未完成波动率对比

一、close to close

公式:
σ ^ = ∑ i = 1 N ( r i − μ ) 2 N \hat\sigma=\sqrt{\frac{\sum_{i=1}^{N}(r_i-\mu)^2}{N}} σ^=Ni=1N(riμ)2

二、Parkinson 1980. aka High low HV

公式:
σ ^ p a r k i n s o n _ N = 1 4 N l n 2 ∑ i = 1 N l n ( H i L i ) 2 \hat{\sigma}_{parkinson\_N}= \sqrt{\frac{1}{4Nln2}\sum_{i=1}^{N}{ln (\frac{H_i}{L_i})^2}} σ^parkinson_N=4Nln21i=1Nln(LiHi)2
H i H_i Hi为最高价, L i L_i Li为最低价。

Python代码如下:

def calculate_parkinson_volatility(data, col_high, col_low, period, trading_periods=252,ori=1):
    #计算parkinson_volatility
    #参数为:data数据列;col_high:最高价列列名;col_low:最低价列列名;n:计算周期;ori:数据日期方向,1降序,-1升序,默认降序。
    rs = (1.0 /(4.0*np.log(2)))*((data[col_high] / data[col_low]).apply(np.log))** 2 #求和项内数据
    
    def f(v):
        return (trading_periods * v.mean())**0.5
    
    #计算parkinson_volatility
    if ori == 1:
        volatility = rs.rolling(window=period,center=False).apply(func=f).shift(-period+1)
        
    elif ori == -1:
        volatility = rs.rolling(window=period,center=False).apply(func=f)
    else:
        print("请检查数据为升序/降序")
        
    return volatility

三、Garman&Klass 波动率

公式:
σ N = 1 2 N [ ∑ i = 1 N l n ( H i L i ) 2 − 2 ( 2 l n 2 − 1 ) ∑ i = 1 N l n ( C i O i ) 2 ] \sigma_N = \sqrt{\frac{1}{2N}[\sum_{i=1}^{N}{ln (\frac{H_i}{L_i})^2}-2(2ln2-1)\sum_{i=1}^{N}{ln (\frac{C_i}{O_{i}})^2}]} σN=2N1[i=1Nln(LiHi)22(2ln21)i=1Nln(OiCi)2]
H i H_i Hi为最高价, L i L_i Li为最低价, C i C_i Ci为最高价, O i O_i Oi为最低价。

Python代码如下:

def calculate_garman_klass_volatility(data, col_high, col_low, col_close,col_open, period,trading_periods=252,ori=1):
    # 计算garman_klass_volatility
    # 参数为:data数据列;col_high:最高价列列名;col_low:最低价列列名;col_close;收盘价列名称;col_open:开盘价列名
    # n:计算周期;ori:数据日期方向,1降序,-1升序,默认降序。
    log_hl = np.log(data[col_high] / data[col_low])  # 最高价和最低价的对数差平方
    log_co = np.log(data[col_close]/ data[col_open]) # 收盘价的对数差平方

    rs = 0.5 * log_hl**2 - (2*np.log(2)-1) * log_co**2
    
    def f(v):
        return (trading_periods * v.mean())**0.5

    # 计算Garman-Klass波动率
    if ori == 1:
        volatility = rs.rolling(window=period).apply(f).shift(-period+1)
    elif ori == -1:
        volatility = rs.rolling(window=period)
    else:
        print("请检查数据为升序/降序")
    return volatility

四、 Rogers & Satchell 波动率

公式:
σ N = 1 N ∑ i = 1 N [ l n ( H i L i ) l n ( H i O i ) + l n ( L i C i ) l n ( L i O i ) ] \sigma_N = \sqrt{\frac{1}{N}\sum_{i=1}^{N}{[ln (\frac{H_i}{L_i})ln (\frac{H_i}{O_i})+ln (\frac{L_i}{C_i})ln (\frac{L_i}{O_i})]}} σN=N1i=1N[ln(LiHi)ln(OiHi)+ln(CiLi)ln(OiLi)]
H i H_i Hi为最高价, L i L_i Li为最低价, C i C_i Ci为最高价, O i O_i Oi为最低价。

Python代码如下:

def calculate_rogers_satchell_volatility(data, col_high, col_low, col_close, col_open, period, trading_periods=252,ori=1):
    # 计算rogers_satchell_volatility
    # 参数为:data数据列;col_high:最高价列列名;col_low:最低价列列名;col_close;收盘价列名称;col_open:开盘价列名
    # n:计算周期;ori:数据日期方向,1降序,-1升序,默认降序。
    log_hc = np.log(data[col_high]/data[col_close]) # high/close
    log_ho = np.log(data[col_high]/data[col_open])  # high/open
    log_lc = np.log(data[col_low]/data[col_close]) # low/close
    log_lo = np.log(data[col_low]/data[col_open])  # low/open
    
    rs = log_hc*log_ho +log_lc*log_lo
    
    def f(v):
        return (trading_periods * v.mean())**0.5
    
    if ori == 1:
        volatility = rs.rolling(window=period,center=False).apply(func=f).shift(-period+1)
    elif ori == -1:
        volatility = rs.rolling(window=period,center=False).apply(func=f)
    else:
        print("请检查数据为升序/降序")
    return volatility

五、小结

  • 需要注意的是:上述公式仅计算了日波动率,一般报告年波动率,所以需要使用交易日期,进行相应调整,即:乘上trading periods(252)的平方根。
  • 关于各种波动率的对比,可参考文章:[【Option 101】【未完成】历史波动率的不同度量方法]。(https://blog.csdn.net/AdamNi_NintyNine/article/details/122808220)
    本人也才刚开始学习,暂时不知哪种方法测算波动率更实用,后续学习填坑。
  • github上也有现成的包:volatility-trading,可以直接用现成的代码包。为了方便后续使用,本次项目仅参考其中核心计算部分代码并进行一定修改,有对比过测算结果,结果一致。

六、测算实例

以螺纹钢为例,分别使用三种方法测算螺纹钢的波动率,并画图:

import pandas as pd
import numpy as np
data = pd.read_excel("黑色能化量价数据.xlsx",index_col=0)

def calculate_parkinson_volatility(data, col_high, col_low, period, trading_periods=252,ori=1):
    #计算parkinson_volatility
    #参数为:data数据列;col_high:最高价列列名;col_low:最低价列列名;n:计算周期;ori:数据日期方向,1降序,-1升序,默认降序。
    rs = (1.0 /(4.0*np.log(2)))*((data[col_high] / data[col_low]).apply(np.log))** 2 #求和项内数据
    
    def f(v):
        return (trading_periods * v.mean())**0.5
    
    #计算parkinson_volatility
    if ori == 1:
        volatility = rs.rolling(window=period,center=False).apply(func=f).shift(-period+1)
        
    elif ori == -1:
        volatility = rs.rolling(window=period,center=False).apply(func=f)
    else:
        print("请检查数据为升序/降序")
        
    return volatility

col_close = data.columns[3]
col_high = data.columns[2]
col_low = data.columns[1]
col_open = data.columns[0]

period_list = [5,20,120]
name ="螺纹钢"
for period in period_list:
    col_volatility_name = name + ":"+str(period)+"日parkinson波动率"
    data[col_volatility_name] = calculate_parkinson_volatility(data, col_high, col_low, period, ori=1)

通过上述代码计算得到Parkinson波动率,画图如下:

parkinson波动率

螺纹钢Parkinson波动率

类似的可以得到:

garmen&klass波动率

螺纹钢garmen&klass波动率

rogers&satchell波动率

螺纹钢rogers&satchell波动率
最后汇总对比三种波动率

三种波动率汇总

三种波动率对比汇总
完整实例见代码包附件

### 历史波动率的概念 历史波动率是一种衡量资产价格在过去一段时间内的变化程度的指标。它反映了标的资产价格的实际变动情况,因此也被称作实际波动率或统计波动率[^1]。 ### 如何计算期权历史波动率 #### 数据准备 为了计算历史波动率,首先需要收集标的资产的一段时间内的每日收盘价数据。这些数据可以来自金融市场的公开资源或者特定的数据提供商。具体来说,可以选择日线级别的收盘价作为输入数据源[^3]。 #### 计算收益率 基于所获取的日收盘价序列 \( P_t \),可以通过以下公式来计算每天的对数收益率: \[ r_t = \ln(P_t / P_{t-1}) \] 其中: - \( r_t \) 表示第 t 天的对数收益率; - \( P_t \) 和 \( P_{t-1} \) 分别代表第 t 天和前一交易日的收盘价。 这一过程的结果是一个由多个收益率组成的数组,用于后续的标准差计算。 #### 标准差计算 接着,利用上述得到的收益率数组,求取其标准差。这是评估价格波动的核心部分之一。假设收益率序列为 \( R = [r_1, r_2, ..., r_n] \),则样本标准差可按如下方式定义: \[ \sigma = \sqrt{\frac{1}{n-1}\sum_{i=1}^{n}(r_i-\bar{r})^2} \] 这里: - \( n \) 是观测值的数量; - \( \bar{r} \) 是平均收益率。 该标准差即为年化之前的历史波动率。 #### 年化处理 由于原始标准差反映的是每日波动幅度,而市场参与者更关心年度化的波动水平,所以还需要进一步将其转换成年化形式。一般情况下,股票市场每年约有 252个交易日(除去节假日),故可通过乘以\( \sqrt{252} \) 来实现年化调整: \[ HV_{annualized} = \sigma * \sqrt{252} \] 这样就得到了最终的历史波动率数值。 ```python import numpy as np def calculate_hv(prices): returns = np.log(prices / prices.shift(1)).dropna() std_dev = returns.std() * np.sqrt(252) return std_dev # Example usage with a list of closing prices closing_prices = [100, 101, 102, 101.5, 103] historical_volatility = calculate_hv(pd.Series(closing_prices)) print(f"Historical Volatility: {historical_volatility}") ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值