1. Black-Litterman模型簡(jiǎn)介
在python實(shí)現(xiàn)資產(chǎn)配置(1)----Markowitz 投資組合模型中, 我們已經(jīng)見過如何使用Markowitz求得最優(yōu)資產(chǎn)配比. 這是一種在已知未來各資產(chǎn)的概率分布,然后再求解的方法.
Markowitz模型輸入?yún)?shù)包括歷史數(shù)據(jù)法和情景分析法兩種方法,情景分析法的缺點(diǎn)是主觀因素,隨意性太強(qiáng),因此使用歷史數(shù)據(jù)法, 將資產(chǎn)的均值和協(xié)方差輸入模型是比較常見的作法. 不過, 不足之處很明顯: 未來的資產(chǎn)收益率分布不一定與過去相同. 此外, Markowitz 模型結(jié)果對(duì)輸入?yún)?shù)過于敏感.
Black-Litterman模型就是基于此的改進(jìn). 其核心思想是將投資者對(duì)大類資產(chǎn)的觀點(diǎn) (主觀觀點(diǎn)) 與市場(chǎng)均衡收益率 (先驗(yàn)預(yù)期收益率)相結(jié)合,從而形成新的預(yù)期收益率(后驗(yàn)預(yù)期收益率). 這里的先驗(yàn)預(yù)期收益率的分布可以是貝葉斯推斷中的先驗(yàn)概率密度函數(shù)的多元正態(tài)分布形式,投資者的主觀觀點(diǎn)就是貝葉斯推斷中的似然函數(shù)(可以看作新的信息, 因?yàn)樽龀鲋饔^判斷必然是從外界獲取得到了這些資產(chǎn)的收益率變化信息), 而相應(yīng)的, 后驗(yàn)預(yù)期收益率也可以從后驗(yàn)概率密度函數(shù)中得到. 具體的推導(dǎo)可以看我的這篇文章:從貝葉斯定理到貝葉斯推斷.
BL模型的求解步驟包括下面幾步:
(1) 使用歷史數(shù)據(jù)估計(jì)預(yù)期收益率的協(xié)方差矩陣作為先驗(yàn)概率密度函數(shù)的協(xié)方差.
(2) 確定市場(chǎng)預(yù)期之收益率向量, 也就是先驗(yàn)預(yù)期收益之期望值. 作為先驗(yàn)概率密度函數(shù)的均值. 或者使用現(xiàn)有的期望值和方差來反推市場(chǎng)隱含的均衡收益率(Implied Equilibrium Return Vector), 不過在使用這種方法時(shí), 需要知道無風(fēng)險(xiǎn)收益率的大小.
(3) 融合投資人的個(gè)人觀點(diǎn),即根據(jù)歷史數(shù)據(jù)(看法變量的方差)和個(gè)人看法(看法向量的均值)
(4) 修正后驗(yàn)收益.
是均衡收益率協(xié)方差的調(diào)整系數(shù),可以根據(jù)信心水平來判斷.
是歷史資產(chǎn)收益率的協(xié)方差矩陣, P是投資者的觀點(diǎn)矩陣,
是似然函數(shù)(即投資者觀點(diǎn)函數(shù))中的協(xié)方差矩陣,其值為
的對(duì)角陣,
是先驗(yàn)收益率的期望值.
(5) 投資組合優(yōu)化: 將修正后的期望值與協(xié)方差矩陣即重新代入Markowitz投資組合模型求解.
2. Black-litterman 模型的python實(shí)現(xiàn)
(1)定義求解函數(shù),輸入為投資者觀點(diǎn)P,Q以及目前資產(chǎn)的市場(chǎng)收益率矩陣,輸出為后驗(yàn)的市場(chǎng)收益率和協(xié)方差矩陣.
import numpy as np
import baostock as bs
import pandas as pd
from numpy import linalg
def blacklitterman(returns,tau,P,Q):
mu = returns.mean()
sigma = returns.cov()
pil = np.expand_dims(mu,axis = 0).T
ts = tau * sigma
ts_1 = linalg.inv(ts)
Omega = np.dot(np.dot(P,ts), P.T)* np.eye(Q.shape[0])
Omega_1 = linalg.inv(Omega)
er = np.dot(linalg.inv(ts_1 + np.dot(np.dot(P.T,Omega_1),P)),(np.dot(ts_1 ,pil)+np.dot(np.dot(P.T,Omega_1),Q)))
posterirorSigma = linalg.inv(ts_1 + np.dot(np.dot(P.T,Omega_1),P))
return [er, posterirorSigma]
(2) 實(shí)列分析
我們繼續(xù)研究python實(shí)現(xiàn)資產(chǎn)配置(1)----Markowitz 投資組合模型中的五支股票: 白云機(jī)場(chǎng), 福建高速, 華夏銀行, 生益科技和浙能電力. 假設(shè)現(xiàn)在分析師的觀點(diǎn)為:
- 白云機(jī)場(chǎng), 華夏銀行, 浙能電力, 生益科技四只股票的日均收益率均值為0.3%
- 白云機(jī)場(chǎng)和福建高速的日均收益率均值高于浙能電力0.1%
則投資者觀點(diǎn)矩陣P為:
Q 為:
則獲取后驗(yàn)收益率和協(xié)方差的代碼為:
pick1 = np.array([1,0,1,1,1])
q1 = np.array([0.003*4])
pick2 = np.array([0.5,0.5,0,0,-1])
q2 = np.array([0.001])
P = np.array([pick1,pick2])
Q = np.array([q1,q2])
獲取股票數(shù)據(jù), 并且獲得后驗(yàn)的均值和方差:
def get_stock_data(t1,t2,stock_name):
lg = bs.login()
print('login respond error_code:' + lg.error_code)
print('login respond error_msg:' + lg.error_msg)
#### 獲取滬深A(yù)股歷史K線數(shù)據(jù) ####
# 詳細(xì)指標(biāo)參數(shù),參見“歷史行情指標(biāo)參數(shù)”章節(jié)
rs = bs.query_history_k_data(stock_name,
"date,code,open,high,low,close,preclose,volume,amount,adjustflag,turn,tradestatus,pctChg,isST",
start_date=t1, end_date=t2,
frequency="d", adjustflag="3")
print('query_history_k_data respond error_code:' + rs.error_code)
print('query_history_k_data respond error_msg:' + rs.error_msg)
#### 打印結(jié)果集 ####
data_list = []
while (rs.error_code == '0') & rs.next():
# 獲取一條記錄,將記錄合并在一起
data_list.append(rs.get_row_data())
result = pd.DataFrame(data_list, columns=rs.fields)
print(result)
#### 結(jié)果集輸出到csv文件 ####
result.to_csv("D:\stockdata\history_A_stock_k_data.csv", index=False)
print(result)
#### 登出系統(tǒng) ####
bs.logout()
result['date'] = pd.to_datetime(result['date'])
result.set_index("date", inplace=True)
return result
byjc = get_stock_data('2014-1-1','2015-1-1','sh.600004')
hxyh = get_stock_data('2014-1-1','2015-1-1','sh.600015')
zndl = get_stock_data('2014-1-1','2015-1-1','sh.600023')
fjgs = get_stock_data('2014-1-1','2015-1-1','sh.600033')
sykj = get_stock_data('2014-1-1','2015-1-1','sh.600183')
by = byjc['pctChg']
by.name = 'byjc'
by = pd.DataFrame(by,dtype=np.float)/100
hx = hxyh['pctChg']
hx.name = 'hxyh'
hx = pd.DataFrame(hx,dtype=np.float)/100
zn = zndl['pctChg']
zn.name = 'zndl'
zn = pd.DataFrame(zn,dtype=np.float)/100
fj = fjgs['pctChg']
fj.name = 'fjgs'
fj = pd.DataFrame(fj,dtype=np.float)/100
sy = sykj['pctChg']
sy.name = 'sykj'
sy = pd.DataFrame(sy,dtype=np.float)/100
sh_return = pd.concat([by,fj,hx,sy,zn],axis=1)
res = blacklitterman(sh_return,0.1,P,Q)
p_mean = pd.DataFrame(res[0],index = sh_return.columns, columns = ['posterior_mean'])
p_cov = res[1]
print(p_mean)
print(p_cov)
這時(shí)候,已經(jīng)可以使用Markowitz模型進(jìn)行資產(chǎn)的配置. 定義新的函數(shù)blminVar以求解資產(chǎn)配置權(quán)重. 該函數(shù)的輸入變量為blacklitterman函數(shù)的輸出結(jié)果, 以及投資人的目標(biāo)收益率goalRet.假設(shè)目標(biāo)收益率為年化70%,則goalRet = 0.7:
def blminVar(blres, goalRet):
covs = np.array(blres[1],dtype=float)
means = np.array(blres[0],dtype=float)
L1 = np.append(np.append(covs.swapaxes(0,1),[means.flatten()],axis=0),
[np.ones(len(means))],axis=0).swapaxes(0,1)
L2 = list(np.ones(len(means)))
L2.extend([0,0])
L3 = list(means)
L3.extend([0,0])
L4 = np.array([L2,L3],dtype=float)
L = np.append(L1,L4,axis=0)
results = linalg.solve(L,np.append(np.zeros(len(means)),[1,goalRet]))
return pd.DataFrame(results[:-2],columns = ['p_weight'])
blresult = blminVar(res,0.70/252)
print(blresult)
輸出結(jié)果為:

0-5分別對(duì)應(yīng)上面的五只股票.
參考文獻(xiàn)
- 蔡立耑:量化投資——以python為工具. 電子工業(yè)出版社
- 華泰證券: 周期輪動(dòng)下的BL資產(chǎn)配置策略
- 中信建投:基于Black-Litterman的多資產(chǎn)配置策略