########################################################################
# Uploading Data
########################################################################
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings("ignore")
# Interest Rates Data
kr = pd.read_excel('KeyRates.xlsx', engine='openpyxl', index_col=0, header=0)/100
# Prices Data
assets = pd.read_excel('Assets.xlsx', engine='openpyxl', index_col=0, header=0)
# Find common dates
a = pd.merge(left=assets, right=kr, how='inner', on='Date')
dates = a.index
# Calculate interest rates returns
kr_returns = kr.loc[dates,:].sort_index().diff().dropna()
kr_returns.sort_index(ascending=False, inplace=True)
# List of instruments
equity = ['APA','CMCSA','CNP','HPQ','PSA','SEE','ZION']
bonds = ['PEP11900D031', 'PEP13000D012', 'PEP13000M088',
'PEP23900M103','PEP70101M530','PEP70101M571',
'PEP70310M156']
factors = ['MTUM','QUAL','SIZE','USMV','VLUE']
# Calculate assets returns
assets_returns = assets.loc[dates, equity + bonds]
assets_returns = assets_returns.sort_index().pct_change().dropna()
assets_returns.sort_index(ascending=False, inplace=True)
# Calculate factors returns
factors_returns = assets.loc[dates, factors]
factors_returns = factors_returns.sort_index().pct_change().dropna()
factors_returns.sort_index(ascending=False, inplace=True)
# Show tables
display(kr_returns.head().style.format("{:.4%}"))
display(assets_returns.head().style.format("{:.4%}"))
0 | 90 | 180 | 360 | 720 | 1800 | 3600 | 7200 | 10800 | |
---|---|---|---|---|---|---|---|---|---|
Date | |||||||||
2017-11-16 00:00:00 | 0.0000% | 0.0059% | 0.0108% | 0.0178% | 0.0246% | 0.0213% | 0.0075% | -0.0048% | -0.0093% |
2017-11-15 00:00:00 | 0.0180% | 0.0247% | 0.0303% | 0.0391% | 0.0495% | 0.0558% | 0.0512% | 0.0450% | 0.0417% |
2017-11-14 00:00:00 | -0.1800% | -0.1710% | -0.1624% | -0.1460% | -0.1167% | -0.0506% | 0.0140% | 0.0676% | 0.0861% |
2017-11-13 00:00:00 | 0.0000% | 0.0013% | 0.0025% | 0.0048% | 0.0088% | 0.0174% | 0.0258% | 0.0334% | 0.0364% |
2017-11-10 00:00:00 | 0.0000% | 0.0026% | 0.0043% | 0.0054% | 0.0017% | -0.0248% | -0.0615% | -0.0936% | -0.1054% |
APA | CMCSA | CNP | HPQ | PSA | SEE | ZION | PEP11900D031 | PEP13000D012 | PEP13000M088 | PEP23900M103 | PEP70101M530 | PEP70101M571 | PEP70310M156 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Date | ||||||||||||||
2017-11-16 00:00:00 | -1.3161% | -0.2958% | -1.0903% | 0.9831% | 1.7234% | 1.4016% | -0.8387% | -0.0411% | -0.0380% | -0.0597% | -0.0737% | -0.0116% | 0.0076% | -0.0633% |
2017-11-15 00:00:00 | -2.0296% | 0.8682% | -1.1202% | 0.0000% | -1.3479% | -0.3326% | 0.0215% | -0.1626% | -0.3076% | -0.3041% | -0.2286% | -0.4459% | -0.4651% | -0.2146% |
2017-11-14 00:00:00 | -3.7020% | -1.0470% | 1.0800% | 0.8975% | -0.1548% | 0.2668% | 2.6950% | 0.2320% | 0.0236% | 0.1040% | 0.2373% | -0.2741% | -0.3932% | 0.2151% |
2017-11-13 00:00:00 | -1.4503% | 1.0855% | 0.7480% | -0.2826% | 0.8179% | 1.4205% | 3.4145% | 0.0906% | 0.0064% | -0.0767% | 0.0354% | -0.0835% | -0.1114% | -0.0081% |
2017-11-10 00:00:00 | -2.4536% | 0.7932% | -1.3418% | -0.5155% | 0.0710% | -0.9381% | -0.0910% | 0.1194% | 0.3792% | 0.3047% | 0.1355% | 0.7118% | 0.8207% | -0.0090% |
########################################################################
# Uploading Duration and Convexity Matrixes
########################################################################
durations = pd.read_excel('durations.xlsx', index_col=0, header=0)
convexity = pd.read_excel('convexity.xlsx', index_col=0, header=0)
print('Durations Matrix')
display(durations.head().style.format("{:.4f}").background_gradient(cmap='YlGn'))
print('')
print('Convexities Matrix')
display(convexity.head().style.format("{:.4f}").background_gradient(cmap='YlGn'))
Durations Matrix
R 0 | R 90 | R 180 | R 360 | R 720 | R 1800 | R 3600 | R 7200 | R 10800 | |
---|---|---|---|---|---|---|---|---|---|
PEP11900D031 | 0.0012 | 0.0057 | 0.0192 | 0.0730 | 0.3685 | 3.0416 | 0.0030 | 0.0000 | 0.0000 |
PEP13000D012 | 0.0000 | 0.0078 | 0.0142 | 0.0617 | 0.3327 | 1.0902 | 4.8055 | 0.2074 | 0.0000 |
PEP13000M088 | 0.0013 | 0.0004 | 0.0147 | 0.0501 | 0.2770 | 2.4626 | 3.0764 | 0.0000 | 0.0000 |
PEP23900M103 | 0.0000 | 0.0005 | 0.0117 | 0.0405 | 0.2274 | 3.9726 | 0.0381 | 0.0000 | 0.0000 |
PEP70101M530 | 0.0000 | 0.0052 | 0.0101 | 0.0442 | 0.2488 | 0.8826 | 4.9147 | 3.5537 | 0.0000 |
Convexities Matrix
R^2 0 | R^2 90 | R^2 180 | R^2 360 | R^2 720 | R^2 1800 | R^2 3600 | R^2 7200 | R^2 10800 | |
---|---|---|---|---|---|---|---|---|---|
PEP11900D031 | 0.0004 | 0.0032 | 0.0167 | 0.0928 | 0.7741 | 15.5617 | 0.0000 | 0.0000 | 0.0000 |
PEP13000D012 | 0.0000 | 0.0057 | 0.0070 | 0.0756 | 0.7210 | 4.4984 | 45.2159 | 0.1105 | 0.0000 |
PEP13000M088 | 0.0010 | 0.0001 | 0.0192 | 0.0736 | 0.6161 | 8.8479 | 16.2880 | 0.0000 | 0.0000 |
PEP23900M103 | 0.0000 | 0.0000 | 0.0156 | 0.0644 | 0.5161 | 22.1272 | 0.0022 | 0.0000 | 0.0000 |
PEP70101M530 | 0.0000 | 0.0038 | 0.0052 | 0.0561 | 0.5530 | 3.7373 | 38.2315 | 26.1464 | 0.0000 |
########################################################################
# Building The Loadings Matrix
########################################################################
loadings = pd.concat([-1.0 * durations, 0.5 * convexity], axis = 1)
display(loadings.style.format("{:.4f}").background_gradient(cmap='YlGn'))
R 0 | R 90 | R 180 | R 360 | R 720 | R 1800 | R 3600 | R 7200 | R 10800 | R^2 0 | R^2 90 | R^2 180 | R^2 360 | R^2 720 | R^2 1800 | R^2 3600 | R^2 7200 | R^2 10800 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
PEP11900D031 | -0.0012 | -0.0057 | -0.0192 | -0.0730 | -0.3685 | -3.0416 | -0.0030 | -0.0000 | -0.0000 | 0.0002 | 0.0016 | 0.0083 | 0.0464 | 0.3871 | 7.7809 | 0.0000 | 0.0000 | 0.0000 |
PEP13000D012 | -0.0000 | -0.0078 | -0.0142 | -0.0617 | -0.3327 | -1.0902 | -4.8055 | -0.2074 | -0.0000 | 0.0000 | 0.0029 | 0.0035 | 0.0378 | 0.3605 | 2.2492 | 22.6080 | 0.0553 | 0.0000 |
PEP13000M088 | -0.0013 | -0.0004 | -0.0147 | -0.0501 | -0.2770 | -2.4626 | -3.0764 | -0.0000 | -0.0000 | 0.0005 | 0.0000 | 0.0096 | 0.0368 | 0.3081 | 4.4240 | 8.1440 | 0.0000 | 0.0000 |
PEP23900M103 | -0.0000 | -0.0005 | -0.0117 | -0.0405 | -0.2274 | -3.9726 | -0.0381 | -0.0000 | -0.0000 | 0.0000 | 0.0000 | 0.0078 | 0.0322 | 0.2581 | 11.0636 | 0.0011 | 0.0000 | 0.0000 |
PEP70101M530 | -0.0000 | -0.0052 | -0.0101 | -0.0442 | -0.2488 | -0.8826 | -4.9147 | -3.5537 | -0.0000 | 0.0000 | 0.0019 | 0.0026 | 0.0280 | 0.2765 | 1.8686 | 19.1157 | 13.0732 | 0.0000 |
PEP70101M571 | -0.0015 | -0.0039 | -0.0126 | -0.0501 | -0.2829 | -1.0108 | -2.5878 | -6.0312 | -0.4501 | 0.0002 | 0.0016 | 0.0064 | 0.0319 | 0.3123 | 2.1336 | 10.1632 | 49.9021 | 0.4523 |
PEP70310M156 | -0.0000 | -0.0039 | -0.0097 | -0.0403 | -0.2614 | -3.8920 | -0.0000 | -0.0000 | -0.0000 | 0.0000 | 0.0010 | 0.0030 | 0.0268 | 0.2508 | 10.6813 | 0.0000 | 0.0000 | 0.0000 |
########################################################################
# Building the risk factors returns matrix
########################################################################
kr_returns_2 = kr_returns ** 2
cols = loadings.columns
X = pd.concat([kr_returns, kr_returns_2], axis=1)
X.columns = cols
display(X.head().style.format("{:.4%}"))
R 0 | R 90 | R 180 | R 360 | R 720 | R 1800 | R 3600 | R 7200 | R 10800 | R^2 0 | R^2 90 | R^2 180 | R^2 360 | R^2 720 | R^2 1800 | R^2 3600 | R^2 7200 | R^2 10800 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Date | ||||||||||||||||||
2017-11-16 00:00:00 | 0.0000% | 0.0059% | 0.0108% | 0.0178% | 0.0246% | 0.0213% | 0.0075% | -0.0048% | -0.0093% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% |
2017-11-15 00:00:00 | 0.0180% | 0.0247% | 0.0303% | 0.0391% | 0.0495% | 0.0558% | 0.0512% | 0.0450% | 0.0417% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% |
2017-11-14 00:00:00 | -0.1800% | -0.1710% | -0.1624% | -0.1460% | -0.1167% | -0.0506% | 0.0140% | 0.0676% | 0.0861% | 0.0003% | 0.0003% | 0.0003% | 0.0002% | 0.0001% | 0.0000% | 0.0000% | 0.0000% | 0.0001% |
2017-11-13 00:00:00 | 0.0000% | 0.0013% | 0.0025% | 0.0048% | 0.0088% | 0.0174% | 0.0258% | 0.0334% | 0.0364% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% |
2017-11-10 00:00:00 | 0.0000% | 0.0026% | 0.0043% | 0.0054% | 0.0017% | -0.0248% | -0.0615% | -0.0936% | -0.1054% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 0.0001% | 0.0001% |
########################################################################
# Building the asset returns matrix
########################################################################
Y = assets_returns[bonds]
display(Y.head())
PEP11900D031 | PEP13000D012 | PEP13000M088 | PEP23900M103 | PEP70101M530 | PEP70101M571 | PEP70310M156 | |
---|---|---|---|---|---|---|---|
Date | |||||||
2017-11-16 | -0.000411 | -0.000380 | -0.000597 | -0.000737 | -0.000116 | 0.000076 | -0.000633 |
2017-11-15 | -0.001626 | -0.003076 | -0.003041 | -0.002286 | -0.004459 | -0.004651 | -0.002146 |
2017-11-14 | 0.002320 | 0.000236 | 0.001040 | 0.002373 | -0.002741 | -0.003932 | 0.002151 |
2017-11-13 | 0.000906 | 0.000064 | -0.000767 | 0.000354 | -0.000835 | -0.001114 | -0.000081 |
2017-11-10 | 0.001194 | 0.003792 | 0.003047 | 0.001355 | 0.007118 | 0.008207 | -0.000090 |
########################################################################
# Showing annualized returns of Fixed Income Risk Factors
########################################################################
display(X.mean()*252)
R 0 -0.002028 R 90 -0.001955 R 180 -0.001819 R 360 -0.001463 R 720 -0.000791 R 1800 -0.000530 R 3600 -0.002041 R 7200 -0.003312 R 10800 -0.003533 R^2 0 0.000173 R^2 90 0.000080 R^2 180 0.000049 R^2 360 0.000038 R^2 720 0.000046 R^2 1800 0.000050 R^2 3600 0.000057 R^2 7200 0.000069 R^2 10800 0.000091 dtype: float64
########################################################################
# Building views on some Risk Factors
########################################################################
views = {'Disabled': [False, False, False],
'Factor': ['R 10800','R 1800','R 3600'],
'Sign': ['>=', '<=', '<='],
'Value': [0.001, -0.001, -0.003],
'Relative Factor': ['R 7200', '', '']}
views = pd.DataFrame(views)
display(views)
Disabled | Factor | Sign | Value | Relative Factor | |
---|---|---|---|---|---|
0 | False | R 10800 | >= | 0.001 | R 7200 |
1 | False | R 1800 | <= | -0.001 | |
2 | False | R 3600 | <= | -0.003 |
########################################################################
# Building views matrixes P_f and Q_f
########################################################################
import riskfolio as rp
P_f, Q_f = rp.factors_views(views, loadings, const=False)
print('Matrix of factors views P_f')
print(P_f)
print('\nMatrix of returns of factors views Q_f')
print(Q_f)
Matrix of factors views P_f [[ 0. 0. 0. 0. 0. 0. 0. -1. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]] Matrix of returns of factors views Q_f [[0.001] [0.001] [0.003]]
########################################################################
# Building the Portfolio Object
########################################################################
# Building the portfolio object
port = rp.Portfolio(returns=Y)
# Select method and estimate input parameters:
method_mu='hist' # Method to estimate expected returns based on historical data.
method_cov='hist' # Method to estimate covariance matrix based on historical data.
port.assets_stats(method_mu=method_mu,
method_cov=method_cov)
port.factors = X
port.factors_stats(method_mu=method_mu,
method_cov=method_cov,
B=loadings,
const=False)
########################################################################
# Calculating optimum portfolios using Mean Vector and
# Covariance Matrix of Black Litterman with Factors
########################################################################
port.alpha = 0.05
rm = 'MV' # Risk measure used, this time will be variance
obj = 'Sharpe' # Objective function, could be MinRisk, MaxRet, Utility or Sharpe
hist = False # False: BL covariance and risk factors scenarios
# True: historical covariance and scenarios
# 2: risk factors covariance and scenarios
rf = 0 # Risk free rate
l = 0 # Risk aversion factor, only useful when obj is 'Utility'
w_fm = port.optimization(model='FM', rm=rm, obj=obj, rf=rf, l=l, hist=hist)
# Estimate Portfolio weights using Black Litterman Bayesian Model:
port.blfactors_stats(flavor='BLB',
B=loadings,
P_f=P_f,
Q_f=Q_f/252,
rf=0,
delta=None,
eq=True,
const=False,
diag=False,
method_mu=method_mu,
method_cov=method_cov)
w_blb = port.optimization(model='BL_FM', rm=rm, obj=obj, rf=rf, l=l, hist=hist)
# Estimate Portfolio weights using Augmented Black Litterman Model:
port.blfactors_stats(flavor='ABL',
B=loadings,
P_f=P_f,
Q_f=Q_f/252,
rf=0,
delta=None,
eq=True,
const=False,
diag=False,
method_mu=method_mu,
method_cov=method_cov)
w_abl = port.optimization(model='BL_FM', rm=rm, obj=obj, rf=rf, l=l, hist=hist)
ws = pd.concat([w_fm, w_blb, w_abl], axis=1)
ws.columns = ['Pure Factors', 'Bayesian BL', 'Augmented BL']
display(ws.style.format("{:.4%}").background_gradient(cmap='YlGn'))
You must convert self.cov_bl_fm to a positive definite matrix You must convert self.cov_bl_fm to a positive definite matrix
Pure Factors | Bayesian BL | Augmented BL | |
---|---|---|---|
PEP11900D031 | 0.0000% | 0.0000% | 0.0000% |
PEP13000D012 | 6.6680% | 33.1060% | 85.2406% |
PEP13000M088 | 0.0000% | 0.0000% | 0.0000% |
PEP23900M103 | 0.0000% | 0.0000% | 0.0000% |
PEP70101M530 | 32.3833% | 0.0001% | 14.7594% |
PEP70101M571 | 60.9486% | 66.8939% | 0.0000% |
PEP70310M156 | 0.0000% | 0.0000% | 0.0000% |
We can see that the we got a messsage that the covariance matrix is not a positive definite matrix, this is common when we work with views on assets or risk factors. In this case, Riskfolio-Lib replace the negative eigenvalues of covariance matrix with zeros and reconstruct the covariance matrix. The problem with this approach is common that the weights that we will get are highly concetrated in few assets.
Other approach is using the mean vector estimated with Black Litterman with Factors and the covariance matrix that we get from historical returns or a factor model. An example with this approach follows:
########################################################################
# Calculating optimum portfolios using only Mean Vector
# of Black Litterman with Factors and Factor Covariance Matrix
########################################################################
hist = 2 # False: BL covariance and risk factors scenarios
# True: historical covariance and scenarios
# 2: risk factors covariance and scenarios (Only in BL_FM)
# Estimate Portfolio weights using Black Litterman Bayesian Model:
port.blfactors_stats(flavor='BLB',
B=loadings,
P_f=P_f,
Q_f=Q_f/252,
rf=0,
delta=None,
eq=True,
const=False,
diag=False,
method_mu=method_mu,
method_cov=method_cov)
w_blb = port.optimization(model='BL_FM', rm=rm, obj=obj, rf=rf, l=l, hist=hist)
# Estimate Portfolio weights using Augmented Black Litterman Model:
port.blfactors_stats(flavor='ABL',
B=loadings,
P_f=P_f,
Q_f=Q_f/252,
rf=0,
delta=None,
eq=True,
const=False,
diag=False,
method_mu=method_mu,
method_cov=method_cov)
w_abl = port.optimization(model='BL_FM', rm=rm, obj=obj, rf=rf, l=l, hist=hist)
ws = pd.concat([w_fm, w_blb, w_abl], axis=1)
ws.columns = ['Pure Factors', 'Bayesian BL', 'Augmented BL']
display(ws.style.format("{:.4%}").background_gradient(cmap='YlGn'))
You must convert self.cov_bl_fm to a positive definite matrix You must convert self.cov_bl_fm to a positive definite matrix
Pure Factors | Bayesian BL | Augmented BL | |
---|---|---|---|
PEP11900D031 | 0.0000% | 0.0000% | 6.1662% |
PEP13000D012 | 6.6680% | 16.6281% | 16.4519% |
PEP13000M088 | 0.0000% | 2.2781% | 5.2878% |
PEP23900M103 | 0.0000% | 0.0000% | 11.2163% |
PEP70101M530 | 32.3833% | 35.1625% | 26.2773% |
PEP70101M571 | 60.9486% | 45.9313% | 23.8393% |
PEP70310M156 | 0.0000% | 0.0000% | 10.7612% |
We can see that when we only use the mean vector of Black Litterman with Factors, the weights that we get are more diversified. Also, we can see that the Augmented Black Litterman creates more diversified portfolios than the Bayesian Black Litterman.
B = rp.loadings_matrix(factors_returns, assets_returns[equity])
display(B.style.format("{:.4f}").background_gradient(cmap='YlGn'))
const | MTUM | QUAL | SIZE | USMV | VLUE | |
---|---|---|---|---|---|---|
APA | -0.0008 | -0.8999 | 1.2674 | 0.0000 | -0.5750 | 1.4874 |
CMCSA | -0.0000 | 0.2426 | 0.0000 | -0.1569 | 0.5483 | 0.3623 |
CNP | -0.0001 | -0.3827 | -0.3579 | 0.0000 | 1.9556 | 0.0000 |
HPQ | 0.0003 | 0.0000 | 0.5164 | 0.0000 | 0.0000 | 0.7550 |
PSA | -0.0000 | 0.0000 | -0.4623 | 0.0000 | 1.8071 | -0.3115 |
SEE | -0.0001 | 0.0000 | 0.4915 | 0.0000 | 0.5043 | 0.2535 |
ZION | 0.0002 | 0.0000 | 1.1589 | 0.0000 | -1.3203 | 1.2202 |
########################################################################
# Building the asset returns matrix
########################################################################
Y = pd.concat([assets_returns[equity], Y], axis=1)
display(Y.head())
APA | CMCSA | CNP | HPQ | PSA | SEE | ZION | PEP11900D031 | PEP13000D012 | PEP13000M088 | PEP23900M103 | PEP70101M530 | PEP70101M571 | PEP70310M156 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Date | ||||||||||||||
2017-11-16 | -0.013161 | -0.002958 | -0.010903 | 0.009831 | 0.017234 | 0.014016 | -0.008387 | -0.000411 | -0.000380 | -0.000597 | -0.000737 | -0.000116 | 0.000076 | -0.000633 |
2017-11-15 | -0.020296 | 0.008682 | -0.011202 | 0.000000 | -0.013479 | -0.003326 | 0.000215 | -0.001626 | -0.003076 | -0.003041 | -0.002286 | -0.004459 | -0.004651 | -0.002146 |
2017-11-14 | -0.037020 | -0.010470 | 0.010800 | 0.008975 | -0.001548 | 0.002668 | 0.026950 | 0.002320 | 0.000236 | 0.001040 | 0.002373 | -0.002741 | -0.003932 | 0.002151 |
2017-11-13 | -0.014503 | 0.010855 | 0.007480 | -0.002826 | 0.008179 | 0.014205 | 0.034145 | 0.000906 | 0.000064 | -0.000767 | 0.000354 | -0.000835 | -0.001114 | -0.000081 |
2017-11-10 | -0.024536 | 0.007932 | -0.013418 | -0.005155 | 0.000710 | -0.009381 | -0.000910 | 0.001194 | 0.003792 | 0.003047 | 0.001355 | 0.007118 | 0.008207 | -0.000090 |
########################################################################
# Building the asset returns matrix
########################################################################
X = pd.concat([factors_returns, X], axis=1)
display(X.head())
MTUM | QUAL | SIZE | USMV | VLUE | R 0 | R 90 | R 180 | R 360 | R 720 | ... | R 10800 | R^2 0 | R^2 90 | R^2 180 | R^2 360 | R^2 720 | R^2 1800 | R^2 3600 | R^2 7200 | R^2 10800 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Date | |||||||||||||||||||||
2017-11-16 | 0.009478 | 0.007556 | 0.006675 | 0.006408 | 0.014509 | 0.00000 | 0.000059 | 0.000108 | 0.000178 | 0.000246 | ... | -0.000093 | 0.000000e+00 | 3.527647e-09 | 1.163831e-08 | 3.181621e-08 | 6.048648e-08 | 4.552420e-08 | 5.573518e-09 | 2.314283e-09 | 8.695936e-09 |
2017-11-15 | -0.003381 | -0.005884 | -0.001974 | -0.006750 | -0.003771 | 0.00018 | 0.000247 | 0.000303 | 0.000391 | 0.000495 | ... | 0.000417 | 3.225005e-08 | 6.082093e-08 | 9.197391e-08 | 1.529780e-07 | 2.448864e-07 | 3.108575e-07 | 2.620815e-07 | 2.025117e-07 | 1.736147e-07 |
2017-11-14 | -0.001687 | 0.000375 | -0.000370 | 0.001932 | -0.004380 | -0.00180 | -0.001710 | -0.001624 | -0.001460 | -0.001167 | ... | 0.000861 | 3.241235e-06 | 2.925701e-06 | 2.636999e-06 | 2.131988e-06 | 1.362113e-06 | 2.555747e-07 | 1.966922e-08 | 4.572289e-07 | 7.417774e-07 |
2017-11-13 | 0.002488 | 0.000877 | 0.003589 | 0.003296 | 0.000751 | 0.00000 | 0.000013 | 0.000025 | 0.000048 | 0.000088 | ... | 0.000364 | 0.000000e+00 | 1.681950e-10 | 6.400900e-10 | 2.324301e-09 | 7.748577e-09 | 3.033345e-08 | 6.657174e-08 | 1.116368e-07 | 1.328391e-07 |
2017-11-10 | 0.002894 | 0.001255 | -0.001730 | -0.000968 | 0.001254 | 0.00000 | 0.000026 | 0.000043 | 0.000054 | 0.000017 | ... | -0.001054 | 0.000000e+00 | 6.770924e-10 | 1.820644e-09 | 2.881542e-09 | 2.791573e-10 | 6.131368e-08 | 3.779975e-07 | 8.759856e-07 | 1.110697e-06 |
5 rows × 23 columns
########################################################################
# Building The Loadings Matrix
########################################################################
loadings = pd.concat([B, loadings], axis = 1)
loadings.fillna(0, inplace=True)
display(loadings.style.format("{:.4f}").background_gradient(cmap='YlGn'))
const | MTUM | QUAL | SIZE | USMV | VLUE | R 0 | R 90 | R 180 | R 360 | R 720 | R 1800 | R 3600 | R 7200 | R 10800 | R^2 0 | R^2 90 | R^2 180 | R^2 360 | R^2 720 | R^2 1800 | R^2 3600 | R^2 7200 | R^2 10800 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
APA | -0.0008 | -0.8999 | 1.2674 | 0.0000 | -0.5750 | 1.4874 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 |
CMCSA | -0.0000 | 0.2426 | 0.0000 | -0.1569 | 0.5483 | 0.3623 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 |
CNP | -0.0001 | -0.3827 | -0.3579 | 0.0000 | 1.9556 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 |
HPQ | 0.0003 | 0.0000 | 0.5164 | 0.0000 | 0.0000 | 0.7550 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 |
PSA | -0.0000 | 0.0000 | -0.4623 | 0.0000 | 1.8071 | -0.3115 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 |
SEE | -0.0001 | 0.0000 | 0.4915 | 0.0000 | 0.5043 | 0.2535 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 |
ZION | 0.0002 | 0.0000 | 1.1589 | 0.0000 | -1.3203 | 1.2202 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 |
PEP11900D031 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | -0.0012 | -0.0057 | -0.0192 | -0.0730 | -0.3685 | -3.0416 | -0.0030 | -0.0000 | -0.0000 | 0.0002 | 0.0016 | 0.0083 | 0.0464 | 0.3871 | 7.7809 | 0.0000 | 0.0000 | 0.0000 |
PEP13000D012 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | -0.0000 | -0.0078 | -0.0142 | -0.0617 | -0.3327 | -1.0902 | -4.8055 | -0.2074 | -0.0000 | 0.0000 | 0.0029 | 0.0035 | 0.0378 | 0.3605 | 2.2492 | 22.6080 | 0.0553 | 0.0000 |
PEP13000M088 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | -0.0013 | -0.0004 | -0.0147 | -0.0501 | -0.2770 | -2.4626 | -3.0764 | -0.0000 | -0.0000 | 0.0005 | 0.0000 | 0.0096 | 0.0368 | 0.3081 | 4.4240 | 8.1440 | 0.0000 | 0.0000 |
PEP23900M103 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | -0.0000 | -0.0005 | -0.0117 | -0.0405 | -0.2274 | -3.9726 | -0.0381 | -0.0000 | -0.0000 | 0.0000 | 0.0000 | 0.0078 | 0.0322 | 0.2581 | 11.0636 | 0.0011 | 0.0000 | 0.0000 |
PEP70101M530 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | -0.0000 | -0.0052 | -0.0101 | -0.0442 | -0.2488 | -0.8826 | -4.9147 | -3.5537 | -0.0000 | 0.0000 | 0.0019 | 0.0026 | 0.0280 | 0.2765 | 1.8686 | 19.1157 | 13.0732 | 0.0000 |
PEP70101M571 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | -0.0015 | -0.0039 | -0.0126 | -0.0501 | -0.2829 | -1.0108 | -2.5878 | -6.0312 | -0.4501 | 0.0002 | 0.0016 | 0.0064 | 0.0319 | 0.3123 | 2.1336 | 10.1632 | 49.9021 | 0.4523 |
PEP70310M156 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | -0.0000 | -0.0039 | -0.0097 | -0.0403 | -0.2614 | -3.8920 | -0.0000 | -0.0000 | -0.0000 | 0.0000 | 0.0010 | 0.0030 | 0.0268 | 0.2508 | 10.6813 | 0.0000 | 0.0000 | 0.0000 |
########################################################################
# Showing annualized returns of Equity Risk Factors
########################################################################
display(factors_returns.mean()*252)
MTUM 0.154379 QUAL 0.113842 SIZE 0.115915 USMV 0.124555 VLUE 0.106612 dtype: float64
########################################################################
# Building views on some Risk Factors
########################################################################
views = {'Disabled': [False, False, False, False, False, False],
'Factor': ['MTUM','USMV','SIZE','R 10800','R 1800','R 3600'],
'Sign': ['>=', '>=', '>=', '>=', '<=', '<='],
'Value': [0.02, 0.09, 0.12, 0.001, -0.001, -0.003],
'Relative Factor': ['VLUE', '', '','R 90', '', '']}
views = pd.DataFrame(views)
display(views)
Disabled | Factor | Sign | Value | Relative Factor | |
---|---|---|---|---|---|
0 | False | MTUM | >= | 0.020 | VLUE |
1 | False | USMV | >= | 0.090 | |
2 | False | SIZE | >= | 0.120 | |
3 | False | R 10800 | >= | 0.001 | R 90 |
4 | False | R 1800 | <= | -0.001 | |
5 | False | R 3600 | <= | -0.003 |
########################################################################
# Building views matrixes P_f and Q_f
########################################################################
P_f, Q_f = rp.factors_views(views, loadings, const=True)
print('Matrix of factors views P_f')
print(P_f)
print('\nMatrix of returns of factors views Q_f')
print(Q_f)
Matrix of factors views P_f [[ 1. 0. 0. 0. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0. -1. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]] Matrix of returns of factors views Q_f [[0.02 ] [0.09 ] [0.12 ] [0.001] [0.001] [0.003]]
########################################################################
# Building Portfolio Object
########################################################################
# Building the portfolio object
port = rp.Portfolio(returns=Y)
# Calculating optimum portfolio
# Select method and estimate input parameters:
method_mu='hist' # Method to estimate expected returns based on historical data.
method_cov='hist' # Method to estimate covariance matrix based on historical data.
port.assets_stats(method_mu=method_mu,
method_cov=method_cov)
port.factors = X
port.factors_stats(method_mu=method_mu,
method_cov=method_cov,
B=loadings,
const=True)
########################################################################
# Calculating optimum portfolios
########################################################################
port.alpha = 0.05
rm = 'MV' # Risk measure used, this time will be variance
obj = 'Sharpe' # Objective function, could be MinRisk, MaxRet, Utility or Sharpe
hist = False # False: BL covariance and risk factors scenarios
# True: historical covariance and scenarios
# 2: risk factors covariance and scenarios
rf = 0 # Risk free rate
l = 0 # Risk aversion factor, only useful when obj is 'Utility'
w_fm = port.optimization(model='FM', rm=rm, obj=obj, rf=rf, l=l, hist=hist)
# Estimate Portfolio weights using Black Litterman Bayesian Model:
port.blfactors_stats(flavor='BLB',
B=loadings,
P_f=P_f,
Q_f=Q_f/252,
rf=0,
delta=None,
eq=True,
const=True,
diag=True,
method_mu=method_mu,
method_cov=method_cov)
w_blb = port.optimization(model='BL_FM', rm=rm, obj=obj, rf=rf, l=l, hist=hist)
# Estimate Portfolio weights using Augmented Black Litterman Model:
port.blfactors_stats(flavor='ABL',
B=loadings,
P_f=P_f,
Q_f=Q_f/252,
rf=0,
delta=None,
eq=True,
const=True,
diag=True,
method_mu=method_mu,
method_cov=method_cov)
w_abl = port.optimization(model='BL_FM', rm=rm, obj=obj, rf=rf, l=l, hist=hist)
ws = pd.concat([w_fm, w_blb, w_abl], axis=1)
ws.columns = ['Pure Factors', 'Bayesian BL', 'Augmented BL']
display(ws.style.format("{:.4%}").background_gradient(cmap='YlGn'))
You must convert self.cov_bl_fm to a positive definite matrix
Pure Factors | Bayesian BL | Augmented BL | |
---|---|---|---|
APA | 0.0000% | 0.0000% | 0.0000% |
CMCSA | 10.6669% | 4.4927% | 0.0000% |
CNP | 12.2572% | 7.6298% | 0.0000% |
HPQ | 16.3690% | 17.0336% | 72.8372% |
PSA | 26.0444% | 19.6223% | 0.0000% |
SEE | 0.0758% | 0.0000% | 0.0000% |
ZION | 7.9950% | 9.8279% | 0.0000% |
PEP11900D031 | 0.0000% | 0.0000% | 0.0000% |
PEP13000D012 | 0.0001% | 6.9747% | 27.1628% |
PEP13000M088 | 0.0000% | 0.4876% | 0.0000% |
PEP23900M103 | 0.0000% | 0.0000% | 0.0000% |
PEP70101M530 | 7.8241% | 14.5620% | 0.0000% |
PEP70101M571 | 18.7674% | 19.3695% | 0.0000% |
PEP70310M156 | 0.0000% | 0.0000% | 0.0000% |
We can see that the we got a messsage that the covariance matrix is not a positive definite matrix, this is common when we work with views on assets or risk factors. In this case, Riskfolio-Lib replace the negative eigenvalues of covariance matrix with zeros and reconstruct the covariance matrix. The problem with this approach is common that the weights that we will get are highly concetrated in few assets.
We can see that in this case the Black Litterman Bayesian model creates a more diversified portfolio than the Augmented Black Litterman model.
Other approach is using the mean vector estimated with Black Litterman with Factors and the covariance matrix that we get from historical returns or a factor model.
########################################################################
# Calculating optimum portfolios
########################################################################
hist = 2 # False: BL covariance and risk factors scenarios
# True: historical covariance and scenarios
# 2: risk factors covariance and scenarios (Only in BL_FM)
# Estimate Portfolio weights using Black Litterman Bayesian Model:
port.blfactors_stats(flavor='BLB',
B=loadings,
P_f=P_f,
Q_f=Q_f/252,
rf=0,
delta=None,
eq=True,
const=True,
diag=True,
method_mu=method_mu,
method_cov=method_cov)
w_blb = port.optimization(model='BL_FM', rm=rm, obj=obj, rf=rf, l=l, hist=hist)
# Estimate Portfolio weights using Augmented Black Litterman Model:
port.blfactors_stats(flavor='ABL',
B=loadings,
P_f=P_f,
Q_f=Q_f/252,
rf=0,
delta=None,
eq=True,
const=True,
diag=True,
method_mu=method_mu,
method_cov=method_cov)
w_abl = port.optimization(model='BL_FM', rm=rm, obj=obj, rf=rf, l=l, hist=hist)
ws = pd.concat([w_fm, w_blb, w_abl], axis=1)
ws.columns = ['Pure Factors', 'Bayesian BL', 'Augmented BL']
display(ws.style.format("{:.4%}").background_gradient(cmap='YlGn'))
You must convert self.cov_bl_fm to a positive definite matrix
Pure Factors | Bayesian BL | Augmented BL | |
---|---|---|---|
APA | 0.0000% | 0.0000% | 0.0000% |
CMCSA | 10.6669% | 5.2672% | 7.3134% |
CNP | 12.2572% | 5.9762% | 1.6711% |
HPQ | 16.3690% | 17.3220% | 21.2692% |
PSA | 26.0444% | 18.0273% | 12.0783% |
SEE | 0.0758% | 0.0000% | 0.0000% |
ZION | 7.9950% | 11.3383% | 20.9051% |
PEP11900D031 | 0.0000% | 0.0000% | 2.3440% |
PEP13000D012 | 0.0001% | 6.2308% | 6.3664% |
PEP13000M088 | 0.0000% | 0.2338% | 2.0322% |
PEP23900M103 | 0.0000% | 0.0000% | 4.1502% |
PEP70101M530 | 7.8241% | 14.6896% | 9.6157% |
PEP70101M571 | 18.7674% | 20.9148% | 8.2701% |
PEP70310M156 | 0.0000% | 0.0000% | 3.9845% |
We can see that when we only use the mean vector of Black Litterman with Factors, the weights that we get are more diversified. Also, we can see that the Augmented Black Litterman creates a more diversified portfolio than the Bayesian Black Litterman.
When we use risk measures different than Standard Deviation, Riskfolio-Lib only considers the vector of expected returns, and use historical returns to calculate risk measures.
# Risk Measures available:
#
# 'MV': Standard Deviation.
# 'MAD': Mean Absolute Deviation.
# 'MSV': Semi Standard Deviation.
# 'FLPM': First Lower Partial Moment (Omega Ratio).
# 'SLPM': Second Lower Partial Moment (Sortino Ratio).
# 'CVaR': Conditional Value at Risk.
# 'EVaR': Entropic Value at Risk.
# 'WR': Worst Realization (Minimax)
# 'MDD': Maximum Drawdown of uncompounded cumulative returns (Calmar Ratio).
# 'ADD': Average Drawdown of uncompounded cumulative returns.
# 'CDaR': Conditional Drawdown at Risk of uncompounded cumulative returns.
# 'EDaR': Entropic Drawdown at Risk of uncompounded cumulative returns.
# 'UCI': Ulcer Index of uncompounded cumulative returns.
rms = ['MV', 'MAD', 'MSV', 'FLPM', 'SLPM', 'CVaR',
'EVaR', 'WR', 'MDD', 'ADD', 'CDaR', 'UCI', 'EDaR']
w_s = pd.DataFrame([])
port.alpha = 0.05
port.blfactors_stats(flavor='BLB',
B=loadings,
P_f=P_f,
Q_f=Q_f/252,
rf=0,
delta=None,
eq=True,
const=True,
diag=True,
method_mu=method_mu,
method_cov=method_cov)
model = 'BL_FM'
obj = 'Sharpe'
for i in rms:
if i == 'MV':
hist = 2
else:
hist = True
w = port.optimization(model=model, rm=i, obj=obj, rf=rf, l=l, hist=hist)
w_s = pd.concat([w_s, w], axis=1)
w_s.columns = rms
w_s.style.format("{:.2%}").background_gradient(cmap='YlGn')
MV | MAD | MSV | FLPM | SLPM | CVaR | EVaR | WR | MDD | ADD | CDaR | UCI | EDaR | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
APA | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
CMCSA | 5.27% | 6.48% | 8.28% | 6.69% | 8.34% | 11.76% | 4.02% | 0.00% | 8.15% | 10.28% | 2.03% | 10.10% | 5.55% |
CNP | 5.98% | 6.22% | 2.27% | 7.88% | 2.13% | 0.00% | 0.00% | 0.00% | 7.08% | 5.60% | 23.19% | 11.26% | 18.31% |
HPQ | 17.32% | 19.10% | 15.45% | 18.15% | 15.33% | 15.79% | 15.73% | 15.78% | 8.45% | 0.00% | 1.99% | 0.00% | 6.33% |
PSA | 18.03% | 19.43% | 18.60% | 18.69% | 18.55% | 18.59% | 12.37% | 3.43% | 43.61% | 34.45% | 39.36% | 34.46% | 38.65% |
SEE | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 3.03% | 4.16% | 10.15% | 6.27% | 9.26% | 7.64% |
ZION | 11.34% | 10.70% | 10.67% | 10.02% | 10.67% | 9.50% | 12.81% | 14.88% | 7.76% | 11.92% | 13.28% | 12.52% | 9.74% |
PEP11900D031 | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
PEP13000D012 | 6.23% | 12.34% | 14.33% | 12.51% | 14.52% | 23.34% | 16.79% | 5.21% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
PEP13000M088 | 0.23% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
PEP23900M103 | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
PEP70101M530 | 14.69% | 0.00% | 5.41% | 0.00% | 5.61% | 4.35% | 3.99% | 10.37% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
PEP70101M571 | 20.91% | 25.72% | 24.98% | 26.06% | 24.84% | 16.66% | 34.29% | 47.30% | 20.80% | 27.60% | 13.88% | 22.40% | 13.78% |
PEP70310M156 | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
import matplotlib.pyplot as plt
# Plotting a comparison of assets weights for each portfolio
fig = plt.gcf()
fig.set_figwidth(14)
fig.set_figheight(6)
ax = fig.subplots(nrows=1, ncols=1)
w_s.plot.bar(ax=ax)
<Axes: >
# Risk Measures available:
#
# 'MV': Standard Deviation.
# 'MAD': Mean Absolute Deviation.
# 'MSV': Semi Standard Deviation.
# 'FLPM': First Lower Partial Moment (Omega Ratio).
# 'SLPM': Second Lower Partial Moment (Sortino Ratio).
# 'CVaR': Conditional Value at Risk.
# 'EVaR': Entropic Value at Risk.
# 'WR': Worst Realization (Minimax)
# 'MDD': Maximum Drawdown of uncompounded cumulative returns (Calmar Ratio).
# 'ADD': Average Drawdown of uncompounded cumulative returns.
# 'CDaR': Conditional Drawdown at Risk of uncompounded cumulative returns.
# 'EDaR': Entropic Drawdown at Risk of uncompounded cumulative returns.
# 'UCI': Ulcer Index of uncompounded cumulative returns.
rms = ['MV', 'MAD', 'MSV', 'FLPM', 'SLPM', 'CVaR',
'EVaR', 'WR', 'MDD', 'ADD', 'CDaR', 'UCI', 'EDaR']
w_s = pd.DataFrame([])
port.alpha = 0.05
port.blfactors_stats(flavor='ABL',
B=loadings,
P_f=P_f,
Q_f=Q_f/252,
rf=0,
delta=None,
eq=True,
const=True,
diag=True,
method_mu=method_mu,
method_cov=method_cov)
model = 'BL_FM'
obj = 'Sharpe'
for i in rms:
if i == 'MV':
hist = 2
else:
hist = True
w = port.optimization(model=model, rm=i, obj=obj, rf=rf, l=l, hist=hist)
w_s = pd.concat([w_s, w], axis=1)
w_s.columns = rms
You must convert self.cov_bl_fm to a positive definite matrix
w_s.style.format("{:.2%}").background_gradient(cmap='YlGn')
MV | MAD | MSV | FLPM | SLPM | CVaR | EVaR | WR | MDD | ADD | CDaR | UCI | EDaR | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
APA | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
CMCSA | 7.31% | 7.34% | 8.79% | 6.38% | 8.88% | 8.36% | 8.79% | 5.47% | 6.11% | 15.07% | 5.27% | 11.85% | 7.29% |
CNP | 1.67% | 3.53% | 0.00% | 2.67% | 0.00% | 0.00% | 0.00% | 0.00% | 18.42% | 4.20% | 25.33% | 10.06% | 20.55% |
HPQ | 21.27% | 22.38% | 19.00% | 24.95% | 18.78% | 16.58% | 15.88% | 14.88% | 13.48% | 3.41% | 6.93% | 1.57% | 10.91% |
PSA | 12.08% | 15.68% | 15.84% | 15.57% | 15.77% | 15.63% | 7.81% | 0.00% | 38.43% | 31.22% | 41.50% | 34.67% | 41.70% |
SEE | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 7.49% | 12.88% | 4.78% | 11.08% | 7.65% |
ZION | 20.91% | 17.88% | 18.28% | 18.92% | 18.22% | 17.27% | 15.12% | 14.63% | 6.48% | 13.10% | 13.29% | 14.57% | 10.48% |
PEP11900D031 | 2.34% | 6.29% | 0.00% | 3.83% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
PEP13000D012 | 6.37% | 15.62% | 19.18% | 15.37% | 19.39% | 25.39% | 24.55% | 18.52% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
PEP13000M088 | 2.03% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 9.59% | 0.00% | 0.00% | 0.00% | 0.00% |
PEP23900M103 | 4.15% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 2.27% | 0.00% | 0.00% | 0.00% |
PEP70101M530 | 9.62% | 5.86% | 4.04% | 4.75% | 4.03% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
PEP70101M571 | 8.27% | 5.43% | 14.87% | 7.56% | 14.93% | 16.77% | 27.86% | 46.51% | 0.00% | 17.84% | 2.90% | 16.20% | 1.41% |
PEP70310M156 | 3.98% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
import matplotlib.pyplot as plt
# Plotting a comparison of assets weights for each portfolio
fig = plt.gcf()
fig.set_figwidth(14)
fig.set_figheight(6)
ax = fig.subplots(nrows=1, ncols=1)
w_s.plot.bar(ax=ax)
<Axes: >
We can see that in the examples the Augmented Black Litterman model and the Bayesian Black Litterman model increase the diversification when we only consider the mean vector obtained through these methods and we use the covariance and scenarios from the factor model.