Financionerioncios
Orenji
Riskfolio-Lib
Dany Cajas
import numpy as np
import pandas as pd
import yfinance as yf
import warnings
warnings.filterwarnings("ignore")
pd.options.display.float_format = '{:.4%}'.format
# Date range
start = '2016-01-01'
end = '2019-12-30'
# Tickers of assets
assets = ['JCI', 'TGT', 'CMCSA', 'CPB', 'MO', 'APA', 'MMC', 'JPM',
'ZION', 'PSA', 'BAX', 'BMY', 'LUV', 'PCAR', 'TXT', 'TMO',
'DE', 'MSFT', 'HPQ', 'SEE', 'VZ', 'CNP', 'NI', 'T', 'BA']
assets.sort()
# Tickers of factors
factors = ['MTUM', 'QUAL', 'VLUE', 'SIZE', 'USMV']
factors.sort()
tickers = assets + factors
tickers.sort()
# Downloading data
data = yf.download(tickers, start = start, end = end)
data = data.loc[:,('Adj Close', slice(None))]
data.columns = tickers
[*********************100%***********************] 30 of 30 completed
# Calculating returns
X = data[factors].pct_change().dropna()
Y = data[assets].pct_change().dropna()
display(X.head())
MTUM | QUAL | SIZE | USMV | VLUE | |
---|---|---|---|---|---|
Date | |||||
2016-01-05 00:00:00-05:00 | 0.4735% | 0.2672% | 0.0000% | 0.6780% | 0.1635% |
2016-01-06 00:00:00-05:00 | -0.5267% | -1.1914% | -0.5380% | -0.6253% | -1.8277% |
2016-01-07 00:00:00-05:00 | -2.2293% | -2.3798% | -1.7181% | -1.6215% | -2.1609% |
2016-01-08 00:00:00-05:00 | -0.9549% | -1.1376% | -1.1978% | -1.0086% | -1.0873% |
2016-01-11 00:00:00-05:00 | 0.6043% | 0.1479% | -0.5898% | 0.1491% | -0.6183% |
import riskfolio as rp
step = 'Forward' # Could be Forward or Backward stepwise regression
loadings = rp.loadings_matrix(X=X, Y=Y, stepwise=step)
loadings.style.format("{:.4f}").background_gradient(cmap='RdYlGn')
const | MTUM | QUAL | SIZE | USMV | VLUE | |
---|---|---|---|---|---|---|
APA | -0.0006 | -0.6551 | 0.0000 | 0.9406 | -0.7883 | 1.7237 |
BA | 0.0005 | 0.0000 | 1.1744 | 0.3616 | -0.4322 | 0.0000 |
BAX | 0.0003 | 0.3146 | 0.0000 | 0.0000 | 0.7717 | 0.0000 |
BMY | -0.0003 | 0.0000 | 0.8123 | 0.0000 | 0.0000 | 0.0000 |
CMCSA | 0.0001 | 0.0000 | 0.4958 | 0.0000 | 0.4962 | 0.0000 |
CNP | 0.0001 | -0.5595 | -0.2157 | 0.0000 | 1.8341 | 0.0000 |
CPB | -0.0003 | -0.4782 | -0.5993 | 0.0000 | 2.0793 | 0.0000 |
DE | 0.0004 | 0.0000 | 0.0000 | 0.3631 | 0.0000 | 0.8090 |
HPQ | 0.0002 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 1.2514 |
JCI | 0.0001 | 0.0000 | 0.0000 | 0.3412 | 0.0000 | 0.5797 |
JPM | 0.0005 | 0.0000 | 0.3076 | 0.0000 | -0.5485 | 1.1512 |
LUV | -0.0001 | 0.0000 | 0.0000 | 0.3642 | 0.0000 | 0.6767 |
MMC | 0.0003 | -0.2693 | 0.6808 | 0.0000 | 0.6066 | 0.0000 |
MO | -0.0004 | -0.4572 | 0.0000 | 0.0000 | 1.4359 | 0.0000 |
MSFT | 0.0005 | 1.0302 | 0.6530 | -0.2640 | -0.2595 | 0.0000 |
NI | -0.0000 | -0.4649 | -0.4611 | 0.0000 | 2.3257 | -0.3532 |
PCAR | 0.0003 | -0.4420 | 1.0319 | 0.2217 | -0.4831 | 0.7536 |
PSA | -0.0004 | -0.3311 | 0.0000 | 0.0000 | 1.7073 | -0.4915 |
SEE | -0.0005 | -0.3267 | 0.0000 | 0.2594 | 0.6973 | 0.4801 |
T | 0.0000 | -0.4414 | -0.3693 | -0.2898 | 1.2928 | 0.7563 |
TGT | 0.0005 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.7562 |
TMO | 0.0002 | 0.2867 | 0.5400 | 0.0000 | 0.3864 | 0.0000 |
TXT | -0.0003 | 0.0000 | 0.4485 | 0.4429 | -0.6363 | 0.8108 |
VZ | 0.0000 | -0.5099 | -0.5271 | -0.2886 | 1.8941 | 0.4321 |
ZION | 0.0004 | -0.2371 | 0.0000 | 0.3554 | -0.8203 | 1.6431 |
# Building the portfolio object
port = rp.Portfolio(returns=Y)
# Calculating optimal 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, d=0.94)
port.factors = X
port.factors_stats(method_mu=method_mu, method_cov=method_cov, d=0.94)
# Estimate optimal portfolio:
port.alpha = 0.05
model='FM' # Factor Model
rm = 'MV' # Risk measure used, this time will be variance
obj = 'Sharpe' # Objective function, could be MinRisk, MaxRet, Utility or Sharpe
hist = False # Use historical scenarios for risk measures that depend on scenarios
rf = 0 # Risk free rate
l = 0 # Risk aversion factor, only useful when obj is 'Utility'
w = port.optimization(model=model, rm=rm, obj=obj, rf=rf, l=l, hist=hist)
display(w.T)
(1004, 25)
APA | BA | BAX | BMY | CMCSA | CNP | CPB | DE | HPQ | JCI | ... | NI | PCAR | PSA | SEE | T | TGT | TMO | TXT | VZ | ZION | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
weights | 0.0000% | 5.9508% | 11.8691% | 0.0000% | 0.0000% | 9.7091% | 0.0000% | 4.3627% | 0.0000% | 0.0000% | ... | 10.4798% | 0.0000% | 0.0000% | 0.0000% | 0.0000% | 5.5106% | 1.3023% | 0.0000% | 4.0977% | 0.0000% |
1 rows × 25 columns
# Plotting the composition of the portfolio
ax = rp.plot_pie(w=w, title='Sharpe FM Mean Variance', others=0.05, nrow=25, cmap = "tab20",
height=6, width=10, ax=None)
points = 50 # Number of points of the frontier
frontier = port.efficient_frontier(model=model, rm=rm, points=points, rf=rf, hist=hist)
display(frontier.T.head())
APA | BA | BAX | BMY | CMCSA | CNP | CPB | DE | HPQ | JCI | ... | NI | PCAR | PSA | SEE | T | TGT | TMO | TXT | VZ | ZION | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.0000% | 0.0000% | 1.9915% | 4.4203% | 3.5982% | 8.4947% | 5.0090% | 0.0000% | 0.0000% | 4.4340% | ... | 12.0935% | 0.0000% | 13.3196% | 1.0089% | 8.3014% | 4.0842% | 0.0000% | 0.0000% | 10.3131% | 1.6678% |
1 | 0.0000% | 1.6589% | 6.2599% | 1.2538% | 3.4251% | 10.4170% | 3.1168% | 0.3986% | 0.0000% | 2.5870% | ... | 13.7067% | 0.0000% | 7.7369% | 0.0000% | 6.7067% | 4.9334% | 0.0000% | 0.0000% | 10.5792% | 1.6507% |
2 | 0.0000% | 2.3022% | 7.3158% | 0.0000% | 3.0350% | 11.1001% | 2.4078% | 0.9815% | 0.0000% | 1.6503% | ... | 14.3023% | 0.0000% | 5.5454% | 0.0000% | 6.0226% | 5.1519% | 0.0000% | 0.0000% | 10.6635% | 1.4140% |
3 | 0.0000% | 2.8523% | 8.2124% | 0.0000% | 2.5287% | 11.5853% | 1.6264% | 1.4954% | 0.0000% | 0.6300% | ... | 14.6708% | 0.0000% | 3.1895% | 0.0000% | 5.2024% | 5.3156% | 0.0757% | 0.0000% | 10.5638% | 1.1082% |
4 | 0.0000% | 3.3061% | 8.9457% | 0.0000% | 2.0093% | 11.9269% | 0.8759% | 1.9173% | 0.0000% | 0.0000% | ... | 14.8951% | 0.0000% | 0.9663% | 0.0000% | 4.3810% | 5.4380% | 0.4388% | 0.0000% | 10.3772% | 0.7801% |
5 rows × 25 columns
# Plotting the efficient frontier
label = 'Max Risk Adjusted Return Portfolio' # Title of point
mu = port.mu_fm # Expected returns
cov = port.cov_fm # Covariance matrix
returns = port.returns_fm # Returns of the assets
ax = rp.plot_frontier(w_frontier=frontier, mu=mu, cov=cov, returns=returns, rm=rm,
rf=rf, alpha=0.05, cmap='viridis', w=w, label=label,
marker='*', s=16, c='r', height=6, width=10, ax=None)
# Plotting efficient frontier composition
ax = rp.plot_frontier_area(w_frontier=frontier, cmap="tab20", height=6, width=10, ax=None)
# Displaying factors statistics
display(loadings.min())
display(loadings.max())
display(X.corr())
const -0.0583% MTUM -65.5125% QUAL -59.9324% SIZE -28.9796% USMV -82.0310% VLUE -49.1495% dtype: float64
const 0.0504% MTUM 103.0208% QUAL 117.4359% SIZE 94.0633% USMV 232.5675% VLUE 172.3667% dtype: float64
MTUM | QUAL | SIZE | USMV | VLUE | |
---|---|---|---|---|---|
MTUM | 100.0000% | 90.4264% | 79.1173% | 87.2320% | 78.5394% |
QUAL | 90.4264% | 100.0000% | 89.8169% | 89.9554% | 91.6580% |
SIZE | 79.1173% | 89.8169% | 100.0000% | 82.5080% | 87.9112% |
USMV | 87.2320% | 89.9554% | 82.5080% | 100.0000% | 76.9678% |
VLUE | 78.5394% | 91.6580% | 87.9112% | 76.9678% | 100.0000% |
# Creating risk factors constraints
constraints = {'Disabled': [False, False, False, False, False],
'Factor': ['MTUM', 'QUAL', 'SIZE', 'USMV', 'VLUE'],
'Sign': ['<=', '<=', '<=', '>=', '<='],
'Value': [-0.3, 0.8, 0.4, 0.8 , 0.9],
'Relative Factor': ['', 'USMV', '', '', '']}
constraints = pd.DataFrame(constraints)
display(constraints)
Disabled | Factor | Sign | Value | Relative Factor | |
---|---|---|---|---|---|
0 | False | MTUM | <= | -30.0000% | |
1 | False | QUAL | <= | 80.0000% | USMV |
2 | False | SIZE | <= | 40.0000% | |
3 | False | USMV | >= | 80.0000% | |
4 | False | VLUE | <= | 90.0000% |
C, D = rp.factors_constraints(constraints, loadings)
port.ainequality = C
port.binequality = D
w = port.optimization(model=model, rm=rm, obj=obj, rf=rf, l=l, hist=hist)
display(w.T)
APA | BA | BAX | BMY | CMCSA | CNP | CPB | DE | HPQ | JCI | ... | NI | PCAR | PSA | SEE | T | TGT | TMO | TXT | VZ | ZION | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
weights | 0.0000% | 6.5843% | 1.4896% | 0.0000% | 0.0000% | 17.4848% | 0.0000% | 4.0876% | 0.0000% | 0.0000% | ... | 13.9652% | 1.3789% | 0.0000% | 0.0000% | 0.3064% | 4.4149% | 0.0000% | 0.0000% | 10.5778% | 2.0946% |
1 rows × 25 columns
To check if the constraints are verified, I will make a regression among the portfolio returns and risk factors:
import statsmodels.api as sm
X1 = sm.add_constant(X)
y = np.matrix(returns) * np.matrix(w)
results = sm.OLS(y, X1).fit()
coefs = results.params
print(coefs)
const 0.0229% MTUM -30.0000% QUAL 15.3036% SIZE 1.7736% USMV 92.6900% VLUE 21.9835% dtype: float64
ax = rp.plot_pie(w=w, title='Sharpe FM Mean Variance', others=0.05, nrow=25, cmap = "tab20",
height=6, width=10, ax=None)
points = 50 # Number of points of the frontier
frontier = port.efficient_frontier(model=model, rm=rm, points=points, rf=rf, hist=hist)
display(frontier.T.head())
APA | BA | BAX | BMY | CMCSA | CNP | CPB | DE | HPQ | JCI | ... | NI | PCAR | PSA | SEE | T | TGT | TMO | TXT | VZ | ZION | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0.0000% | 0.0000% | 1.9926% | 4.4202% | 3.5980% | 8.4936% | 5.0087% | 0.0000% | 0.0000% | 4.4337% | ... | 12.0932% | 0.0000% | 13.3197% | 1.0130% | 8.3001% | 4.0840% | 0.0000% | 0.0000% | 10.3121% | 1.6674% |
1 | 0.0000% | 1.0475% | 4.5030% | 1.9695% | 3.3300% | 10.3898% | 3.6703% | 0.0001% | 0.0000% | 2.9604% | ... | 13.4551% | 0.0000% | 9.0989% | 0.0000% | 7.4172% | 4.6595% | 0.0000% | 0.0000% | 10.8691% | 1.9813% |
2 | 0.0000% | 1.7533% | 4.8601% | 0.7459% | 2.9456% | 11.4506% | 3.1270% | 0.3774% | 0.0000% | 2.0699% | ... | 14.1330% | 0.0000% | 7.2013% | 0.0000% | 7.1319% | 4.7870% | 0.0000% | 0.0000% | 11.2907% | 2.0815% |
3 | 0.0000% | 2.2850% | 5.0718% | 0.0000% | 2.6007% | 12.3054% | 2.6939% | 0.7947% | 0.0000% | 1.3267% | ... | 14.6720% | 0.0000% | 5.6643% | 0.0000% | 6.8992% | 4.8726% | 0.0000% | 0.0000% | 11.6306% | 2.1410% |
4 | 0.0000% | 2.7534% | 5.1132% | 0.0000% | 2.1862% | 13.1588% | 2.2596% | 1.1574% | 0.0000% | 0.5350% | ... | 15.1825% | 0.0000% | 4.1051% | 0.0000% | 6.6679% | 4.9234% | 0.0000% | 0.0000% | 11.9726% | 2.1890% |
5 rows × 25 columns
# Plotting efficient frontier composition
ax = rp.plot_frontier(w_frontier=frontier, mu=mu, cov=cov, returns=returns, rm=rm,
rf=rf, alpha=0.05, cmap='viridis', w=w, label=label,
marker='*', s=16, c='r', height=6, width=10, ax=None)
# Plotting efficient frontier composition
ax = rp.plot_frontier_area(w_frontier=frontier, cmap="tab20", height=6, width=10, ax=None)
display(returns)
APA | BA | BAX | BMY | CMCSA | CNP | CPB | DE | HPQ | JCI | ... | NI | PCAR | PSA | SEE | T | TGT | TMO | TXT | VZ | ZION | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
2016-01-05 00:00:00-05:00 | -0.6212% | 0.0684% | 0.7015% | 0.1909% | 0.4772% | 0.9283% | 0.9912% | 0.1761% | 0.2252% | 0.1002% | ... | 1.1712% | -0.1122% | 0.8782% | 0.3502% | 0.6946% | 0.1709% | 0.5662% | -0.2137% | 0.9753% | -0.3551% |
2016-01-06 00:00:00-05:00 | -2.8766% | -1.2758% | -0.6189% | -0.9939% | -0.8928% | -0.5879% | -0.3663% | -1.6301% | -2.2664% | -1.2376% | ... | -0.0189% | -2.1655% | -0.0371% | -1.3275% | -1.3599% | -1.3348% | -1.0117% | -1.8914% | -0.9195% | -2.5117% |
2016-01-07 00:00:00-05:00 | -2.6603% | -2.6676% | -1.9233% | -1.9591% | -1.9763% | -1.2059% | -0.9113% | -2.3282% | -2.6834% | -1.8334% | ... | -0.8785% | -2.6708% | -1.0103% | -1.9321% | -1.3673% | -1.5868% | -2.5264% | -2.5833% | -1.1151% | -2.2578% |
2016-01-08 00:00:00-05:00 | -1.6385% | -1.2855% | -1.0494% | -0.9502% | -1.0563% | -1.0629% | -0.9909% | -1.2707% | -1.3400% | -1.0335% | ... | -0.9977% | -1.3239% | -0.9137% | -1.2706% | -0.9353% | -0.7750% | -1.2535% | -1.3153% | -0.9453% | -1.1138% |
2016-01-11 00:00:00-05:00 | -2.1923% | -0.0564% | 0.3345% | 0.0940% | 0.1556% | -0.0892% | -0.0996% | -0.6705% | -0.7531% | -0.5542% | ... | 0.2116% | -0.7575% | 0.3162% | -0.5897% | -0.4231% | -0.4203% | 0.3350% | -0.8259% | -0.1979% | -1.4465% |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
2019-12-23 00:00:00-05:00 | 0.6972% | 0.2476% | -0.4231% | -0.0181% | -0.1988% | -0.5600% | -0.7397% | 0.1196% | 0.1321% | 0.0606% | ... | -0.8527% | 0.4842% | -0.6862% | -0.1714% | -0.3171% | 0.1146% | -0.2473% | 0.3183% | -0.5772% | 0.6376% |
2019-12-24 00:00:00-05:00 | -0.1965% | 0.0028% | 0.1506% | -0.0503% | 0.0391% | 0.0929% | 0.1005% | 0.0557% | -0.0072% | 0.0206% | ... | 0.1566% | -0.1185% | 0.0728% | -0.0238% | 0.0208% | 0.0304% | 0.0896% | -0.0882% | 0.0777% | -0.0760% |
2019-12-26 00:00:00-05:00 | 0.0839% | 0.3934% | 0.3568% | 0.2717% | 0.3344% | 0.2787% | 0.1966% | 0.3099% | 0.3689% | 0.2053% | ... | 0.2526% | 0.3537% | 0.2094% | 0.2125% | 0.2761% | 0.2577% | 0.4284% | 0.2202% | 0.2812% | 0.2258% |
2019-12-27 00:00:00-05:00 | -0.7229% | -0.0384% | 0.2654% | -0.0101% | 0.1392% | 0.3665% | 0.3917% | -0.1305% | -0.2432% | -0.1203% | ... | 0.5586% | -0.2999% | 0.4284% | -0.0293% | 0.0874% | -0.1122% | 0.1726% | -0.3568% | 0.2897% | -0.5416% |
2019-12-30 00:00:00-05:00 | -0.0583% | 0.0476% | 0.0293% | -0.0261% | 0.0082% | 0.0074% | -0.0320% | 0.0439% | 0.0207% | 0.0054% | ... | -0.0045% | 0.0257% | -0.0422% | -0.0464% | 0.0022% | 0.0473% | 0.0243% | -0.0347% | 0.0028% | 0.0447% |
1004 rows × 25 columns
In this part I will calculate optimal portfolios for several risk measures. I will find the portfolios that maximize the risk adjusted return for all available risk measures.
I will mantain the constraints on risk factors.
# 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.
# port.reset_linear_constraints() # To reset linear constraints (factor constraints)
rms = ['MV', 'MAD', 'MSV', 'FLPM', 'SLPM', 'CVaR',
'EVaR', 'WR', 'MDD', 'ADD', 'CDaR', 'UCI', 'EDaR']
w_s = pd.DataFrame([])
# When we use hist = True the risk measures all calculated
# using historical returns, while when hist = False the
# risk measures are calculated using the expected returns
# based on risk factor model: R = a + B * F
hist = False
for i in rms:
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% |
BA | 6.58% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
BAX | 1.49% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
BMY | 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 | 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% |
CNP | 17.48% | 42.32% | 53.62% | 41.97% | 53.62% | 41.32% | 53.62% | 48.75% | 0.00% | 46.96% | 23.97% | 46.45% | 48.69% |
CPB | 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% |
DE | 4.09% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
HPQ | 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% |
JCI | 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% |
JPM | 9.54% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
LUV | 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% |
MMC | 28.07% | 23.48% | 0.00% | 24.20% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 13.82% | 61.60% | 14.88% | 0.00% |
MO | 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% |
MSFT | 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% |
NI | 13.97% | 0.00% | 0.00% | 0.00% | 0.00% | 14.80% | 0.00% | 0.00% | 64.54% | 0.00% | 0.00% | 0.00% | 5.93% |
PCAR | 1.38% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
PSA | 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% |
SEE | 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% |
T | 0.31% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
TGT | 4.41% | 34.20% | 46.38% | 33.83% | 46.38% | 43.88% | 46.38% | 39.77% | 35.46% | 39.21% | 14.43% | 38.66% | 45.38% |
TMO | 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% |
TXT | 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% |
VZ | 10.58% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
ZION | 2.09% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 11.48% | 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)
<AxesSubplot:>
w_s = pd.DataFrame([])
# When we use hist = True the risk measures all calculated
# using historical returns, while when hist = False the
# risk measures are calculated using the expected returns
# based on risk factor model: R = a + B * F
hist = True
for i in rms:
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% |
BA | 7.45% | 6.99% | 8.25% | 6.48% | 8.43% | 8.52% | 8.49% | 0.00% | 7.16% | 13.63% | 16.38% | 15.08% | 8.71% |
BAX | 1.03% | 1.30% | 0.36% | 0.95% | 0.22% | 3.48% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
BMY | 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 | 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% |
CNP | 17.82% | 13.25% | 17.50% | 12.81% | 17.98% | 21.30% | 31.96% | 29.80% | 55.32% | 12.02% | 27.50% | 16.60% | 44.54% |
CPB | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.10% | 7.20% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
DE | 3.77% | 1.99% | 2.68% | 2.93% | 2.82% | 3.09% | 1.73% | 0.00% | 5.45% | 0.38% | 0.00% | 1.08% | 0.00% |
HPQ | 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% |
JCI | 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% |
JPM | 7.34% | 10.09% | 6.11% | 10.54% | 5.68% | 0.00% | 0.00% | 7.70% | 0.00% | 1.62% | 0.00% | 3.72% | 0.00% |
LUV | 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% |
MMC | 32.90% | 31.48% | 35.58% | 30.04% | 35.91% | 36.88% | 44.83% | 33.51% | 15.77% | 36.47% | 34.25% | 36.34% | 24.80% |
MO | 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% |
MSFT | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.96% | 8.42% | 0.00% | 3.35% | 0.00% | 6.91% |
NI | 11.40% | 14.37% | 11.04% | 15.88% | 10.64% | 6.20% | 0.00% | 0.00% | 0.00% | 20.22% | 9.44% | 14.85% | 5.47% |
PCAR | 0.89% | 2.93% | 0.60% | 2.70% | 0.34% | 0.00% | 0.00% | 4.18% | 7.87% | 1.22% | 0.80% | 0.00% | 6.73% |
PSA | 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% |
SEE | 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% |
T | 0.00% | 1.59% | 0.00% | 0.15% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 1.62% | 0.00% |
TGT | 6.02% | 4.56% | 7.40% | 4.97% | 7.70% | 8.05% | 12.90% | 16.64% | 0.00% | 3.79% | 0.25% | 2.60% | 2.84% |
TMO | 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% |
TXT | 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% |
VZ | 11.37% | 11.46% | 10.48% | 12.54% | 10.28% | 12.48% | 0.00% | 0.00% | 0.00% | 3.63% | 8.03% | 5.08% | 0.00% |
ZION | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% | 7.02% | 0.00% | 3.04% | 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)
<AxesSubplot:>