diff --git a/src/strategy_team/strategy_004.rs b/src/strategy_team/strategy_004.rs index 4dd5303..09ff4a5 100644 --- a/src/strategy_team/strategy_004.rs +++ b/src/strategy_team/strategy_004.rs @@ -81,179 +81,130 @@ pub async fn list_up_for_buy( // 3rd filtering: supertrend(ATR period 10, multiplier: 2, 30m close price), area should be DOWN let filtered_data_2nd = filtered_data_2nd_arc.lock().await.clone(); let mut filtered_data_3rd: Vec = Vec::new(); - let mut filtered_data_3rd_arc: Arc>> = - Arc::new(Mutex::new(filtered_data_3rd)); - let mut task_vec = Vec::new(); - for element in filtered_data_2nd { let mut rt_30m_vec: Vec = Vec::new(); let mut supertrend_vec: Vec = Vec::new(); - let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); - let filtered_data_3rd_arc_c = Arc::clone(&filtered_data_3rd_arc); - task_vec.push(tokio::spawn(async move { - let rt_30m_option = rt_price_30m_vec_c - .iter() - .position(|x| *x.0 == element.symbol); - let supertrend_option_30m = - supertrend(&element.symbol, &rt_price_30m_vec_c, 10, 2.0, true).await; + let rt_30m_option = alldata.rt_price_30m_vec + .iter() + .position(|x| *x.0 == element.symbol); + let supertrend_option_30m = + supertrend(&element.symbol, &alldata.rt_price_30m_vec, 10, 2.0, true).await; - if rt_30m_option.is_some() && supertrend_option_30m.is_some() { - rt_30m_vec = rt_price_30m_vec_c[rt_30m_option.unwrap()].1.clone(); - supertrend_vec = supertrend_option_30m.unwrap(); - let server_epoch = server_epoch().await; - if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch { - let supertrend_search_result = supertrend_vec.binary_search_by_key( - &rt_30m_vec.last().unwrap().close_time, - |SupertrendData { - band_value, - signal, - area, - close_time, - }| *close_time, - ); - if supertrend_search_result.is_ok() { - if supertrend_vec[supertrend_search_result.unwrap()].area.contains("DOWN") - && supertrend_vec[supertrend_search_result.unwrap()].band_value > element.current_price.to_f64().unwrap() - { - let mut filtered_data_3rd_lock = filtered_data_3rd_arc_c.lock().await; - let mut filtered_data = FilteredData::new(); - filtered_data.symbol = element.symbol.clone(); - filtered_data.closetime = element.closetime; - filtered_data.current_price = element.current_price; - filtered_data.target_price = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec[supertrend_search_result.unwrap()].band_value).unwrap(); - let stop_loss = decimal_sub(filtered_data.current_price, decimal_div(decimal_sub(filtered_data.target_price, filtered_data.current_price), dec!(2))); - filtered_data.stoploss = stop_loss; - - filtered_data_3rd_lock.push(filtered_data); - } - } + if rt_30m_option.is_some() && supertrend_option_30m.is_some() { + rt_30m_vec = alldata.rt_price_30m_vec[rt_30m_option.unwrap()].1.clone(); + supertrend_vec = supertrend_option_30m.unwrap(); + let server_epoch = server_epoch().await; + if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch { + let supertrend_search_result = supertrend_vec.binary_search_by_key( + &rt_30m_vec.last().unwrap().close_time, + |SupertrendData { + band_value, + signal, + area, + close_time, + }| *close_time, + ); + if supertrend_search_result.is_ok_and(|x| + supertrend_vec[x].area.contains("DOWN") && supertrend_vec[x].band_value > element.current_price.to_f64().unwrap()) { + let mut filtered_data = FilteredData::new(); + filtered_data.symbol = element.symbol.clone(); + filtered_data.closetime = element.closetime; + filtered_data.current_price = element.current_price; + filtered_data.target_price = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec[supertrend_search_result.unwrap()].band_value).unwrap(); + let stop_loss = decimal_sub(filtered_data.current_price, decimal_div(decimal_sub(filtered_data.target_price, filtered_data.current_price), dec!(2))); + filtered_data.stoploss = stop_loss; + + filtered_data_3rd.push(filtered_data); + } } - })); + } } - try_join_all(task_vec).await?; // 4th filtering: the latest 5 30m candle close prices > EMA 200 - let filtered_data_3rd = filtered_data_3rd_arc.lock().await.clone(); let mut filtered_data_4th: Vec = Vec::new(); - let mut filtered_data_4th_arc: Arc>> = - Arc::new(Mutex::new(filtered_data_4th)); - let mut task_vec = Vec::new(); let ema_vec = ema(200, &alldata.rt_price_30m_vec, &filtered_data_3rd).await?; for element in filtered_data_3rd { - let mut opclo_30m_vec = alldata.rt_price_30m_vec.clone(); - let mut supertrend_vec: Vec = Vec::new(); - let ema_vec_c = ema_vec.clone(); - let filtered_data_4th_arc_c = Arc::clone(&filtered_data_4th_arc); - task_vec.push(tokio::spawn(async move { - let ema_search_result = ema_vec_c.iter().position(|x| x.0 == element.symbol); - let candle_search_result = opclo_30m_vec.iter().position(|x| x.0 == element.symbol); - if ema_search_result.is_some() && candle_search_result.is_some() { - let search_result = ema_vec_c[ema_search_result.unwrap()].1.binary_search_by_key( - &opclo_30m_vec[candle_search_result.unwrap()].1.last().unwrap().close_time, - |EmaData { - ema_value, - close_time, - }| *close_time); - if search_result.is_ok_and(|x| ema_vec_c[ema_search_result.unwrap()].1[search_result.unwrap()].ema_value < opclo_30m_vec[candle_search_result.unwrap()].1[opclo_30m_vec[candle_search_result.unwrap()].1.len()-1].close_price) && - search_result.is_ok_and(|x| ema_vec_c[ema_search_result.unwrap()].1[search_result.unwrap()-1].ema_value < opclo_30m_vec[candle_search_result.unwrap()].1[opclo_30m_vec[candle_search_result.unwrap()].1.len()-2].close_price) && - search_result.is_ok_and(|x| ema_vec_c[ema_search_result.unwrap()].1[search_result.unwrap()-2].ema_value < opclo_30m_vec[candle_search_result.unwrap()].1[opclo_30m_vec[candle_search_result.unwrap()].1.len()-3].close_price) && - search_result.is_ok_and(|x| ema_vec_c[ema_search_result.unwrap()].1[search_result.unwrap()-3].ema_value < opclo_30m_vec[candle_search_result.unwrap()].1[opclo_30m_vec[candle_search_result.unwrap()].1.len()-4].close_price) && - search_result.is_ok_and(|x| ema_vec_c[ema_search_result.unwrap()].1[search_result.unwrap()-4].ema_value < opclo_30m_vec[candle_search_result.unwrap()].1[opclo_30m_vec[candle_search_result.unwrap()].1.len()-5].close_price) { - let mut filtered_4th_symbols_lock = - filtered_data_4th_arc_c.lock().await; + let ema_search_result = ema_vec.iter().position(|x| x.0 == element.symbol); + let candle_search_result = alldata.rt_price_30m_vec.iter().position(|x| x.0 == element.symbol); + if ema_search_result.is_some() && candle_search_result.is_some() { + let search_result = ema_vec[ema_search_result.unwrap()].1.binary_search_by_key( + &alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.last().unwrap().close_time, + |EmaData { + ema_value, + close_time, + }| *close_time); + if search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-1].close_price) && + search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-1].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-2].close_price) && + search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-2].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-3].close_price) && + search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-3].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-4].close_price) && + search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-4].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-5].close_price) { + let mut filtered_data = FilteredData::new(); + filtered_data.symbol = element.symbol.clone(); + filtered_data.closetime = element.closetime; + filtered_data.current_price = element.current_price; + filtered_data.stoploss = element.stoploss; + filtered_data.target_price = element.target_price; + + filtered_data_4th.push(filtered_data); + } + } + } + + // 5th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0% + let mut filtered_data_5th: Vec = Vec::new(); + for element in filtered_data_4th { + let position_idx = alldata.rt_price_30m_vec.iter().position(|elem| elem.0 == element.symbol); + + if position_idx.is_some() { + let vec_len = alldata.rt_price_30m_vec[position_idx.unwrap()].1.len(); + if vec_len >= 11 { + let candles = alldata.rt_price_30m_vec[position_idx.unwrap()].1.get(vec_len-12..vec_len-1).unwrap(); + let windows = candles.windows(2); + let mut average_amplitude = 0.0; + + for window in windows { + average_amplitude += (window.last().unwrap().high_price - window.last().unwrap().low_price) / window.first().unwrap().close_price; + } + average_amplitude /= 10.0; + + if 0.005 <= average_amplitude && average_amplitude <= 0.01 { let mut filtered_data = FilteredData::new(); filtered_data.symbol = element.symbol.clone(); filtered_data.closetime = element.closetime; filtered_data.current_price = element.current_price; filtered_data.stoploss = element.stoploss; filtered_data.target_price = element.target_price; - - filtered_4th_symbols_lock.push(filtered_data); + + filtered_data_5th.push(filtered_data); } } - })); + } } - try_join_all(task_vec).await?; - - // 5th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0% - let filtered_data_4th_c = filtered_data_4th_arc.lock().await.clone(); - let mut filtered_data_5th: Vec = Vec::new(); - let mut filtered_data_5th_arc: Arc>> = - Arc::new(Mutex::new(filtered_data_5th)); - let mut task_vec = Vec::new(); - for element in filtered_data_4th_c { - let mut supertrend_vec: Vec = Vec::new(); - let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); - let filtered_data_5th_arc_c = Arc::clone(&filtered_data_5th_arc); - - task_vec.push(tokio::spawn(async move { - let position_idx = rt_price_30m_vec_c.iter().position(|elem| elem.0 == element.symbol); - - if position_idx.is_some() { - let vec_len = rt_price_30m_vec_c[position_idx.unwrap()].1.len(); - if vec_len >= 11 { - let candles = rt_price_30m_vec_c[position_idx.unwrap()].1.get(vec_len-12..vec_len-1).unwrap(); - let windows = candles.windows(2); - let mut average_amplitude = 0.0; - - for window in windows { - average_amplitude += (window.last().unwrap().high_price - window.last().unwrap().low_price) / window.first().unwrap().close_price; - } - average_amplitude /= 10.0; - - if 0.005 <= average_amplitude && average_amplitude <= 0.01 { - let mut filtered_data_5th_lock = filtered_data_5th_arc_c.lock().await; - let mut filtered_data = FilteredData::new(); - filtered_data.symbol = element.symbol.clone(); - filtered_data.closetime = element.closetime; - filtered_data.current_price = element.current_price; - filtered_data.stoploss = element.stoploss; - filtered_data.target_price = element.target_price; - - filtered_data_5th_lock.push(filtered_data); - } - } - } - })); - } - try_join_all(task_vec).await?; // 6th filtering: 30m StochRSI (RSI_len: 10, StochRSI_len: 10, K: 3, D: 3) current K, D < 20 - let filtered_data_5th_c = filtered_data_5th_arc.lock().await.clone(); let mut filtered_data_6th: Vec = Vec::new(); - let mut filtered_data_6th_arc: Arc>> = - Arc::new(Mutex::new(filtered_data_6th)); - let mut task_vec = Vec::new(); - let stoch_rsis = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data_5th_c).await?; - for element in filtered_data_5th_c { - let stoch_rsis_c = stoch_rsis.clone(); - let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); - let filtered_data_6th_arc_c = Arc::clone(&filtered_data_6th_arc); - - task_vec.push(tokio::spawn(async move { - let position_idx = stoch_rsis_c.iter().position(|elem| elem.0 == element.symbol); - - if position_idx.is_some() { - let stoch_rsi_vec = stoch_rsis_c[position_idx.unwrap()].1.clone(); - let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == element.closetime); - if search_result.is_some_and(|a| stoch_rsi_vec[a].k < 15.0 && stoch_rsi_vec[a].d < 15.0) { - let mut filtered_data_6th_lock = filtered_data_6th_arc_c.lock().await; - let mut filtered_data = FilteredData::new(); - filtered_data.symbol = element.symbol.clone(); - filtered_data.closetime = element.closetime; - filtered_data.current_price = element.current_price; - filtered_data.stoploss = element.stoploss; - filtered_data.target_price = element.target_price; - - filtered_data_6th_lock.push(filtered_data); - } + let stoch_rsis = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data_5th).await?; + for element in filtered_data_5th { + let position_idx = stoch_rsis.iter().position(|elem| elem.0 == element.symbol); + + if position_idx.is_some() { + let stoch_rsi_vec = stoch_rsis[position_idx.unwrap()].1.clone(); + let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == element.closetime); + if search_result.is_some_and(|a| stoch_rsi_vec[a].k < 15.0 && stoch_rsi_vec[a].d < 15.0) { + let mut filtered_data = FilteredData::new(); + filtered_data.symbol = element.symbol.clone(); + filtered_data.closetime = element.closetime; + filtered_data.current_price = element.current_price; + filtered_data.stoploss = element.stoploss; + filtered_data.target_price = element.target_price; + + filtered_data_6th.push(filtered_data); } - })); + } } - try_join_all(task_vec).await?; - let final_filtered_data = duplicate_filter(4, &filtered_data_6th_arc.lock().await.clone()).await?; + let final_filtered_data = duplicate_filter(4, &filtered_data_6th).await?; insert_pre_suggested_coins(4, false, &final_filtered_data, &alldata).await; Ok(())