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 last_epoch_time = data.last().unwrap().epoch_time(); // it's safe since the vector's length > 0
47
48        // 각 bar의 단일 Fast %K를 구한 뒤 SMA → into_slow()와 동일한 로직
49        let fast_values: Vec<Self> = data
50            .iter()
51            .map(|elem| {
52                Self::Fast(
53                    (elem.close_price() - elem.low_price())
54                        / (elem.high_price() - elem.low_price())
55                        * 100f64,
56                    elem.epoch_time(),
57                )
58            })
59            .collect();
60
61        Ok(Self::Slow(
62            MovingAverage::simple(&fast_values).inner(),
63            last_epoch_time,
64        ))
65    }
66
67    pub fn inner(&self) -> f64 {
68        match self {
69            Self::Fast(f, _epoch_time) | Self::Slow(f, _epoch_time) => f.to_owned(),
70        }
71    }
72
73    pub fn into_slow(data: &[Self]) -> Result<Self, ToolkitError> {
74        if data
75            .iter()
76            .filter(|elem| match elem {
77                Self::Slow(_slow, _epoch_time) => true,
78                _ => false,
79            })
80            .count()
81            > 0
82        {
83            return Err(ToolkitError::InvalidData);
84        }
85        let mut data = data.to_vec();
86        data.sort_by_key(|k| k.epoch_time());
87        let last_epoch_time = data.last().unwrap().epoch_time(); // it's safe since the vector's length > 0
88        Ok(Self::Slow(
89            MovingAverage::simple(&data).inner(),
90            last_epoch_time,
91        ))
92    }
93}
94
95impl BaseData for Stochastic {
96    fn value(&self) -> f64 {
97        match self {
98            Self::Fast(f, _epoch_time) | Self::Slow(f, _epoch_time) => f.to_owned(),
99        }
100    }
101
102    fn weight(&self) -> u64 {
103        1
104    }
105
106    fn epoch_time(&self) -> u128 {
107        match self {
108            Self::Fast(_f, epoch_time) | Self::Slow(_f, epoch_time) => epoch_time.to_owned(),
109        }
110    }
111}