finlib_ta/indicators/
rate_of_change.rs1use 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#[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}