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); } }