use super::MovingAverage;
use crate::types::{
data::{BaseData, Candle},
error::ToolkitError,
};
#[derive(Debug, Clone, Copy)]
pub enum Stochastic {
Fast(f64, u128),
Slow(f64, u128),
}
impl Stochastic {
pub fn fast<T>(data: &[T]) -> Result<Self, ToolkitError>
where
T: Candle + Clone,
{
if data.len() == 0 {
return Err(ToolkitError::EmptyData);
}
let mut data = data.to_vec();
data.sort_by_key(|k| k.epoch_time());
let last_close_price = data.last().unwrap().close_price(); let mut max_high_price = 0f64;
let mut min_low_price = std::f64::MAX;
let last_epoch_time = data.last().unwrap().epoch_time(); for elem in data.iter() {
max_high_price = max_high_price.max(elem.high_price());
min_low_price = min_low_price.min(elem.low_price());
}
Ok(Self::Fast(
(last_close_price - min_low_price) / (max_high_price - min_low_price) * 100f64,
last_epoch_time,
))
}
pub fn slow<T>(data: &[T]) -> Result<Self, ToolkitError>
where
T: Candle + Clone,
{
if data.len() == 0 {
return Err(ToolkitError::EmptyData);
}
let mut data = data.to_vec();
data.sort_by_key(|k| k.epoch_time());
let last_epoch_time = data.last().unwrap().epoch_time();
let fast_values: Vec<Self> = data
.iter()
.map(|elem| {
Self::Fast(
(elem.close_price() - elem.low_price())
/ (elem.high_price() - elem.low_price())
* 100f64,
elem.epoch_time(),
)
})
.collect();
Ok(Self::Slow(
MovingAverage::simple(&fast_values).inner(),
last_epoch_time,
))
}
pub fn inner(&self) -> f64 {
match self {
Self::Fast(f, _epoch_time) | Self::Slow(f, _epoch_time) => f.to_owned(),
}
}
pub fn into_slow(data: &[Self]) -> Result<Self, ToolkitError> {
if data
.iter()
.filter(|elem| match elem {
Self::Slow(_slow, _epoch_time) => true,
_ => false,
})
.count()
> 0
{
return Err(ToolkitError::InvalidData);
}
let mut data = data.to_vec();
data.sort_by_key(|k| k.epoch_time());
let last_epoch_time = data.last().unwrap().epoch_time(); Ok(Self::Slow(
MovingAverage::simple(&data).inner(),
last_epoch_time,
))
}
}
impl BaseData for Stochastic {
fn value(&self) -> f64 {
match self {
Self::Fast(f, _epoch_time) | Self::Slow(f, _epoch_time) => f.to_owned(),
}
}
fn weight(&self) -> u64 {
1
}
fn epoch_time(&self) -> u128 {
match self {
Self::Fast(_f, epoch_time) | Self::Slow(_f, epoch_time) => epoch_time.to_owned(),
}
}
}