use charts::SourceSeries;
use indicators::sma::SimpleMovingAverage;
pub struct ExponentialMovingAverage<'source> {
source: SourceSeries<'source>,
alpha: f64,
length: usize,
}
impl<'source> ExponentialMovingAverage<'source> {
pub fn new(source: SourceSeries<'source>, length: usize) -> Self {
let alpha = 2.0 / ((length as f64) + 1.0);
ExponentialMovingAverage {
source: source,
alpha: alpha,
length: length,
}
}
pub fn get(&self, index: usize) -> Option<f64> {
let last_index: i64 = (self.source.len() as i64) - 1;
if last_index < 0 {
return None;
}
let num_of_data_points_between_current_and_last = last_index - (index as i64) + 1;
if num_of_data_points_between_current_and_last < (self.length as i64) {
return None;
}
if num_of_data_points_between_current_and_last == (self.length as i64) {
let sma = SimpleMovingAverage::new(self.source.clone(), self.length);
return sma.get(index);
}
let current_value = match self.source.get(index) {
None => {
return None;
}
Some(current_value) => current_value,
};
let prev_value = match self.get(index + 1) {
None => 0.0,
Some(prev_value) => prev_value,
};
let ema_value = self.alpha * current_value + (1.0 - self.alpha) * prev_value;
Some(ema_value)
}
}