1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::core::Method;
use crate::core::{Error, PeriodType, ValueType};
use crate::methods::SMA;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MeanAbsDev(SMA);
impl MeanAbsDev {
#[must_use]
pub const fn get_sma(&self) -> &SMA {
&self.0
}
}
impl Method<'_> for MeanAbsDev {
type Params = PeriodType;
type Input = ValueType;
type Output = Self::Input;
fn new(length: Self::Params, value: Self::Input) -> Result<Self, Error> {
match length {
0 => Err(Error::WrongMethodParameters),
length => Ok(Self(SMA::new(length, value)?)),
}
}
#[inline]
fn next(&mut self, value: Self::Input) -> Self::Output {
let sma = self.0.next(value);
self.0
.get_window()
.as_slice()
.iter()
.map(|x| (x - sma).abs())
.sum::<ValueType>()
* self.0.get_divider()
}
}
#[cfg(test)]
mod tests {
use super::{MeanAbsDev as TestingMethod, Method};
use crate::core::ValueType;
use crate::helpers::{assert_eq_float, RandomCandles};
#[test]
fn test_mean_abs_dev_const() {
for i in 2..255 {
let input = (i as ValueType + 56.0) / 16.3251;
let mut method = TestingMethod::new(i, input).unwrap();
let output = method.next(input);
assert_eq_float(0.0, output);
}
}
#[test]
fn test_mean_abs_dev1() {
let mut candles = RandomCandles::default();
let mut ma = TestingMethod::new(1, candles.first().close).unwrap();
candles.take(100).for_each(|x| {
assert_eq_float(0.0, ma.next(x.close));
});
}
#[test]
fn test_mean_abs_dev0() {
let candles = RandomCandles::default();
let src: Vec<ValueType> = candles.take(300).map(|x| x.close).collect();
(2..255).for_each(|length| {
let mut method = TestingMethod::new(length, src[0]).unwrap();
src.iter().enumerate().for_each(|(i, &x)| {
let mut sum = 0.0;
for j in 0..length {
sum += src[i.saturating_sub(j as usize)];
}
let sma = sum / length as ValueType;
let mut sum2 = 0.0;
for j in 0..length {
sum2 += (sma - src[i.saturating_sub(j as usize)]).abs();
}
let q = sum2 / length as ValueType;
let value = method.next(x);
assert_eq_float(q, value);
});
});
}
}