MCPcopy Create free account
hub / github.com/Open-Quant/openquant / project_to_bounds

Function project_to_bounds

crates/openquant/src/portfolio_optimization.rs:248–280  ·  view source on GitHub ↗
(weights: &mut [f64], bounds: &[(f64, f64)])

Source from the content-addressed store, hash-verified

246}
247
248fn project_to_bounds(weights: &mut [f64], bounds: &[(f64, f64)]) -> Result<(), AllocError> {
249 for (w, (lo, hi)) in weights.iter_mut().zip(bounds.iter()) {
250 *w = w.clamp(*lo, hi.min(1.0));
251 }
252 let sum: f64 = weights.iter().sum();
253 if (sum - 1.0).abs() < 1e-12 {
254 return Ok(());
255 }
256 if sum < 1.0 {
257 let deficit = 1.0 - sum;
258 let capacities: Vec<f64> =
259 bounds.iter().zip(weights.iter()).map(|(b, w)| b.1.min(1.0) - *w).collect();
260 let total_cap: f64 = capacities.iter().sum();
261 if total_cap <= 1e-12 {
262 return Err(AllocError::InfeasibleBounds { lower_sum: 1.0, upper_sum: 0.0 });
263 }
264 for i in 0..weights.len() {
265 weights[i] += deficit * capacities[i] / total_cap;
266 }
267 } else {
268 let excess = sum - 1.0;
269 let removable: Vec<f64> =
270 bounds.iter().zip(weights.iter()).map(|(b, w)| (w - b.0).max(0.0)).collect();
271 let total_rm: f64 = removable.iter().sum();
272 if total_rm <= 1e-12 {
273 return Err(AllocError::InfeasibleBounds { lower_sum: 1.0, upper_sum: 0.0 });
274 }
275 for i in 0..weights.len() {
276 weights[i] -= excess * removable[i] / total_rm;
277 }
278 }
279 Ok(())
280}
281
282fn inverse_variance(cov: &DMatrix<f64>, bounds: &[(f64, f64)]) -> Result<Vec<f64>, AllocError> {
283 check_bounds_feasible(bounds)?;

Callers 4

inverse_varianceFunction · 0.70
solve_min_volFunction · 0.70
solve_max_sharpeFunction · 0.70

Calls 1

lenMethod · 0.80

Tested by

no test coverage detected