pub fn rolling_std(prices: &[f64], period: usize) -> Vec<Option<f64>> {
if period == 0 || prices.len() < period {
return vec![None; prices.len()];
}
let mut stds = vec![None; prices.len()];
for i in (period - 1)..prices.len() {
let window = &prices[i + 1 - period..=i];
let mean = window.iter().sum::<f64>() / period as f64;
let variance = window.iter().map(|p| (p - mean).powi(2)).sum::<f64>() / period as f64;
stds[i] = Some(variance.sqrt());
}
stds
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rolling_std_basic() {
let prices = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let std = rolling_std(&prices, 3);
assert_eq!(std.len(), 5);
assert!(std[2].is_some() && std[3].is_some() && std[4].is_some());
}
#[test]
fn test_rolling_std_short_input() {
let prices = vec![1.0, 2.0];
let std = rolling_std(&prices, 3);
assert_eq!(std, vec![None, None]);
}
#[test]
fn test_rolling_std_zero_period() {
let prices = vec![1.0, 2.0, 3.0];
let std = rolling_std(&prices, 0);
assert_eq!(std, vec![None, None, None]);
}
}