专栏名称: 挖地兔
金融数据采集与挖掘,开启量化金融的第一扇大门。
目录
相关文章推荐
单向街书店  ·  我在这儿,和浪漫主义狗一起 ·  昨天  
龙岩图书馆  ·  2月23日(下午4时)妙妙绘本屋报名 | ... ·  昨天  
单向街书店  ·  【单向历】2 月 19 日,宜埋首 ·  3 天前  
十点读书会  ·  陈晓陈妍希,爱没爱过 ·  2 天前  
51好读  ›  专栏  ›  挖地兔

利用Python创建不同资产组合的基本框架

挖地兔  · 公众号  ·  · 2019-05-28 10:43

正文



T U SHARE 金融与技术学习兴趣小组


翻译整理 | Apathy


本期编辑 | Little monster


译者简介: 国防科技大学控制工程与科学专业研二在读,目前在学习Python爬虫和量化投资。



作者: Mariano Scandizzo




本文比较了两个多元投资组合的风险调整回报,研究目标如下:

① 比较两个不同投资组合的 风险调整后边际回报率,一个投资组合增加 新兴市场债务,另一个投资组合增加的是黄金。



② 创建一个基本框架,利用Python分析和比较N个资产的投资组合。



基于描述性统计和蒙特卡罗概念创建易于部署的可视化和模拟。



【注】由于代码较长,本文只列出了与统计分析相关的代码,跳过了与可视化相关的代码。文末已附含完整代码的GitHub链接。





投资组合和关键统计数据



【数据集来源】 雅虎财经

【周期】20130429—20180430

【数据量】262

【资产】

SPY——SPDR S&P 500 ETF

QQQ——PowerShares QQQ ETF

AGG——iShares Core US Aggregate Bond ETF

GLD——SPDR Gold Shares

EMB——iShares JP Morgan USD Em Mkts Bd ETF


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()
plt.style.use(‘ggplot’)
semana = 52
datos = pd.read_excel(‘MasterAllocation.xlsx’,sheet_name=’Summary’,index_col=’Date’)





历史演变


数据可视化是形成初始直观的重要一步。下面是整个观察周期的历史价格演变:




资产类别的相对表现


由于每个资产类别的初始值不同,我们很难比较它们的相对表现。如果在观察期开始时在每项资产上投入1美元,会发生什么?



为了回答上面的问题,我们需要对数据进行标准化。





normalized_series = (datos/datos.iloc[0])





描述性统计


下面我们用一些数字来帮助我们描述每项资产类别的行为。



为了对每种资产的回报率和内在风险有一个直观的认识,我们可以先从年化回报率和离散度的测量开始入手。



【注】因为我们用的是周数据,需要转化为年化数据,通常假设每年有52周。





datos_returns = np.log(datos/datos.shift(1))
datos_returns.dropna(inplace=True)
stats = pd.DataFrame()
stats[‘Annualized Returns(%)’] =datos_returns.mean() * semana *100
stats[‘Annualized Volatility(%)’] = datos_returns.std() * np.sqrt(semana)*100
stats[‘Sharpe Ratio’] = stats[‘Annualized Returns(%)’] /stats[‘Annualized Volatility(%)’]
print(82*’-’)
print(‘Assets Classes Annualized Statistics — full observation period’)
stats.style.bar(color=[‘red’,’green’], align=’zero’)





回报的分散性


下一层的分析由数据的三阶和四阶矩驱动,即偏度和峰度。



作为投资组合风险管理的一部分,我们需要了解回报是否比正态分布更频繁地偏向于正值或负值,即偏度。



同样重要的是,我们要知道这些资产是否比正态分布的资产更倾向于发生极端事件,这些极端事件可以是正面的,也可以是负面的,这种现象也叫肥尾效应。



下面的图表显示了每种资产回报的直方图。 为了便于比较,绘制了一个钟形曲线,其平均值和标准偏差等于所考虑的资产。



形外部的值表示资产行为不能通过正态假设完全描述。为便于参考,图表中包含了偏度值和峰度值。





美国投资级债券与新兴市场政府债券


让我们具体比较投资组合中两种固定收益资产的收益分布。



很明显,与投资级美国政府债券相比,新兴市场债券回报率的分布更分散。回报率越高,波动性越大。





投资组合分析


到目前为止,我们只考虑了单个资产。



投资组合拥有的资产越多,在确定投资组合风险行为中,每个资产与投资组合中其他资产的相对行为就越重要。



模拟


【投资组合1】

美国投资级固定收益:30%(AGG)

美国股票:50%(SPY和QQQ)

黄金:20%(GLD)


【投资组合2】

美国投资级固定收益:30%(AGG)

美国股票:50%(SPY和QQQ)

EM政府债券:20%(EMB)





