1use crate::core::{Error, PeriodType, ValueType};
2use crate::core::{Method, MovingAverage};
3use crate::helpers::{Buffered, Peekable};
4use crate::methods::SMA;
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone)]
49#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50pub struct TRIMA {
51 sma1: SMA,
52 sma2: SMA,
53}
54
55impl Method for TRIMA {
56 type Params = PeriodType;
57 type Input = ValueType;
58 type Output = Self::Input;
59
60 fn new(length: Self::Params, value: &Self::Input) -> Result<Self, Error> {
61 Ok(Self {
62 sma1: SMA::new(length, value)?,
63 sma2: SMA::new(length, value)?,
64 })
65 }
66
67 #[inline]
68 fn next(&mut self, value: &Self::Input) -> Self::Output {
69 self.sma2.next(&self.sma1.next(value))
70 }
71}
72
73impl MovingAverage for TRIMA {}
74
75impl Peekable<<Self as Method>::Output> for TRIMA {
76 fn peek(&self) -> <Self as Method>::Output {
77 self.sma2.peek()
78 }
79}
80
81impl Buffered<<Self as Method>::Output> for TRIMA {
82 fn get(&self, index: usize) -> Option<<Self as Method>::Output> {
83 self.sma2.get(index)
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::{Method, TRIMA as TestingMethod};
90 use crate::core::ValueType;
91 use crate::helpers::{assert_eq_float, RandomCandles};
92 use crate::methods::tests::test_const;
93
94 #[test]
95 fn test_trima_const() {
96 for i in 1..255 {
97 let input = (i as ValueType + 56.0) / 16.3251;
98 let mut method = TestingMethod::new(i, &input).unwrap();
99
100 let output = method.next(&input);
101 test_const(&mut method, &input, &output);
102 }
103 }
104
105 #[test]
106 fn test_trima1() {
107 let mut candles = RandomCandles::default();
108
109 let mut ma = TestingMethod::new(1, &candles.first().close).unwrap();
110
111 candles.take(100).for_each(|x| {
112 assert_eq_float(x.close, ma.next(&x.close));
113 });
114 }
115
116 #[test]
117 fn test_trima() {
118 let candles = RandomCandles::default();
119
120 let src: Vec<ValueType> = candles.take(300).map(|x| x.close).collect();
121
122 (1..255).for_each(|sma_length| {
123 let mut ma = TestingMethod::new(sma_length, &src[0]).unwrap();
124 let mut level2 = Vec::new();
125
126 src.iter().enumerate().for_each(|(i, x)| {
127 let value = ma.next(x);
128 let slice_from = i.saturating_sub((sma_length - 1) as usize);
129 let slice_to = i;
130 let slice = &src[slice_from..=slice_to];
131
132 let mut sum: ValueType = slice.iter().sum();
133 if slice.len() < sma_length as usize {
134 sum += (sma_length as usize - slice.len()) as ValueType * src.first().unwrap();
135 }
136
137 level2.push(sum / sma_length as ValueType);
138
139 let mut sum: ValueType = level2.iter().rev().take(sma_length as usize).sum();
140 if level2.len() < sma_length as usize {
141 sum += (sma_length as usize - level2.len()) as ValueType * src.first().unwrap();
142 }
143
144 assert_eq_float(sum / sma_length as ValueType, value);
145 });
146 });
147 }
148}