(
returns: &DMatrix<f64>,
cov: &DMatrix<f64>,
confidence_level: f64,
indices: &[usize],
)
| 429 | } |
| 430 | |
| 431 | fn cluster_conditional_drawdown( |
| 432 | returns: &DMatrix<f64>, |
| 433 | cov: &DMatrix<f64>, |
| 434 | confidence_level: f64, |
| 435 | indices: &[usize], |
| 436 | ) -> Result<f64, HcaaError> { |
| 437 | let w = inverse_variance_weights(cov, indices)?; |
| 438 | let mut wealth = Vec::with_capacity(returns.nrows() + 1); |
| 439 | wealth.push(1.0); |
| 440 | for r in 0..returns.nrows() { |
| 441 | let mut ret = 0.0; |
| 442 | for (ii, &idx) in indices.iter().enumerate() { |
| 443 | ret += returns[(r, idx)] * w[ii]; |
| 444 | } |
| 445 | let next = wealth.last().copied().unwrap_or(1.0) * (1.0 + ret); |
| 446 | wealth.push(next); |
| 447 | } |
| 448 | let mut peak = wealth[0]; |
| 449 | let mut drawdowns = Vec::with_capacity(wealth.len()); |
| 450 | for v in wealth { |
| 451 | if v > peak { |
| 452 | peak = v; |
| 453 | } |
| 454 | let dd = if peak > 0.0 { (peak - v) / peak } else { 0.0 }; |
| 455 | drawdowns.push(dd); |
| 456 | } |
| 457 | let threshold = quantile(drawdowns.clone(), 1.0 - confidence_level); |
| 458 | let tail: Vec<f64> = drawdowns.into_iter().filter(|x| *x >= threshold).collect(); |
| 459 | if tail.is_empty() { |
| 460 | return Ok(0.0); |
| 461 | } |
| 462 | Ok(tail.iter().sum::<f64>() / tail.len() as f64) |
| 463 | } |
| 464 | |
| 465 | fn recursive_bisection( |
| 466 | ordered_indices: &[usize], |
no test coverage detected