Skip to content

Instantly share code, notes, and snippets.

@soyart
Last active March 10, 2023 17:08
Show Gist options
  • Select an option

  • Save soyart/58ad514f8c5902122227963f2e93db28 to your computer and use it in GitHub Desktop.

Select an option

Save soyart/58ad514f8c5902122227963f2e93db28 to your computer and use it in GitHub Desktop.
Draw down, i.e. financial securiry performance indicator
// Generic draw down
fn draw_down<T, U>(points: &[T]) -> U
where
T: Clone + Into<U>,
U: Copy + Default + PartialOrd + std::ops::Sub<Output = U>,
{
if points.len() <= 1 {
return U::default();
}
points
.iter()
.skip(1)
.fold(
(points[0].clone().into(), U::default()),
|(mut max, mut max_down), item| {
let item_u: U = item.clone().into();
if item_u > max {
max = item_u;
// Return in closure = continue iteration
return (max, max_down);
}
let down = max - item_u;
if down > max_down {
max_down = down;
}
(max, max_down)
},
)
.1
}
// Draw down with f64 result
fn draw_down_f64<T>(points: &[T]) -> f64
where
T: Into<f64> + Clone,
{
if points.len() <= 1 {
return 0.0;
}
points
.iter()
.skip(1)
.fold(
(points[0].clone().into(), 0.0),
|(mut max, mut max_down), item| {
let item_f64: f64 = item.clone().into();
if item_f64 > max {
max = item_f64;
// Return in closure = continue iteration
return (max, max_down);
}
let down = max - item_f64;
if down > max_down {
max_down = down;
}
(max, max_down)
},
)
.1
}
#[cfg(test)]
mod test {
#[test]
fn test_draw_down() {
use super::draw_down;
let tests = vec![
(&[1][..], 0.),
(&[1, 2], 0.),
(&[1, 4, 2, 1], 3.),
(&[1, 10, 12, 14, 7, 4, 20, 9], 11.),
(&[100, 90, 80, 10, 110, 10, 1], 109.),
(&[200, 90, 80, 10, 110, 10, 1], 199.),
(&[7, 8, 9, 1, 10, 8, 6, 11, 200], 8.),
];
tests
.into_iter()
.for_each(|test| assert_eq!(draw_down::<i32, f64>(test.0), test.1))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment