use crate::core::Method;
use crate::core::{Error, PeriodType, Window};
use crate::helpers::{Buffered, Peekable};
use std::convert::TryInto;
use std::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Past<T>(Window<T>)
where
T: Clone + fmt::Debug;
impl<T> Method for Past<T>
where
T: Clone + fmt::Debug,
{
type Params = PeriodType;
type Input = T;
type Output = T;
fn new(length: Self::Params, value: &Self::Input) -> Result<Self, Error> {
match length {
0 => Err(Error::WrongMethodParameters),
length => Ok(Self(Window::new(length, value.clone()))),
}
}
#[inline]
fn next(&mut self, value: &Self::Input) -> T {
self.0.push(value.clone())
}
}
impl<T> Peekable<<Self as Method>::Output> for Past<T>
where
T: Clone + fmt::Debug,
{
fn peek(&self) -> <Self as Method>::Output {
self.0.newest().clone()
}
}
impl<T: Clone + std::fmt::Debug> Buffered<<Self as Method>::Output> for Past<T> {
fn get(&self, index: usize) -> Option<<Self as Method>::Output> {
let index = index.try_into().ok()?;
self.0.get(index).cloned()
}
}
#[cfg(test)]
mod tests {
use super::{Method, Past as TestingMethod};
use crate::core::ValueType;
use crate::helpers::{assert_eq_float, RandomCandles};
use crate::methods::tests::test_const;
#[test]
fn test_past_const() {
for i in 1..255 {
let input = (i as ValueType + 56.0) / 16.3251;
let mut method = TestingMethod::new(i, &input).unwrap();
let output = method.next(&input);
test_const(&mut method, &input, &output);
}
}
#[test]
fn test_past1() {
let mut candles = RandomCandles::default();
let mut ma = TestingMethod::new(1, &candles.first()).unwrap();
let mut prev = None;
candles.take(100).for_each(|x| {
let q = ma.next(&x);
let p = prev.unwrap_or(x);
assert_eq!(p, q);
prev = Some(x);
});
}
#[test]
fn test_past() {
let candles = RandomCandles::default();
let src: Vec<ValueType> = candles.take(300).map(|x| x.close).collect();
(1..255).for_each(|length| {
let mut ma = TestingMethod::new(length, &src[0]).unwrap();
src.iter().enumerate().for_each(|(i, x)| {
assert_eq_float(src[i.saturating_sub(length as usize)], ma.next(x));
});
});
}
}