quantaxis_rs/indicators/
fast_stochastic.rs1use std::fmt;
2
3use crate::errors::*;
4use crate::indicators::{Maximum, Minimum};
5use crate::{Close, High, Low, Next, Reset};
6
7#[derive(Debug, Clone)]
42pub struct FastStochastic {
43 length: u32,
44 minimum: Minimum,
45 maximum: Maximum,
46}
47
48impl FastStochastic {
49 pub fn new(length: u32) -> Result<Self> {
50 let indicator = Self {
51 length: length,
52 minimum: Minimum::new(length)?,
53 maximum: Maximum::new(length)?,
54 };
55 Ok(indicator)
56 }
57
58 pub fn length(&self) -> u32 {
59 self.length
60 }
61}
62
63impl Next<f64> for FastStochastic {
64 type Output = f64;
65
66 fn next(&mut self, input: f64) -> Self::Output {
67 let min = self.minimum.next(input);
68 let max = self.maximum.next(input);
69
70 if min == max {
71 50.0
74 } else {
75 (input - min) / (max - min) * 100.0
76 }
77 }
78}
79
80impl<'a, T: High + Low + Close> Next<&'a T> for FastStochastic {
81 type Output = f64;
82
83 fn next(&mut self, input: &'a T) -> Self::Output {
84 let highest = self.maximum.next(input.high());
85 let lowest = self.minimum.next(input.low());
86 let close = input.close();
87
88 if highest == lowest {
89 50.0
91 } else {
92 (close - lowest) / (highest - lowest) * 100.0
93 }
94 }
95}
96
97impl Reset for FastStochastic {
98 fn reset(&mut self) {
99 self.minimum.reset();
100 self.maximum.reset();
101 }
102}
103
104impl Default for FastStochastic {
105 fn default() -> Self {
106 Self::new(14).unwrap()
107 }
108}
109
110impl fmt::Display for FastStochastic {
111 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112 write!(f, "FAST_STOCH({})", self.length)
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use crate::test_helper::*;
120 macro_rules! test_indicator {
121 ($i:tt) => {
122 #[test]
123 fn test_indicator() {
124 let bar = Bar::new();
125
126 let mut indicator = $i::default();
128
129 let first_output = indicator.next(12.3);
131
132 indicator.next(&bar);
134
135 indicator.reset();
137 assert_eq!(indicator.next(12.3), first_output);
138
139 format!("{}", indicator);
141 }
142 };
143 }
144 test_indicator!(FastStochastic);
145
146 #[test]
147 fn test_new() {
148 assert!(FastStochastic::new(0).is_err());
149 assert!(FastStochastic::new(1).is_ok());
150 }
151
152 #[test]
153 fn test_next_with_f64() {
154 let mut stoch = FastStochastic::new(3).unwrap();
155 assert_eq!(stoch.next(0.0), 50.0);
156 assert_eq!(stoch.next(200.0), 100.0);
157 assert_eq!(stoch.next(100.0), 50.0);
158 assert_eq!(stoch.next(120.0), 20.0);
159 assert_eq!(stoch.next(115.0), 75.0);
160 }
161
162 #[test]
163 fn test_next_with_bars() {
164 let test_data = vec![
165 (20.0, 20.0, 20.0, 50.0), (30.0, 10.0, 25.0, 75.0), (40.0, 20.0, 16.0, 20.0), (35.0, 15.0, 19.0, 30.0), (30.0, 20.0, 25.0, 40.0), (35.0, 25.0, 30.0, 75.0), ];
173
174 let mut stoch = FastStochastic::new(3).unwrap();
175
176 for (high, low, close, expected) in test_data {
177 let input_bar = Bar::new().high(high).low(low).close(close);
178 assert_eq!(stoch.next(&input_bar), expected);
179 }
180 }
181
182 #[test]
183 fn test_reset() {
184 let mut indicator = FastStochastic::new(10).unwrap();
185 assert_eq!(indicator.next(10.0), 50.0);
186 assert_eq!(indicator.next(210.0), 100.0);
187 assert_eq!(indicator.next(10.0), 0.0);
188 assert_eq!(indicator.next(60.0), 25.0);
189
190 indicator.reset();
191 assert_eq!(indicator.next(10.0), 50.0);
192 assert_eq!(indicator.next(20.0), 100.0);
193 assert_eq!(indicator.next(12.5), 25.0);
194 }
195
196 #[test]
197 fn test_default() {
198 FastStochastic::default();
199 }
200
201 #[test]
202 fn test_display() {
203 let indicator = FastStochastic::new(21).unwrap();
204 assert_eq!(format!("{}", indicator), "FAST_STOCH(21)");
205 }
206}