ux_indicators/indicators/
ssto.rs

1#![allow(dead_code)]
2
3use std::fmt;
4
5use crate::errors::Result;
6use crate::indicators::{ExponentialMovingAverage, FastStochastic};
7use crate::{Close, High, Low, Next, Reset};
8
9use crate::{Factory};
10use crate::indicators::SimpleMovingAverage;
11
12pub struct SstoFactory {
13}
14
15impl SstoFactory {
16    pub fn new() -> Self {
17        Self{}
18    }
19}
20
21impl Factory for SstoFactory {
22    fn create() -> Box<dyn Next<f64, Output = Box<[f64]>>> {
23        Box::new(SimpleMovingAverage::default())
24    }
25}
26
27/// Slow stochastic oscillator.
28///
29/// Basically it is a fast stochastic oscillator smoothed with exponential moving average.
30///
31/// # Parameters
32///
33/// * _stochastic_n_ - number of periods for fast stochastic (integer greater than 0). Default is 14.
34/// *_ema_n_ - length for EMA (integer greater than 0). Default is 3.
35///
36/// # Example
37///
38/// ```
39/// use core::indicators::SlowStochastic;
40/// use core::Next;
41///
42/// let mut stoch = SlowStochastic::new(3, 2).unwrap();
43/// assert_eq!(stoch.next(10.0), 50.0);
44/// assert_eq!(stoch.next(50.0).round(), 83.0);
45/// assert_eq!(stoch.next(50.0).round(), 94.0);
46/// assert_eq!(stoch.next(30.0).round(), 31.0);
47/// assert_eq!(stoch.next(55.0).round(), 77.0);
48/// ```
49
50#[derive(Clone, Debug)]
51pub struct SlowStochastic {
52    fast_stochastic: FastStochastic,
53    ema: ExponentialMovingAverage,
54}
55
56impl SlowStochastic {
57    pub fn new(stochastic_n: u32, ema_n: u32) -> Result<Self> {
58        let indicator = Self {
59            fast_stochastic: FastStochastic::new(stochastic_n)?,
60            ema: ExponentialMovingAverage::new(ema_n)?,
61        };
62        Ok(indicator)
63    }
64}
65
66impl Next<f64> for SlowStochastic {
67    type Output = f64;
68
69    fn next(&mut self, input: f64) -> Self::Output {
70        self.ema.next(self.fast_stochastic.next(input))
71    }
72}
73
74impl<'a, T: High + Low + Close> Next<&'a T> for SlowStochastic {
75    type Output = f64;
76
77    fn next(&mut self, input: &'a T) -> Self::Output {
78        self.ema.next(self.fast_stochastic.next(input))
79    }
80}
81
82impl Reset for SlowStochastic {
83    fn reset(&mut self) {
84        self.fast_stochastic.reset();
85        self.ema.reset();
86    }
87}
88
89impl Default for SlowStochastic {
90    fn default() -> Self {
91        Self::new(14, 3).unwrap()
92    }
93}
94
95impl fmt::Display for SlowStochastic {
96    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
97        write!(
98            f,
99            "SLOW_STOCH({}, {})",
100            self.fast_stochastic.length(),
101            self.ema.length()
102        )
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use super::*;
109    use crate::test_helper::*;
110
111    // test_indicator!(SlowStochastic);
112
113    #[test]
114    fn test_new() {
115        assert!(SlowStochastic::new(0, 1).is_err());
116        assert!(SlowStochastic::new(1, 0).is_err());
117        assert!(SlowStochastic::new(1, 1).is_ok());
118    }
119
120    #[test]
121    fn test_next_with_f64() {
122        let mut stoch = SlowStochastic::new(3, 2).unwrap();
123        assert_eq!(stoch.next(10.0), 50.0);
124        assert_eq!(stoch.next(50.0).round(), 83.0);
125        assert_eq!(stoch.next(50.0).round(), 94.0);
126        assert_eq!(stoch.next(30.0).round(), 31.0);
127        assert_eq!(stoch.next(55.0).round(), 77.0);
128    }
129
130    #[test]
131    fn test_next_with_bars() {
132        let test_data = vec![
133            // high, low , close, expected
134            (30.0, 10.0, 25.0, 75.0),
135            (20.0, 20.0, 20.0, 58.0),
136            (40.0, 20.0, 16.0, 33.0),
137            (35.0, 15.0, 19.0, 22.0),
138            (30.0, 20.0, 25.0, 34.0),
139            (35.0, 25.0, 30.0, 61.0),
140        ];
141
142        let mut stoch = SlowStochastic::new(3, 2).unwrap();
143
144        for (high, low, close, expected) in test_data {
145            let input_bar = Bar::new().high(high).low(low).close(close);
146            assert_eq!(stoch.next(&input_bar).round(), expected);
147        }
148    }
149
150    #[test]
151    fn test_reset() {
152        let mut stoch = SlowStochastic::new(3, 2).unwrap();
153        assert_eq!(stoch.next(10.0), 50.0);
154        assert_eq!(stoch.next(50.0).round(), 83.0);
155        assert_eq!(stoch.next(50.0).round(), 94.0);
156
157        stoch.reset();
158        assert_eq!(stoch.next(10.0), 50.0);
159    }
160
161    #[test]
162    fn test_default() {
163        SlowStochastic::default();
164    }
165
166    #[test]
167    fn test_display() {
168        let indicator = SlowStochastic::new(10, 2).unwrap();
169        assert_eq!(format!("{}", indicator), "SLOW_STOCH(10, 2)");
170    }
171}