quantaxis_rs/indicators/
slow_stochastic.rs1use std::fmt;
2
3use crate::errors::Result;
4use crate::indicators::{ExponentialMovingAverage, FastStochastic};
5use crate::{Close, High, Low, Next, Reset};
6
7#[derive(Clone, Debug)]
30pub struct SlowStochastic {
31 fast_stochastic: FastStochastic,
32 ema: ExponentialMovingAverage,
33}
34
35impl SlowStochastic {
36 pub fn new(stochastic_n: u32, ema_n: u32) -> Result<Self> {
37 let indicator = Self {
38 fast_stochastic: FastStochastic::new(stochastic_n)?,
39 ema: ExponentialMovingAverage::new(ema_n)?,
40 };
41 Ok(indicator)
42 }
43}
44
45impl Next<f64> for SlowStochastic {
46 type Output = f64;
47
48 fn next(&mut self, input: f64) -> Self::Output {
49 self.ema.next(self.fast_stochastic.next(input))
50 }
51}
52
53impl<'a, T: High + Low + Close> Next<&'a T> for SlowStochastic {
54 type Output = f64;
55
56 fn next(&mut self, input: &'a T) -> Self::Output {
57 self.ema.next(self.fast_stochastic.next(input))
58 }
59}
60
61impl Reset for SlowStochastic {
62 fn reset(&mut self) {
63 self.fast_stochastic.reset();
64 self.ema.reset();
65 }
66}
67
68impl Default for SlowStochastic {
69 fn default() -> Self {
70 Self::new(14, 3).unwrap()
71 }
72}
73
74impl fmt::Display for SlowStochastic {
75 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76 write!(
77 f,
78 "SLOW_STOCH({}, {})",
79 self.fast_stochastic.length(),
80 self.ema.length()
81 )
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88 use crate::test_helper::*;
89 macro_rules! test_indicator {
90 ($i:tt) => {
91 #[test]
92 fn test_indicator() {
93 let bar = Bar::new();
94
95 let mut indicator = $i::default();
97
98 let first_output = indicator.next(12.3);
100
101 indicator.next(&bar);
103
104 indicator.reset();
106 assert_eq!(indicator.next(12.3), first_output);
107
108 format!("{}", indicator);
110 }
111 };
112 }
113 test_indicator!(SlowStochastic);
114
115 #[test]
116 fn test_new() {
117 assert!(SlowStochastic::new(0, 1).is_err());
118 assert!(SlowStochastic::new(1, 0).is_err());
119 assert!(SlowStochastic::new(1, 1).is_ok());
120 }
121
122 #[test]
123 fn test_next_with_f64() {
124 let mut stoch = SlowStochastic::new(3, 2).unwrap();
125 assert_eq!(stoch.next(10.0), 50.0);
126 assert_eq!(stoch.next(50.0).round(), 83.0);
127 assert_eq!(stoch.next(50.0).round(), 94.0);
128 assert_eq!(stoch.next(30.0).round(), 31.0);
129 assert_eq!(stoch.next(55.0).round(), 77.0);
130 }
131
132 #[test]
133 fn test_next_with_bars() {
134 let test_data = vec![
135 (30.0, 10.0, 25.0, 75.0),
137 (20.0, 20.0, 20.0, 58.0),
138 (40.0, 20.0, 16.0, 33.0),
139 (35.0, 15.0, 19.0, 22.0),
140 (30.0, 20.0, 25.0, 34.0),
141 (35.0, 25.0, 30.0, 61.0),
142 ];
143
144 let mut stoch = SlowStochastic::new(3, 2).unwrap();
145
146 for (high, low, close, expected) in test_data {
147 let input_bar = Bar::new().high(high).low(low).close(close);
148 assert_eq!(stoch.next(&input_bar).round(), expected);
149 }
150 }
151
152 #[test]
153 fn test_reset() {
154 let mut stoch = SlowStochastic::new(3, 2).unwrap();
155 assert_eq!(stoch.next(10.0), 50.0);
156 assert_eq!(stoch.next(50.0).round(), 83.0);
157 assert_eq!(stoch.next(50.0).round(), 94.0);
158
159 stoch.reset();
160 assert_eq!(stoch.next(10.0), 50.0);
161 }
162
163 #[test]
164 fn test_default() {
165 SlowStochastic::default();
166 }
167
168 #[test]
169 fn test_display() {
170 let indicator = SlowStochastic::new(10, 2).unwrap();
171 assert_eq!(format!("{}", indicator), "SLOW_STOCH(10, 2)");
172 }
173}