第10課 Python金融學基礎——資產(chǎn)優(yōu)化問題

在上一節(jié)課當中主要講了幾個重要的概念麻裁,包括股票的日回報率断国,日回報率的均值,累積回報率鱼鸠,波動(也就是標準差)猛拴,進而以日回報率的均值和波動來計算夏普比率,并說明夏普比率可以用來衡量每份風險背后所具有的收益蚀狰,以此來定量衡量我們投資決策的真實收益大小愉昆。

在這節(jié)課,我們要解決第二個問題麻蹋,給定一定的股票跛溉,比如說我給你四只股票的一系列的時間序列數(shù)據(jù),以及給你限定10000元的投資,那么如何根據(jù)所給的股票數(shù)據(jù)來劃分每只股票各投資多少占比以求得最大收益芳室,也就是我要計算出股票購買所占資本的權重专肪,這個權重可以實現(xiàn)總體的夏普比率最大化。
總體大綱:


流程

一堪侯、加載數(shù)據(jù)及預處理

1.1 計算累積收益率嚎尤,對數(shù)收益率和算術收益率

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
AAPL=pd.read_csv('AAPL_CLOSE',index_col='Date',parse_dates=True)
AMZN=pd.read_csv('AMZN_CLOSE',index_col='Date',parse_dates=True)
CISCO=pd.read_csv('CISCO_CLOSE',index_col='Date',parse_dates=True)
IBM=pd.read_csv('IBM_CLOSE',index_col='Date',parse_dates=True)
AAPL.head()
輸出結果

接下來我們把這四只股票的收盤價都合在一張dataframe里面

stock=pd.concat([AAPL, AMZN, CISCO, IBM],axis=1)
stock.columns=['AAPL', 'AMZN', 'CISCO', 'IBM']
stock.head()
輸出結果

然后我們計算一下日收益率的平均值

stock.pct_change(1).mean()
輸出結果

我們接下來看一下日收益率的偏相關性所引起的偏方差攀涵。關于這里的偏相關性我是這么理解的画株,因為這是股票市場,并且這幾只股票都是科技股票婶博,它們的市場是趨同的雹拄,因此在這里應該是認為彼此的價格變化是有相互影響的收奔,因此在計算波動的時候,要考慮權重轉變后其他股票對單只股票的影響滓玖。偏方差函數(shù)是cov()

stock.pct_change(1).cov()

在這里以第一行為例子坪哄,AAPL是蘋果股票的代號,它除了有自身波動的影響势篡,即第一列翩肌。也有其他三只股票的影響,也就是其他三列禁悠,這部分的相關性導致的波動即為偏方差念祭。

我們繪制一下股票的累積收益率的變化情況。

normed_ret=stock/stock.iloc[0]
normed_ret.plot(kind='line',figsize=(12,8),grid=True)
plt.legend(loc='best')

我們在這里引入對數(shù)收益率碍侦,原因是對數(shù)收益率相對于我們上面提到的算術收益率來說更加適合模型的計算粱坤,具體原因我覺得知乎這個回答是不錯的,一方面是為了讓我們的數(shù)據(jù)符合模型的平穩(wěn)性假設瓷产,另外一方面應該是方便計算表達站玄,而且可以發(fā)現(xiàn)對數(shù)收益率和算術收益率其實差的不多。關于對數(shù)收益率我還有些不理解的地方濒旦,還得繼續(xù)研究下株旷。我們繪制下對數(shù)收益率和算術收益率的分布吧。

#算術收益率
stock.pct_change(1).plot.hist(bins=100)
plt.legend(loc='best')
#對數(shù)收益率
log_ret=np.log(stock/stock.shift(1))
log_ret.plot.hist(bins=100)
plt.legend(loc='best')
算術收益率的分布
對數(shù)收益率的分布

可以看到差別并不是很大尔邓。

1.2 計算252天的平均收益率的總和以及偏方差矩陣

#252天的四只股票的平均對數(shù)收益率總和
total_mean_ret=log_ret.mean()*252
#252天的四只股票構成的偏方差矩陣
total_covariance=log_ret.cov()*252
print total_mean_ret
print total_covariance

