1use 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)]
58#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
59pub struct HighestLowestDelta {
60 highest: ValueType,
63 lowest: ValueType,
64 window: Window<ValueType>,
65}
66
67impl Method for HighestLowestDelta {
68 type Params = PeriodType;
69 type Input = ValueType;
70 type Output = Self::Input;
71
72 fn new(length: Self::Params, &value: &Self::Input) -> Result<Self, Error>
73 where
74 Self: Sized,
75 {
76 if !value.is_finite() {
77 return Err(Error::InvalidCandles);
78 }
79
80 match length {
81 0 => Err(Error::WrongMethodParameters),
82 length => Ok(Self {
83 window: Window::new(length, value),
84 highest: value,
85 lowest: value,
86 }),
87 }
88 }
89
90 #[inline]
91 fn next(&mut self, &value: &Self::Input) -> ValueType {
92 let left_value = self.window.push(value);
93
94 let mut search = false;
95 if value >= self.highest {
96 self.highest = value;
97 } else if left_value.to_bits() == self.highest.to_bits() {
99 search = true;
100 }
101
102 if value <= self.lowest {
103 self.lowest = value;
104 } else if left_value.to_bits() == self.lowest.to_bits() {
106 search = true;
107 }
108
109 if search {
110 let (min, max) = self
111 .window
112 .iter()
113 .fold((value, value), |(min, max), &v| (min.min(v), max.max(v)));
114 self.highest = max;
115 self.lowest = min;
116 }
117
118 self.highest - self.lowest
119 }
120}
121
122impl Peekable<<Self as Method>::Output> for HighestLowestDelta {
123 fn peek(&self) -> <Self as Method>::Output {
124 self.highest - self.lowest
125 }
126}
127
128#[derive(Debug, Clone)]
176#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
177pub struct Highest {
178 value: ValueType,
179 window: Window<ValueType>,
180}
181
182impl Method for Highest {
183 type Params = PeriodType;
184 type Input = ValueType;
185 type Output = Self::Input;
186
187 fn new(length: Self::Params, &value: &Self::Input) -> Result<Self, Error> {
188 if !value.is_finite() {
189 return Err(Error::InvalidCandles);
190 }
191
192 match length {
193 0 => Err(Error::WrongMethodParameters),
194 length => Ok(Self {
195 window: Window::new(length, value),
196 value,
197 }),
198 }
199 }
200
201 #[inline]
202 fn next(&mut self, &value: &Self::Input) -> ValueType {
203 assert!(
204 value.is_finite(),
205 "Highest method cannot operate with NAN values"
206 );
207
208 let left_value = self.window.push(value);
209
210 if value >= self.value {
211 self.value = value;
212 } else if left_value.to_bits() == self.value.to_bits() {
214 self.value = self.window.iter().fold(value, |a, &b| a.max(b));
215 }
216
217 self.value
218 }
219}
220
221impl Peekable<<Self as Method>::Output> for Highest {
222 fn peek(&self) -> <Self as Method>::Output {
223 self.value
224 }
225}
226
227#[derive(Debug, Clone)]
275#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
276pub struct Lowest {
277 value: ValueType,
278 window: Window<ValueType>,
279}
280
281impl Method for Lowest {
282 type Params = PeriodType;
283 type Input = ValueType;
284 type Output = Self::Input;
285
286 fn new(length: Self::Params, &value: &Self::Input) -> Result<Self, Error> {
287 if !value.is_finite() {
288 return Err(Error::InvalidCandles);
289 }
290
291 match length {
292 0 => Err(Error::WrongMethodParameters),
293 length => Ok(Self {
294 window: Window::new(length, value),
295 value,
296 }),
297 }
298 }
299
300 #[inline]
301 fn next(&mut self, &value: &Self::Input) -> ValueType {
302 assert!(
303 value.is_finite(),
304 "Lowest method cannot operate with NAN values"
305 );
306
307 let left_value = self.window.push(value);
308
309 if value <= self.value {
310 self.value = value;
311 } else if left_value.to_bits() == self.value.to_bits() {
313 self.value = self.window.iter().fold(value, |a, &b| a.min(b));
314 }
315
316 self.value
317 }
318}
319
320impl Peekable<<Self as Method>::Output> for Lowest {
321 fn peek(&self) -> <Self as Method>::Output {
322 self.value
323 }
324}
325
326#[cfg(test)]
327mod tests {
328 use super::{Highest, HighestLowestDelta, Lowest};
329 use crate::core::{Method, ValueType};
330 use crate::helpers::{assert_eq_float, RandomCandles};
331 use crate::methods::tests::test_const;
332
333 #[test]
334 fn test_highest_const() {
335 for i in 1..255 {
336 let input = (i as ValueType + 56.0) / 16.3251;
337 let mut method = Highest::new(i, &input).unwrap();
338
339 let output = method.next(&input);
340 test_const(&mut method, &input, &output);
341 }
342 }
343
344 #[test]
345 fn test_highest1() {
346 use super::Highest as TestingMethod;
347
348 let mut candles = RandomCandles::default();
349
350 let mut ma = TestingMethod::new(1, &candles.first().close).unwrap();
351
352 candles.take(100).for_each(|x| {
353 assert_eq_float(x.close, ma.next(&x.close));
354 });
355 }
356
357 #[test]
358 fn test_highest() {
359 use super::Highest as TestingMethod;
360
361 let candles = RandomCandles::default();
362
363 let src: Vec<ValueType> = candles.take(300).map(|x| x.close).collect();
364
365 (2..255).for_each(|length| {
366 let mut ma = TestingMethod::new(length, &src[0]).unwrap();
367 let length = length as usize;
368
369 src.iter().enumerate().for_each(|(i, x)| {
370 let value1 = ma.next(x);
371 let value2 = (0..length).fold(src[i], |m, j| m.max(src[i.saturating_sub(j)]));
372 assert_eq_float(value2, value1);
373 });
374 });
375 }
376
377 #[test]
378 fn test_lowest_const() {
379 for i in 1..255 {
380 let input = (i as ValueType + 56.0) / 16.3251;
381 let mut method = Lowest::new(i, &input).unwrap();
382
383 let output = method.next(&input);
384 test_const(&mut method, &input, &output);
385 }
386 }
387
388 #[test]
389 fn test_lowest1() {
390 use super::Lowest as TestingMethod;
391 let mut candles = RandomCandles::default();
392
393 let mut ma = TestingMethod::new(1, &candles.first().close).unwrap();
394
395 candles.take(100).for_each(|x| {
396 assert_eq_float(x.close, ma.next(&x.close));
397 });
398 }
399
400 #[test]
401 fn test_lowest() {
402 use super::Lowest as TestingMethod;
403 let candles = RandomCandles::default();
404
405 let src: Vec<ValueType> = candles.take(300).map(|x| x.close).collect();
406
407 (2..255).for_each(|length| {
408 let mut ma = TestingMethod::new(length, &src[0]).unwrap();
409 let length = length as usize;
410
411 src.iter().enumerate().for_each(|(i, x)| {
412 let value1 = ma.next(x);
413 let value2 = (0..length).fold(src[i], |m, j| m.min(src[i.saturating_sub(j)]));
414 assert_eq_float(value2, value1);
415 });
416 });
417 }
418
419 #[test]
420 fn test_highest_lowest_delta_const() {
421 for i in 1..255 {
422 let input = (i as ValueType + 56.0) / 16.3251;
423 let mut method = HighestLowestDelta::new(i, &input).unwrap();
424
425 let output = method.next(&input);
426 test_const(&mut method, &input, &output);
427 }
428 }
429
430 #[test]
431 fn test_highest_lowest_delta1() {
432 use super::HighestLowestDelta as TestingMethod;
433 let mut candles = RandomCandles::default();
434
435 let mut ma = TestingMethod::new(1, &candles.first().close).unwrap();
436
437 candles.take(100).for_each(|x| {
438 assert_eq_float(0.0, ma.next(&x.close));
439 });
440 }
441
442 #[test]
443 fn test_highest_lowest_delta() {
444 use super::HighestLowestDelta as TestingMethod;
445 let candles = RandomCandles::default();
446
447 let src: Vec<ValueType> = candles.take(300).map(|x| x.close).collect();
448
449 (2..255).for_each(|length| {
450 let mut ma = TestingMethod::new(length, &src[0]).unwrap();
451 let length = length as usize;
452
453 src.iter().enumerate().for_each(|(i, x)| {
454 let value1 = ma.next(x);
455 let min = (0..length).fold(src[i], |m, j| m.min(src[i.saturating_sub(j)]));
456 let max = (0..length).fold(src[i], |m, j| m.max(src[i.saturating_sub(j)]));
457 assert_eq_float(max - min, value1);
458 });
459 });
460 }
461}