| 196 | fn exponential_expected_returns(returns: &DMatrix<f64>, span: usize) -> Vec<f64> { |
| 197 | let rows = returns.nrows(); |
| 198 | let cols = returns.ncols(); |
| 199 | if rows == 0 { |
| 200 | return vec![0.0; cols]; |
| 201 | } |
| 202 | let alpha = 2.0 / (span as f64 + 1.0); |
| 203 | let mut out = vec![0.0; cols]; |
| 204 | for c in 0..cols { |
| 205 | let mut weight = 1.0; |
| 206 | let mut num = 0.0; |
| 207 | let mut denom = 0.0; |
| 208 | for r in (0..rows).rev() { |
| 209 | num += weight * returns[(r, c)]; |
| 210 | denom += weight; |
| 211 | weight *= 1.0 - alpha; |
| 212 | } |
| 213 | out[c] = if denom > 0.0 { num / denom * 252.0 } else { 0.0 }; |
| 214 | } |
| 215 | out |
| 216 | } |
| 217 | |
| 218 | fn cov2corr(covariance: &DMatrix<f64>) -> Result<DMatrix<f64>, HcaaError> { |
| 219 | let n = covariance.nrows(); |
| 220 | if n == 0 || covariance.ncols() != n { |
| 221 | return Err(HcaaError::DimensionMismatch("covariance must be square and non-empty")); |