finlib_ta/indicators/
rate_of_change.rs

1use alloc::boxed::Box;
2use alloc::vec;
3use core::fmt;
4
5use crate::errors::{Result, TaError};
6use crate::traits::{Close, Next, Period, Reset};
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10/// Rate of Change (ROC)
11///
12/// # Formula
13///
14/// ROC = (Price<sub>t</sub> - Price<sub>t-n</sub>) / Price<sub>t-n</sub> * 100
15///
16/// Where:
17///
18/// * ROC - current value of Rate of Change indicator
19/// * P<sub>t</sub> - price at the moment
20/// * P<sub>t-n</sub> - price _n_ periods ago
21///
22/// # Parameters
23///
24/// * _period_ - number of periods integer greater than 0
25///
26/// # Example
27///
28/// ```
29/// use finlib_ta::indicators::RateOfChange;
30/// use finlib_ta::Next;
31///
32/// let mut roc = RateOfChange::new(2).unwrap();
33/// assert_eq!(roc.next(10.0), 0.0);            //  0
34/// assert_eq!(roc.next(9.7).round(), -3.0);    //  (9.7 - 10) / 10  * 100 = -3
35/// assert_eq!(roc.next(20.0).round(), 100.0);  //  (20 - 10)  / 10  * 100 = 100
36/// assert_eq!(roc.next(20.0).round(), 106.0);  //  (20 - 9.7) / 9.7 * 100 = 106
37/// ```
38///
39/// # Links
40///
41/// * [Rate of Change, Wikipedia](https://en.wikipedia.org/wiki/Momentum_(technical_analysis))
42///
43#[doc(alias = "ROC")]
44#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
45#[derive(Debug, Clone)]
46pub struct RateOfChange {
47    period: usize,
48    index: usize,
49    count: usize,
50    deque: Box<[f64]>,
51}
52
53impl RateOfChange {
54    pub fn new(period: usize) -> Result<Self> {
55        match period {
56            0 => Err(TaError::InvalidParameter),
57            _ => Ok(Self {
58                period,
59                index: 0,
60                count: 0,
61                deque: vec![0.0; period].into_boxed_slice(),
62            }),
63        }
64    }
65}
66
67impl Period for RateOfChange {
68    fn period(&self) -> usize {
69        self.period
70    }
71}
72
73impl Next<f64> for RateOfChange {
74    type Output = f64;
75
76    fn next(&mut self, input: f64) -> f64 {
77        let previous = if self.count > self.period {
78            self.deque[self.index]
79        } else {
80            self.count += 1;
81            if self.count == 1 {
82                input
83            } else {
84                self.deque[0]
85            }
86        };
87        self.deque[self.index] = input;
88
89        self.index = if self.index + 1 < self.period {
90            self.index + 1
91        } else {
92            0
93        };
94
95        (input - previous) / previous * 100.0
96    }
97}
98
99impl<T: Close> Next<&T> for RateOfChange {
100    type Output = f64;
101
102    fn next(&mut self, input: &T) -> f64 {
103        self.next(input.close())
104    }
105}
106
107impl Default for RateOfChange {
108    fn default() -> Self {
109        Self::new(9).unwrap()
110    }
111}
112
113impl fmt::Display for RateOfChange {
114    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
115        write!(f, "ROC({})", self.period)
116    }
117}
118
119impl Reset for RateOfChange {
120    fn reset(&mut self) {
121        self.index = 0;
122        self.count = 0;
123        for i in 0..self.period {
124            self.deque[i] = 0.0;
125        }
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132    use crate::test_helper::*;
133    use alloc::format;
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}