use crate::core::{Error, PeriodType, ValueType};
use crate::core::{Method, MovingAverage};
use crate::helpers::Peekable;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct EMA {
alpha: ValueType,
value: ValueType,
}
impl Method for EMA {
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 => {
let alpha = 2. / ((length + 1) as ValueType);
Ok(Self { alpha, value })
}
}
}
#[inline]
fn next(&mut self, value: &Self::Input) -> Self::Output {
self.value = (value - self.value).mul_add(self.alpha, self.value);
self.value
}
}
impl MovingAverage for EMA {}
impl Peekable<<Self as Method>::Output> for EMA {
fn peek(&self) -> <Self as Method>::Output {
self.value
}
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DMA {
ema: EMA,
dma: EMA,
}
impl Method for DMA {
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 {
ema: EMA::new(length, value)?,
dma: EMA::new(length, value)?,
}),
}
}
#[inline]
fn next(&mut self, value: &Self::Input) -> Self::Output {
self.dma.next(&self.ema.next(value))
}
}
impl MovingAverage for DMA {}
impl Peekable<<Self as Method>::Output> for DMA {
fn peek(&self) -> <Self as Method>::Output {
self.dma.value
}
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TMA {
dma: DMA,
tma: EMA,
}
impl Method for TMA {
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 {
dma: DMA::new(length, value)?,
tma: EMA::new(length, value)?,
}),
}
}
#[inline]
fn next(&mut self, value: &Self::Input) -> Self::Output {
self.tma.next(&self.dma.next(value))
}
}
impl MovingAverage for TMA {}
impl Peekable<<Self as Method>::Output> for TMA {
fn peek(&self) -> <Self as Method>::Output {
self.tma.value
}
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct DEMA {
ema: EMA,
dma: EMA,
}
impl Method for DEMA {
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 {
ema: EMA::new(length, value)?,
dma: EMA::new(length, value)?,
}),
}
}
#[inline]
fn next(&mut self, value: &Self::Input) -> Self::Output {
let e_ma = self.ema.next(value);
self.dma.next(&e_ma);
self.peek()
}
}
impl MovingAverage for DEMA {}
impl Peekable<<Self as Method>::Output> for DEMA {
fn peek(&self) -> <Self as Method>::Output {
let e_ma = self.ema.value;
let d_ma = self.dma.value;
e_ma.mul_add(2., -d_ma)
}
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TEMA {
ema: EMA,
dma: EMA,
tma: EMA,
}
impl Method for TEMA {
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 {
ema: EMA::new(length, value)?,
dma: EMA::new(length, value)?,
tma: EMA::new(length, value)?,
}),
}
}
#[inline]
fn next(&mut self, value: &Self::Input) -> Self::Output {
let e_ma = self.ema.next(value);
let d_ma = self.dma.next(&e_ma);
self.tma.next(&d_ma);
self.peek()
}
}
impl MovingAverage for TEMA {}
impl Peekable<<Self as Method>::Output> for TEMA {
fn peek(&self) -> <Self as Method>::Output {
let e_ma = self.ema.value;
let d_ma = self.dma.value;
let t_ma = self.tma.value;
(e_ma - d_ma).mul_add(3., t_ma)
}
}
#[cfg(test)]
#[allow(clippy::suboptimal_flops)]
mod tests {
use super::{DEMA, DMA, EMA, TEMA, TMA};
use crate::core::{Method, ValueType};
use crate::helpers::{assert_eq_float, RandomCandles};
use crate::methods::tests::test_const_float;
#[test]
fn test_ema_const() {
for i in 1..255 {
let input = (i as ValueType + 56.0) / 16.3251;
let mut method = EMA::new(i, &input).unwrap();
let output = method.next(&input);
test_const_float(&mut method, &input, output);
}
}
#[test]
fn test_ema1() {
use super::EMA 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_ema() {
use super::EMA as TestingMethod;
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();
let alpha = 2. / (length + 1) as ValueType;
let mut prev_value = src[0];
for &x in &src {
let value = ma.next(&x);
let value2 = alpha * x + (1. - alpha) * prev_value;
prev_value = value2;
assert_eq_float(value2, value);
}
});
}
#[test]
fn test_dma_const() {
for i in 1..255 {
let input = (i as ValueType + 56.0) / 16.3251;
let mut method = DMA::new(i, &input).unwrap();
let output = method.next(&input);
test_const_float(&mut method, &input, output);
}
}
#[test]
fn test_dma1() {
use super::DMA 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_dma() {
use super::DMA as TestingMethod;
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();
let alpha = 2. / (length + 1) as ValueType;
let mut prev_value1 = src[0];
let mut prev_value2 = src[0];
for &x in &src {
let value = ma.next(&x);
let ema1 = alpha * x + (1. - alpha) * prev_value1;
let ema2 = alpha * ema1 + (1. - alpha) * prev_value2;
prev_value1 = ema1;
prev_value2 = ema2;
let value2 = ema2;
assert_eq_float(value2, value);
}
});
}
#[test]
fn test_dema_const() {
for i in 1..255 {
let input = (i as ValueType + 56.0) / 16.3251;
let mut method = DEMA::new(i, &input).unwrap();
let output = method.next(&input);
test_const_float(&mut method, &input, output);
}
}
#[test]
fn test_dema1() {
use super::DEMA 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_dema() {
use super::DEMA as TestingMethod;
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();
let alpha = 2. / (length + 1) as ValueType;
let mut prev_value1 = src[0];
let mut prev_value2 = src[0];
for &x in &src {
let value = ma.next(&x);
let ema1 = alpha * x + (1. - alpha) * prev_value1;
let ema2 = alpha * ema1 + (1. - alpha) * prev_value2;
prev_value1 = ema1;
prev_value2 = ema2;
let value2 = 2. * ema1 - ema2;
assert_eq_float(value2, value);
}
});
}
#[test]
fn test_tma_const() {
for i in 1..255 {
let input = (i as ValueType + 56.0) / 16.3251;
let mut method = TMA::new(i, &input).unwrap();
let output = method.next(&input);
test_const_float(&mut method, &input, output);
}
}
#[test]
fn test_tma1() {
use super::TMA 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_tma() {
use super::TMA as TestingMethod;
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();
let alpha = 2. / (length + 1) as ValueType;
let mut prev_value1 = src[0];
let mut prev_value2 = src[0];
let mut prev_value3 = src[0];
for &x in &src {
let value = ma.next(&x);
let ema1 = alpha * x + (1. - alpha) * prev_value1;
let ema2 = alpha * ema1 + (1. - alpha) * prev_value2;
let ema3 = alpha * ema2 + (1. - alpha) * prev_value3;
prev_value1 = ema1;
prev_value2 = ema2;
prev_value3 = ema3;
let value2 = ema3;
assert_eq_float(value2, value);
}
});
}
#[test]
fn test_tema_const() {
for i in 1..255 {
let input = (i as ValueType + 56.0) / 16.3251;
let mut method = TEMA::new(i, &input).unwrap();
let output = method.next(&input);
test_const_float(&mut method, &input, output);
}
}
#[test]
fn test_tema1() {
use super::{Method, TEMA 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_tema() {
use super::{Method, TEMA as TestingMethod};
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();
let alpha = 2. / (length + 1) as ValueType;
let mut prev_value1 = src[0];
let mut prev_value2 = src[0];
let mut prev_value3 = src[0];
for &x in &src {
let value = ma.next(&x);
let e_ma = alpha * x + (1. - alpha) * prev_value1;
let d_ma = alpha * e_ma + (1. - alpha) * prev_value2;
let t_ma = alpha * d_ma + (1. - alpha) * prev_value3;
prev_value1 = e_ma;
prev_value2 = d_ma;
prev_value3 = t_ma;
let value2 = 3. * e_ma - 3. * d_ma + t_ma;
assert_eq_float(value2, value);
}
});
}
}