finance_query/indicators/
roc.rs1use super::{IndicatorError, Result};
4
5pub fn roc(data: &[f64], period: usize) -> Result<Vec<Option<f64>>> {
24 if period == 0 {
25 return Err(IndicatorError::InvalidPeriod(
26 "Period must be greater than 0".to_string(),
27 ));
28 }
29 if data.len() <= period {
30 return Err(IndicatorError::InsufficientData {
31 need: period + 1,
32 got: data.len(),
33 });
34 }
35
36 let mut result = vec![None; data.len()];
37
38 for i in period..data.len() {
39 let current = data[i];
40 let past = data[i - period];
41
42 if past != 0.0 {
43 let roc_val = ((current - past) / past) * 100.0;
44 result[i] = Some(roc_val);
45 } else {
46 result[i] = None;
47 }
48 }
49
50 Ok(result)
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn test_roc() {
59 let prices = vec![10.0, 11.0, 12.0, 13.0];
60 let result = roc(&prices, 2).unwrap();
61
62 assert_eq!(result.len(), 4);
63 assert!(result[0].is_none());
64 assert!(result[1].is_none());
65
66 assert_eq!(result[2], Some(20.0));
68 assert!(result[3].is_some());
70 }
71}