sliding_features/sliding_windows/
my_rsi.rs1use std::{
5 collections::VecDeque,
6 num::NonZeroUsize,
7};
8
9use getset::CopyGetters;
10use num::Float;
11
12use crate::View;
13
14#[derive(Debug, Clone, CopyGetters)]
17pub struct MyRSI<T, V> {
18 view: V,
19 #[getset(get_copy = "pub")]
21 window_len: NonZeroUsize,
22 cu: T,
23 cd: T,
24 out: T,
25 q_vals: VecDeque<T>,
26 last_val: T,
27 oldest_val: T,
28}
29
30impl<T, V> MyRSI<T, V>
31where
32 V: View<T>,
33 T: Float,
34{
35 pub fn new(view: V, window_len: NonZeroUsize) -> Self {
37 MyRSI {
38 view,
39 window_len,
40 cu: T::zero(),
41 cd: T::zero(),
42 out: T::zero(),
43 q_vals: VecDeque::with_capacity(window_len.get()),
44 last_val: T::zero(),
45 oldest_val: T::zero(),
46 }
47 }
48}
49
50impl<T, V> View<T> for MyRSI<T, V>
51where
52 V: View<T>,
53 T: Float,
54{
55 fn update(&mut self, val: T) {
56 debug_assert!(val.is_finite(), "value must be finite");
57 self.view.update(val);
58 let Some(val) = self.view.last() else { return };
59 debug_assert!(val.is_finite(), "value must be finite");
60
61 if self.q_vals.is_empty() {
62 self.oldest_val = val;
63 self.last_val = val;
64 }
65 if self.q_vals.len() >= self.window_len.get() {
66 let old_val = self.q_vals.pop_front().unwrap();
67 if old_val > self.oldest_val {
68 self.cu = self.cu - (old_val - self.oldest_val);
69 } else {
70 self.cd = self.cd - (self.oldest_val - old_val);
71 }
72 self.oldest_val = old_val;
73 }
74 self.q_vals.push_back(val);
75
76 if val > self.last_val {
78 self.cu = self.cu + val - self.last_val;
79 } else {
80 self.cd = self.cd + self.last_val - val;
81 }
82 self.last_val = val;
83
84 if self.cu + self.cd != T::zero() {
85 self.out = (self.cu - self.cd) / (self.cu + self.cd);
86 }
87 }
88
89 #[inline]
90 fn last(&self) -> Option<T> {
91 if self.q_vals.len() < self.window_len.get() {
92 return None;
93 }
94 debug_assert!(self.out.is_finite(), "value must be finite");
95 Some(self.out)
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::{
103 plot::plot_values,
104 pure_functions::Echo,
105 test_data::TEST_DATA,
106 };
107
108 #[test]
109 fn my_rsi() {
110 let mut my_rsi = MyRSI::<f64, _>::new(Echo::new(), NonZeroUsize::new(16).unwrap());
112 for v in &TEST_DATA {
113 my_rsi.update(*v);
114 if let Some(val) = my_rsi.last() {
115 dbg!(val);
116 assert!(val <= 1.0);
117 assert!(val >= -1.0);
118 }
119 }
120 }
121
122 #[test]
123 fn my_rsi_plot() {
124 let mut my_rsi = MyRSI::new(Echo::new(), NonZeroUsize::new(16).unwrap());
125 let mut out: Vec<f64> = Vec::new();
126 for v in &TEST_DATA {
127 my_rsi.update(*v);
128 if let Some(rsi) = my_rsi.last() {
129 out.push(rsi);
130 }
131 }
132 println!("out: {:?}", out);
133 let filename = "img/my_rsi.png";
134 plot_values(out, filename).unwrap();
135 }
136}