Modern Portfolio Theory & Markowitz
Relevant source files
The following files were used as context for generating this wiki page:
Modern Portfolio Theory (MPT) and Markowitz optimization form a central pillar of the universal-portfolios project, providing mathematical frameworks for selecting portfolio weights that optimize the trade-off between expected return and risk. These implementations allow for both online selection (adjusting weights as new data arrives) and hindsight analysis to determine the best possible static portfolio for a given historical period.
The project implements these theories through classes like MPT and BestMarkowitz, utilizing robust covariance and mean estimators to handle real-world financial data complexities such as missing values and transaction costs.
Sources: universal/algos/mpt.py:22-23, universal/algos/best_markowitz.py:9-13, README.md:15-20
Core Architecture and Logic
The MPT implementation follows the standard Algo template, where weights are updated at each timestep (for MPT) or calculated once (for BestMarkowitz). The optimization logic typically involves solving a quadratic programming (QP) problem to find weights $b$ that minimize variance for a target return or maximize a risk-adjusted objective.
Optimization Objectives
The system supports multiple optimization methods:
- MPT: Minimizes $b^T \Sigma b - q \cdot b^T \mu$, where $q$ is the risk aversion parameter.
- Sharpe: Maximizes the Sharpe Ratio $\frac{b^T \mu}{\sqrt{b^T \Sigma b + q}}$.
- Variance: Minimizes portfolio variance $b^T \Sigma b$ subject to a minimum return constraint $b^T \mu \geq q$.
Sources: universal/algos/mpt.py:252-254, universal/algos/mpt.py:293-294, universal/algos/mpt.py:343-345
Data Flow for Online Optimization
The following diagram illustrates the data flow within the step function of the MPT algorithm.
The diagram shows how raw historical data is transformed into statistical estimates (Mu and Sigma) before being passed to specific optimization solvers based on the chosen method.
Sources: universal/algos/mpt.py:168-203, universal/algos/mpt.py:206-214
Key Components and Estimators
The accuracy of MPT is highly dependent on the estimation of the mean ($\mu$) and covariance ($\Sigma$). The project provides a modular architecture to plug in different estimation strategies.
Covariance Estimators
Located in estimators.py, these components provide different ways to calculate the risk relationship between assets:
| Estimator | Description | Source |
|---|---|---|
EmpiricalCovariance | Standard sample covariance. | universal/algos/mpt.py:76 |
LedoitWolf | Shrunk covariance estimator to reduce estimation error. | universal/algos/mpt.py:78 |
OAS | Oracle Approximating Shrinkage. | universal/algos/mpt.py:82 |
SingleIndexCovariance | Estimation using a single-index model (CAPM based). | universal/algos/estimators.py:465-475 |
Mean (Mu) Estimators
| Estimator | Description | Source |
|---|---|---|
HistoricalEstimator | Uses simple arithmetic mean of historical returns. | universal/algos/estimators.py:228-235 |
SharpeEstimator | Deduces return from volatility assuming a fixed target Sharpe ratio. | universal/algos/estimators.py:114-140 |
PCAEstimator | Predicts mean using Principal Component Analysis. | universal/algos/estimators.py:279-296 |
Implementation Details: MPT Class
The MPT class in universal/algos/mpt.py inherits from Algo and manages the lifecycle of the optimization process.
Optimization Logic Sequence
The sequence below depicts how MPT interacts with the cvxopt solver during a weight update.
Key Configuration Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
window | int | None | Rolling window for mean/variance calculation. |
method | str | "mpt" | Optimization objective ("mpt", "sharpe", "variance"). |
q | float | 0.01 | Risk aversion/tuning parameter; $q=2$ is full-Kelly. |
gamma | float/Series | 0.0 | Penalty for weight changes (transaction costs). |
max_leverage | float | 1.0 | Maximum allowed leverage (sum of absolute weights). |
Sources: universal/algos/mpt.py:39-65
Best Markowitz (Hindsight Optimization)
The BestMarkowitz class, found in universal/algos/best_markowitz.py, is a variation of the Constant Rebalanced Portfolio (CRP). Unlike online MPT, it looks at the entire dataset $X$ to find the single set of weights that would have performed best historically.
def weights(self, X):
freq = tools.freq(X.index)
R = X - 1
sigma = R.cov() * freq
# ... Mu calculation logic ...
self.b = tools.opt_markowitz(mu, sigma, **self.opt_markowitz_kwargs)
return super().weights(R)
Sources: universal/algos/best_markowitz.py:23-40
Risk and Constraints Handling
The system utilizes cvxopt to enforce complex constraints during optimization.
- Bounds: Individual asset weight limits (e.g., $0 \leq b_i \leq 0.25$).
- Force Weights: Ability to lock specific assets to fixed weights.
- Short Selling: Controlled by constraints in the QP problem or the
allow_selllogic. - Transaction Cost Penalization: Implemented via the
gammaparameter, which modifies the objective function to penalize the distance between current weights $b$ and $last_b$.
Sources: universal/algos/mpt.py:307-338, universal/algos/mpt.py:408-422, universal/tools.py:186-215
Summary
The Markowitz and Modern Portfolio Theory module provides a high-fidelity implementation of classic financial optimization. By integrating with the project's estimator framework and using robust QP solvers, it allows users to simulate sophisticated investment strategies that account for risk, return, and operational constraints like transaction fees. Its flexibility in switching between different optimization objectives (Sharpe vs. MPT) makes it a versatile tool for both research and benchmark analysis.
Sources: universal/algos/mpt.py:25-30, README.md:15-18