use crate::core::Method;
use crate::core::{Error, PeriodType, ValueType, Window};
use crate::helpers::Peekable;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct HighestLowestDelta {
highest: ValueType,
lowest: ValueType,
window: Window<ValueType>,
}
impl Method for HighestLowestDelta {
type Params = PeriodType;
type Input = ValueType;
type Output = Self::Input;
fn new(length: Self::Params, &value: &Self::Input) -> Result<Self, Error>
where
Self: Sized,
{
if !value.is_finite() {
return Err(Error::InvalidCandles);
}
match length {
0 => Err(Error::WrongMethodParameters),
length => Ok(Self {
window: Window::new(length, value),
highest: value,
lowest: value,
}),
}
}
#[inline]
fn next(&mut self, &value: &Self::Input) -> ValueType {
let left_value = self.window.push(value);
let mut search = false;
if value >= self.highest {
self.highest = value;
} else if left_value.to_bits() == self.highest.to_bits() {
search = true;
}
if value <= self.lowest {
self.lowest = value;
} else if left_value.to_bits() == self.lowest.to_bits() {
search = true;
}
if search {
let (min, max) = self
.window
.iter()
.fold((value, value), |(min, max), &v| (min.min(v), max.max(v)));
self.highest = max;
self.lowest = min;
}
self.highest - self.lowest
}
}
impl Peekable<<Self as Method>::Output> for HighestLowestDelta {
fn peek(&self) -> <Self as Method>::Output {
self.highest - self.lowest
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Highest {
value: ValueType,
window: Window<ValueType>,
}
impl Method for Highest {
type Params = PeriodType;
type Input = ValueType;
type Output = Self::Input;
fn new(length: Self::Params, &value: &Self::Input) -> Result<Self, Error> {
if !value.is_finite() {
return Err(Error::InvalidCandles);
}
match length {
0 => Err(Error::WrongMethodParameters),
length => Ok(Self {
window: Window::new(length, value),
value,
}),
}
}
#[inline]
fn next(&mut self, &value: &Self::Input) -> ValueType {
assert!(
value.is_finite(),
"Highest method cannot operate with NAN values"
);
let left_value = self.window.push(value);
if value >= self.value {
self.value = value;
} else if left_value.to_bits() == self.value.to_bits() {
self.value = self.window.iter().fold(value, |a, &b| a.max(b));
}
self.value
}
}
impl Peekable<<Self as Method>::Output> for Highest {
fn peek(&self) -> <Self as Method>::Output {
self.value
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Lowest {
value: ValueType,
window: Window<ValueType>,
}
impl Method for Lowest {
type Params = PeriodType;
type Input = ValueType;
type Output = Self::Input;
fn new(length: Self::Params, &value: &Self::Input) -> Result<Self, Error> {
if !value.is_finite() {
return Err(Error::InvalidCandles);
}
match length {
0 => Err(Error::WrongMethodParameters),
length => Ok(Self {
window: Window::new(length, value),
value,
}),
}
}
#[inline]
fn next(&mut self, &value: &Self::Input) -> ValueType {
assert!(
value.is_finite(),
"Lowest method cannot operate with NAN values"
);
let left_value = self.window.push(value);
if value <= self.value {
self.value = value;
} else if left_value.to_bits() == self.value.to_bits() {
self.value = self.window.iter().fold(value, |a, &b| a.min(b));
}
self.value
}
}
impl Peekable<<Self as Method>::Output> for Lowest {
fn peek(&self) -> <Self as Method>::Output {
self.value
}
}
#[cfg(test)]
mod tests {
use super::{Highest, HighestLowestDelta, Lowest};
use crate::core::{Method, ValueType};
use crate::helpers::{assert_eq_float, RandomCandles};
use crate::methods::tests::test_const;
#[test]
fn test_highest_const() {
for i in 1..255 {
let input = (i as ValueType + 56.0) / 16.3251;
let mut method = Highest::new(i, &input).unwrap();
let output = method.next(&input);
test_const(&mut method, &input, &output);
}
}
#[test]
fn test_highest1() {
use super::Highest as TestingMethod;
let mut candles = RandomCandles::default();
let mut ma = TestingMethod::new(1, &candles.first().close).unwrap();
candles.take(100).for_each(|x| {
assert_eq_float(x.close, ma.next(&x.close));
});
}
#[test]
fn test_highest() {
use super::Highest as TestingMethod;
let candles = RandomCandles::default();
let src: Vec<ValueType> = candles.take(300).map(|x| x.close).collect();
(2..255).for_each(|length| {
let mut ma = TestingMethod::new(length, &src[0]).unwrap();
let length = length as usize;
src.iter().enumerate().for_each(|(i, x)| {
let value1 = ma.next(x);
let value2 = (0..length).fold(src[i], |m, j| m.max(src[i.saturating_sub(j)]));
assert_eq_float(value2, value1);
});
});
}
#[test]
fn test_lowest_const() {
for i in 1..255 {
let input = (i as ValueType + 56.0) / 16.3251;
let mut method = Lowest::new(i, &input).unwrap();
let output = method.next(&input);
test_const(&mut method, &input, &output);
}
}
#[test]
fn test_lowest1() {
use super::Lowest as TestingMethod;
let mut candles = RandomCandles::default();
let mut ma = TestingMethod::new(1, &candles.first().close).unwrap();
candles.take(100).for_each(|x| {
assert_eq_float(x.close, ma.next(&x.close));
});
}
#[test]
fn test_lowest() {
use super::Lowest as TestingMethod;
let candles = RandomCandles::default();
let src: Vec<ValueType> = candles.take(300).map(|x| x.close).collect();
(2..255).for_each(|length| {
let mut ma = TestingMethod::new(length, &src[0]).unwrap();
let length = length as usize;
src.iter().enumerate().for_each(|(i, x)| {
let value1 = ma.next(x);
let value2 = (0..length).fold(src[i], |m, j| m.min(src[i.saturating_sub(j)]));
assert_eq_float(value2, value1);
});
});
}
#[test]
fn test_highest_lowest_delta_const() {
for i in 1..255 {
let input = (i as ValueType + 56.0) / 16.3251;
let mut method = HighestLowestDelta::new(i, &input).unwrap();
let output = method.next(&input);
test_const(&mut method, &input, &output);
}
}
#[test]
fn test_highest_lowest_delta1() {
use super::HighestLowestDelta as TestingMethod;
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_highest_lowest_delta() {
use super::HighestLowestDelta as TestingMethod;
let candles = RandomCandles::default();
let src: Vec<ValueType> = candles.take(300).map(|x| x.close).collect();
(2..255).for_each(|length| {
let mut ma = TestingMethod::new(length, &src[0]).unwrap();
let length = length as usize;
src.iter().enumerate().for_each(|(i, x)| {
let value1 = ma.next(x);
let min = (0..length).fold(src[i], |m, j| m.min(src[i.saturating_sub(j)]));
let max = (0..length).fold(src[i], |m, j| m.max(src[i.saturating_sub(j)]));
assert_eq_float(max - min, value1);
});
});
}
}