第一部分:沪深300指数正态性检验
正态分布是金融学中的最重要的分布,也是金融学理论的主要统计学基础之一。
a.投资组合理论:当股票收益率呈正态分布时,最优化投资组合可以在如下假设中选择:只有平均收益和收益的方差以及不同的股票之间的协方差与投资决策相关。
b.资本性资产定价模型:当股票收益呈现正态分布时,单独证券的价格可以很好地以某种大规模市场指数的关系表示。
c.有效市场假设:有效市场是指价格反映所有可用信息的市场,若假设成立,股票价格波动则是随机的,那么收益则呈现正态分布。
d.期权定价理论:著名的BSM期权定价模型中一个重要的假设为股票收益呈正态分布。
那么,在现实的资本市场中,正态性的假设不一定是成立的。
为了验证,从以下几个方面对沪深300指数数据进行分析,数据时间为2015年1月5日到2021年2月10日。
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
mpl.rcParams['font.family'] = 'serif'
def dN(x, mu, sigma):
''' Probability density function of a normal random variable x.
Parameters
==========
mu : float
expected value #平均值/期望值
sigma : float
standard deviation #标准差
Returns
=======
pdf : float
value of probability density function #概率密度函数
'''
z = (x - mu) / sigma #正态分布的标准化,z服从标准正态分布
pdf = np.exp(-0.5 * z ** 2) / math.sqrt(2 * math.pi * sigma ** 2) #z的概率密度函数
return pdf
#引入数据
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.dates as mdates
fig=plt.figure(figsize=(12,6))
data = pd.read_csv('C:/Users/gws/Desktop/沪深300指数历史数据.csv')
data['returns'] = np.log(data['price'] / data['price'].shift(1))
times = pd.read_excel(r'C:/Users/gws/Desktop/time.xlsx')
# 指数日报价
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.dates as mdates
data = pd.read_csv('C:/Users/gws/Desktop/沪深300指数历史数据.csv')
plt.figure(figsize=(9, 6))
x_time=times
y_index=data['price']
plt.plot(x_time,y_index)
plt.legend()
plt.xlabel('time')
ax=fig.add_subplot(111)
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d"))
plt.ylabel('daily quotes')
# 指数日对数价格波动率
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
import matplotlib.dates as mdates
data = pd.read_csv('C:/Users/gws/Desktop/沪深300指数历史数据.csv')
data['returns'] = np.log(data['price'] / data['price'].shift(1))
plt.plot(times,data['returns'],color='b',linewidth=3)
plt.xlabel('TIME')
ax=fig.add_subplot(111)
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d"))
plt.ylabel('Daily log returns')
plt.show()
以上分析得到沪深300指数的日报价波动率和日对数收益率波动率。
# 指数日对数收益率图
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('log returns')
plt.ylabel('frequency/probability')
plt.grid(True)
return_histogram(data)
以上分析得到日对数收益率的直方图。
# QQ图
sm.qqplot(data['returns'].dropna(),line = 's')
plt.grid(True)
plt.xlabel('theoretical quantiles')
plt.ylabel('sample quantiles')
以上分析得到沪深300指数对数收益率的QQ图
以上的图形可以初步判断,沪深300指数的收益率不是正态分布的。
接下来通过描述性统计来继续证明。
# 描述性统计分析
import numpy as np
import matplotlib.pyplot as plt
import math
import numpy as np
import quandl
import scipy.stats as stats
# print(data['returns'])
print('均值:',np.mean(data['returns'])) #均值
print('最小值:',np.min(data['returns'])) #最小值
print('最大值:',np.max(data['returns'])) #最大值
print('标准差:',np.std(data['returns'])) #标准差
print('方差:',np.var(data['returns'])) #方差
print('偏度:',pd.Series(data['returns']).skew())#偏度
print('峰度:',pd.Series(data['returns']).kurt()) #峰度
# J_B检验
import numpy as np
import scipy.stats as stats
def self_JBtest(y):
n = y.size
y_ = y - y.mean()
"""
M2:二阶中心钜
skew 偏度 = 三阶中心矩 与 M2^1.5的比
krut 峰值 = 四阶中心钜 与 M2^2 的比
"""
M2 = np.mean(y_**2)
skew = np.mean(y_**3)/M2**1.5
krut = np.mean(y_**4)/M2**2
"""
计算JB统计量,以及建立假设检验
"""
JB = n*(skew**2/6 + (krut-3 )**2/24)
pvalue = 1 - stats.chi2.cdf(JB,df=2)
print("JB检验:",stats.jarque_bera(y))
return np.array([JB,pvalue])
print(self_JBtest(data['returns']))
以上的结果为:
均值: 0.0003134864995930646
最小值: -0.09154437253073909
最大值: 0.06498873052235105
标准差: 0.015329468087087158
方差: 0.00023499259183302362
偏度: -1.015554440888655
峰度: 6.3043654925582535
JB检验: Jarque_beraResult(statistic=nan, pvalue=nan)
[2703.43766602 0. ]
以上数据中,样本峰度为6.304,可以看出样本分布存在厚尾现象。所以可以判断沪深300指数的收益率不呈现正态分布,所以市场收益率的正态假设不成立。
第二部分:均值-方差投资组合理论
a.马科维茨均值-方差模型为多目标优化问题,有效前沿即多目标优化问题的pareto解(风险一定,收益最大;收益一定,风险最小)
b.马科维茨模型以预期收益率期望度量收益,以收益率方差度量风险
一般用均值方差理论来研究股票投资组合,这里用来研究基金的投资组合。
选取5只基金数据,时间从20191月1日年到2021年2月10日。
1.5只基金的净值数据如图所示。
2.计算不同基金的均值、协方差
2.1 基金收益率的均值
每年252个交易日,用每日收益得到年化收益。
returns1 = np.log(p1 / p1.shift(1))
print('a005827的均值为:',returns1.mean()*252)
returns2 = np.log(p2 / p2.shift(1))
print('a118001的均值为:',returns2.mean()*252)
returns3 = np.log(p3 / p3.shift(1))
print('a003095的均值为:',returns3.mean()*252)
returns4 = np.log(p4 / p4.shift(1))
print('a002891的均值为:',returns4.mean()*252)
returns5 = np.log(p5 / p5.shift(1))
print('a260108的均值为:',returns5.mean()*252)
结果为
a005827的均值为: 0.6722697561451413
a118001的均值为: 0.39795665784070866
a003095的均值为: 0.6318566234567989
a002891的均值为: 0.6283258141278733
a260108的均值为: 0.6174217494140353
2.2 基金收益率的协方差
计算投资资产的协方差是构建资产组合过程的核心部分。运用pandas内置方法生产协方差矩阵。
import pandas as pd
df = pd.DataFrame({
'returns1': list(returns1)[1:],
'returns2': list(returns2)[1:],
'returns3': list(returns3)[1:],
'returns4':list(returns4)[1:],
'returns5':list(returns5)[1:]})
df_corr = df.corr()
# 可视化
import matplotlib.pyplot as mp, seaborn
seaborn.heatmap(df_corr, center=0, annot=True, cmap='YlGnBu')
mp.show()
2.3 给不同资产随机分配初始权重
weights = np.random.random(5)
weights /= np.sum(weights)
weights
比重如下
array([0.19022422, 0.26289541, 0.2368989 , 0.1765832 , 0.13339827])
2.4 .计算预期组合年化收益、组合方差和组合标准差
np.sum(returns.mean()*weights)*252
np.dot(weights.T, np.dot(df_corr,weights))
np.sqrt(np.dot(weights.T, np.dot(df_corr,weights)))
结果如下
0.5895661201969116
0.24679615559426255
0.4967858246712184
2.5 用蒙特卡洛模拟产生大量随机组合
得到随机权重投资组合散点图如下:
2.6投资组合的优化
2.6.1 得到夏普比率最大时的期望收益
def statistics(weights):
weights = np.array(weights)
port_returns = np.sum(ret*weights)*252
port_variance = np.sqrt(np.dot(weights.T, np.dot(df_corr,weights)))
return np.array([port_returns, port_variance, port_returns/port_variance])
#最优化投资组合的推导是一个约束最优化问题
import scipy.optimize as sco
#最小化夏普指数的负值
def min_sharpe(weights):
return -statistics(weights)[2]
#约束是所有参数(权重)的总和为1。这可以用minimize函数的约定表达如下
cons = ({'type':'eq', 'fun':lambda x: np.sum(x)-1})
#我们还将参数值(权重)限制在0和1之间。这些值以多个元组组成的一个元组形式提供给最小化函数
bnds = tuple((0,1) for x in range(noa))
#优化函数调用中忽略的唯一输入是起始参数列表(对权重的初始猜测)。我们简单的使用平均分布。
opts = sco.minimize(min_sharpe, noa*[1./noa,], method = 'SLSQP', bounds = bnds, constraints = cons)
opts
得到的结果如下:
fun: -1.3002339742302418
jac: array([-6.55651093e-07, 6.04987144e-06, 8.98540020e-06, -1.29044056e-05,
-1.11758709e-06])
message: 'Optimization terminated successfully'
nfev: 47
nit: 7
njev: 7
status: 0
success: True
x: array([0.2446469 , 0.09458952, 0.24748957, 0.18258173, 0.23069229])
得到的最优权重组合为:
array([0.245, 0.095, 0.247, 0.183, 0.231])
使用最优化得到投资组合的权重,得到以下统计结果
array([0.616, 0.473, 1.3 ])
由此可知,预期收益率为61.6%,预期波动率为47.3%,得到的最优夏普指数为1.3
2.6.2 投资组合优化-方差最小
通过计算得到结果如下:
fun: 0.4661049635012212
jac: array([0.46630891, 0.46531815, 0.46595777, 0.46669132, 0.46624486])
message: 'Optimization terminated successfully'
nfev: 22
nit: 3
njev: 3
status: 0
success: True
x: array([0.21494791, 0.17201182, 0.23323061, 0.16222558, 0.21758409])
可以得到绝对方差最小投资组合
array([0.215, 0.172, 0.233, 0.162, 0.218])
得到的预期收益率、波动率和夏普指数为:
array([0.597, 0.466, 1.28 ])
可知,预期收益率为59.7%,预期波动率为46.6%,预期夏普指数为1.28
2.7 组合的有效边界
所谓最优投资组合,即目标收益率水平下波动率最小。
下图是最优化结果的展示:
叉号:构成的曲线是有效前沿(目标收益率下最优的投资组合)
红星:sharpe最大的投资组合
黄星:方差最小的投资组合
有效边界由所有收益率高于绝对最小方差的投资组合的最优投资组合构成,这些投资组合在给定某一风险水平的预期收益率上优于其他投资组合。
2.8 投资组合回测
通过模拟得到组合投资权重为:
a005827的权重为: 0.245
a118001的权重为: 0.095
a003095的权重为: 0.247
a002891的权重为: 0.182
a260108的权重为: 0.231
回测结果为:
第一列为夏普比率,第二列为波动率,第三列为最大回撤。一般认为夏普比率越高挣钱效应越好,波动率和最大回测越大风险越大。