Mean-Variance Framework

\[\max_w \quad w^T \mu - \frac{\lambda}{2} w^T \Sigma w - \gamma \lvert\lvert w - w_0 \rvert\rvert\]

where:

Constraints

Common constraints:

Python Implementation

from scipy.optimize import minimize

def optimize_portfolio(expected_returns, cov_matrix, 
                      current_weights=None,
                      risk_aversion=1.0,
                      turnover_penalty=0.0):
    """
    Mean-variance portfolio optimization.
    
    Returns
    -------
    dict with keys: weights, expected_return, volatility, sharpe_ratio
    """
    n_assets = len(expected_returns)
    
    # Objective function
    def objective(w):
        ret = w @ expected_returns
        risk = w @ cov_matrix @ w
        turnover = 0
        if current_weights is not None:
            turnover = np.sum(np.abs(w - current_weights))
        return -(ret - risk_aversion * risk - turnover_penalty * turnover)
    
    # Constraints
    constraints = [
        {'type': 'eq', 'fun': lambda w: np.sum(w) - 1}
    ]
    
    # Bounds
    bounds = tuple((0, 1) for _ in range(n_assets))
    
    # Initial guess
    x0 = np.ones(n_assets) / n_assets
    
    # Optimize
    result = minimize(objective, x0, method='SLSQP',
                     bounds=bounds, constraints=constraints)
    
    if not result.success:
        raise ValueError(f"Optimization failed: {result.message}")
    
    weights = result.x
    
    return {
        'weights': weights,
        'expected_return': weights @ expected_returns,
        'volatility': np.sqrt(weights @ cov_matrix @ weights)
    }

Turnover Penalty

The turnover penalty $\gamma$ should approximately equal your transaction cost:

Robustness

Optimization is sensitive to estimation error. To improve robustness:

  1. Shrink expected returns toward zero
  2. Use robust covariance estimates
  3. Add position limits
  4. Include turnover penalty