use super::{FilteredDataValue, RealtimePriceData, try_join_all, Arc, Mutex, HashMap}; #[derive(Clone, Debug)] pub struct AdxData { pub adx: f64, pub close_time: i64 } struct BasicData { dm_plus: f64, dm_minus: f64, true_range: f64, close_time: i64, } struct DiData { di_plus: f64, di_minus: f64, close_time: i64, } pub async fn adx(adx_len: usize, di_len: usize, input_rt_data: &HashMap>, filtered_symbols: &HashMap,) -> Result>, Box> { if filtered_symbols.is_empty() { Err(("Err"))?; } let mut adx_vec: HashMap> = HashMap::new(); let mut adx_vec_arc = Arc::new(Mutex::new(adx_vec)); let mut task_vec = Vec::new(); for (filtered_symbol, filtered_data) in filtered_symbols { let mut rt_data_map = input_rt_data.clone(); let adx_vec_arc_c = Arc::clone(&adx_vec_arc); let symbol = filtered_symbol.clone(); task_vec.push(tokio::spawn(async move { if let Some(rt_price_data) = rt_data_map.get(&symbol) { if rt_price_data.len()-1 > adx_len && rt_price_data.len() > di_len { // step 1: calculate +DM, -DM, TR let windows = rt_price_data.windows(2); let mut basic_data_vec: Vec = Vec::new(); for window in windows { let prev_rt_data = window.first().unwrap(); let current_rt_data = window.last().unwrap(); let mut up = current_rt_data.high_price - prev_rt_data.high_price; let mut down = prev_rt_data.low_price - current_rt_data.low_price; let basic_data = BasicData { dm_plus: if up > down && up > 0.0 { up } else { 0.0 }, dm_minus: if down > up && down > 0.0 { down } else { 0.0 }, true_range: f64::max(f64::max(current_rt_data.high_price - current_rt_data.low_price, current_rt_data.high_price - prev_rt_data.close_price), current_rt_data.low_price - prev_rt_data.close_price), close_time: current_rt_data.close_time, }; basic_data_vec.push(basic_data); } // step 2: smoothing +DM, -DM, TR let alpha: f64 = 1.0/(di_len as f64); let mut smoothed_basic_data_vec: Vec = Vec::new(); let partial_vec1 = basic_data_vec.get(..di_len).unwrap(); // for calculation of initial value let partial_vec2 = basic_data_vec.get(di_len..).unwrap(); // for calculation of the rest let mut dm_plus_calculated = 0.0; let mut dm_minus_calculated = 0.0; let mut tr_calculated = 0.0; for element in partial_vec1 { dm_plus_calculated += element.dm_plus; dm_minus_calculated += element.dm_minus; tr_calculated += element.true_range; } dm_plus_calculated /= di_len as f64; dm_minus_calculated /= di_len as f64; tr_calculated /= di_len as f64; let basic_data = BasicData { dm_plus: dm_plus_calculated, dm_minus: dm_minus_calculated, true_range: tr_calculated, close_time: partial_vec1.last().unwrap().close_time }; smoothed_basic_data_vec.push(basic_data); for element in partial_vec2 { dm_plus_calculated = alpha * element.dm_plus + (1.0 - alpha) * dm_plus_calculated; dm_minus_calculated = alpha * element.dm_minus + (1.0 - alpha) * dm_minus_calculated; tr_calculated = alpha * element.true_range + (1.0 - alpha) * tr_calculated; let basic_data = BasicData { dm_plus: dm_plus_calculated, dm_minus: dm_minus_calculated, true_range: tr_calculated, close_time: element.close_time }; smoothed_basic_data_vec.push(basic_data); } // step 3: calculate DI let mut di_data_vec: Vec = Vec::new(); for basic_data in smoothed_basic_data_vec { let di_data = DiData { di_plus: (100.0 * basic_data.dm_plus) / basic_data.true_range, di_minus: (100.0 * basic_data.dm_minus) / basic_data.true_range, close_time: basic_data.close_time}; di_data_vec.push(di_data); } // step 4: calculate ADX let mut initial_adx_vec: Vec = Vec::new(); for di_data in di_data_vec { let sum = di_data.di_plus + di_data.di_minus; let difference = (di_data.di_plus - di_data.di_minus).abs(); let divisor = if sum <= 0.00000001 { 1.0 } else { sum }; let adx_data = AdxData { adx: difference.abs()/divisor, close_time: di_data.close_time }; initial_adx_vec.push(adx_data); } let partial_vec1 = initial_adx_vec.get(..adx_len).unwrap(); // for calculation of initial value let partial_vec2 = initial_adx_vec.get(adx_len..).unwrap(); // for calculation of the rest let mut smoothed_adx_vec: Vec = Vec::new(); let mut adx_calculated = 0.0; for element in partial_vec1 { adx_calculated += element.adx; } adx_calculated /= adx_len as f64; let adx_data = AdxData { adx: adx_calculated, close_time: partial_vec1.last().unwrap().close_time }; smoothed_adx_vec.push(adx_data); let alpha: f64 = 1.0 /(adx_len as f64); for element in partial_vec2 { adx_calculated = alpha * element.adx + (1.0 - alpha) * adx_calculated; let adx_data = AdxData { adx: 100.0 * adx_calculated, close_time: element.close_time }; smoothed_adx_vec.push(adx_data); } let mut adx_vec_arc_lock = adx_vec_arc_c.lock().await; adx_vec_arc_lock.insert(symbol.clone(), smoothed_adx_vec.clone()); } } })); } try_join_all(task_vec).await?; let a = adx_vec_arc.lock().await.to_owned(); Ok(a) }