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


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

一、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波动率
最后汇总对比三种波动率

三种波动率汇总

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

猜你喜欢

转载自blog.csdn.net/jojojuejue/article/details/131184409