PortfolioOptimizer

Python program implementing Mean-Variance Portfolio Theory to construct optimal portfolios and functions for evaluating the model: efficient frontier visualization, Monte Carlo simulation, and real-world performance.

View repository Watch demo Published November 8, 2021

Overview

Python implementation of Markowitz mean-variance optimization with closed-form solutions. Given historical returns, compute the efficient frontier analytically and backtest the portfolios on different time periods.

Features

  • Closed-form solution for minimum variance portfolios
  • Efficient frontier visualization
  • Backtesting on out-of-sample data
  • Monte Carlo simulation
  • Yahoo Finance data integration

The Math

We begin with the explicit, finite-asset formulation and then generalize. Consider three assets with weights \(w_A, w_B, w_C\), expected returns \(\mu_A, \mu_B, \mu_C\), and covariances \(\sigma_{ij}\).

Portfolio Variance (Expanded Form)

\[ \sigma_p^2 = w_A^2\sigma_A^2 + w_B^2\sigma_B^2 + w_C^2\sigma_C^2 + 2w_A w_B\sigma_{AB} + 2w_A w_C\sigma_{AC} + 2w_B w_C\sigma_{BC} \]

with the full-investment constraint:

\[ w_A + w_B + w_C = 1 \]

Lagrangian Formulation

We minimize variance subject to the constraint using a Lagrange multiplier:

\[ L(w_A,w_B,w_C,\lambda) = \sigma_p^2 + \lambda(w_A+w_B+w_C-1) \]

Taking partial derivatives yields a linear system in the portfolio weights and the multiplier.

Matrix (KKT) System

\[ \begin{bmatrix} 2\sigma_A^2 & 2\sigma_{AB} & 2\sigma_{AC} & 1 \\ 2\sigma_{AB} & 2\sigma_B^2 & 2\sigma_{BC} & 1 \\ 2\sigma_{AC} & 2\sigma_{BC} & 2\sigma_C^2 & 1 \\ 1 & 1 & 1 & 0 \end{bmatrix} \begin{bmatrix} w_A \\ w_B \\ w_C \\ \lambda \end{bmatrix} = \begin{bmatrix} 0 \\ 0 \\ 0 \\ 1 \end{bmatrix} \]

This system characterizes the global minimum variance portfolio.

General Vector Form

For \(n\) assets, define weights \(w \in \mathbb{R}^n\), expected returns \(\mu \in \mathbb{R}^n\), and covariance matrix \(\Sigma \in \mathbb{R}^{n \times n}\).

\[ \sigma_p^2 = w^T \Sigma w \quad\quad \mu_p = w^T \mu \]

Mean–Variance Optimization

\[ \min_w \quad w^T \Sigma w \quad \text{s.t.} \quad \begin{cases} w^T \mu = \mu_p^* \\ w^T \mathbf{1} = 1 \end{cases} \]

Solving the associated KKT system yields the closed-form efficient frontier and the global minimum variance portfolio as special cases.

Demo & Explainer

Complete walkthrough demonstrating portfolio construction, efficient frontier analysis, and backtesting workflows.

Implementation

1. Compute Covariance Matrix

Fetch historical prices from Yahoo Finance. Compute daily returns. Calculate the sample covariance matrix \(\Sigma\) and mean return vector \(\mu\).

2. Invert and Compute Constants

Compute \(\Sigma^{-1}\). Calculate the scalar constants \(A, B, C, D\) using matrix multiplications: \(A = \mathbf{1}^T \Sigma^{-1} \mu\), etc. These appear in the closed-form solution.

3. Generate Efficient Frontier

For a range of target returns \(\mu_p^*\), apply the closed-form formula to get \(w^*\). Compute \(\sigma_p = \sqrt{w^{*T} \Sigma w^*}\). Plot \((\sigma_p, \mu_p^*)\).

4. Backtest on New Data

Take the optimized weights \(w^*\) from the training period. Apply them to a different time period. Measure actual return \(w^{*T} \mu_{\text{test}}\) and variance \(w^{*T} \Sigma_{\text{test}} w^*\). Compare to predictions.

Interpretation

The closed-form solution tells you exactly how to weight your assets given their historical returns and covariances. The constants \(A, B, C, D\) encode the geometry of the efficient frontier.

Key insight: The optimal weights \(w^*\) are a linear combination of \(\Sigma^{-1} \mu\) and \(\Sigma^{-1} \mathbf{1}\). The first term weights assets by risk-adjusted return. The second ensures full investment.

Global minimum variance portfolio: This is where the efficient frontier turns. Below this point, you're taking on risk without increasing expected return. The formula \(w_{gmv} = \frac{\Sigma^{-1} \mathbf{1}}{C}\) shows you just weight assets inversely to their contribution to portfolio variance.

Backtesting reveals model failure: If the out-of-sample scatter plot shows actual returns far below predictions, your covariance matrix was wrong (non-stationary), or the efficient frontier shifted. This is common in real markets.

How to Run

# Clone and install
git clone https://github.com/aarwitz/PortfolioOptimizer.git
cd PortfolioOptimizer
pip install pandas numpy matplotlib yfinance

# Run
python -c "from find_optimized_portfolio import main; main()"

Interactive CLI guides you through ticker selection, date ranges, and backtesting options.

Code Structure

  • matrix_manip.py — Compute \(\Sigma^{-1}\), constants \(A, B, C, D\), and optimal weights \(w^*\)
  • DF_helper.py — Fetch data from Yahoo Finance, compute returns and covariance
  • RealTest.py — Apply weights to out-of-sample data, measure performance
  • plots.py — Efficient frontier and backtest scatter plots
  • MonteCarlo.py — Simulate portfolio paths using historical statistics