Skip to content

CLA returns silently suboptimal portfolios on ordinary inputs, and HRPOpt.optimize() is dead on scipy >= 1.18 #750

Description

@lenamonj

Everything below is backed by a reproduction script, with the numbers measured rather than estimated.

1. CLA produces off-budget turning points, and the error purge hides it. cla.py:201 slices wB from self.w[-1], which is stale by that point. Across 300 randomly generated ordinary problems, 50 produce a turning point whose weights do not sum to 1 (worst |sum(w) - 1| = 9.07e-01). _purge_num_err then deletes those points, so max_sharpe interpolates across the gap and returns a silently suboptimal portfolio in 22 of 300 cases, worst case 2.02% of Sharpe. No error is raised. cvxpy and scipy SLSQP independently agree on the correct answers. With the slice corrected: 0 of 300 and 0 of 300.

2. Equal expected returns. 244 of 300 such problems raise a raw TypeError, one raises IndexError, and of the 55 that return, 31 are wrong (worst 76.2% Sharpe shortfall). This is a bug rather than a precondition violation: at eps = 1e-10 the answer is exactly right and at eps = 0 it is not. Worth noting that the obvious _infnone fix is worse, at 256 of 300 silently suboptimal, so please do not take that route.

3. Your CI is red on main. Run 28899115146 is at the current SHA. HRPOpt.optimize() calls sch._LINKAGE_METHODS, removed in scipy 1.18.0, while pyproject.toml pins scipy>=1.3.0 unbounded. The whole HRP feature is unreachable on a fresh install.

I have a patch for all of it: repro goes 3/13 to 13/13 and your suite goes from 7 failed / 305 passed to 312 passed. One existing test assertion needed widening and that is called out explicitly rather than hidden. Glad to open a PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions