yata/methods/
volatility.rs1use crate::core::Method;
2use crate::core::{Error, PeriodType, ValueType, Window};
3use crate::helpers::Peekable;
4
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone)]
50#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
51pub struct LinearVolatility {
52 window: Window<ValueType>,
53 prev_value: ValueType,
54 volatility: ValueType,
55}
56
57impl Method for LinearVolatility {
58 type Params = PeriodType;
59 type Input = ValueType;
60 type Output = Self::Input;
61
62 fn new(length: Self::Params, &value: &Self::Input) -> Result<Self, Error> {
63 match length {
64 0 => Err(Error::WrongMethodParameters),
65 length => Ok(Self {
66 window: Window::new(length, 0.),
67 prev_value: value,
68 volatility: 0.,
69 }),
70 }
71 }
72
73 #[inline]
74 fn next(&mut self, &value: &Self::Input) -> Self::Output {
75 let derivative = (value - self.prev_value).abs();
76 self.prev_value = value;
77
78 let past_derivative = self.window.push(derivative);
79
80 self.volatility += derivative - past_derivative;
81
82 self.volatility
83 }
84}
85
86impl Peekable<<Self as Method>::Output> for LinearVolatility {
87 fn peek(&self) -> <Self as Method>::Output {
88 self.volatility
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::{LinearVolatility as TestingMethod, Method};
95 use crate::core::ValueType;
96 use crate::helpers::{assert_eq_float, RandomCandles};
97 use crate::methods::tests::test_const;
98 use crate::methods::Derivative;
99
100 #[test]
101 fn test_volatility_const() {
102 for i in 1..255 {
103 let input = (i as ValueType + 56.0) / 16.3251;
104 let mut method = TestingMethod::new(i, &input).unwrap();
105
106 test_const(&mut method, &input, &0.0);
107 }
108 }
109
110 #[test]
111 fn test_volatility1() {
112 let mut candles = RandomCandles::default();
113
114 let mut ma = TestingMethod::new(1, &candles.first().close).unwrap();
115 let mut der = Derivative::new(1, &candles.first().close).unwrap();
116
117 candles.take(100).for_each(|x| {
118 let v1 = der.next(&x.close).abs();
119 let v2 = ma.next(&x.close);
120
121 assert_eq_float(v1, v2);
122 });
123 }
124
125 #[test]
126 fn test_linear_volatility() {
127 let candles = RandomCandles::default();
128
129 let src: Vec<ValueType> = candles.take(300).map(|x| x.close).collect();
130
131 (1..255).for_each(|ma_length| {
132 let mut ma = TestingMethod::new(ma_length, &src[0]).unwrap();
133 let ma_length = ma_length as usize;
134
135 src.iter().enumerate().for_each(|(i, x)| {
136 let mut s = 0.;
137 for j in 0..ma_length {
138 let d = src[i.saturating_sub(j)] - src[i.saturating_sub(j + 1)];
139 s += d.abs();
140 }
141
142 let value = ma.next(x);
143 let value2 = s;
144
145 assert_eq_float(value2, value);
146 });
147 });
148 }
149}