Skip to main content

trading_toolkit/indicator/
stochastic.rs

1use super::MovingAverage;
2use crate::types::{
3    data::{BaseData, Candle},
4    error::ToolkitError,
5};
6
7#[derive(Debug, Clone, Copy)]
8pub enum Stochastic {
9    Fast(f64, u128),
10    Slow(f64, u128),
11}
12
13impl Stochastic {
14    pub fn fast<T>(data: &[T]) -> Result<Self, ToolkitError>
15    where
16        T: Candle + Clone,
17    {
18        if data.len() == 0 {
19            return Err(ToolkitError::EmptyData);
20        }
21        let mut data = data.to_vec();
22        data.sort_by_key(|k| k.epoch_time());
23        let last_close_price = data.last().unwrap().close_price(); // it's safe since the vector's length > 0
24        let mut max_high_price = 0f64;
25        let mut min_low_price = std::f64::MAX;
26        let last_epoch_time = data.last().unwrap().epoch_time(); // it's safe since the vector's length > 0
27        for elem in data.iter() {
28            max_high_price = max_high_price.max(elem.high_price());
29            min_low_price = min_low_price.min(elem.low_price());
30        }
31        Ok(Self::Fast(
32            (last_close_price - min_low_price) / (max_high_price - min_low_price) * 100f64,
33            last_epoch_time,
34        ))
35    }
36
37    pub fn slow<T>(data: &[T]) -> Result<Self, ToolkitError>
38    where
39        T: Candle + Clone,
40    {
41        if data.len() == 0 {
42            return Err(ToolkitError::EmptyData);
43        }
44        let mut data = data.to_vec();
45        data.sort_by_key(|k| k.epoch_time());
46        let mut sum_numerator = 0f64;
47        let mut sum_denominator = 0f64;
48        let last_epoch_time = data.last().unwrap().epoch_time(); // it's safe since the vector's length > 0
49        for elem in data.iter() {
50            sum_numerator += elem.close_price() - elem.low_price();
51            sum_denominator += elem.high_price() - elem.low_price();
52        }
53        Ok(Self::Slow(
54            (sum_numerator / sum_denominator) * 100f64,
55            last_epoch_time,
56        ))
57    }
58
59    pub fn inner(&self) -> f64 {
60        match self {
61            Self::Fast(f, _epoch_time) | Self::Slow(f, _epoch_time) => f.to_owned(),
62        }
63    }
64
65    pub fn into_slow(data: &[Self]) -> Result<Self, ToolkitError> {
66        if data
67            .iter()
68            .filter(|elem| match elem {
69                Self::Slow(_slow, _epoch_time) => true,
70                _ => false,
71            })
72            .count()
73            > 0
74        {
75            return Err(ToolkitError::InvalidData);
76        }
77        let mut data = data.to_vec();
78        data.sort_by_key(|k| k.epoch_time());
79        let last_epoch_time = data.last().unwrap().epoch_time(); // it's safe since the vector's length > 0
80        Ok(Self::Slow(
81            MovingAverage::simple(&data).inner(),
82            last_epoch_time,
83        ))
84    }
85}
86
87impl BaseData for Stochastic {
88    fn value(&self) -> f64 {
89        match self {
90            Self::Fast(f, _epoch_time) | Self::Slow(f, _epoch_time) => f.to_owned(),
91        }
92    }
93
94    fn weight(&self) -> u64 {
95        1
96    }
97
98    fn epoch_time(&self) -> u128 {
99        match self {
100            Self::Fast(_f, epoch_time) | Self::Slow(_f, epoch_time) => epoch_time.to_owned(),
101        }
102    }
103}