use crate::value_estimation_team::indicators::ema::{EmaData, ema}; use crate::value_estimation_team::datapoints::price_data::RealtimePriceData; use super::FilteredData; use std::sync::Arc; use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*}; use futures::future::try_join_all; #[derive(Debug, Clone)] pub struct MacdData { pub macd_value: f64, pub signal_value: f64, pub close_time: i64, } impl MacdData { fn new() -> MacdData { let a = MacdData { macd_value: 0.0, signal_value: 0.0, close_time: 0, }; a } } #[derive(Debug, Clone)] pub struct TempData { pub value: f64, pub close_time: i64, } impl TempData { fn new() -> TempData { let a = TempData { value: 0.0, close_time: 0, }; a } } pub async fn ema_macd( fast_len: usize, slow_len: usize, signal_smoothing: usize, input_rt_data: &Vec<(String, Vec)>, filtered_symbols: &Vec ) -> Result)>, Box> { let mut macd_oscil_vec: Vec<(String, Vec)> = Vec::new(); let fast_emas = ema(fast_len, input_rt_data, filtered_symbols).await?; let slow_emas = ema(slow_len, input_rt_data, filtered_symbols).await?; let mut macd_data_wrapper: Vec<(String, Vec)> = Vec::new(); let mut macd_data_wrapper_arc = Arc::new(Mutex::new(macd_data_wrapper)); let mut task_vec = Vec::new(); for filtered_elem in filtered_symbols { let fast_emas_c = fast_emas.clone(); let slow_emas_c = slow_emas.clone(); let filtered_elem_c = filtered_elem.clone(); let macd_data_wrapper_arc_c = Arc::clone(&macd_data_wrapper_arc); task_vec.push(tokio::spawn(async move { let fast_search_result = fast_emas_c.iter().position(|x| x.0 == filtered_elem_c.symbol); let slow_search_result = slow_emas_c.iter().position(|x| x.0 == filtered_elem_c.symbol); if fast_search_result.is_some_and(|a| fast_emas_c[a].1.len() >= signal_smoothing) && slow_search_result.is_some_and(|a| slow_emas_c[a].1.len() >= signal_smoothing) { let fast_ema = fast_emas_c[fast_search_result.unwrap()].1.clone(); let slow_ema = slow_emas_c[fast_search_result.unwrap()].1.clone(); let result = fast_ema.binary_search_by_key( &slow_ema.first().unwrap().close_time, |&EmaData { ema_value, close_time, }| close_time, ); if result.is_ok() { // making MACD let temp_vec = fast_ema.get(result.unwrap()..).unwrap(); let zipped = temp_vec.iter().zip(slow_ema); let mut macd = TempData::new(); let mut macd_vec: Vec = Vec::new(); for element in zipped { macd.value = element.0.ema_value - element.1.ema_value; macd.close_time = element.0.close_time; macd_vec.push(macd.clone()); } // making signal (smoothed MACD) // TODO: this should be calculated in EMA (currently, SMA) // let macd_vec_window = macd_vec.windows(signal_smoothing); // let mut macd_signal_vec: Vec = Vec::new(); // for window in macd_vec_window { // let mut sum_value = 0.0; // for element in window { // sum_value += element.value; // } // macd.value = sum_value / signal_smoothing as f64; // macd.close_time = window.last().unwrap().close_time; // macd_signal_vec.push(macd.clone()); // } let mut macd_signal = TempData::new(); let mut macd_signal_vec: Vec = Vec::new(); let partial_vec1 = macd_vec.get(..signal_smoothing).unwrap(); let partial_vec2 = macd_vec.get(signal_smoothing..).unwrap(); let mut sma_for_initial_value = 0.0; for element in partial_vec1 { sma_for_initial_value += element.value; } sma_for_initial_value /= signal_smoothing as f64; macd_signal.value = sma_for_initial_value; macd_signal.close_time = partial_vec1.last().unwrap().close_time; macd_signal_vec.push(macd_signal.clone()); let alpha: f64 = 2.0 / (signal_smoothing as f64 + 1.0); let mut ema_prev = sma_for_initial_value; for element in partial_vec2 { let ema_t = (1.0 - alpha) * ema_prev + alpha * element.value; macd_signal.value = ema_t; macd_signal.close_time = element.close_time; macd_signal_vec.push(macd_signal.clone()); ema_prev = ema_t; } let result = macd_vec.binary_search_by_key( &macd_signal_vec.first().unwrap().close_time, |&TempData { value, close_time, }| close_time, ); if result.is_ok() { let result = macd_vec.get(result.unwrap()..); if result.is_some() { let zipped = result.unwrap().iter().zip(macd_signal_vec); let mut macd_vec: Vec = Vec::new(); for element in zipped { let mut macd = MacdData::new(); macd.macd_value = element.0.value; macd.signal_value = element.1.value; macd.close_time = element.0.close_time; macd_vec.push(macd); } let mut macd_data_wrapper_lock = macd_data_wrapper_arc_c.lock().await; macd_data_wrapper_lock.push((filtered_elem_c.symbol.clone(), macd_vec.clone())); } } } } })); } try_join_all(task_vec).await?; let a = macd_data_wrapper_arc.lock().await.to_owned(); Ok(a) }