QuantConnect/Lean · error · ArgumentException
Total must be > 0 for Euclidean Projection onto the Simplex.
Error message
Total must be > 0 for Euclidean Projection onto the Simplex.
What it means
MeanReversionPortfolioConstructionModel.normalize() projects a weight vector onto the L1 simplex (sum-to-total) via the Duchi et al. algorithm. A non-positive 'total' makes the projection undefined (it cannot normalize onto a negative/zero-mass simplex), so it raises ArgumentException before running the sort/cumsum logic.
Source
Thrown at Algorithm.Framework/Portfolio/MeanReversionPortfolioConstructionModel.py:165
for symbol in symbols:
if symbol not in self.symbol_data:
self.symbol_data[symbol] = self.MeanReversionSymbolData(algorithm, symbol, self.window_size, self.resolution)
def SimplexProjection(self, vector, total=1):
"""Normalize the updated portfolio into weight vector:
v_{t+1} = arg min || v - v_{t+1} || ^ 2
Implementation from:
Duchi, J., Shalev-Shwartz, S., Singer, Y., & Chandra, T. (2008, July).
Efficient projections onto the l 1-ball for learning in high dimensions.
In Proceedings of the 25th international conference on Machine learning
(pp. 272-279).
Args:
vector: unnormalized weight vector
total: total weight of output, default to be 1, making it a probabilistic simplex
"""
if total <= 0:
raise ArgumentException("Total must be > 0 for Euclidean Projection onto the Simplex.")
vector = np.asarray(vector)
# Sort v into u in descending order
mu = np.sort(vector)[::-1]
sv = np.cumsum(mu)
rho = np.where(mu > (sv - total) / np.arange(1, len(vector) + 1))[0][-1]
theta = (sv[rho] - total) / (rho + 1)
w = (vector - theta)
w[w < 0] = 0
return w
class MeanReversionSymbolData:
def __init__(self, algo, symbol, window_size, resolution):
# Indicator of price
self.Identity = algo.Identity(symbol, resolution)
# Moving average indicator for mean reversion levelView on GitHub (pinned to d2c3659f87)
Solutions
- Do not override the 'total' argument; let it default to 1 so weights sum to 100%.
- If computing total dynamically, clamp/guard it to a positive minimum before calling normalize().
- Ensure the algorithm has positive total portfolio value / budget before rebalancing.
Example fix
# before
total = sum_of_signed_targets # could be <= 0
w = self.normalize(vector, total)
# after
total = sum_of_signed_targets
if total <= 0:
raise ValueError('normalize requires positive total')
w = self.normalize(vector, total) Defensive patterns
Strategy: validation
Validate before calling
def safe_normalize(model, vector, total=1):
if total is None or total <= 0:
total = 1.0
return model.normalize(vector, total) Type guard
def valid_total(total) -> bool:
return isinstance(total, (int, float)) and total > 0 Prevention
- Don't override the 'total' argument unless you understand the simplex projection.
- Keep total portfolio value positive before rebalancing so any derived budget stays positive.
When it happens
Trigger: normalize(vector, total) is called with total <= 0. In normal use total defaults to 1; this fires only if a caller overrides total with zero or a negative number, or passes a degenerate budget.
Common situations: Subclass overriding normalize() and forwarding a computed total that became 0/negative (e.g., a sum of signed targets that cancelled out), or passing a budget parameter derived from total portfolio value when that value is zero/under-margin.
Related errors
- ShareClassMeanReversionAlphaModel: symbols parameter must co
- Expected open order for emitted insight
- Unexpected open order for emitted insight: {order}
- MaximumSharpeRatioPortfolioOptimizer.portfolio_variance: Vol
- Long position must be allowed in MeanReversionPortfolioConst
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/cdad2310e79637a5.
Report an issue: GitHub.