finance_query/indicators/
aroon.rs1use super::{IndicatorError, Result};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct AroonResult {
9 pub aroon_up: Vec<Option<f64>>,
11 pub aroon_down: Vec<Option<f64>>,
13}
14
15pub fn aroon(highs: &[f64], lows: &[f64], period: usize) -> Result<AroonResult> {
36 if period == 0 {
37 return Err(IndicatorError::InvalidPeriod(
38 "Period must be greater than 0".to_string(),
39 ));
40 }
41 let len = highs.len();
42 if lows.len() != len {
43 return Err(IndicatorError::InvalidPeriod(
44 "Data lengths must match".to_string(),
45 ));
46 }
47 if len < period {
48 return Err(IndicatorError::InsufficientData {
49 need: period,
50 got: len,
51 });
52 }
53
54 let mut aroon_up = vec![None; len];
55 let mut aroon_down = vec![None; len];
56
57 for i in (period - 1)..len {
58 let start_idx = i + 1 - period;
59 let slice_highs = &highs[start_idx..=i];
60 let slice_lows = &lows[start_idx..=i];
61
62 let mut highest_idx = 0;
63 let mut highest_val = f64::NEG_INFINITY;
64
65 for (j, &val) in slice_highs.iter().enumerate() {
66 if val >= highest_val {
67 highest_val = val;
68 highest_idx = j;
69 }
70 }
71
72 let periods_since_high = (period - 1) - highest_idx;
73 let up = ((period as f64 - periods_since_high as f64) / period as f64) * 100.0;
74
75 let mut lowest_idx = 0;
76 let mut lowest_val = f64::INFINITY;
77
78 for (j, &val) in slice_lows.iter().enumerate() {
79 if val <= lowest_val {
80 lowest_val = val;
81 lowest_idx = j;
82 }
83 }
84
85 let periods_since_low = (period - 1) - lowest_idx;
86 let down = ((period as f64 - periods_since_low as f64) / period as f64) * 100.0;
87
88 aroon_up[i] = Some(up);
89 aroon_down[i] = Some(down);
90 }
91
92 Ok(AroonResult {
93 aroon_up,
94 aroon_down,
95 })
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn test_aroon() {
104 let highs = vec![10.0, 11.0, 12.0, 11.0, 10.0];
105 let lows = vec![8.0, 9.0, 10.0, 9.0, 8.0];
106 let result = aroon(&highs, &lows, 3).unwrap();
107
108 assert_eq!(result.aroon_up.len(), 5);
109 assert!(result.aroon_up[0].is_none());
110 assert!(result.aroon_up[1].is_none());
111 assert!(result.aroon_up[2].is_some());
112 }
113}