在這里計算資產(chǎn)組合的最優(yōu)化權重晾剖,我們可以用到兩個方法:一個是蒙特卡羅模擬法,另外一個是限制條件下的數(shù)學優(yōu)化方法铃拇。我們分別來看一下钞瀑。

二、蒙特卡羅模擬法

2.1 原理

這個方法聽起來很高大上慷荔,其實方法很接地氣,也很暴力。就是舉出很多很多權重組合(多到幾乎窮舉)显晶,然后計算所有的點的夏普比率贷岸,哪個最高就取哪個點的均值和波動。

2.2 方法實現(xiàn)

2.2.1 計算單個權重的夏普比率

在這里我們先用代碼實現(xiàn)一組投資資產(chǎn)權重的計算夏普比率磷雇,窮舉只用在單次的外圍加上一個遍歷就可以了偿警。


numpy的random函數(shù)用法
#在這里我們用numpy的random.randn函數(shù)實現(xiàn)隨機取四個數(shù),這個方法是從[0, 1]中取出特定個數(shù)的數(shù)字的方法
weight=np.random.random(4)
print weight

在這里我們看到的確是返回了四個隨機的[0, 1]的值唯笙,但是要注意我們的權重之和是需要等于1的螟蒸,所以要進行歸一化。

normed_weight=weight/np.sum(weight)
print normed_weight

可以看到歸一化以后的權重確實是之和為1了崩掘。然后我們試下用這個權重去計算對應的資產(chǎn)組合的夏普比率七嫌。
按照權重去計算對應的252天的預期回報率和波動(也就是方差)

#預期回報率
exp_ret=np.sum(log_ret.mean()*normed_weight*252)
#波動
volat=np.sqrt(np.dot(normed_weight.T, np.dot(log_ret.cov()*252, normed_weight)))
print exp_ret, volat
#計算夏普比率
SR=exp_ret/volat
print SR
夏普比率

在這里關于波動的計算方式,我是這么理解的后面的一個點乘實際上是計算出每個股票單獨的方差苞慢,然后每只股票的方差又按照權重加和得到最終整體的方差诵原。原因是每只股票波動是跟其他三只股票都是有聯(lián)系的,所以要按照權重先算出每只股票自身的波動挽放。第一步得到的是41的矩陣绍赛,然后前面的weights在轉置以后是14的矩陣,兩者的點乘就是最終經(jīng)過權重轉化的方差辑畦,開方后為標準差吗蚌。

2.2.3 生成多個隨機權重進行模擬

接下來我們就在外面套上一層循環(huán),生成許多組不同的權重序列纯出,按照上面的方式計算每組權重所得的期望回報和波動蚯妇。

#隨機權重的組數(shù)為15000
num=15000
#初始化總預期收益率和波動以及夏普比率的numpy數(shù)列
exp_rets=np.zeros(num)
exp_vols=np.zeros(num)
exp_SRs=np.zeros(num)
#迭代15000次
for ind in range(num):
    weight=np.random.random(4)
    normed_weight=weight/np.sum(weight)
    #預期回報率
    exp_ret=np.sum(log_ret.mean()*normed_weight*252)
    exp_rets[ind]=exp_ret
    #波動
    volat=np.sqrt(np.dot(normed_weight.T, np.dot(log_ret.cov()*252, normed_weight)))
    exp_vols[ind]=volat
    #計算夏普比率
    SR=exp_ret/volat
    exp_SRs[ind]=SR
#我們找出Sharp Ratio對應最大的Volatility和return那個點,可以用numpy的argmax函數(shù)
max_ind=np.argmax(exp_SRs)
max_SR_vol=exp_vols[max_ind]
max_SR_ret=exp_rets[max_ind]
print 'Sharp Ratio maximum is ', exp_SRs[max_ind]
print '-'*20
print 'Volatility is ', exp_vols[max_ind]
print '-'*20
print 'Return is ', exp_rets[max_ind]

#我們以波動為橫坐標潦刃,總收益率為縱坐標侮措,夏普比率為顏色條,繪制出散點圖的分布乖杠,并且標識出最大夏普比率的那個點
plt.scatter(x=exp_vols, y=exp_rets, c=exp_SRs, alpha=0.5, cmap='coolwarm')
plt.title('Volatility versus Return')
plt.xlabel('Volatility')
plt.ylabel('Return')
plt.colorbar(label='Sharp Ratio')
plt.scatter(max_SR_vol, max_SR_ret, s=50, edgecolors='black')
三個值的輸出結果
可視化模擬結果

