| 494 | } |
| 495 | |
| 496 | pub fn allocate_from_inputs( |
| 497 | expected_returns: &[f64], |
| 498 | covariance: &DMatrix<f64>, |
| 499 | solution: &str, |
| 500 | opts: &AllocationOptions, |
| 501 | ) -> Result<MeanVariance, AllocError> { |
| 502 | if expected_returns.len() != covariance.nrows() || covariance.nrows() != covariance.ncols() { |
| 503 | return Err(AllocError::DimensionMismatch); |
| 504 | } |
| 505 | let bounds = build_bounds(covariance.nrows(), &opts.bounds, opts.tuple_bounds); |
| 506 | match solution { |
| 507 | "inverse_variance" => { |
| 508 | let w = inverse_variance(covariance, &bounds)?; |
| 509 | Ok(MeanVariance { |
| 510 | portfolio_risk: quad_risk(covariance, &w).sqrt(), |
| 511 | portfolio_return: dot(expected_returns, &w), |
| 512 | portfolio_sharpe: 0.0, |
| 513 | weights: w, |
| 514 | }) |
| 515 | } |
| 516 | "min_volatility" => { |
| 517 | let w = solve_min_vol(covariance, &bounds)?; |
| 518 | Ok(MeanVariance { |
| 519 | portfolio_risk: quad_risk(covariance, &w).sqrt(), |
| 520 | portfolio_return: dot(expected_returns, &w), |
| 521 | portfolio_sharpe: 0.0, |
| 522 | weights: w, |
| 523 | }) |
| 524 | } |
| 525 | "max_sharpe" => { |
| 526 | let w = solve_max_sharpe(covariance, expected_returns, opts.risk_free_rate, &bounds)?; |
| 527 | let risk = quad_risk(covariance, &w).sqrt(); |
| 528 | Ok(MeanVariance { |
| 529 | portfolio_risk: risk, |
| 530 | portfolio_return: dot(expected_returns, &w), |
| 531 | portfolio_sharpe: if risk > 0.0 { |
| 532 | (dot(expected_returns, &w) - opts.risk_free_rate) / risk |
| 533 | } else { |
| 534 | 0.0 |
| 535 | }, |
| 536 | weights: w, |
| 537 | }) |
| 538 | } |
| 539 | "efficient_risk" => { |
| 540 | let w = efficient_risk_from_inputs( |
| 541 | expected_returns, |
| 542 | covariance, |
| 543 | opts.target_return, |
| 544 | &bounds, |
| 545 | opts.risk_free_rate, |
| 546 | )?; |
| 547 | Ok(MeanVariance { |
| 548 | portfolio_risk: quad_risk(covariance, &w).sqrt(), |
| 549 | portfolio_return: dot(expected_returns, &w), |
| 550 | portfolio_sharpe: 0.0, |
| 551 | weights: w, |
| 552 | }) |
| 553 | } |