quantaxis_rs/indicators/
relative_strength_index.rs1use std::fmt;
2
3use crate::errors::*;
4use crate::indicators::ExponentialMovingAverage as Ema;
5use crate::{Close, Next, Reset};
6
7#[derive(Debug, Clone)]
70pub struct RelativeStrengthIndex {
71 n: u32,
72 up_ema_indicator: Ema,
73 down_ema_indicator: Ema,
74 prev_val: f64,
75 is_new: bool,
76}
77
78impl RelativeStrengthIndex {
79 pub fn new(n: u32) -> Result<Self> {
80 let rsi = Self {
81 n: n,
82 up_ema_indicator: Ema::new(n)?,
83 down_ema_indicator: Ema::new(n)?,
84 prev_val: 0.0,
85 is_new: true,
86 };
87 Ok(rsi)
88 }
89}
90
91impl Next<f64> for RelativeStrengthIndex {
92 type Output = f64;
93
94 fn next(&mut self, input: f64) -> Self::Output {
95 let mut up = 0.0;
96 let mut down = 0.0;
97
98 if self.is_new {
99 self.is_new = false;
100 up = 0.1;
102 down = 0.1;
103 } else {
104 if input > self.prev_val {
105 up = input - self.prev_val;
106 } else {
107 down = self.prev_val - input;
108 }
109 }
110
111 self.prev_val = input;
112 let up_ema = self.up_ema_indicator.next(up);
113 let down_ema = self.down_ema_indicator.next(down);
114 100.0 * up_ema / (up_ema + down_ema)
115 }
116}
117
118impl<'a, T: Close> Next<&'a T> for RelativeStrengthIndex {
119 type Output = f64;
120
121 fn next(&mut self, input: &'a T) -> Self::Output {
122 self.next(input.close())
123 }
124}
125
126impl Reset for RelativeStrengthIndex {
127 fn reset(&mut self) {
128 self.is_new = true;
129 self.prev_val = 0.0;
130 self.up_ema_indicator.reset();
131 self.down_ema_indicator.reset();
132 }
133}
134
135impl Default for RelativeStrengthIndex {
136 fn default() -> Self {
137 Self::new(14).unwrap()
138 }
139}
140
141impl fmt::Display for RelativeStrengthIndex {
142 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143 write!(f, "RSI({})", self.n)
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150 use crate::test_helper::*;
151 macro_rules! test_indicator {
152 ($i:tt) => {
153 #[test]
154 fn test_indicator() {
155 let bar = Bar::new();
156
157 let mut indicator = $i::default();
159
160 let first_output = indicator.next(12.3);
162
163 indicator.next(&bar);
165
166 indicator.reset();
168 assert_eq!(indicator.next(12.3), first_output);
169
170 format!("{}", indicator);
172 }
173 };
174 }
175 test_indicator!(RelativeStrengthIndex);
176
177 #[test]
178 fn test_new() {
179 assert!(RelativeStrengthIndex::new(0).is_err());
180 assert!(RelativeStrengthIndex::new(1).is_ok());
181 }
182
183 #[test]
184 fn test_next() {
185 let mut rsi = RelativeStrengthIndex::new(3).unwrap();
186 assert_eq!(rsi.next(10.0), 50.0);
187 assert_eq!(rsi.next(10.5).round(), 86.0);
188 assert_eq!(rsi.next(10.0).round(), 35.0);
189 assert_eq!(rsi.next(9.5).round(), 16.0);
190 }
191
192 #[test]
193 fn test_reset() {
194 let mut rsi = RelativeStrengthIndex::new(3).unwrap();
195 assert_eq!(rsi.next(10.0), 50.0);
196 assert_eq!(rsi.next(10.5).round(), 86.0);
197
198 rsi.reset();
199 assert_eq!(rsi.next(10.0).round(), 50.0);
200 assert_eq!(rsi.next(10.5).round(), 86.0);
201 }
202
203 #[test]
204 fn test_default() {
205 RelativeStrengthIndex::default();
206 }
207
208 #[test]
209 fn test_display() {
210 let rsi = RelativeStrengthIndex::new(16).unwrap();
211 assert_eq!(format!("{}", rsi), "RSI(16)");
212 }
213}