cxmr_ta_core/indicators/
fast_stochastic.rs1use std::fmt;
2
3use crate::errors::*;
4use crate::indicators::{Maximum, Minimum};
5use crate::{Calculate, 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 Calculate for FastStochastic {
64 fn calc(&mut self, input: f64) -> f64 {
65 let min = self.minimum.calc(input);
66 let max = self.maximum.calc(input);
67
68 if min == max {
69 50.0
72 } else {
73 (input - min) / (max - min) * 100.0
74 }
75 }
76}
77
78impl<T: High + Low + Close> Next<T> for FastStochastic {
79 fn next(&mut self, input: &T) -> f64 {
80 let highest = self.maximum.calc(input.high());
81 let lowest = self.minimum.calc(input.low());
82 let close = input.close();
83
84 if highest == lowest {
85 50.0
87 } else {
88 (close - lowest) / (highest - lowest) * 100.0
89 }
90 }
91}
92
93impl Reset for FastStochastic {
94 fn reset(&mut self) {
95 self.minimum.reset();
96 self.maximum.reset();
97 }
98}
99
100impl Default for FastStochastic {
101 fn default() -> Self {
102 Self::new(14).unwrap()
103 }
104}
105
106impl fmt::Display for FastStochastic {
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
108 write!(f, "FAST_STOCH({})", self.length)
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115 use crate::test_helper::*;
116
117 test_indicator!(FastStochastic);
118
119 #[test]
120 fn test_new() {
121 assert!(FastStochastic::new(0).is_err());
122 assert!(FastStochastic::new(1).is_ok());
123 }
124
125 #[test]
126 fn test_next_with_f64() {
127 let mut stoch = FastStochastic::new(3).unwrap();
128 assert_eq!(stoch.calc(0.0), 50.0);
129 assert_eq!(stoch.calc(200.0), 100.0);
130 assert_eq!(stoch.calc(100.0), 50.0);
131 assert_eq!(stoch.calc(120.0), 20.0);
132 assert_eq!(stoch.calc(115.0), 75.0);
133 }
134
135 #[test]
136 fn test_next_with_bars() {
137 let test_data = vec![
138 (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), ];
146
147 let mut stoch = FastStochastic::new(3).unwrap();
148
149 for (high, low, close, expected) in test_data {
150 let input_bar = Bar::new().high(high).low(low).close(close);
151 assert_eq!(stoch.next(&input_bar), expected);
152 }
153 }
154
155 #[test]
156 fn test_reset() {
157 let mut indicator = FastStochastic::new(10).unwrap();
158 assert_eq!(indicator.calc(10.0), 50.0);
159 assert_eq!(indicator.calc(210.0), 100.0);
160 assert_eq!(indicator.calc(10.0), 0.0);
161 assert_eq!(indicator.calc(60.0), 25.0);
162
163 indicator.reset();
164 assert_eq!(indicator.calc(10.0), 50.0);
165 assert_eq!(indicator.calc(20.0), 100.0);
166 assert_eq!(indicator.calc(12.5), 25.0);
167 }
168
169 #[test]
170 fn test_default() {
171 FastStochastic::default();
172 }
173
174 #[test]
175 fn test_display() {
176 let indicator = FastStochastic::new(21).unwrap();
177 assert_eq!(format!("{}", indicator), "FAST_STOCH(21)");
178 }
179}