use crate::bar_indicators::average::{MovingAverageProvider, MovingAverageType};
use crate::bar_indicators::indicator_value::IndicatorValue;
use crate::bar_indicators::ohlcv_field::OhlcvField;
#[derive(Debug, Clone)]
pub struct Trima {
period: usize,
sma1: MovingAverageProvider,
sma2: MovingAverageProvider,
value: f64,
source: OhlcvField,
}
impl Trima {
pub fn new(period: usize) -> Self {
let p = period.max(1);
Self {
period: p,
sma1: MovingAverageProvider::new(MovingAverageType::SMA, p),
sma2: MovingAverageProvider::new(MovingAverageType::SMA, p),
value: 0.0,
source: OhlcvField::Close,
}
}
pub fn with_source(period: usize, source: OhlcvField) -> Self {
let p = period.max(1);
Self {
period: p,
sma1: MovingAverageProvider::new(MovingAverageType::SMA, p),
sma2: MovingAverageProvider::new(MovingAverageType::SMA, p),
value: 0.0,
source,
}
}
#[inline]
pub fn reset(&mut self) {
self.sma1.reset();
self.sma2.reset();
self.value = 0.0;
}
#[inline]
pub fn is_ready(&self) -> bool {
self.sma1.is_ready() && self.sma2.is_ready()
}
#[inline]
pub fn value(&self) -> IndicatorValue {
IndicatorValue::Single(self.value)
}
pub fn update_bar(&mut self, o: f64, h: f64, l: f64, c: f64, v: f64) -> f64 {
let price = self.source.extract(o, h, l, c, v);
let a = self.sma1.update_bar(0.0, 0.0, 0.0, price, 0.0);
self.value = self.sma2.update_bar(0.0, 0.0, 0.0, a, 0.0);
self.value
}
pub fn period(&self) -> usize {
self.period
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_trima_basic_calculation() {
let mut trima = Trima::new(3);
for i in 1..=6 {
trima.update_bar(0.0, 0.0, 0.0, i as f64 * 10.0, 0.0);
}
assert!(trima.is_ready());
assert!(trima.value().main() > 0.0);
}
#[test]
fn test_trima_reset() {
let mut trima = Trima::new(3);
for i in 1..=6 {
trima.update_bar(0.0, 0.0, 0.0, i as f64 * 10.0, 0.0);
}
assert!(trima.is_ready());
trima.reset();
assert!(!trima.is_ready());
}
}