Skip to content

Fix MaximumSharpeRatioPortfolioOptimizer to maximize the Sharpe ratio#9560

Open
Ruuudy1 wants to merge 1 commit into
QuantConnect:masterfrom
Ruuudy1:bug-9322-maximum-sharpe-optimizer
Open

Fix MaximumSharpeRatioPortfolioOptimizer to maximize the Sharpe ratio#9560
Ruuudy1 wants to merge 1 commit into
QuantConnect:masterfrom
Ruuudy1:bug-9322-maximum-sharpe-optimizer

Conversation

@Ruuudy1

@Ruuudy1 Ruuudy1 commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Description

Fix MaximumSharpeRatioPortfolioOptimizer so it maximizes the Sharpe ratio. Python optimizes (mu - rf)'w / sqrt(w'Sw) directly with SLSQP. C# uses a bounds-aware Charnes-Cooper QP (y = kw, minimize y'Sy s.t. (mu - rf)'y = 1, recover w = y / (1'y)), with the per-weight bounds written as linear constraints in y so it stays a convex QP. Both honor the [lower, upper] range and reach the same optimum. Unit test expectations updated to the corrected weights.

Related Issue

#9322

Motivation and Context

The optimizer constrained the portfolio return to the equal-weight return ((mu - rf)'w = k) and minimized variance, so it behaved like a minimum-variance model and returned near-flat weights regardless of the inputs instead of the maximum Sharpe ratio portfolio.

Requires Documentation Change

N/A

How Has This Been Tested?

Updated MaximumSharpeRatioPortfolioOptimizerTests with the corrected weights (regenerated from the solver output) and confirmed every case passes, including the bounds and fallback cases. No regression algorithm consumes this optimizer (the BlackLitterman models and tests pass UnconstrainedMeanVariancePortfolioOptimizer explicitly), so the impact is limited to this optimizer and its unit tests.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • Refactor (non-breaking change which improves implementation)
  • Performance (non-breaking change which improves performance. Please add associated performance test and results)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Non-functional change (xml comments/documentation/etc)

Checklist:

  • My code follows the code style of this project.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • My branch follows the naming convention bug-<issue#>- or feature-<issue#>-

The optimizer fixed the portfolio return to the equal-weight return
((µ − r_f)ᵀw = k) and minimized variance, which collapsed it to a
minimum-variance optimizer instead of maximizing the Sharpe ratio.

Python now maximizes (µ − r_f)ᵀw / √(wᵀΣw) directly with SLSQP, keeping
the budget constraint Σw = 1 and the per-weight bounds. C# applies the
Charnes-Cooper substitution y = κw, minimizing yᵀΣy subject to
(µ − r_f)ᵀy = 1 and recovering w = y / (1ᵀy); the per-weight bounds are
written as linear constraints in y (yᵢ − up·(1ᵀy) ≤ 0, yᵢ − lw·(1ᵀy) ≥ 0)
so the problem stays a convex QP and the [lower, upper] range is honored.

Both languages reach the same optimum, and the unit-test expectations are
updated to the corrected weights.

Addresses QuantConnect#9322
@Ruuudy1 Ruuudy1 force-pushed the bug-9322-maximum-sharpe-optimizer branch from 9b5cb20 to d5af87f Compare June 23, 2026 22:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant