ux_indicators/indicators/
roc.rs

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