ux_indicators/indicators/
fsto.rs1#![allow(dead_code)]
2
3use std::fmt;
4
5use crate::errors::*;
6use crate::indicators::{Maximum, Minimum};
7use crate::{Close, High, Low, Next, Reset};
8
9use crate::{Factory};
10use crate::indicators::SimpleMovingAverage;
11
12pub struct FstoFactory {
13}
14
15impl FstoFactory {
16 pub fn new() -> Self {
17 Self{}
18 }
19}
20
21impl Factory for FstoFactory {
22 fn create() -> Box<dyn Next<f64, Output = Box<[f64]>>> {
23 Box::new(SimpleMovingAverage::default())
24 }
25}
26
27#[derive(Debug, Clone)]
63pub struct FastStochastic {
64 length: u32,
65 minimum: Minimum,
66 maximum: Maximum,
67}
68
69impl FastStochastic {
70 pub fn new(length: u32) -> Result<Self> {
71 let indicator = Self {
72 length: length,
73 minimum: Minimum::new(length)?,
74 maximum: Maximum::new(length)?,
75 };
76 Ok(indicator)
77 }
78
79 pub fn length(&self) -> u32 {
80 self.length
81 }
82}
83
84impl Next<f64> for FastStochastic {
85 type Output = f64;
86
87 fn next(&mut self, input: f64) -> Self::Output {
88 let min = self.minimum.next(input);
89 let max = self.maximum.next(input);
90
91 if min == max {
92 50.0
95 } else {
96 (input - min) / (max - min) * 100.0
97 }
98 }
99}
100
101impl<'a, T: High + Low + Close> Next<&'a T> for FastStochastic {
102 type Output = f64;
103
104 fn next(&mut self, input: &'a T) -> Self::Output {
105 let highest = self.maximum.next(input.high());
106 let lowest = self.minimum.next(input.low());
107 let close = input.close();
108
109 if highest == lowest {
110 50.0
112 } else {
113 (close - lowest) / (highest - lowest) * 100.0
114 }
115 }
116}
117
118impl Reset for FastStochastic {
119 fn reset(&mut self) {
120 self.minimum.reset();
121 self.maximum.reset();
122 }
123}
124
125impl Default for FastStochastic {
126 fn default() -> Self {
127 Self::new(14).unwrap()
128 }
129}
130
131impl fmt::Display for FastStochastic {
132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133 write!(f, "FAST_STOCH({})", self.length)
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140 use crate::test_helper::*;
141
142 #[test]
145 fn test_new() {
146 assert!(FastStochastic::new(0).is_err());
147 assert!(FastStochastic::new(1).is_ok());
148 }
149
150 #[test]
151 fn test_next_with_f64() {
152 let mut stoch = FastStochastic::new(3).unwrap();
153 assert_eq!(stoch.next(0.0), 50.0);
154 assert_eq!(stoch.next(200.0), 100.0);
155 assert_eq!(stoch.next(100.0), 50.0);
156 assert_eq!(stoch.next(120.0), 20.0);
157 assert_eq!(stoch.next(115.0), 75.0);
158 }
159
160 #[test]
161 fn test_next_with_bars() {
162 let test_data = vec![
163 (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), ];
171
172 let mut stoch = FastStochastic::new(3).unwrap();
173
174 for (high, low, close, expected) in test_data {
175 let input_bar = Bar::new().high(high).low(low).close(close);
176 assert_eq!(stoch.next(&input_bar), expected);
177 }
178 }
179
180 #[test]
181 fn test_reset() {
182 let mut indicator = FastStochastic::new(10).unwrap();
183 assert_eq!(indicator.next(10.0), 50.0);
184 assert_eq!(indicator.next(210.0), 100.0);
185 assert_eq!(indicator.next(10.0), 0.0);
186 assert_eq!(indicator.next(60.0), 25.0);
187
188 indicator.reset();
189 assert_eq!(indicator.next(10.0), 50.0);
190 assert_eq!(indicator.next(20.0), 100.0);
191 assert_eq!(indicator.next(12.5), 25.0);
192 }
193
194 #[test]
195 fn test_default() {
196 FastStochastic::default();
197 }
198
199 #[test]
200 fn test_display() {
201 let indicator = FastStochastic::new(21).unwrap();
202 assert_eq!(format!("{}", indicator), "FAST_STOCH(21)");
203 }
204}