1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
#![feature(external_doc)]

use std::ops::{Div, Sub};
use ta_common::fixed_queue::FixedQueue;
use ta_common::traits::Indicator;

pub enum ROCType {
    ROCR,
    ROCP,
    ROC100,
    ROC,
}


#[doc(include = "../README.md")]
pub struct ROC {
    history: FixedQueue<f64>,
    price_ago: u32,
    result_type: ROCType,
}

impl ROC {
    pub fn new(price_ago: u32, result_type: Option<ROCType>) -> ROC {
        let result_type = result_type.unwrap_or(ROCType::ROC);
        Self {
            history: FixedQueue::new(price_ago),
            price_ago,
            result_type,
        }
    }
    pub fn calc(&self, input: f64) -> Option<f32> {
        let history = &self.history;
        let size = history.size() as i32;
        let period = self.price_ago as i32;
        let prev_index: i32 = (size - period) as i32;
        let prev = history.at(prev_index);
        return prev.map(|v|input.div(v) as f32);
    }
}


impl Indicator<f64, Option<f32>> for ROC {
    fn next(&mut self, input: f64) -> Option<f32> {
        let value = self.calc(input);
        let result = match &self.result_type {
            ROCType::ROCR => value,
            ROCType::ROCP => value.map(|v| v - 1_f32),
            ROCType::ROC => value.map(|v| (v - 1_f32) * 100_f32),
            ROCType::ROC100 => value.map(|v| v * 100_f32),
        };
        self.history.add(input);
        result
    }

    fn reset(&mut self) {
        self.history.clear();
    }
}


#[cfg(test)]
mod tests {
    use crate::{ROC, ROCType};
    use ta_common::traits::{Indicator};

    #[test]
    fn roc_percent_works() {
        let mut roc = ROC::new(1, None);
        let res = roc.next(100 as f64);
        assert_eq!(None, res);
        let res = roc.next(50 as f64);
        assert_eq!(Some(-50_f32), res);
    }

    #[test]
    fn roc_value_works() {
        let mut roc = ROC::new(1, Some(ROCType::ROCR));
        let res = roc.next(100 as f64);
        assert_eq!(None, res);
        let res = roc.next(50 as f64);
        assert_eq!(Some(0.5_f32), res);
    }

    #[test]
    fn roc_hundred_works() {
        let mut roc = ROC::new(1, Some(ROCType::ROC100));
        let res = roc.next(100 as f64);
        assert_eq!(None, res);
        let res = roc.next(50 as f64);
        assert_eq!(Some(50_f32), res);
    }

    #[test]
    fn roc_momentum_works() {
        let mut roc = ROC::new(1, Some(ROCType::ROCP));
        let res = roc.next(100 as f64);
        assert_eq!(None, res);
        let res = roc.next(50 as f64);
        assert_eq!(Some(-0.5_f32), res);
    }
}