ux_indicators/indicators/
ssto.rs1#![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#[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]
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 (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}