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
- Increase the optimizer's lookback/period so the covariance matrix has enough non-flat return samples.
- Before optimizing, verify each symbol actually has price variation in the history window; drop flat or illiquid symbols.
- Confirm History() returned data (check the DataFrame is non-empty and not all-NaN) before feeding it to the optimizer.
- 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
- Always pull a sufficiently long History() window for every symbol before computing covariance.
- Drop symbols whose return standard deviation is zero before forming the covariance matrix.
- Check that History() returned non-empty, finite data — never feed an all-zero covariance to the optimizer.
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
- MinimumVariancePortfolioOptimizer.portfolio_variance: Volati
- Total must be > 0 for Euclidean Projection onto the Simplex.
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/ec0f6ac28428a397.
Report an issue: GitHub.