代码如下:
####### step1
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from scipy.optimize import minimize
# 读取收盘价数据
def read_data(file):
s="C:/Users\Anita\Desktop"
file_address=s+file
df= pd.read_excel(file_address,sheetname="data")
# 保证金比例
marginal_cost=[0.15,0.3,0.02,0.15,1,1]
# 删除前两行说明行
df.drop(0,inplace=True)
df.drop(1,inplace=True)
# 删除最后一行2018年的3月数据
df.drop(1497,inplace=True)
# 把日期列设置为索引
df.set_index('Date',inplace=True)
# 缺失值检验:没有缺失值
df.isnull().any()
# 把日数据转换为月数据
period_type = 'M'
__df= df.resample(period_type).last()
monthly_df=pd.concat([df.iloc[0,0::].T,__df.T],axis=1).T
return monthly_df
# 计算对数收益率
def calculate_log_return(file):
data=read_data(file)
variable_list=['IF00.CFE','IC00.CFE','TF00.CFE','AU00.SHF','159920.OF','511880.SH']
for j in variable_list:
data['return_'+str(j)]=0.0
for i in range(1,len(data)):
data['return_'+str(j)][i]=np.log(float(data[j][i])/float(data[j][i-1]))
return data.iloc[1::,0::]
# 将收益率进行标准化处理,形成新的表格std_data
def standardlize_process(file):
data=calculate_log_return(file)
scaler=StandardScaler()
scaler.fit(data)
column_list=['IF00.CFE','IC00.CFE','TF00.CFE','AU00.SHF','159920.OF','511880.SH','return_IF00.CFE','return_IC00.CFE','return_TF00.CFE','return_AU00.SHF','return_159920.OF','return_511880.SH']
std_data=pd.DataFrame(scaler.transform(data),columns=column_list,index=data.index)
std_data=std_data.iloc[:,6::]
return std_data
#资产收益率序列相关性检验:滚动计算资产的协方差矩阵
def cov_asset(file):
return standardlize_process(file).rolling(window=12).cov().iloc[66::,0::]
# 风险度量期间为一年,故滚动窗口设置为12个月,从2012-12月末到2018-02月末共计 63个月,每个月6条记录,共63*6=378条记录
# 协方差矩阵
cov_matrix=np.matrix(cov_asset("\数据.xlsx"))
##### step2
# 计算每类资产对总资产组合的风险贡献
def calculate_risk_contribution(weight,one_cov_matrix):
weight=np.matrix(weight)
sigma=np.sqrt(weight*one_cov_matrix*np.matrix(weight).T)
# 边际风险贡献 Marginal Risk Contribution (MRC)
MRC=one_cov_matrix*weight.T/sigma
# 风险贡献 Risk Contribution (RC)
RC=np.multiply(MRC,weight.T)
return RC
# 定义优化问题的目标函数,即最小化资产之间的风险贡献差
def risk_budget_objective(x_weight,parameters):
# x_weight是带求解的各个大类资产下面子标的的权重,parameters是下面函数中的args=[one_cov_matrix,RC_set_ratio]参数传递
# x_weight的初始值是函数 calculate_portfolio_weight中的 weight0
# 协方差矩阵,也即函数 calculate_portfolio_weight 中传递的 args中的第一个参数 one_cov_matrix
one_cov_matrix=parameters[0]
# 风险平价下的目标风险贡献度向量,也即函数 calculate_portfolio_weight 中传递的 args中的第二个参数 RC_set_ratio
RC_target_ratio=parameters[1]
# RC_target为风险平价下的目标风险贡献,一旦参数传递以后,RC_target就是一个常数,不随迭代而改变
sigma_portfolio=np.sqrt(x_weight*one_cov_matrix*np.matrix(x_weight).T)
RC_target=np.asmatrix(np.multiply(sigma_portfolio,RC_target_ratio))
# RC_real是 每次迭代以后最新的真实风险贡献,随迭代而改变
RC_real=calculate_risk_contribution(x_weight,one_cov_matrix)
sum_squared_error= sum(np.square(RC_real-RC_target.T))[0,0]
return sum_squared_error
# 优化问题的第一个约束条件
def constraint1(x_weight):
return np.sum(x_weight)-1.0
# 优化问题的第二个约束条件
def constraint2(x_weight):
return x_weight
# 根据资产预期目标风险贡献度来计算各资产的权重
def calculate_portfolio_weight(RC_set_ratio,one_cov_matrix):
weight0=[0.2, 0.2, 0.2, 0.1, 0.1, 0.2]
cons=({'type': 'eq', 'fun': constraint1},{'type': 'ineq', 'fun': constraint2})
res= minimize(risk_budget_objective, weight0, args=[one_cov_matrix,RC_set_ratio], method='SLSQP',constraints=cons, options={'disp': True})
weight_final= np.asmatrix(res.x)
return weight_final
def calculate_monthly_weight(RC_set_ratio):
result={}
year=['2012','2013','2014','2015','2016','2017','2018']
month=['01','02','03','04','05','06','07','08','09','10','11','12']
for i in range(63):
date=str(2012+int((i+11)/12))+'-'+ month[(i-1)%12]
one_cov_matrix=cov_matrix[i*6:(i*6+6)]
result[date]=pd.DataFrame(calculate_portfolio_weight(RC_set_ratio,one_cov_matrix)).iloc[0,0::]
#xx=pd.DataFrame(result,index=date)
return result
## 计算风险平价下每月的资产配置权重
# 假设1:四个资产的风险贡献度相等
# 假设2:同类资产下每个标的的风险贡献相同
df_monthly_weight=pd.DataFrame(calculate_monthly_weight([0.25/3, 0.25/3, 0.25, 0.25, 0.25/3, 0.25])).T
df_monthly_weight.columns=['IF00.CFE','IC00.CFE','TF00.CFE','AU00.SHF','159920.OF','511880.SH']
df_monthly_weight
#### step3:回测Backtest
## 基于过去一年的风险分配权重,计算各资产的月度收益率
def calculate_RC_monthly_return(file):
std_df=standardlize_process(file)
date_list=[]
for i in range(63):
date_list.append(str(2012+int((i+11)/12))+'-'+ month[(i-1)%12])
#date_list
_std_df=std_df.iloc[11::,0::].T
_std_df.columns=date_list
__std__df=_std_df.T
__std__df['key']=__std__df.index
df_monthly_weight['key']=df_monthly_weight.index
# 合并表,将月收益数据和权重表横向合并
monthly_return=pd.merge(__std__df, df_monthly_weight,on='key')
monthly_return.set_index('key',inplace=True)
column_list=['return_IF00.CFE','return_IC00.CFE','return_TF00.CFE','return_AU00.SHF','return_159920.OF','return_511880.SH','IF00.CFE','IC00.CFE','TF00.CFE','AU00.SHF','159920.OF','511880.SH']
# 计算加权后的各资产收益率:权重乘以资产收益率
for i in range(6):
monthly_return['weight'+'_'+column_list[i]]=monthly_return[column_list[i]]*monthly_return[column_list[i+6]]
monthly__return=monthly_return.iloc[0::,-6::]
monthly__return['all_portfolio_return']=monthly__return.apply(lambda x: x.sum(), axis=1)
# 用债券收益率作为benchmark
monthly__return['benchmark']=monthly_return['return_TF00.CFE']
return monthly__return
## 收益回测,模型评价
def backtest_model1(monthly_data):
# 设置评价指标
total_return={}
annual_return={}
excess_return={}
annual_volatility={}
sharpe={}
information_ratio={}
win_prob={}
drawdown={}
tr={}
# 单独计算benchmark的相关指标
portfolio_list=['weight_return_IF00.CFE','weight_return_IC00.CFE','weight_return_TF00.CFE','weight_return_AU00.SHF','weight_return_159920.OF','weight_return_511880.SH','all_portfolio_return']
bench_total_return=(monthly_data['benchmark']+1).T.cumprod()[-1]-1
bench_annual_return=(float(bench_total_return)+1.0)**(1./(5+1/6))-1
# 每一种指标的具体构建方法
for i in portfolio_list:
monthly=monthly_data[i]
total_return[i]=(monthly+1).T.cumprod()[-1]-1
annual_return[i]=(float(total_return[i])+1.0)**(1./(5+1/6))-1
annual_volatility[i]=monthly.std()
sharpe[i]=(annual_return[i]-bench_annual_return)/annual_volatility[i]
drawdown[i]=monthly.min()
win_excess=monthly-monthly_data['benchmark']
win_prob[i]=win_excess[win_excess>0].count()/float(len(win_excess))
# 将字典转换为dataframe
ar=pd.DataFrame(annual_return,index=monthly.index).drop_duplicates().T
tr=pd.DataFrame(total_return,index=monthly.index).drop_duplicates().T
av=pd.DataFrame(annual_volatility,index=monthly.index).drop_duplicates().T
sp=pd.DataFrame(sharpe,index=monthly.index).drop_duplicates().T
dd=pd.DataFrame(drawdown,index=monthly.index).drop_duplicates().T
wp=pd.DataFrame(win_prob,index=monthly.index).drop_duplicates().T
ar['key']=ar.index #年化收益
tr['key']=tr.index #累积收益
av['key']=av.index #年化波动
sp['key']=sp.index #夏普比率
dd['key']=dd.index #最大回撤
wp['key']=wp.index #胜率
backtest_df=pd.merge(ar,pd.merge(tr,pd.merge(av,pd.merge(sp,pd.merge(dd,wp,on='key'),on='key'),on='key'),on='key'),on='key')
backtest_df.set_index('key',inplace=True)
backtest_df.columns=['annual return','total return','annual volatility','sharpe ratio','drawdown','win prob']
return backtest_df
hh=backtest_model1(calculate_RC_monthly_return("\数据.xlsx"))
hh