cxmr_ta_core/indicators/
minimum.rs

1use std::f64::INFINITY;
2use std::fmt;
3
4use crate::errors::*;
5use crate::{Calculate, Low, Next, Reset};
6
7/// Returns the lowest value in a given time frame.
8///
9/// # Parameters
10///
11/// * _n_ - size of the time frame (integer greater than 0). Default value is 14.
12///
13/// # Example
14///
15/// ```
16/// use ta::indicators::Minimum;
17/// use ta::{Calculate, Next};
18///
19/// let mut min = Minimum::new(3).unwrap();
20/// assert_eq!(min.calc(10.0), 10.0);
21/// assert_eq!(min.calc(11.0), 10.0);
22/// assert_eq!(min.calc(12.0), 10.0);
23/// assert_eq!(min.calc(13.0), 11.0);
24/// ```
25#[derive(Debug, Clone)]
26pub struct Minimum {
27    n: usize,
28    vec: Vec<f64>,
29    min_index: usize,
30    cur_index: usize,
31}
32
33impl Minimum {
34    pub fn new(n: u32) -> Result<Self> {
35        let n = n as usize;
36
37        if n <= 0 {
38            return Err(Error::from_kind(ErrorKind::InvalidParameter));
39        }
40
41        let indicator = Self {
42            n: n,
43            vec: vec![INFINITY; n],
44            min_index: 0,
45            cur_index: 0,
46        };
47
48        Ok(indicator)
49    }
50
51    fn find_min_index(&self) -> usize {
52        let mut min = ::std::f64::INFINITY;
53        let mut index: usize = 0;
54
55        for (i, &val) in self.vec.iter().enumerate() {
56            if val < min {
57                min = val;
58                index = i;
59            }
60        }
61
62        index
63    }
64}
65
66impl Calculate for Minimum {
67    fn calc(&mut self, input: f64) -> f64 {
68        self.cur_index = (self.cur_index + 1) % (self.n as usize);
69        self.vec[self.cur_index] = input;
70
71        if input < self.vec[self.min_index] {
72            self.min_index = self.cur_index;
73        } else if self.min_index == self.cur_index {
74            self.min_index = self.find_min_index();
75        }
76
77        self.vec[self.min_index]
78    }
79}
80
81impl<T: Low> Next<T> for Minimum {
82    fn next(&mut self, input: &T) -> f64 {
83        self.calc(input.low())
84    }
85}
86
87impl Reset for Minimum {
88    fn reset(&mut self) {
89        for i in 0..self.n {
90            self.vec[i] = INFINITY;
91        }
92    }
93}
94
95impl Default for Minimum {
96    fn default() -> Self {
97        Self::new(14).unwrap()
98    }
99}
100
101impl fmt::Display for Minimum {
102    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
103        write!(f, "MIN({})", self.n)
104    }
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110    use crate::test_helper::*;
111
112    test_indicator!(Minimum);
113
114    #[test]
115    fn test_new() {
116        assert!(Minimum::new(0).is_err());
117        assert!(Minimum::new(1).is_ok());
118    }
119
120    #[test]
121    fn test_next() {
122        let mut min = Minimum::new(3).unwrap();
123
124        assert_eq!(min.calc(4.0), 4.0);
125        assert_eq!(min.calc(1.2), 1.2);
126        assert_eq!(min.calc(5.0), 1.2);
127        assert_eq!(min.calc(3.0), 1.2);
128        assert_eq!(min.calc(4.0), 3.0);
129        assert_eq!(min.calc(6.0), 3.0);
130        assert_eq!(min.calc(7.0), 4.0);
131        assert_eq!(min.calc(8.0), 6.0);
132        assert_eq!(min.calc(-9.0), -9.0);
133        assert_eq!(min.calc(0.0), -9.0);
134    }
135
136    #[test]
137    fn test_next_with_bars() {
138        fn bar(low: f64) -> Bar {
139            Bar::new().low(low)
140        }
141
142        let mut min = Minimum::new(3).unwrap();
143
144        assert_eq!(min.next(&bar(4.0)), 4.0);
145        assert_eq!(min.next(&bar(4.0)), 4.0);
146        assert_eq!(min.next(&bar(1.2)), 1.2);
147        assert_eq!(min.next(&bar(5.0)), 1.2);
148    }
149
150    #[test]
151    fn test_reset() {
152        let mut min = Minimum::new(10).unwrap();
153
154        assert_eq!(min.calc(5.0), 5.0);
155        assert_eq!(min.calc(7.0), 5.0);
156
157        min.reset();
158        assert_eq!(min.calc(8.0), 8.0);
159    }
160
161    #[test]
162    fn test_default() {
163        Minimum::default();
164    }
165
166    #[test]
167    fn test_display() {
168        let indicator = Minimum::new(10).unwrap();
169        assert_eq!(format!("{}", indicator), "MIN(10)");
170    }
171}