ux_indicators/indicators/
rsi.rs1#![allow(dead_code)]
2
3use std::fmt;
4
5use crate::errors::*;
6use crate::indicators::ExponentialMovingAverage as Ema;
7use crate::{Close, Next, Reset};
8
9use crate::{Factory};
10use crate::indicators::SimpleMovingAverage;
11
12pub struct RsiFactory {
13}
14
15impl RsiFactory {
16 pub fn new() -> Self {
17 Self{}
18 }
19}
20
21impl Factory for RsiFactory {
22 fn create() -> Box<dyn Next<f64, Output = Box<[f64]>>> {
23 Box::new(SimpleMovingAverage::default())
24 }
25}
26
27#[derive(Debug, Clone)]
91pub struct RelativeStrengthIndex {
92 n: u32,
93 up_ema_indicator: Ema,
94 down_ema_indicator: Ema,
95 prev_val: f64,
96 is_new: bool,
97}
98
99impl RelativeStrengthIndex {
100 pub fn new(n: u32) -> Result<Self> {
101 let rsi = Self {
102 n: n,
103 up_ema_indicator: Ema::new(n)?,
104 down_ema_indicator: Ema::new(n)?,
105 prev_val: 0.0,
106 is_new: true,
107 };
108 Ok(rsi)
109 }
110}
111
112impl Next<f64> for RelativeStrengthIndex {
113 type Output = f64;
114
115 fn next(&mut self, input: f64) -> Self::Output {
116 let mut up = 0.0;
117 let mut down = 0.0;
118
119 if self.is_new {
120 self.is_new = false;
121 up = 0.1;
123 down = 0.1;
124 } else {
125 if input > self.prev_val {
126 up = input - self.prev_val;
127 } else {
128 down = self.prev_val - input;
129 }
130 }
131
132 self.prev_val = input;
133 let up_ema = self.up_ema_indicator.next(up);
134 let down_ema = self.down_ema_indicator.next(down);
135 100.0 * up_ema / (up_ema + down_ema)
136 }
137}
138
139impl<'a, T: Close> Next<&'a T> for RelativeStrengthIndex {
140 type Output = f64;
141
142 fn next(&mut self, input: &'a T) -> Self::Output {
143 self.next(input.close())
144 }
145}
146
147impl Reset for RelativeStrengthIndex {
148 fn reset(&mut self) {
149 self.is_new = true;
150 self.prev_val = 0.0;
151 self.up_ema_indicator.reset();
152 self.down_ema_indicator.reset();
153 }
154}
155
156impl Default for RelativeStrengthIndex {
157 fn default() -> Self {
158 Self::new(14).unwrap()
159 }
160}
161
162impl fmt::Display for RelativeStrengthIndex {
163 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164 write!(f, "RSI({})", self.n)
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171 #[test]
176 fn test_new() {
177 assert!(RelativeStrengthIndex::new(0).is_err());
178 assert!(RelativeStrengthIndex::new(1).is_ok());
179 }
180
181 #[test]
182 fn test_next() {
183 let mut rsi = RelativeStrengthIndex::new(3).unwrap();
184 assert_eq!(rsi.next(10.0), 50.0);
185 assert_eq!(rsi.next(10.5).round(), 86.0);
186 assert_eq!(rsi.next(10.0).round(), 35.0);
187 assert_eq!(rsi.next(9.5).round(), 16.0);
188 }
189
190 #[test]
191 fn test_reset() {
192 let mut rsi = RelativeStrengthIndex::new(3).unwrap();
193 assert_eq!(rsi.next(10.0), 50.0);
194 assert_eq!(rsi.next(10.5).round(), 86.0);
195
196 rsi.reset();
197 assert_eq!(rsi.next(10.0).round(), 50.0);
198 assert_eq!(rsi.next(10.5).round(), 86.0);
199 }
200
201 #[test]
202 fn test_default() {
203 RelativeStrengthIndex::default();
204 }
205
206 #[test]
207 fn test_display() {
208 let rsi = RelativeStrengthIndex::new(16).unwrap();
209 assert_eq!(format!("{}", rsi), "RSI(16)");
210 }
211}