在這里我們標識出了那個夏普比率最大的那個點分扎。

三、數(shù)學優(yōu)化方法

上面是通過隨機模擬的方式來找出最優(yōu)的投資配置胧洒,但實際上我們也可以通過邊界條件下的優(yōu)化來找出最優(yōu)的權重畏吓。這里要用到scipy.optimize.minimize方法。


scipy.optimize.minimize方法

這里我們可以看到這個函數(shù)要做的事情就是給定邊界條件


然后計算這個一個或多個變量所決定的標量目標函數(shù)f(x)的最小值卫漫。


從官方文檔可以看到有幾個重要參數(shù)菲饼,我們在這里只傳入幾個參數(shù):fun最小化的目標函數(shù),x0是一開始的初始值列赎,method是用于優(yōu)化的方法宏悦,這里選用‘SLSQP’,constraints是約束條件,整體是一個字典饼煞,type有兩種:‘eq’和'ineq'源葫,分別表示后面?zhèn)魅氲募s束條件函數(shù)'fun'等于0或者大于等于0。
在這里要注意兩點砖瞧,一個是我們是要最大化夏普比率的息堂,所以為了用這個minimize方法,我們應該定義目標函數(shù)為夏普比率的負值块促;第二個是約束條件函數(shù)在這里應該是權重之和也就是自變量之和為1荣堰,要稍微調(diào)整成權重之和減1等于0的約束條件形式才滿足minimize方法的要求。

#以權重作為輸入竭翠,計算所得252天的總收益率振坚,總的波動,夏普比率
def get_ret_vol_SR(weight):
    #預期回報率
    exp_ret=np.sum(log_ret.mean()*weight*252)
    #波動
    volat=np.sqrt(np.dot(weight.T, np.dot(log_ret.cov()*252, weight)))
    #計算夏普比率
    SR=exp_ret/volat
    return np.array([exp_ret,  volat, SR])
#定義目標函數(shù)逃片,返回夏普比率的負值
def get_neg_sharp_ratio(weight):
    return get_ret_vol_SR(weight)[2]*-1
#定義限制的邊界函數(shù)屡拨,返回權重之和減1的計算結果,之后會用來跟0作比較褥实,判斷是否相等
def con(weight):
    return np.sum(weight)-1
#初始化四個值為0.25
x0=np.array([0.25,0.25,0.25,0.25])
#設置自變量的取值范圍
bounds=((0,1),(0,1),(0,1),(0,1))
#設置限制條件的字典
constraints={'type':'eq','fun':con }
#進行邊界條件下對目標函數(shù)優(yōu)化的權重計算
from scipy.optimize import minimize
res=minimize(fun=get_neg_sharp_ratio, x0=x0, constraints=constraints, method='SLSQP',bounds=bounds)
print res.x#打印出最優(yōu)化夏普比率后的權重

然后我們接下來根據(jù)計算得到的權重呀狼,來帶入到我們計算三個值的函數(shù)當中求出總的收益率,總的波動损离,以及夏普比率哥艇。

print 'Epxcted return is', get_ret_vol_SR(res.x)[0]
print '-'*20
print 'Epxcted volatility is', get_ret_vol_SR(res.x)[1]
print '-'*20
print 'Epxcted return is', get_ret_vol_SR(res.x)[2]

四、有效邊界

有效邊界可以這么認為僻澎,是一條在給定波動也就是風險下貌踏,所能達到的最大收益的那個點,這種類似的點的組合即為有效邊界窟勃。我們繪制一下這條有效邊界祖乳。


#numpy的linspace方法可以生成一系列梯度漸進的值
lin_y=np.linspace(0,0.3,100)
#然后我們在這里定義的最小化的目標函數(shù)是波動,也就是在確定的return也就是y值以及權重之和為1的限制條件下秉氧,最小化波動值眷昆。
def get_vol(weight):
    return get_ret_vol_SR(weight)[1]
