QuantConnect/Lean · error · ValueError

MaximumSharpeRatioPortfolioOptimizer.portfolio_variance: Vol

Error message

MaximumSharpeRatioPortfolioOptimizer.portfolio_variance: Volatility cannot be zero. Weights: {weights}

What it means

MaximumSharpeRatioPortfolioOptimizer (Python) computes portfolio variance as wᵀ·Σ·w and uses it as a scipy SLSQP constraint. It raises ValueError when variance is exactly 0 but at least one weight is non-zero, because a non-zero allocation can never have zero volatility with a valid covariance matrix — a zero result means the covariance matrix is degenerate.

Source

Thrown at Algorithm.Framework/Portfolio/MaximumSharpeRatioPortfolioOptimizer.py:86

            {'type': 'eq', 'fun': lambda weights: self.get_budget_constraint(weights)}]

        opt = minimize(lambda weights: -expected_returns.dot(weights) / np.sqrt(self.portfolio_variance(weights, covariance)),   # Objective function: −Sharpe ratio
                       x0,                                                        # Initial guess
                       bounds = self.get_boundary_conditions(size),               # Bounds for variables: lw ≤ w ≤ up
                       constraints = constraints,                                 # Constraints definition
                       method='SLSQP')        # Optimization method:  Sequential Least SQuares Programming

        return opt['x'] if opt['success'] else x0

    def portfolio_variance(self, weights, covariance):
        '''Computes the portfolio variance
        Args:
            weighs: Portfolio weights
            covariance: Covariance matrix of historical returns'''
        variance = np.dot(weights.T, np.dot(covariance, weights))
        if variance == 0 and np.any(weights):
            # variance can't be zero, with non zero weights
            raise ValueError(f'MaximumSharpeRatioPortfolioOptimizer.portfolio_variance: Volatility cannot be zero. Weights: {weights}')
        return variance

    def get_boundary_conditions(self, size):
        '''Creates the boundary condition for the portfolio weights'''
        return tuple((self.minimum_weight, self.maximum_weight) for x in range(size))

    def get_budget_constraint(self, weights):
        '''Defines a budget constraint: the sum of the weights equals unity'''
        return np.sum(weights) - 1

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Increase the optimizer's lookback/period so the covariance matrix has enough non-flat return samples.
  2. Before optimizing, verify each symbol actually has price variation in the history window; drop flat or illiquid symbols.
  3. Confirm History() returned data (check the DataFrame is non-empty and not all-NaN) before feeding it to the optimizer.
  4. If some assets legitimately have near-zero volatility, raise the optimizer's minimum_weight or exclude them from the universe.

Example fix

# before
variance = np.dot(weights.T, np.dot(covariance, weights))
if variance == 0 and np.any(weights):
    raise ValueError(...)

# guard upstream: skip optimization when covariance is degenerate
if not np.any(np.diag(covariance)):
    algorithm.Debug('Skipping Sharpe optimization: zero covariance')
    return x0  # fall back to equal/fallback weights
Defensive patterns

Strategy: validation

Validate before calling

import numpy as np

def safe_optimize(optimizer, weights, covariance, fallback):
    diag = np.diag(covariance)
    if covariance.size == 0 or not np.any(diag) or np.any(np.isnan(covariance)):
        return fallback  # e.g., equal weights
    return optimizer.optimize(weights, covariance)

Type guard

def has_real_variance(covariance: np.ndarray) -> bool:
    return covariance.size > 0 and np.any(np.diag(covariance) > 0) and np.all(np.isfinite(covariance))

Prevention

When it happens

Trigger: portfolio_variance() is called by the optimizer with a weights vector and a covariance matrix where np.dot(weights.T, np.dot(covariance, weights)) == 0 while np.any(weights) is true. Happens when the covariance matrix is all-zeros (flat/constant returns) or rank-deficient.

Common situations: Lookback/history window too short, securities with no price movement (constant closes), weekend/holiday flat data, duplicated symbols, or a History() call that returned empty rows so the covariance collapsed to zeros.

Related errors


AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13). Data as JSON: /api/errors/ec0f6ac28428a397. Report an issue: GitHub.