cxmr_ta_core/indicators/
slow_stochastic.rs1use std::fmt;
2
3use crate::errors::Result;
4use crate::indicators::{ExponentialMovingAverage, FastStochastic};
5use crate::{Calculate, 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 Calculate for SlowStochastic {
46 fn calc(&mut self, input: f64) -> f64 {
47 self.ema.calc(self.fast_stochastic.calc(input))
48 }
49}
50
51impl<T: High + Low + Close> Next<T> for SlowStochastic {
52 fn next(&mut self, input: &T) -> f64 {
53 self.ema.calc(self.fast_stochastic.next(input))
54 }
55}
56
57impl Reset for SlowStochastic {
58 fn reset(&mut self) {
59 self.fast_stochastic.reset();
60 self.ema.reset();
61 }
62}
63
64impl Default for SlowStochastic {
65 fn default() -> Self {
66 Self::new(14, 3).unwrap()
67 }
68}
69
70impl fmt::Display for SlowStochastic {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 write!(
73 f,
74 "SLOW_STOCH({}, {})",
75 self.fast_stochastic.length(),
76 self.ema.length()
77 )
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::test_helper::*;
85
86 test_indicator!(SlowStochastic);
87
88 #[test]
89 fn test_new() {
90 assert!(SlowStochastic::new(0, 1).is_err());
91 assert!(SlowStochastic::new(1, 0).is_err());
92 assert!(SlowStochastic::new(1, 1).is_ok());
93 }
94
95 #[test]
96 fn test_next_with_f64() {
97 let mut stoch = SlowStochastic::new(3, 2).unwrap();
98 assert_eq!(stoch.calc(10.0), 50.0);
99 assert_eq!(stoch.calc(50.0).round(), 83.0);
100 assert_eq!(stoch.calc(50.0).round(), 94.0);
101 assert_eq!(stoch.calc(30.0).round(), 31.0);
102 assert_eq!(stoch.calc(55.0).round(), 77.0);
103 }
104
105 #[test]
106 fn test_next_with_bars() {
107 let test_data = vec![
108 (30.0, 10.0, 25.0, 75.0),
110 (20.0, 20.0, 20.0, 58.0),
111 (40.0, 20.0, 16.0, 33.0),
112 (35.0, 15.0, 19.0, 22.0),
113 (30.0, 20.0, 25.0, 34.0),
114 (35.0, 25.0, 30.0, 61.0),
115 ];
116
117 let mut stoch = SlowStochastic::new(3, 2).unwrap();
118
119 for (high, low, close, expected) in test_data {
120 let input_bar = Bar::new().high(high).low(low).close(close);
121 assert_eq!(stoch.next(&input_bar).round(), expected);
122 }
123 }
124
125 #[test]
126 fn test_reset() {
127 let mut stoch = SlowStochastic::new(3, 2).unwrap();
128 assert_eq!(stoch.calc(10.0), 50.0);
129 assert_eq!(stoch.calc(50.0).round(), 83.0);
130 assert_eq!(stoch.calc(50.0).round(), 94.0);
131
132 stoch.reset();
133 assert_eq!(stoch.calc(10.0), 50.0);
134 }
135
136 #[test]
137 fn test_default() {
138 SlowStochastic::default();
139 }
140
141 #[test]
142 fn test_display() {
143 let indicator = SlowStochastic::new(10, 2).unwrap();
144 assert_eq!(format!("{}", indicator), "SLOW_STOCH(10, 2)");
145 }
146}