frontier_volatility=[]
#初始化四個值為0.25
x0=np.array([0.25,0.25,0.25,0.25])
#設置自變量的取值范圍
bounds=((0,1),(0,1),(0,1),(0,1))
for y in lin_y:
    constraints2=[{'type':'eq','fun':lambda x:get_ret_vol_SR(x)[1]-y},{'type':'eq','fun':con}]
    res2=minimize(fun=get_vol, x0=x0, constraints=constraints2, method='SLSQP',bounds=bounds)
    frontier_volatility.append(res2.fun)
print frontier_volatility[:10]

輸出結果


我們繪制一下邊界曲線

#我們以波動為橫坐標,總收益率為縱坐標汁咏,夏普比率為顏色條亚斋,繪制出散點圖的分布,并且標識出最大夏普比率的那個點
plt.scatter(x=exp_vols, y=exp_rets, c=exp_SRs, alpha=0.5, cmap='coolwarm')
plt.title('Volatility versus Return')
plt.xlabel('Volatility')
plt.ylabel('Return')
plt.colorbar(label='Sharp Ratio')
plt.scatter(max_SR_vol, max_SR_ret, s=50, edgecolors='black')
plt.plot(frontier_volatility, lin_y, 'g--', linewidth=1.5)
有效邊界

在這里如果從縱向上看攘滩,相同的波動情況下帅刊,有效邊界上面的點能夠達到最大的收益,相同的收益下漂问,有效邊界上面的點能夠達到風險最小赖瞒,因此有效邊界上面的點都是投資配置最優(yōu)化的點女揭。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市冒黑,隨后出現(xiàn)的幾起案子田绑,更是在濱河造成了極大的恐慌勤哗,老刑警劉巖抡爹,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異芒划,居然都是意外死亡冬竟,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門民逼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泵殴,“玉大人,你說我怎么就攤上這事拼苍⌒ψ纾” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵疮鲫,是天一觀的道長吆你。 經(jīng)常有香客問我,道長俊犯,這世上最難降的妖魔是什么妇多? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮燕侠,結果婚禮上者祖,老公的妹妹穿的比我還像新娘。我一直安慰自己绢彤,他們只是感情好七问,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著茫舶,像睡著了一般械巡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奇适,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天坟比,我揣著相機與錄音,去河邊找鬼嚷往。 笑死葛账,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的皮仁。 我是一名探鬼主播籍琳,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼菲宴,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了趋急?” 一聲冷哼從身側響起喝峦,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎呜达,沒想到半個月后谣蠢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡查近,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年眉踱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霜威。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡谈喳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出戈泼,到底是詐尸還是另有隱情婿禽,我是刑警寧澤,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布大猛,位于F島的核電站扭倾,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏胎署。R本人自食惡果不足惜吆录,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望琼牧。 院中可真熱鬧恢筝,春花似錦、人聲如沸巨坊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趾撵。三九已至侄柔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間占调,已是汗流浹背暂题。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留究珊,地道東北人薪者。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像剿涮,于是被迫代替她去往敵國和親言津。 傳聞我的和親對象是個殘疾皇子攻人,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容

  • 最近研究了下最優(yōu)風險資產(chǎn)組合這個題目。本小白在金融領域是個純粹的初學者悬槽,開始的時候怀吻,有點不知所措。 后來在網(wǎng)上找了...
    丁立在簡書閱讀 34,020評論 16 109
  • “績效度量”是基于一本量化交易書: “Successful Algorithmic Trading”第十二章的翻譯...
    北冥Master閱讀 1,815評論 0 1
  • 俗話說不要將所有的雞蛋放在同一個籃子里初婆,在投資股票的時候我們也會多買幾只以抵抗風險蓬坡。本文將帶領著你使用Python...
    魚心DrFish閱讀 36,683評論 11 56
  • 一鍵克隆代碼 在多因子量化投資體系中,具有穩(wěn)定的預期收益烟逊,可解釋的經(jīng)濟驅動理論渣窜,與其他因子的低相關性是選擇alph...
    Ricequant米筐閱讀 3,056評論 0 8
  • “你還不如三歲孩子”這句話總被用以批評別人犯一些低級的錯誤或做一些特別不著調(diào)的事。稚嫩小孩宪躯,真有那么厲害嗎?...
    萌耕閱讀 1,555評論 12 23