pub trait Mean {
fn h_mean(&self) -> f64;
}
impl<T> Mean for [T]
where
T: Copy + Into<f64>,
{
fn h_mean(&self) -> f64 {
if self.is_empty() {
return 0.0;
}
let sum: f64 = self.iter().map(|&x| x.into()).sum();
sum / self.len() as f64
}
}
pub trait Median {
fn h_median(&self) -> f64;
}
impl<T> Median for [T]
where
T: Copy + Into<f64> + PartialOrd,
{
fn h_median(&self) -> f64 {
if self.is_empty() {
return 0.0;
}
let mut sorted: Vec<f64> = self.iter().map(|&x| x.into()).collect();
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap());
let mid = sorted.len() / 2;
if sorted.len() % 2 == 1 {
sorted[mid]
} else {
(sorted[mid - 1] + sorted[mid]) / 2.0
}
}
}
pub trait PopulationVariance {
fn h_population_variance(&self) -> f64;
}
impl<T> PopulationVariance for [T]
where
T: Copy + Into<f64>,
{
fn h_population_variance(&self) -> f64 {
let n = self.len();
if n < 2 {
return 0.0;
}
let mean: f64 = self.h_mean();
self.iter()
.map(|&x| {
let diff = x.into() - mean;
diff * diff
})
.sum::<f64>() / n as f64
}
}
pub trait SampleVariance {
fn h_sample_variance(&self) -> f64;
}
impl<T> SampleVariance for [T]
where
T: Copy + Into<f64>,
{
fn h_sample_variance(&self) -> f64 {
let n = self.len();
if n < 2 {
return 0.0;
}
let mean: f64 = self.h_mean();
self.iter()
.map(|&x| {
let diff = x.into() - mean;
diff * diff
})
.sum::<f64>() / (n - 1) as f64
}
}
pub trait ModusMult {
fn h_modus_mult(&self) -> Vec<f64>;
}
impl<T> ModusMult for [T]
where
T: Copy + Into<f64> + PartialEq,
{
fn h_modus_mult(&self) -> Vec<f64> {
let mut list_modus: Vec<(f64, i32)> = vec![];
let mut found_list: Vec<f64> = vec![];
for &x in self {
let val = x.into();
if !found_list.contains(&val) {
found_list.push(val);
list_modus.push((val, 0));
}
}
for &x in self {
let val = x.into();
for j in &mut list_modus {
if j.0 == val {
j.1 += 1;
}
}
}
let mut max_count = 0;
for &(_, count) in &list_modus {
if count > max_count {
max_count = count;
}
}
if max_count <= 1 {
return vec![];
}
list_modus
.into_iter()
.filter(|(_, count)| *count == max_count)
.map(|(val, _)| val)
.collect()
}
}
pub trait StdDevPopulation {
fn h_std_dev_population(&self) -> f64;
}
impl<T> StdDevPopulation for [T]
where
T: Copy + Into<f64>,
{
fn h_std_dev_population(&self) -> f64 {
let variance = self.h_population_variance();
variance.sqrt()
}
}
pub trait StdDevSample {
fn h_std_dev_sample(&self) -> f64;
}
impl<T> StdDevSample for [T]
where
T: Copy + Into<f64>,
{
fn h_std_dev_sample(&self) -> f64 {
let variance = self.h_sample_variance();
variance.sqrt()
}
}
pub trait GoldenCross {
fn h_golden_cross(&self, short_moving_average: usize, long_moving_average: usize) -> Option<Vec<usize>>;
}
impl<D> GoldenCross for [D]
where
D: Copy + Into<f64>,
{
fn h_golden_cross(&self, short_moving_average: usize, long_moving_average: usize) -> Option<Vec<usize>> {
if self.len() < long_moving_average {
return None;
}
if short_moving_average >= long_moving_average {
return None;
}
let mut short_ma: Vec<(f64, usize)> = Vec::new();
let mut long_ma: Vec<(f64, usize)> = Vec::new();
let mut short_moving_data: Vec<f64> = Vec::new();
let mut long_moving_data: Vec<f64> = Vec::new();
for (index, d) in self.iter().enumerate() {
short_moving_data.push((*d).into());
long_moving_data.push((*d).into());
if short_moving_data.len() > short_moving_average {
short_moving_data.remove(0);
}
if long_moving_data.len() > long_moving_average {
long_moving_data.remove(0);
}
if short_moving_data.len() == short_moving_average {
short_ma.push((short_moving_data.h_mean(), index));
}
if long_moving_data.len() == long_moving_average {
long_ma.push((long_moving_data.h_mean(), index));
}
}
let mut golden_crosses: Vec<usize> = Vec::new();
for i in 1..long_ma.len() {
let (long_curr, idx) = long_ma[i];
let (long_prev, _) = long_ma[i - 1];
if let (Some(s_curr), Some(s_prev)) = (
short_ma.iter().find(|x| x.1 == idx),
short_ma.iter().find(|x| x.1 == idx - 1),
) {
if s_curr.0 > long_curr && s_prev.0 <= long_prev {
golden_crosses.push(idx);
}
}
}
Some(golden_crosses)
}
}
pub trait DeathCross {
fn h_death_cross(&self, short_moving_average: usize, long_moving_average: usize) -> Option<Vec<usize>>;
}
impl<D> DeathCross for [D]
where
D: Copy + Into<f64>,
{
fn h_death_cross(&self, short_moving_average: usize, long_moving_average: usize) -> Option<Vec<usize>> {
if self.len() < long_moving_average {
return None;
}
if short_moving_average >= long_moving_average {
return None;
}
let mut short_ma: Vec<(f64, usize)> = Vec::new();
let mut long_ma: Vec<(f64, usize)> = Vec::new();
let mut short_moving_data: Vec<f64> = Vec::new();
let mut long_moving_data: Vec<f64> = Vec::new();
for (index, d) in self.iter().enumerate() {
short_moving_data.push((*d).into());
long_moving_data.push((*d).into());
if short_moving_data.len() > short_moving_average {
short_moving_data.remove(0);
}
if long_moving_data.len() > long_moving_average {
long_moving_data.remove(0);
}
if short_moving_data.len() == short_moving_average {
short_ma.push((short_moving_data.h_mean(), index));
}
if long_moving_data.len() == long_moving_average {
long_ma.push((long_moving_data.h_mean(), index));
}
}
let mut death_crosses: Vec<usize> = Vec::new();
for i in 1..long_ma.len() {
let (long_curr, idx) = long_ma[i];
let (long_prev, _) = long_ma[i - 1];
if let (Some(s_curr), Some(s_prev)) = (
short_ma.iter().find(|x| x.1 == idx),
short_ma.iter().find(|x| x.1 == idx - 1),
) {
if s_curr.0 < long_curr && s_prev.0 >= long_prev {
death_crosses.push(idx);
}
}
}
Some(death_crosses)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mean() {
let data = vec![1.0, 2.0, 3.0];
assert_eq!(data.h_mean(), 2.0);
}
#[test]
fn test_median_odd() {
let data = vec![1.0, 2.0, 3.0];
assert_eq!(data.h_median(), 2.0);
}
#[test]
fn test_median_even() {
let data = vec![1.0, 2.0, 3.0, 4.0];
assert_eq!(data.h_median(), 2.5);
}
#[test]
fn test_population_variance() {
let data = vec![1.0, 2.0, 3.0];
assert!((data.h_population_variance() - 0.6666666666666666).abs() < 1e-10);
}
#[test]
fn test_sample_variance() {
let data = vec![1.0, 2.0, 3.0];
assert_eq!(data.h_sample_variance(), 1.0);
}
#[test]
fn test_modus_mult() {
let data = vec![1.0, 2.0, 2.0, 3.0];
let modes = data.h_modus_mult();
assert_eq!(modes, vec![2.0]);
}
#[test]
fn test_modus_mult_no_mode() {
let data = vec![1.0, 2.0, 3.0];
let modes = data.h_modus_mult();
assert_eq!(modes, vec![]);
}
#[test]
fn test_std_dev_population() {
let data = vec![1.0, 2.0, 3.0];
assert!((data.h_std_dev_population() - 0.816496580927726).abs() < 1e-10);
}
#[test]
fn test_std_dev_sample() {
let data = vec![1.0, 2.0, 3.0];
assert_eq!(data.h_std_dev_sample(), 1.0);
}
#[test]
fn test_golden_cross() {
let data = vec![5.0, 4.0, 3.0, 4.0, 6.0, 8.0, 10.0];
let golden_crosses = data.h_golden_cross(2, 3);
assert!(golden_crosses.unwrap().len() > 0);
}
#[test]
fn test_death_cross() {
let data = vec![5.0, 6.0, 8.0, 6.0, 4.0, 2.0, 1.0];
let death_crosses = data.h_death_cross(2, 3);
assert!(death_crosses.unwrap().len() > 0);
}
}