金融时间序列是金融市场的一个重要组成部分。在研究金融市场的各种现象以及对进行建模时,金融时间序列的描述性统计分析都是一项基础的且必不可少的工作。
本章主要介绍描述性统计分析的相关知识,并且利用python进行量化。
对于金融时间序列,本章主要通过几何布朗运动模拟的时间序列以及沪深300指数的时间序列进行分析。
波动率是分析期权和衍生品的重要概念。这里介绍一下几个波动率的概念。
历史波动率:
指的是一个金融时间序列对数收益率的标准差。
计算历史收益率时,首先计算序列的对数收益率:
针对资产的对数收益率求平均数:
然后对历史波动率进行求解:
瞬时波动率:
瞬时波动率是指一个扩散过程的波动率因子。在BS模型中,瞬时波动率σ可以在随机微分方程中得到:
BSM的随机微分方程:dSt=rStdt+σStdZt
偏度:
用于测度样本对于其均值的位置。
对于n个样本值的偏度,计算方法如下:
这里 xi 是第i个样本,, sd是样本标准差. g1 是总体偏度的有偏估计。
峰度:
峰度用于测度分布的峰度以及分为的尾部大小。
import math
import numpy as np
import pandas as pd
import scipy.stats as scs
import statsmodels.api as sm
import matplotlib as mpl
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 标准正态分布的概率密度函数
# 假设x服从正态分布,即x~N(mu,sigma**2)
# z=(x-mu)/sigma则服从标准正态分布,即z~N(0,1)
def dN(x,mu,sigma):
"' mu:期望值,sigma:标准差,pdf:概率密度函数'"
z=(x-mu)/sigma
pdf=np.exp(-0.5*z**2)/math.sqrt(2*math.pi*sigma**2)
return pdf
#几何布朗运动模型
# BSM的随机微分方程:dSt=r*St*dt+σ*St*dZt
def simulate_gbm():
# model parameters
S0 = 2.7 #标的资产价格
T = 1 # 到期期限
r = 0.05 # 无风险利率
vol = 0.2 # 瞬时波动率
# 参数模拟
np.random.seed(250000)
rng = pd.date_range('2016-09-07','2020-06-30', freq='B') #生成起始时间和终止时间的若干个交易日
gbm_dates = rng
M = len(gbm_dates) # 时间步长
I = 1 #
dt = 1 / 252. #
df = math.exp(-r * dt) #
# 股票价格路径生成
rand = np.random.standard_normal((M, I)) # random numbers
S = np.zeros_like(rand) # stock matrix
S[0] = S0 # initial values
for t in range(1, M): # stock price paths
S[t] = S[t - 1] * np.exp((r - vol ** 2 / 2) * dt +
vol * rand[t] * math.sqrt(dt))
gbm = pd.DataFrame(S[:, 0], index=gbm_dates, columns=['index'])
gbm['returns'] = np.log(gbm['index'] / gbm['index'].shift(1))
# Realized Volatility (eg. as defined for variance swaps)
gbm['rea_var'] = 252 * np.cumsum(gbm['returns'] ** 2) / np.arange(len(gbm))
gbm['rea_vol'] = np.sqrt(gbm['rea_var'])
gbm = gbm.dropna()
return gbm
# 收益率统计分析及正态分布检验
def print_statistics(data):
print("样本收益率统计值")
print("---------------------------------------------")
print("日对数收益率均值 %9.6f" % np.mean(data['returns']))
print("年对数收益率均值 %9.6f" %
(np.mean(data['returns']) * 252))
print("年对数收益率的标准差 %9.6f" %
(np.std(data['returns']) * math.sqrt(252)))
print("---------------------------------------------")
print("样本对数收益率的偏度 %9.6f" % scs.skew(data['returns']))
print("偏度的正态分布检验p值 %9.6f" %
scs.skewtest(data['returns'])[1])
print("---------------------------------------------")
print("样本对数收益率的峰度 %9.6f" % scs.kurtosis(data['returns']))
print("峰度的正态分布检验p值 %9.6f" %
scs.kurtosistest(data['returns'])[1])
print("---------------------------------------------")
print("正态分布检验p值 %9.6f" %
scs.normaltest(data['returns'])[1])
print("---------------------------------------------")
print("已实现波动率 %9.6f" % data['rea_vol'].iloc[-1])
print("已实现方差 %9.6f" % data['rea_var'].iloc[-1])
# 日报价和日对数收益率
def quotes_returns(data):
''' Plots quotes and returns. '''
plt.figure(figsize=(9, 6))
plt.subplot(211)
data['index'].plot()
plt.ylabel('日报价')
plt.grid(True)
plt.axis('tight')
plt.subplot(212)
data['returns'].plot()
plt.ylabel('日对数收益率')
plt.grid(True)
plt.axis('tight')
# histogram of annualized daily log returns
def return_histogram(data):
''' Plots a histogram of the returns. '''
plt.figure(figsize=(9, 5))
x = np.linspace(min(data['returns']), max(data['returns']), 100)
plt.hist(np.array(data['returns']), bins=50, density=True) #normed改成density
y = dN(x, np.mean(data['returns']), np.std(data['returns'])) #求收益率的均值和方差
plt.plot(x, y, linewidth=2)
plt.xlabel('对数收益率')
plt.ylabel('频率/概率')
plt.grid(True)
# Q-Q plot of annualized daily log returns
def return_qqplot(data):
''' Generates a Q-Q plot of the returns.'''
plt.figure(figsize=(9, 5))
sm.qqplot(data['returns'], line='s')
plt.grid(True)
plt.xlabel('理论分位数')
plt.ylabel('样本分位数')
# realized volatility
def realized_volatility(data):
''' Plots the realized volatility. '''
plt.figure(figsize=(9, 5))
data['rea_vol'].plot()
plt.ylabel('已实现波动率')
plt.grid(True)
# mean return, volatility and correlation (252 days moving = 1 year)
def rolling_statistics(data):
''' Calculates and plots rolling statistics (mean, std, correlation). '''
plt.figure(figsize=(11, 8))
plt.subplot(311)
mr = data['returns'].rolling(252).mean() * 252
mr.plot()
plt.grid(True)
plt.ylabel('年收益率')
plt.axhline(mr.mean(), color='r', ls='dashed', lw=1.5)
plt.subplot(312)
vo = data['returns'].rolling(252).std() * math.sqrt(252)
vo.plot()
plt.grid(True)
plt.ylabel('年波动率')
plt.axhline(vo.mean(), color='r', ls='dashed', lw=1.5)
vx = plt.axis()
plt.subplot(313)
co = mr.rolling(252).corr(vo)
co.plot()
plt.grid(True)
plt.ylabel('年相关系数')
cx = plt.axis()
plt.axis([vx[0], vx[1], cx[2], cx[3]])
plt.axhline(co.mean(), color='r', ls='dashed', lw=1.5)
首先通过几何布朗运动来模拟一段时间序列的数据,几何布朗运动的介绍在前文已经给出了,这里不再赘述。
几何布朗运动的序列数据如下所示:
gbm = simulate_gbm()
print_statistics(gbm)
样本收益率统计值
---------------------------------------------
日对数收益率均值 -0.000129
年对数收益率均值 -0.032411
年对数收益率的标准差 0.202453
---------------------------------------------
样本对数收益率的偏度 -0.128567
偏度的正态分布检验p值 0.096832
---------------------------------------------
样本对数收益率的峰度 0.294140
峰度的正态分布检验p值 0.073261
---------------------------------------------
正态分布检验p值 0.050657
---------------------------------------------
已实现波动率 0.202463
已实现方差 0.040991
quotes_returns(gbm) #日报价和日对数收益率
return_histogram(gbm)#日对数收益率直方图和具有相同收益,方差的正态分布的概率密度函数图
return_qqplot(gbm) #几何布朗运动的日对数收益率的QQ图
realized_volatility(gbm)#模拟路径的实际波动率
rolling_statistics(gbm)
通过上述的描述性统计分析数值和分布图、QQ图可知,几何布朗运动模拟下生成的时间序列数据是符合正态分布的。
通过数据库导入沪深300的数据,并且进行处理
df['returns']=np.log(df['close']/df['close'].shift(1))
df['rea_var']=np.cumsum(df['returns']**2)/np.arange(len(df))*252
df['rea_vol']=np.sqrt(df['rea_var'])
df=df.dropna()
df
print_statistics(df)
样本收益率统计值
---------------------------------------------
日对数收益率均值 0.000250
年对数收益率均值 0.063086
年对数收益率的标准差 0.183886
---------------------------------------------
样本对数收益率的偏度 -0.603087
偏度的正态分布检验p值 0.000000
---------------------------------------------
样本对数收益率的峰度 5.390226
峰度的正态分布检验p值 0.000000
---------------------------------------------
正态分布检验p值 0.000000
---------------------------------------------
已实现波动率 0.183929
已实现方差 0.033830
df['index']=df['close']
quotes_returns(df) #日报价和日对数收益率
return_histogram(df)#
return_qqplot(df) #QQ图
realized_volatility(df)#实际波动率
rolling_statistics(df)
通过上述描述性统计分析的数值和图可知,沪深300指数的收益率序列是不服从正态分布的。这也是金融市场的一个普遍现象。
本章对金融时间序列的描述性统计分析进行了介绍,并且基于几何布朗运动模拟下的数据和沪深300指数数据进行了量化分析。