ux_indicators/indicators/
rsi.rs

1#![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/// The relative strength index (RSI).
28///
29/// It is a momentum oscillator,
30/// that compares the magnitude of recent gains
31/// and losses over a specified time period to measure speed and change of price
32/// movements of a security. It is primarily used to attempt to identify
33/// overbought or oversold conditions in the trading of an asset.
34///
35/// The oscillator returns output in the range of 0..100.
36///
37/// ![RSI](https://upload.wikimedia.org/wikipedia/commons/6/67/RSIwiki.gif)
38///
39/// # Formula
40///
41/// RSI<sub>t</sub> = EMA<sub>Ut</sub> * 100 / (EMA<sub>Ut</sub> + EMA<sub>Dt</sub>)
42///
43/// Where:
44///
45/// * RSI<sub>t</sub> - value of RSI indicator in a moment of time _t_
46/// * EMA<sub>Ut</sub> - value of [EMA](struct.ExponentialMovingAverage.html) of up periods in a moment of time _t_
47/// * EMA<sub>Dt</sub> - value of [EMA](struct.ExponentialMovingAverage.html) of down periods in a moment of time _t_
48///
49/// If current period has value higher than previous period, than:
50///
51/// U = p<sub>t</sub> - p<sub>t-1</sub>
52///
53/// D = 0
54///
55/// Otherwise:
56///
57/// U = 0
58///
59/// D = p<sub>t-1</sub> - p<sub>t</sub>
60///
61/// Where:
62///
63/// * U = up period value
64/// * D = down period value
65/// * p<sub>t</sub> - input value in a moment of time _t_
66/// * p<sub>t-1</sub> - input value in a moment of time _t-1_
67///
68/// # Parameters
69///
70/// * _n_ - number of periods (integer greater than 0). Default value is 14.
71///
72/// # Example
73///
74/// ```
75/// use core::indicators::RelativeStrengthIndex;
76/// use core::Next;
77///
78/// let mut rsi = RelativeStrengthIndex::new(3).unwrap();
79/// assert_eq!(rsi.next(10.0), 50.0);
80/// assert_eq!(rsi.next(10.5).round(), 86.0);
81/// assert_eq!(rsi.next(10.0).round(), 35.0);
82/// assert_eq!(rsi.next(9.5).round(), 16.0);
83/// ```
84///
85/// # Links
86/// * [Relative strength index (Wikipedia)](https://en.wikipedia.org/wiki/Relative_strength_index)
87/// * [RSI (Investopedia)](http://www.investopedia.com/terms/r/rsi.asp)
88///
89
90#[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            // Initialize with some small seed numbers to avoid division by zero
122            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    // use crate::test_helper::*;
172
173    // test_indicator!(RelativeStrengthIndex);
174
175    #[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}