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

Function cluster_conditional_drawdown

crates/openquant/src/hcaa.rs:431–463  ·  view source on GitHub ↗
(
    returns: &DMatrix<f64>,
    cov: &DMatrix<f64>,
    confidence_level: f64,
    indices: &[usize],
)

Source from the content-addressed store, hash-verified

429}
430
431fn 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
465fn recursive_bisection(
466 ordered_indices: &[usize],

Callers 1

recursive_bisectionFunction · 0.85

Calls 4

quantileFunction · 0.85
lenMethod · 0.80
is_emptyMethod · 0.80
inverse_variance_weightsFunction · 0.70

Tested by

no test coverage detected