quantaxis_rs/indicators/
rate_of_change.rs

1use std::collections::VecDeque;
2use std::fmt;
3
4use crate::errors::*;
5use crate::traits::{Close, Next, Reset};
6
7/// Rate of Change (ROC)
8///
9/// # Formula
10///
11/// ROC = (Price<sub>t</sub> - Price<sub>t-n</sub>) / Price<sub>t-n</sub> * 100
12///
13/// Where:
14///
15/// * ROC - current value of Rate of Change indicator
16/// * P<sub>t</sub> - price at the moment
17/// * P<sub>t-n</sub> - price _n_ periods ago
18///
19/// # Parameters
20///
21/// * _length_ - number of periods (_n_), integer greater than 0
22///
23/// # Example
24///
25/// ```
26/// use quantaxis_rs::indicators::RateOfChange;
27/// use quantaxis_rs::Next;
28///
29/// let mut roc = RateOfChange::new(2).unwrap();
30/// assert_eq!(roc.next(10.0), 0.0);            //  0
31/// assert_eq!(roc.next(9.7).round(), -3.0);    //  (9.7 - 10) / 10  * 100 = -3
32/// assert_eq!(roc.next(20.0).round(), 100.0);  //  (20 - 10)  / 10  * 100 = 100
33/// assert_eq!(roc.next(20.0).round(), 106.0);  //  (20 - 9.7) / 9.7 * 100 = 106
34/// ```
35///
36/// # Links
37///
38/// * [Rate of Change, Wikipedia](https://en.wikipedia.org/wiki/Momentum_(technical_analysis))
39///
40#[derive(Debug, Clone)]
41pub struct RateOfChange {
42    length: u32,
43    prices: VecDeque<f64>,
44}
45
46impl RateOfChange {
47    pub fn new(length: u32) -> Result<Self> {
48        match length {
49            0 => Err(Error::from_kind(ErrorKind::InvalidParameter)),
50            _ => {
51                let indicator = Self {
52                    length: length,
53                    prices: VecDeque::with_capacity(length as usize + 1),
54                };
55                Ok(indicator)
56            }
57        }
58    }
59}
60
61impl Next<f64> for RateOfChange {
62    type Output = f64;
63
64    fn next(&mut self, input: f64) -> f64 {
65        self.prices.push_back(input);
66
67        if self.prices.len() == 1 {
68            return 0.0;
69        }
70
71        let initial_price = if self.prices.len() > (self.length as usize) {
72            // unwrap is safe, because the check above.
73            // At this moment there must be at least 2 items in self.prices
74            self.prices.pop_front().unwrap()
75        } else {
76            self.prices[0]
77        };
78
79        (input - initial_price) / initial_price * 100.0
80    }
81}
82
83impl<'a, T: Close> Next<&'a T> for RateOfChange {
84    type Output = f64;
85
86    fn next(&mut self, input: &'a T) -> f64 {
87        self.next(input.close())
88    }
89}
90
91impl Default for RateOfChange {
92    fn default() -> Self {
93        Self::new(9).unwrap()
94    }
95}
96
97impl fmt::Display for RateOfChange {
98    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99        write!(f, "ROC({})", self.length)
100    }
101}
102
103impl Reset for RateOfChange {
104    fn reset(&mut self) {
105        self.prices.clear();
106    }
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112    use crate::test_helper::*;
113    macro_rules! test_indicator {
114        ($i:tt) => {
115            #[test]
116            fn test_indicator() {
117                let bar = Bar::new();
118
119                // ensure Default trait is implemented
120                let mut indicator = $i::default();
121
122                // ensure Next<f64> is implemented
123                let first_output = indicator.next(12.3);
124
125                // ensure next accepts &DataItem as well
126                indicator.next(&bar);
127
128                // ensure Reset is implemented and works correctly
129                indicator.reset();
130                assert_eq!(indicator.next(12.3), first_output);
131
132                // ensure Display is implemented
133                format!("{}", indicator);
134            }
135        };
136    }
137    test_indicator!(RateOfChange);
138
139    #[test]
140    fn test_new() {
141        assert!(RateOfChange::new(0).is_err());
142        assert!(RateOfChange::new(1).is_ok());
143        assert!(RateOfChange::new(100_000).is_ok());
144    }
145
146    #[test]
147    fn test_next_f64() {
148        let mut roc = RateOfChange::new(3).unwrap();
149
150        assert_eq!(round(roc.next(10.0)), 0.0);
151        assert_eq!(round(roc.next(10.4)), 4.0);
152        assert_eq!(round(roc.next(10.57)), 5.7);
153        assert_eq!(round(roc.next(10.8)), 8.0);
154        assert_eq!(round(roc.next(10.9)), 4.808);
155        assert_eq!(round(roc.next(10.0)), -5.393);
156    }
157
158    #[test]
159    fn test_next_bar() {
160        fn bar(close: f64) -> Bar {
161            Bar::new().close(close)
162        }
163
164        let mut roc = RateOfChange::new(3).unwrap();
165
166        assert_eq!(round(roc.next(&bar(10.0))), 0.0);
167        assert_eq!(round(roc.next(&bar(10.4))), 4.0);
168        assert_eq!(round(roc.next(&bar(10.57))), 5.7);
169    }
170
171    #[test]
172    fn test_reset() {
173        let mut roc = RateOfChange::new(3).unwrap();
174
175        roc.next(12.3);
176        roc.next(15.0);
177
178        roc.reset();
179
180        assert_eq!(round(roc.next(10.0)), 0.0);
181        assert_eq!(round(roc.next(10.4)), 4.0);
182        assert_eq!(round(roc.next(10.57)), 5.7);
183    }
184}