基于风险平价的资产配置策略

代码如下:

####### 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

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页