让我们比较一下它们的相对表现。 投资组合2的风险调整回报比投资组合1更高,表明在观察期内新兴市场债券是比黄金更好的选择。




投资组合的波动性


每个投资组合的风险状况由其波动率值描述。





datos_returns.corr(‘pearson’)





用全周期相关矩阵(Pearson公式),计算年化投资组合收益率和波动率。



Expected_Return_noEM = np.sum(datos_returns.mean()* allocation.No_EM)* semana
Expected_Std_noEM = np.sqrt(np.dot(allocation.No_EM.T,np.dot(datos_returns.cov()*semana,
 allocation.No_EM)))
Sharpe_noEM = Expected_Return_noEM / Expected_Std_noEM
Expected_Return_EM = np.sum(datos_returns.mean()* allocation.EM)* semana
Expected_Std_EM = np.sqrt (np.dot(allocation.EM.T,np.dot(datos_returns.cov()*semana,
 allocation.EM)))
Sharpe_EM = Expected_Return_EM / Expected_Std_EM
print(‘Key Stats: Portfolio with no EM Securities ‘)
print(82*’=’)
print(‘Annualized Returns: {:.3%}’.format(Expected_Return_noEM))
print(‘Annualized Volatility: {:.3%}’.format(Expected_Std_noEM))
print(‘Sharpe Ratio: {:.4}’.format(Sharpe_noEM))
print(82*’-’)
print(‘Key Stats: Portfolio with EM Securities ‘)
print(82*’=’)
print(‘Annualized Returns: {:.3%}’.format(Expected_Return_EM))
print(‘Annualized Volatility: {:.3%}’.format(Expected_Std_EM))
print(‘Sharpe Ratio: {:.4}’.format(Sharpe_EM))
print(82*’-’)





采用和之前可视化单个资产类别回报的分散性相同的方法,我们观察一下这两个投资组合的收益符合怎样的正态分布。





蒙特卡罗模拟


最后,我们模拟一下马科维茨有效边界。 我们不仅要计算最优投资组合,还要计算内部(次优)投资组合。


为了计算每个投资组合,我们将随机改变资产权重,同时保持每个投资组合的资产类别不变。



该练习将为每个投资组合运行2,500次模拟。此外,色标基于每个投资组合的夏普比率,通过风险调整效率的程度在视觉上区分投资组合。



pretsEM = []
pvolsEM = []
prets_noEM = []
pvols_noEM = []
[[‘AGG’,’SPY’,’QQQ’,’EMB’]]
[[‘AGG’,’SPY’,’QQQ’,’GLD’]]
for p in range(2500):
 weights = np.random.random(len(allocation)-1)
 weights /= np.sum(weights)
 pretsEM.append(np.sum(datos_returns[[‘AGG’,’SPY’,’QQQ’,’EMB’]].mean()* weights)* semana)
 pvolsEM.append(np.sqrt(np.dot(weights.T,np.dot(datos_returns[[‘AGG’,’SPY’,’QQQ’,’EMB’]].cov()*semana,
 weights))))
pretsEM = np.array(pretsEM)
pvolsEM = np.array(pvolsEM)
for p in range(2500):
 weights = np.random.random(len(allocation)-1)
 weights /= np.sum(weights)
 prets_noEM.append(np.sum(datos_returns[[‘AGG’,’SPY’,’QQQ’,’GLD’]].mean()* weights)* semana)
 pvols_noEM.append(np.sqrt(np.dot(weights.T,np.dot(datos_returns[[‘AGG’,’SPY’,’QQQ’,’GLD’]].cov()*semana,
 weights))))
prets_noEM = np.array(prets_noEM)
pvols_noEM = np.array(pvols_noEM)
# the charts
fig8 = plt.figure(figsize = (12,16))
plt.subplots_adjust(wspace=.5)
plt.subplot(211)
plt.scatter(pvolsEM, pretsEM, c = pretsEM / pvolsEM, marker = ‘o’,cmap=’coolwarm’)
plt.grid(True)
plt.xlabel(‘expected volatility’)
plt.ylabel(‘expected return’)
plt.colorbar(label = ‘Sharpe Ratio’)
plt.title(‘Monte Carlo Simulation Efficient Frontier with EM’)
plt.subplot(212)
plt.scatter(pvols_noEM, prets_noEM, c = prets_noEM / pvols_noEM, marker = ‘o’,cmap=’viridis’)
plt.grid(True)
plt.xlabel(‘expected volatility’)
plt.ylabel(‘expected return’)
plt.colorbar(label = ‘Sharpe Ratio’)
plt.title(‘Monte Carlo Simulation Efficient Frontier with no EM’)
plt.show();
fig8.savefig(‘frontiers.png’,dpi=fig8.dpi)









请到「今天看啥」查看全文