As part of an ongoing effort to provide finance-related Python libraries, I will start with portfolio optimization. This page documents the library’s Hello-World version.
Installation
If you have Python 3.6+ installed, run the following in your terminal:
pip install git+https://github.com/WizardKingZ/portfolio_optimization.git
To uninstall it, run:
pip uninstall portfolio_optimization
Getting Started
Unconstrained Portfolio
## import MarkowitzPortfolio
from portfolio_optimization import MarkowitzPortfolio
import numpy as np
## Load the Fama-French Five Factor Dataset to calculate annualized return and covariance
rts = np.array([0.11, 0.07, 0.09, 0.08, 0.08])
cov = np.array([[ 0.0242, -0.0015, -0.0025, -0.0019, -0.0033],
[-0.0015, 0.0067, 0.0004, -0.0013 , 0.0001 ],
[-0.0025, 0.0004, 0.0063, -0.0002, 0.0025],
[-0.0019, -0.0013 , -0.0002, 0.0033, 0.0001],
[-0.0033, 0.0001 , 0.0025, 0.0001, 0.0033]])
ffFactorNames = ['Market', 'SMB', 'HML', 'RMW', 'CMA']
## Initialize the MarkowitzPortfolio with the expected return, covariance and asset names
## both cov and rts are numpy arrays. rts is a row vector
## ffFactorNames should be a list
port = MarkowitzPortfolio(rts, cov, ffFactorNames, riskFreeRate=0.046)
## set the target return as 0.1
## you can set risk aversion as well
## we will cover constraints optimization later
configuration = {'constraints': None,
'riskAversion': None,
'targetReturn': 0.1}
## obtain weights allocated on each asset
weights = port.get_allocations(configuration=configuration)
## plot the efficient frontier and capital market line
port.display_efficient_frontier(assetsAnnotation=True,
specialPortfolioAnnotation=True,
addTangencyLine=True,
upper_bound=0.14)

Constrained Portfolio
Continuing with the Fama-French five-factor (FF-5) data, suppose you want a portfolio with the following constraints:
\[\begin{array}{c|c|c} \textbf{Asset} & \textbf{Lower Bound %} & \textbf{Upper Bound %}\\\ \text{MKT} & 0 & 100 \\\ \text{HML} & 50 & 100\\\ \text{SMB} & 0 & 100 \\\ \text{RMW} & 0 & 100 \\\ \text{CMA} & -50 & 100 \\\ \end{array}\]Set up these constraints as follows:
constraints = {'Market': [0, 1],
'HML': [0.5, 1],
'SMB': [0, 1],
'RMW': [0, 1],
'CMA': [-.5, 1]}
configuration['constraints'] = constraints
## obtain weights allocated on each asset
weights = port.get_allocations(configuration=configuration)
Black-Litterman Portfolio Allocation
Investors often want to incorporate their own views when solving asset allocation problems. For example:
\[\begin{array}{c|c|c} \textbf{View} & \textbf{Confidence Level %} & \textbf{Plus and Minus %}\\\ \text{Market outperforms by 1%} & 95 & 5 \\\ \text{SMB beats RMW by 1%} & 90 & 5\\\ \text{A portfolio of 20% of SMB and 80% of HML beats RMW by 1%} & 99 & 1\\\ \end{array}\]Use BlackLittermanPortfolio to incorporate these views:
from portfolio_optimization import BlackLittermanPortfolio
## assetNames are ['Market', 'HML', 'SMB', 'RMW', 'CMA']
port = BlackLittermanPortfolio(modeledReturn, modeledCovariance, assetNames, riskFreeRate=0.046)
views = {'Market': {'type': 'absolute', 'scale': 0.01, 'confidence': 95, 'plusminus%': 5},
'SMB|RMW' : {'type': 'relative', 'scale': 0.01, 'confidence': 90, 'plusminus%': 5, 'weights': [1., -1.]},
'SMB|HML|RMW' : {'type': 'relative', 'scale': 0.01, 'confidence': 99, 'plusminus%': 1, 'weights': [.2, .8, -1.]},
}
## second parameter is the R^2 used in estimating your modeled expected returns
port.update_views(views, 0.1)
## Let's use the same parameters
configuration = {'constraints': None,
'riskAversion': None,
'targetReturn': 0.1}
## you can obtain the BL weights
weights = port.get_allocations(configuration=configuration)
## you can reset the portfolio to become a regular Markowitz portfolio
port.reset()
The second argument of update_view is the \(R^2\) of your modeled returns; I will add factor modeling tools in a later iteration. As a starting point, consider the most widely used factor model, the Capital Asset Pricing Model (CAPM). CAPM-estimated returns typically have an \(R^2\) below 15%, so set this parameter below 15% (the example above uses 10%).
I will add more functionality over time. The next iteration will include:
- Hansen-Jagannathan bound test
- Factor models for estimating stochastic discount factors
- Style analysis