From f0f3384be47c094326da08728cf017ad2ef0841e Mon Sep 17 00:00:00 2001 From: Sik Yoon Date: Sun, 15 Oct 2023 15:22:35 +0900 Subject: [PATCH] Add strategists #2~#6 --- src/coex/strategy_team.rs | 1583 ++++++++++++++++++++++++++++++++----- 1 file changed, 1405 insertions(+), 178 deletions(-) diff --git a/src/coex/strategy_team.rs b/src/coex/strategy_team.rs index 3943bf9..d270ae2 100644 --- a/src/coex/strategy_team.rs +++ b/src/coex/strategy_team.rs @@ -5,7 +5,7 @@ use crate::database_control::*; use crate::value_estimation_team; use crate::value_estimation_team::datapoints::price_data::RealtimePriceData; use crate::value_estimation_team::indicators::bollingerband::{bollingerband, BollingerBandData}; -use crate::value_estimation_team::indicators::ema::EmaData; +use crate::value_estimation_team::indicators::ema::{ema, EmaData}; use crate::value_estimation_team::indicators::heatmap_volume::{ heatmap_volume, HeatMapLevel, HeatmapVolumeData, }; @@ -106,7 +106,11 @@ pub async fn execute_strategists( all_data: &AllData, ) -> Result<(), Box> { strategist_001(all_data).await?; - // strategist_002(all_data).await?; + strategist_002(all_data).await?; + strategist_003(all_data).await?; + strategist_004(all_data).await?; + strategist_005(all_data).await?; + strategist_006(all_data).await?; Ok(()) } @@ -118,7 +122,54 @@ pub async fn strategist_001( // let a = alldata.rt_price_30m_vec.iter().position(|a| a.0 == "BTCUSDT"); // println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap()); - // 1st filtering: supertrend(ATR period 10, multiplier: 1.3, 30m close price), the area should be in SELL area. + // // 1st filtering: supertrend(ATR period 10, multiplier: 1.3, 30m close price), the area should be in SELL area. + // let mut filtered_2nd_symbols: Vec<(String, i64)> = Vec::new(); + // let mut filtered_2nd_symbols_arc: Arc>> = + // Arc::new(Mutex::new(filtered_2nd_symbols)); // (symbol, closetime) + // let mut task_vec = Vec::new(); + // let valid_symbol_vec_c = alldata.valid_symbol_vec.clone(); + // for symbol in valid_symbol_vec_c { + // let mut opclo_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_2nd_symbols_arc_c = Arc::clone(&filtered_2nd_symbols_arc); + // task_vec.push(tokio::spawn(async move { + // let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == symbol); + // let supertrend_option_30m = + // supertrend(&symbol, &rt_price_30m_vec_c, 10, 1.3, true).await; + + // if opclo_30m_option.is_some() && supertrend_option_30m.is_some() { + // opclo_30m_vec = rt_price_30m_vec_c[opclo_30m_option.unwrap()].1.clone(); + // supertrend_vec = supertrend_option_30m.unwrap(); + + // if opclo_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 { + // let supertrend_search_result = supertrend_vec.binary_search_by_key( + // &opclo_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") + // { + // let mut filtered_2nd_symbols_lock = + // filtered_2nd_symbols_arc_c.lock().await; + // filtered_2nd_symbols_lock + // .push((symbol.clone(), opclo_30m_vec.last().unwrap().close_time)); + // } + // } + // } + // } + // })); + // } + // try_join_all(task_vec).await?; + + // 1st filtering: making basic form let mut filtered_2nd_symbols: Vec<(String, i64)> = Vec::new(); let mut filtered_2nd_symbols_arc: Arc>> = Arc::new(Mutex::new(filtered_2nd_symbols)); // (symbol, closetime) @@ -126,39 +177,20 @@ pub async fn strategist_001( let valid_symbol_vec_c = alldata.valid_symbol_vec.clone(); for symbol in valid_symbol_vec_c { let mut opclo_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_2nd_symbols_arc_c = Arc::clone(&filtered_2nd_symbols_arc); task_vec.push(tokio::spawn(async move { let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == symbol); - let supertrend_option_30m = - supertrend(&symbol, &rt_price_30m_vec_c, 10, 1.3, true).await; - if opclo_30m_option.is_some() && supertrend_option_30m.is_some() { + if opclo_30m_option.is_some() { opclo_30m_vec = rt_price_30m_vec_c[opclo_30m_option.unwrap()].1.clone(); - supertrend_vec = supertrend_option_30m.unwrap(); - if opclo_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 { - let supertrend_search_result = supertrend_vec.binary_search_by_key( - &opclo_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") - { - let mut filtered_2nd_symbols_lock = - filtered_2nd_symbols_arc_c.lock().await; - filtered_2nd_symbols_lock - .push((symbol.clone(), opclo_30m_vec.last().unwrap().close_time)); - } - } + if opclo_30m_vec.len() >= 3 { + let mut filtered_2nd_symbols_lock = + filtered_2nd_symbols_arc_c.lock().await; + filtered_2nd_symbols_lock + .push((symbol.clone(), opclo_30m_vec.last().unwrap().close_time)); } } })); @@ -180,8 +212,10 @@ pub async fn strategist_001( for element in filtered_2nd_iter { let mut exists_condition_build = String::from("symbol=\'"); exists_condition_build.push_str(element.0.as_str()); - exists_condition_build.push_str("\' AND close_time="); - exists_condition_build.push_str(element.1.to_string().as_str()); + exists_condition_build.push_str("\' AND registerer="); + exists_condition_build.push_str(1.to_string().as_str()); + // exists_condition_build.push_str("\' AND close_time="); + // exists_condition_build.push_str(element.1.to_string().as_str()); let exists_condition = Some(exists_condition_build); let exists_condition_c = exists_condition.clone(); let inspect_table_name_1_c = inspect_table_name_1.clone(); @@ -224,7 +258,7 @@ pub async fn strategist_001( let bb10_30m_data: Vec<(String, Vec)> = bollingerband( 10, - 2.5, + 3.0, &sma10_30m_data, &alldata.rt_price_30m_vec, &filtered_3rd_symbols_c, @@ -273,32 +307,68 @@ pub async fn strategist_001( } try_join_all(task_vec).await?; - // 4th filtering: RSI (length: 10, 30m close price) the current index should be lower than 20, 25, 28. - let filtered_4th_symbol_c = filtered_4th_symbols_arc.lock().await.clone(); + // 4th filtering: the current price should be lower than lowest price from the latest 20 candles. + let mut task_vec = Vec::new(); + let filtered_4th_symbols_c = filtered_4th_symbols_arc.lock().await.clone(); + let mut filtered_5th_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_5th_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_5th_symbols)); // (symbol, closetime) + for element in filtered_4th_symbols_c { + let rt_price_30m_option = alldata.rt_price_30m_vec.iter().position(|x| *x.0 == element.0); + let element_c = element.clone(); + let filtered_5th_symbols_arc_c = Arc::clone(&filtered_5th_symbols_arc); + + if rt_price_30m_option.is_some() { + let mut rt_price_30m_vec_c = alldata.rt_price_30m_vec[rt_price_30m_option.unwrap()].1.clone(); + let current_price = get_current_price(&element_c.0, &alldata.rt_price_30m_vec) + .await + .unwrap(); + + task_vec.push(tokio::spawn(async move { + if rt_price_30m_vec_c.len() >= 21 { + rt_price_30m_vec_c.pop(); + rt_price_30m_vec_c.reverse(); + rt_price_30m_vec_c.truncate(20); + + let lowest_price_option = rt_price_30m_vec_c.iter() + .enumerate() + .min_by(|(_, a), (_, b)| { + a.low_price + .partial_cmp(&b.low_price) + .expect("Nan was forbidden.") + }) + .map(|(index, _)| index); + + if lowest_price_option.is_some() { + let lowest_price = rt_price_30m_vec_c[lowest_price_option.unwrap()].low_price; + if lowest_price > current_price { + let mut filtered_5th_symbols_lock = + filtered_5th_symbols_arc_c.lock().await; + filtered_5th_symbols_lock.push(element_c); + } + } + } + })); + } + } + try_join_all(task_vec).await?; + + // 5th filtering: RSI (length: 10, 30m close price) the current index should be lower than 30. + let filtered_5th_symbol_c = filtered_5th_symbols_arc.lock().await.clone(); let mut rsi10_30m_data: Vec<(String, Vec)> = rsi( 10, &alldata.rt_price_30m_vec, - &filtered_4th_symbol_c, + &filtered_5th_symbol_c, ) .await?; let mut task_vec = Vec::new(); - let mut filtered_5th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) - let mut filtered_5th_symbols_arc: Arc>> = - Arc::new(Mutex::new(filtered_5th_symbols)); // (symbol, closetime) - let market_cap_angle = select_marketcap().await; - let rsi_criterion = if market_cap_angle.last().unwrap().market_cap_index < -30.0 { - 15.0 - } else if market_cap_angle.last().unwrap().market_cap_index > -30.0 && market_cap_angle.last().unwrap().market_cap_index < -20.0 { - 20.0 - } else if market_cap_angle.last().unwrap().market_cap_index > -20.0 && market_cap_angle.last().unwrap().market_cap_index < -10.0 { - 25.0 - } else { - 28.0 - }; + let mut filtered_6th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) + let mut filtered_6th_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_6th_symbols)); // (symbol, closetime) - for element in filtered_4th_symbol_c { + for element in filtered_5th_symbol_c { let rsi10_30m_option = rsi10_30m_data.iter().position(|x| *x.0 == element.0); - let filtered_5th_symbols_arc_c = Arc::clone(&filtered_5th_symbols_arc); + let filtered_6th_symbols_arc_c = Arc::clone(&filtered_6th_symbols_arc); if rsi10_30m_option.is_some() { let mut rsi10_30m_vec = rsi10_30m_data[rsi10_30m_option.unwrap()].1.clone(); @@ -314,10 +384,10 @@ pub async fn strategist_001( }| close_time, ); if rsi_search_result.is_ok() { - if rsi10_30m_vec[rsi_search_result.unwrap()].rsi_value <= rsi_criterion { - let mut filtered_5th_symbols_lock = - filtered_5th_symbols_arc_c.lock().await; - filtered_5th_symbols_lock.push(element_c); + if rsi10_30m_vec[rsi_search_result.unwrap()].rsi_value <= 20.0 { + let mut filtered_6th_symbols_lock = + filtered_6th_symbols_arc_c.lock().await; + filtered_6th_symbols_lock.push(element_c); } } @@ -327,18 +397,18 @@ pub async fn strategist_001( } try_join_all(task_vec).await?; - // 5th filtering: StochRSI (RSI length: 14, Stoch length: 14, smooth k: 3, smooth d: 3) smooth kn <= 15, kn-1 <= 25 - let filtered_5th_symbol_c = filtered_5th_symbols_arc.lock().await.clone(); + // 6th filtering: StochRSI (RSI length: 14, Stoch length: 14, smooth k: 3, smooth d: 3) smooth kn <= 10, kn-1 <= 25.0 + let filtered_6th_symbol_c = filtered_6th_symbols_arc.lock().await.clone(); let mut rsi14_30m_data: Vec<(String, Vec)> = rsi( 14, &alldata.rt_price_30m_vec, - &filtered_5th_symbol_c, + &filtered_6th_symbol_c, ) .await?; - let stoch_rsi_data = stoch_rsi(&rsi10_30m_data, 14, 3, 3).await?; + let stoch_rsi_data = stoch_rsi(&rsi14_30m_data, 14, 3, 3).await?; let mut stoch_rsi14_30m_vec: Vec = Vec::new(); - let mut filtered_6th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) - for element in filtered_5th_symbol_c { + let mut filtered_7th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) + for element in filtered_6th_symbol_c { let stoch_rsi14_30m_option = stoch_rsi_data.iter().position(|x| *x.0 == element.0); if stoch_rsi14_30m_option.is_some() { @@ -354,17 +424,17 @@ pub async fn strategist_001( }| close_time, ); if stoch_rsi_search_result.is_ok() { - if stoch_rsi14_30m_vec[stoch_rsi_search_result.unwrap()].k <= 15.0 && stoch_rsi14_30m_vec[stoch_rsi_search_result.unwrap()-1].k <= 25.0 { - filtered_6th_symbols.push(element); + if stoch_rsi14_30m_vec[stoch_rsi_search_result.unwrap()].k <= 10.0 && stoch_rsi14_30m_vec[stoch_rsi_search_result.unwrap()-1].k <= 25.0 { + filtered_7th_symbols.push(element); } } } } } - // 6th filtering: heatmap volume(MA length 10, std length 10, 30m close price), the current candle should be over than high at least. - let mut filtered_7th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) - for element in filtered_6th_symbols { + // 7th filtering: heatmap volume(MA length 10, std length 10, 30m close price), the current candle should be over than high at least. + let mut filtered_8th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) + for element in filtered_7th_symbols { let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.0); if opclo_30m_option.is_some() { @@ -387,12 +457,13 @@ pub async fn strategist_001( if heatmap_search_result.is_ok() { if heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level == HeatMapLevel::Medium - || heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level + || + heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level == HeatMapLevel::High || heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level == HeatMapLevel::ExtraHigh { - filtered_7th_symbols.push(element); + filtered_8th_symbols.push(element); } } } @@ -404,7 +475,7 @@ pub async fn strategist_001( let mut filtered_symbols: Vec<(String, i64, f64)> = Vec::new(); // (symbol, closetime, current price) let mut filtered_symbols_arc = Arc::new(Mutex::new(filtered_symbols)); let mut task_vec = Vec::new(); - for element in filtered_7th_symbols { + for element in filtered_8th_symbols { let mut filtered_symbols_arc_c = Arc::clone(&filtered_symbols_arc); let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); @@ -464,7 +535,7 @@ pub async fn strategist_001( // } // } let a = filtered_symbols_arc.lock().await.clone(); - insert_pre_suggested_coins(1, &a, alldata).await; + insert_pre_suggested_coins(1, false, &a, alldata).await; Ok(()) } @@ -473,127 +544,1225 @@ pub async fn strategist_002( alldata: &AllData, ) -> Result<(), Box> { // print rt_price for debugging - let a = alldata.rt_price_30m_vec.iter().position(|a| a.0 == "BTCUSDT"); - let b = alldata.rt_price_30m_vec.iter().position(|a| a.0 == "XRPUSDT"); + // let a = alldata.rt_price_30m_vec.iter().position(|a| a.0 == "BTCUSDT"); // println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap()); - - // 1st filtering: supertrend(ATR period 10, multiplier: 1.3, 30m close price), the area should be in SELL area. + // 1st filtering: making basic form let mut filtered_2nd_symbols: Vec<(String, i64)> = Vec::new(); - filtered_2nd_symbols.push((String::from("BTCUSDT"), alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap().close_time)); - filtered_2nd_symbols.push((String::from("XRPUSDT"), alldata.rt_price_30m_vec[b.unwrap()].1.last().unwrap().close_time)); + let mut filtered_2nd_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_2nd_symbols)); // (symbol, closetime) + let mut task_vec = Vec::new(); + let valid_symbol_vec_c = alldata.valid_symbol_vec.clone(); + for symbol in valid_symbol_vec_c { + let mut opclo_30m_vec: Vec = Vec::new(); + + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + let filtered_2nd_symbols_arc_c = Arc::clone(&filtered_2nd_symbols_arc); + task_vec.push(tokio::spawn(async move { + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == symbol); - // 4th filtering: RSI (length: 10, 30m close price) the current index should be lower than 28. - - let mut rsi10_30m_data: Vec<(String, Vec)> = rsi( - 14, + if opclo_30m_option.is_some() { + opclo_30m_vec = rt_price_30m_vec_c[opclo_30m_option.unwrap()].1.clone(); + + if opclo_30m_vec.len() >= 3 { + let mut filtered_2nd_symbols_lock = + filtered_2nd_symbols_arc_c.lock().await; + filtered_2nd_symbols_lock + .push((symbol.clone(), opclo_30m_vec.last().unwrap().close_time)); + } + } + })); + } + try_join_all(task_vec).await?; + + // 2nd filtering: lookup tables if the tradepair is already there + let inspect_table_name_1 = String::from("buy_ordered_coin_list"); + let inspect_table_name_2 = String::from("sell_ordered_coin_list"); + let inspect_table_name_3 = String::from("pre_suggested_coin_list"); + let inspect_table_name_4 = String::from("suggested_coin_list"); + + let mut filtered_3rd_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_3rd_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_3rd_symbols)); // (symbol, closetime) + let mut task_vec = Vec::new(); + + let filtered_2nd_iter = filtered_2nd_symbols_arc.lock().await.clone().into_iter(); + for element in filtered_2nd_iter { + let mut exists_condition_build = String::from("symbol=\'"); + exists_condition_build.push_str(element.0.as_str()); + exists_condition_build.push_str("\' AND registerer="); + exists_condition_build.push_str(2.to_string().as_str()); + // exists_condition_build.push_str("\' AND close_time="); + // exists_condition_build.push_str(element.1.to_string().as_str()); + + let exists_condition = Some(exists_condition_build); + let exists_condition_c = exists_condition.clone(); + let inspect_table_name_1_c = inspect_table_name_1.clone(); + let inspect_table_name_2_c = inspect_table_name_2.clone(); + let inspect_table_name_3_c = inspect_table_name_3.clone(); + let inspect_table_name_4_c = inspect_table_name_4.clone(); + let element_c = element.clone(); + let filtered_3rd_symbols_arc_c = Arc::clone(&filtered_3rd_symbols_arc); + task_vec.push(tokio::spawn(async move { + let inspect_result_1 = + exists_record(&inspect_table_name_1_c, &exists_condition_c).await; + let inspect_result_2 = + exists_record(&inspect_table_name_2_c, &exists_condition_c).await; + let inspect_result_3 = + exists_record(&inspect_table_name_3_c, &exists_condition_c).await; + let inspect_result_4 = + exists_record(&inspect_table_name_4_c, &exists_condition_c).await; + + if inspect_result_1 == false + && inspect_result_2 == false + && inspect_result_3 == false + && inspect_result_4 == false + { + let mut filtered_3rd_symbols_lock = filtered_3rd_symbols_arc_c.lock().await; + filtered_3rd_symbols_lock.push(element_c); + } + })); + } + try_join_all(task_vec).await?; + + // 3rd filtering: EMA30 > EMA 150 + let filtered_3rd_symbols_c = filtered_3rd_symbols_arc.lock().await.clone(); + let ema30_30m_data: Vec<(String, Vec)> = ema( + 30, &alldata.rt_price_30m_vec, - &filtered_2nd_symbols, + &filtered_3rd_symbols_c, + ) + .await?; + let ema150_30m_data: Vec<(String, Vec)> = ema( + 150, + &alldata.rt_price_30m_vec, + &filtered_3rd_symbols_c, ) .await?; - let stoch_rsi = stoch_rsi(&rsi10_30m_data, 14, 3, 3).await?; + let mut task_vec = Vec::new(); + let mut filtered_4th_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_4th_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_4th_symbols)); // (symbol, closetime) + for element in filtered_3rd_symbols_c { + let mut ema30_30m_vec: Vec = Vec::new(); + let mut ema150_30m_vec: Vec = Vec::new(); + let ema30_30m_option = ema30_30m_data.iter().position(|x| *x.0 == element.0); + let ema30_30m_option_c = ema30_30m_option.clone(); + let ema150_30m_option = ema150_30m_data.iter().position(|x| *x.0 == element.0); + let ema150_30m_option_c = ema150_30m_option.clone(); + let element_c = element.clone(); + let filtered_4th_symbols_arc_c = Arc::clone(&filtered_4th_symbols_arc); - // for element in filtered_2nd_symbols { - // let rsi10_30m_option = rsi10_30m_data.iter().position(|x| *x.0 == element.0); + if ema30_30m_option_c.is_some() && ema150_30m_option_c.is_some() { + ema30_30m_vec = ema30_30m_data[ema30_30m_option.unwrap()].1.clone(); + ema150_30m_vec = ema150_30m_data[ema150_30m_option.unwrap()].1.clone(); - // if rsi10_30m_option.is_some() { - // rsi10_30m_vec = rsi10_30m_data[rsi10_30m_option.unwrap()].1.clone(); + if ema30_30m_vec.len() >= 10 && ema150_30m_vec.len() >= 10 { + let ema30_30m_vec_c = ema30_30m_vec.clone(); + let ema150_30m_vec_c = ema150_30m_vec.clone(); - // if rsi10_30m_vec.len() >= 3 { - // let rsi_search_result = rsi10_30m_vec.binary_search_by_key( - // &element.1, - // |&RsiData { - // rsi_value, - // close_time, - // }| close_time, - // ); - // if rsi_search_result.is_ok() { - // if rsi10_30m_vec[rsi_search_result.unwrap()].rsi_value <= 28.0 { - // filtered_5th_symbols.push(element); - // } - // } - // } - // } - // } + task_vec.push(tokio::spawn(async move { + let ema30_search_result = ema30_30m_vec_c.binary_search_by_key( + &element_c.1, + |&EmaData { + ema_value, + close_time, + }| close_time, + ); + let ema150_search_result = ema150_30m_vec_c.binary_search_by_key( + &element_c.1, + |&EmaData { + ema_value, + close_time, + }| close_time, + ); - // // 5th filtering: heatmap volume(MA length 10, std length 10, 30m close price), the current candle should be over than high at least. - // let mut filtered_6th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) - // for element in filtered_5th_symbols { - // let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); - // let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.0); - // if opclo_30m_option.is_some() { - // let opclo_30m_vec = rt_price_30m_vec_c[opclo_30m_option.unwrap()].1.clone(); + if ema30_search_result.is_ok() && ema150_search_result.is_ok() { + if ema30_30m_vec_c[ema30_search_result.unwrap()-3].ema_value > ema150_30m_vec_c[ema150_search_result.unwrap()-3].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-2].ema_value > ema150_30m_vec_c[ema150_search_result.unwrap()-2].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-1].ema_value > ema150_30m_vec_c[ema150_search_result.unwrap()-1].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()].ema_value > ema150_30m_vec_c[ema150_search_result.unwrap()].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()].ema_value > ema30_30m_vec_c[ema30_search_result.unwrap()-1].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-1].ema_value > ema30_30m_vec_c[ema30_search_result.unwrap()-2].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-2].ema_value > ema30_30m_vec_c[ema30_search_result.unwrap()-3].ema_value + { + let mut filtered_4th_symbols_lock = + filtered_4th_symbols_arc_c.lock().await; + filtered_4th_symbols_lock.push(element_c); + } + } + })); + } + } + } + try_join_all(task_vec).await?; - // if opclo_30m_vec.len() >= 3 { - // let heatmap_volume_option = - // heatmap_volume(&element.0, &rt_price_30m_vec_c, 10, 10, 4.0, 2.5, 1.0, -0.5) - // .await; - // if heatmap_volume_option.is_some() { - // let heatmap_volume_vec = heatmap_volume_option.unwrap(); - // let heatmap_search_result = heatmap_volume_vec.binary_search_by_key( - // &element.1, - // |HeatmapVolumeData { - // heatmap_value, - // heatmap_level, - // close_time, - // }| *close_time, - // ); - // if heatmap_search_result.is_ok() { - // if heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level - // == HeatMapLevel::Medium - // || heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level - // == HeatMapLevel::High - // || heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level - // == HeatMapLevel::ExtraHigh - // { - // filtered_6th_symbols.push(element); - // } - // } - // } - // } - // } - // } + // 6th filtering: StochRSI (RSI length: 10, Stoch length: 10, smooth k: 3, smooth d: 3) smooth dn == 0, kn == 0, kn-1 < 5 + let filtered_4th_symbol_c = filtered_4th_symbols_arc.lock().await.clone(); + let mut rsi10_30m_data: Vec<(String, Vec)> = rsi( + 10, + &alldata.rt_price_30m_vec, + &filtered_4th_symbol_c, + ) + .await?; + let stoch_rsi_data = stoch_rsi(&rsi10_30m_data, 10, 3, 3).await?; + let mut stoch_rsi10_30m_vec: Vec = Vec::new(); + let mut filtered_5th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) + for element in filtered_4th_symbol_c { + let stoch_rsi10_30m_option = stoch_rsi_data.iter().position(|x| *x.0 == element.0); - // // final job: adding price information to filtered results - // let mut filtered_symbols: Vec<(String, i64, f64)> = Vec::new(); // (symbol, closetime, current price) - // let mut filtered_symbols_arc = Arc::new(Mutex::new(filtered_symbols)); - // let mut task_vec = Vec::new(); + if stoch_rsi10_30m_option.is_some() { + stoch_rsi10_30m_vec = stoch_rsi_data[stoch_rsi10_30m_option.unwrap()].1.clone(); + + if stoch_rsi10_30m_vec.len() >= 3 { + let stoch_rsi_search_result = stoch_rsi10_30m_vec.binary_search_by_key( + &element.1, + |&StochRsiData { + k, + d, + close_time, + }| close_time, + ); + if stoch_rsi_search_result.is_ok() { + if stoch_rsi10_30m_vec[stoch_rsi_search_result.unwrap()].k <= 5.0 && + stoch_rsi10_30m_vec[stoch_rsi_search_result.unwrap()].d <= 5.0 && + stoch_rsi10_30m_vec[stoch_rsi_search_result.unwrap()-1].k <= 5.0 { + filtered_5th_symbols.push(element); + } + } + } + } + } + + // 7th filtering: heatmap volume(MA length 10, std length 10, 30m close price), the current candle should be over than high at least. + let mut filtered_6th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) + for element in filtered_5th_symbols { + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.0); + if opclo_30m_option.is_some() { + let opclo_30m_vec = rt_price_30m_vec_c[opclo_30m_option.unwrap()].1.clone(); + + if opclo_30m_vec.len() >= 3 { + let heatmap_volume_option = + heatmap_volume(&element.0, &rt_price_30m_vec_c, 10, 10, 4.0, 2.5, 1.0, -0.5) + .await; + if heatmap_volume_option.is_some() { + let heatmap_volume_vec = heatmap_volume_option.unwrap(); + let heatmap_search_result = heatmap_volume_vec.binary_search_by_key( + &element.1, + |HeatmapVolumeData { + heatmap_value, + heatmap_level, + close_time, + }| *close_time, + ); + if heatmap_search_result.is_ok() { + if + // heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level + // == HeatMapLevel::Medium + // || + heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level + == HeatMapLevel::High + || heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level + == HeatMapLevel::ExtraHigh + { + filtered_6th_symbols.push(element); + } + } + } + } + } + } + + // final job: adding price information to filtered results + let mut filtered_symbols: Vec<(String, i64, f64)> = Vec::new(); // (symbol, closetime, current price) + let mut filtered_symbols_arc = Arc::new(Mutex::new(filtered_symbols)); + let mut task_vec = Vec::new(); + for element in filtered_6th_symbols { + let mut filtered_symbols_arc_c = Arc::clone(&filtered_symbols_arc); + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + + let elememt_c = element.clone(); + task_vec.push(tokio::spawn(async move { + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.0); + if opclo_30m_option.is_some() { + if rt_price_30m_vec_c[opclo_30m_option.unwrap()] + .1 + .last() + .is_some() + { + let mut filtered_symbols_lock: tokio::sync::MutexGuard< + '_, + Vec<(String, i64, f64)>, + > = filtered_symbols_arc_c.lock().await; + filtered_symbols_lock.push(( + elememt_c.0, + elememt_c.1, + rt_price_30m_vec_c[opclo_30m_option.unwrap()] + .1 + .last() + .unwrap() + .close_price, + )); + } + } + })); + } + + try_join_all(task_vec).await?; + + let a = filtered_symbols_arc.lock().await.clone(); + insert_pre_suggested_coins(2, false, &a, alldata).await; + + Ok(()) +} + +pub async fn strategist_003( + alldata: &AllData, +) -> Result<(), Box> { + // print rt_price for debugging + // let a = alldata.rt_price_30m_vec.iter().position(|a| a.0 == "BTCUSDT"); + // println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap()); + + // 1st filtering: supertrend(ATR period 100, multiplier: 3.0, 30m close price), the area should be in UP area. + let mut filtered_2nd_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_2nd_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_2nd_symbols)); // (symbol, closetime) + let mut task_vec = Vec::new(); + let valid_symbol_vec_c = alldata.valid_symbol_vec.clone(); + for symbol in valid_symbol_vec_c { + let mut opclo_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_2nd_symbols_arc_c = Arc::clone(&filtered_2nd_symbols_arc); + task_vec.push(tokio::spawn(async move { + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == symbol); + let supertrend_option_30m = + supertrend(&symbol, &rt_price_30m_vec_c, 100, 3.0, true).await; + + if opclo_30m_option.is_some() && supertrend_option_30m.is_some() { + opclo_30m_vec = rt_price_30m_vec_c[opclo_30m_option.unwrap()].1.clone(); + supertrend_vec = supertrend_option_30m.unwrap(); + + if opclo_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 { + let supertrend_search_result = supertrend_vec.binary_search_by_key( + &opclo_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("UP") + { + let mut filtered_2nd_symbols_lock = + filtered_2nd_symbols_arc_c.lock().await; + filtered_2nd_symbols_lock + .push((symbol.clone(), opclo_30m_vec.last().unwrap().close_time)); + } + } + } + } + })); + } + try_join_all(task_vec).await?; + + // 2nd filtering: lookup tables if the tradepair is already there + let inspect_table_name_1 = String::from("buy_ordered_coin_list"); + let inspect_table_name_2 = String::from("sell_ordered_coin_list"); + let inspect_table_name_3 = String::from("pre_suggested_coin_list"); + let inspect_table_name_4 = String::from("suggested_coin_list"); + + let mut filtered_3rd_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_3rd_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_3rd_symbols)); // (symbol, closetime) + let mut task_vec = Vec::new(); + + let filtered_2nd_iter = filtered_2nd_symbols_arc.lock().await.clone().into_iter(); + for element in filtered_2nd_iter { + let mut exists_condition_build = String::from("symbol=\'"); + exists_condition_build.push_str(element.0.as_str()); + exists_condition_build.push_str("\' AND registerer="); + exists_condition_build.push_str(3.to_string().as_str()); + // exists_condition_build.push_str("\' AND close_time="); + // exists_condition_build.push_str(element.1.to_string().as_str()); + let exists_condition = Some(exists_condition_build); + let exists_condition_c = exists_condition.clone(); + let inspect_table_name_1_c = inspect_table_name_1.clone(); + let inspect_table_name_2_c = inspect_table_name_2.clone(); + let inspect_table_name_3_c = inspect_table_name_3.clone(); + let inspect_table_name_4_c = inspect_table_name_4.clone(); + let element_c = element.clone(); + let filtered_3rd_symbols_arc_c = Arc::clone(&filtered_3rd_symbols_arc); + task_vec.push(tokio::spawn(async move { + let inspect_result_1 = + exists_record(&inspect_table_name_1_c, &exists_condition_c).await; + let inspect_result_2 = + exists_record(&inspect_table_name_2_c, &exists_condition_c).await; + let inspect_result_3 = + exists_record(&inspect_table_name_3_c, &exists_condition_c).await; + let inspect_result_4 = + exists_record(&inspect_table_name_4_c, &exists_condition_c).await; + + if inspect_result_1 == false + && inspect_result_2 == false + && inspect_result_3 == false + && inspect_result_4 == false + { + let mut filtered_3rd_symbols_lock = filtered_3rd_symbols_arc_c.lock().await; + filtered_3rd_symbols_lock.push(element_c); + } + })); + } + try_join_all(task_vec).await?; + + // 3rd filtering: EMA30 > EMA 150 + let filtered_3rd_symbols_c = filtered_3rd_symbols_arc.lock().await.clone(); + let ema30_30m_data: Vec<(String, Vec)> = ema( + 30, + &alldata.rt_price_30m_vec, + &filtered_3rd_symbols_c, + ) + .await?; + let ema150_30m_data: Vec<(String, Vec)> = ema( + 150, + &alldata.rt_price_30m_vec, + &filtered_3rd_symbols_c, + ) + .await?; + + let mut task_vec = Vec::new(); + let mut filtered_4th_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_4th_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_4th_symbols)); // (symbol, closetime) + for element in filtered_3rd_symbols_c { + let mut ema30_30m_vec: Vec = Vec::new(); + let mut ema150_30m_vec: Vec = Vec::new(); + let ema30_30m_option = ema30_30m_data.iter().position(|x| *x.0 == element.0); + let ema30_30m_option_c = ema30_30m_option.clone(); + let ema150_30m_option = ema150_30m_data.iter().position(|x| *x.0 == element.0); + let ema150_30m_option_c = ema150_30m_option.clone(); + let element_c = element.clone(); + let filtered_4th_symbols_arc_c = Arc::clone(&filtered_4th_symbols_arc); + + if ema30_30m_option_c.is_some() && ema150_30m_option_c.is_some() { + ema30_30m_vec = ema30_30m_data[ema30_30m_option.unwrap()].1.clone(); + ema150_30m_vec = ema150_30m_data[ema150_30m_option.unwrap()].1.clone(); + + if ema30_30m_vec.len() >= 10 && ema150_30m_vec.len() >= 10 { + let ema30_30m_vec_c = ema30_30m_vec.clone(); + let ema150_30m_vec_c = ema150_30m_vec.clone(); + + task_vec.push(tokio::spawn(async move { + let ema30_search_result = ema30_30m_vec_c.binary_search_by_key( + &element_c.1, + |&EmaData { + ema_value, + close_time, + }| close_time, + ); + let ema150_search_result = ema150_30m_vec_c.binary_search_by_key( + &element_c.1, + |&EmaData { + ema_value, + close_time, + }| close_time, + ); + + if ema30_search_result.is_ok() && ema150_search_result.is_ok() { + if ema30_30m_vec_c[ema30_search_result.unwrap()-3].ema_value > ema150_30m_vec_c[ema150_search_result.unwrap()-3].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-2].ema_value > ema150_30m_vec_c[ema150_search_result.unwrap()-2].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-1].ema_value > ema150_30m_vec_c[ema150_search_result.unwrap()-1].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()].ema_value > ema150_30m_vec_c[ema150_search_result.unwrap()].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()].ema_value > ema30_30m_vec_c[ema30_search_result.unwrap()-1].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-1].ema_value > ema30_30m_vec_c[ema30_search_result.unwrap()-2].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-2].ema_value > ema30_30m_vec_c[ema30_search_result.unwrap()-3].ema_value + { + let mut filtered_4th_symbols_lock = + filtered_4th_symbols_arc_c.lock().await; + filtered_4th_symbols_lock.push(element_c); + } + } + })); + } + } + } + try_join_all(task_vec).await?; + + // 4th filtering: StochRSI (RSI length: 10, Stoch length: 10, smooth k: 3, smooth d: 3) 20 > k > kn-1 > kn-2 > kn-3, + let filtered_4th_symbol_c = filtered_4th_symbols_arc.lock().await.clone(); + let mut rsi10_30m_data: Vec<(String, Vec)> = rsi( + 10, + &alldata.rt_price_30m_vec, + &filtered_4th_symbol_c, + ) + .await?; + let stoch_rsi_data = stoch_rsi(&rsi10_30m_data, 10, 3, 3).await?; + let mut stoch_rsi10_30m_vec: Vec = Vec::new(); + let mut filtered_5th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) + for element in filtered_4th_symbol_c { + let stoch_rsi10_30m_option = stoch_rsi_data.iter().position(|x| *x.0 == element.0); + + if stoch_rsi10_30m_option.is_some() { + stoch_rsi10_30m_vec = stoch_rsi_data[stoch_rsi10_30m_option.unwrap()].1.clone(); + + if stoch_rsi10_30m_vec.len() >= 3 { + let stoch_rsi_search_result = stoch_rsi10_30m_vec.binary_search_by_key( + &element.1, + |&StochRsiData { + k, + d, + close_time, + }| close_time, + ); + if stoch_rsi_search_result.is_ok() { + if 10.0 > stoch_rsi10_30m_vec[stoch_rsi_search_result.unwrap()].k && + stoch_rsi10_30m_vec[stoch_rsi_search_result.unwrap()].k > stoch_rsi10_30m_vec[stoch_rsi_search_result.unwrap()-1].k && + stoch_rsi10_30m_vec[stoch_rsi_search_result.unwrap()-1].k <= stoch_rsi10_30m_vec[stoch_rsi_search_result.unwrap()-2].k && + stoch_rsi10_30m_vec[stoch_rsi_search_result.unwrap()-2].k <= stoch_rsi10_30m_vec[stoch_rsi_search_result.unwrap()-3].k { + filtered_5th_symbols.push(element); + } + } + } + } + } + + // final job: adding price information to filtered results + let mut filtered_symbols: Vec<(String, i64, f64)> = Vec::new(); // (symbol, closetime, current price) + let mut filtered_symbols_arc = Arc::new(Mutex::new(filtered_symbols)); + let mut task_vec = Vec::new(); + for element in filtered_5th_symbols { + let mut filtered_symbols_arc_c = Arc::clone(&filtered_symbols_arc); + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + + let elememt_c = element.clone(); + task_vec.push(tokio::spawn(async move { + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.0); + if opclo_30m_option.is_some() { + if rt_price_30m_vec_c[opclo_30m_option.unwrap()] + .1 + .last() + .is_some() + { + let mut filtered_symbols_lock: tokio::sync::MutexGuard< + '_, + Vec<(String, i64, f64)>, + > = filtered_symbols_arc_c.lock().await; + filtered_symbols_lock.push(( + elememt_c.0, + elememt_c.1, + rt_price_30m_vec_c[opclo_30m_option.unwrap()] + .1 + .last() + .unwrap() + .close_price, + )); + } + } + })); + } + + try_join_all(task_vec).await?; + + // 6th filtering condition: MACD + // let mut opclo_30m_vec: Vec = Vec::new(); + // let mut ema3_1d_vec: &Vec = &Vec::new(); + // let mut ema10_1d_vec: &Vec = &Vec::new(); + + // let mut filtered_7th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) // for element in filtered_6th_symbols { - // let mut filtered_symbols_arc_c = Arc::clone(&filtered_symbols_arc); - // let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + // let ema3_1d_option = alldata.ema3_1d_data.iter().position(|x| *x.0 == *element.0); + // let ema10_1d_option = alldata.ema10_1d_data.iter().position(|x| *x.0 == *element.0); - // let elememt_c = element.clone(); - // task_vec.push(tokio::spawn(async move { - // let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.0); - // if opclo_30m_option.is_some() { - // if rt_price_30m_vec_c[opclo_30m_option.unwrap()] - // .1 - // .last() - // .is_some() - // { - // let mut filtered_symbols_lock: tokio::sync::MutexGuard< - // '_, - // Vec<(String, i64, f64)>, - // > = filtered_symbols_arc_c.lock().await; - // filtered_symbols_lock.push(( - // elememt_c.0, - // elememt_c.1, - // rt_price_30m_vec_c[opclo_30m_option.unwrap()] - // .1 - // .last() - // .unwrap() - // .close_price, - // )); - // } + // if ema3_1d_option.is_some() && ema10_1d_option.is_some() { + // ema3_1d_vec = &alldata.ema3_1d_data[ema3_1d_option.unwrap()].1; + // ema10_1d_vec = &alldata.ema10_1d_data[ema10_1d_option.unwrap()].1; + + // if ema3_1d_vec.len() > 20 && ema10_1d_vec.len() > 20 { + // let macd_vec = ema_macd(&ema3_1d_vec, &ema10_1d_vec, 10).await?; + // // let macd_search_result = macd_vec.binary_search_by_key(&element.1, |&EmaMacd{macd_value, close_time}|close_time); + + // // if macd_search_result.is_ok() { + // if macd_vec.last().unwrap().macd_value - macd_vec[macd_vec.len() -2].macd_value >= 0.0 { + // filtered_7th_symbols.push(element); + // } + // // } // } - // })); + // } // } + let a = filtered_symbols_arc.lock().await.clone(); + insert_pre_suggested_coins(3, false, &a, alldata).await; - // try_join_all(task_vec).await?; + Ok(()) +} - // let a = filtered_symbols_arc.lock().await.clone(); - // insert_pre_suggested_coins(2, &a, alldata).await; +pub async fn strategist_004( + alldata: &AllData, +) -> Result<(), Box> { + // print rt_price for debugging + // let a = alldata.rt_price_30m_vec.iter().position(|a| a.0 == "BTCUSDT"); + // println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap()); + + // 1st filtering: supertrend(ATR period 10, multiplier: 2.0, 30m close price), the area should be in UP area. + let mut filtered_2nd_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_2nd_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_2nd_symbols)); // (symbol, closetime) + let mut task_vec = Vec::new(); + let valid_symbol_vec_c = alldata.valid_symbol_vec.clone(); + for symbol in valid_symbol_vec_c { + let mut opclo_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_2nd_symbols_arc_c = Arc::clone(&filtered_2nd_symbols_arc); + task_vec.push(tokio::spawn(async move { + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == symbol); + let supertrend_option_30m = + supertrend(&symbol, &rt_price_30m_vec_c, 10, 2.0, true).await; + + if opclo_30m_option.is_some() && supertrend_option_30m.is_some() { + opclo_30m_vec = rt_price_30m_vec_c[opclo_30m_option.unwrap()].1.clone(); + supertrend_vec = supertrend_option_30m.unwrap(); + + if opclo_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 { + let supertrend_search_result = supertrend_vec.binary_search_by_key( + &opclo_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("UP") + { + let mut filtered_2nd_symbols_lock = + filtered_2nd_symbols_arc_c.lock().await; + filtered_2nd_symbols_lock + .push((symbol.clone(), opclo_30m_vec.last().unwrap().close_time)); + } + } + } + } + })); + } + try_join_all(task_vec).await?; + + // 2nd filtering: lookup tables if the tradepair is already there + let inspect_table_name_1 = String::from("buy_ordered_coin_list"); + let inspect_table_name_2 = String::from("sell_ordered_coin_list"); + let inspect_table_name_3 = String::from("pre_suggested_coin_list"); + let inspect_table_name_4 = String::from("suggested_coin_list"); + + let mut filtered_3rd_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_3rd_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_3rd_symbols)); // (symbol, closetime) + let mut task_vec = Vec::new(); + + let filtered_2nd_iter = filtered_2nd_symbols_arc.lock().await.clone().into_iter(); + for element in filtered_2nd_iter { + let mut exists_condition_build = String::from("symbol=\'"); + exists_condition_build.push_str(element.0.as_str()); + exists_condition_build.push_str("\' AND registerer="); + exists_condition_build.push_str(4.to_string().as_str()); + // exists_condition_build.push_str("\' AND close_time="); + // exists_condition_build.push_str(element.1.to_string().as_str()); + let exists_condition = Some(exists_condition_build); + let exists_condition_c = exists_condition.clone(); + let inspect_table_name_1_c = inspect_table_name_1.clone(); + let inspect_table_name_2_c = inspect_table_name_2.clone(); + let inspect_table_name_3_c = inspect_table_name_3.clone(); + let inspect_table_name_4_c = inspect_table_name_4.clone(); + let element_c = element.clone(); + let filtered_3rd_symbols_arc_c = Arc::clone(&filtered_3rd_symbols_arc); + task_vec.push(tokio::spawn(async move { + let inspect_result_1 = + exists_record(&inspect_table_name_1_c, &exists_condition_c).await; + let inspect_result_2 = + exists_record(&inspect_table_name_2_c, &exists_condition_c).await; + let inspect_result_3 = + exists_record(&inspect_table_name_3_c, &exists_condition_c).await; + let inspect_result_4 = + exists_record(&inspect_table_name_4_c, &exists_condition_c).await; + + if inspect_result_1 == false + && inspect_result_2 == false + && inspect_result_3 == false + && inspect_result_4 == false + { + let mut filtered_3rd_symbols_lock = filtered_3rd_symbols_arc_c.lock().await; + filtered_3rd_symbols_lock.push(element_c); + } + })); + } + try_join_all(task_vec).await?; + + // 3rd filtering: EMA30 >= EMA 150 + let filtered_3rd_symbols_c = filtered_3rd_symbols_arc.lock().await.clone(); + let ema30_30m_data: Vec<(String, Vec)> = ema( + 30, + &alldata.rt_price_30m_vec, + &filtered_3rd_symbols_c, + ) + .await?; + let ema150_30m_data: Vec<(String, Vec)> = ema( + 150, + &alldata.rt_price_30m_vec, + &filtered_3rd_symbols_c, + ) + .await?; + + let mut task_vec = Vec::new(); + let mut filtered_4th_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_4th_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_4th_symbols)); // (symbol, closetime) + for element in filtered_3rd_symbols_c { + let mut ema30_30m_vec: Vec = Vec::new(); + let mut ema150_30m_vec: Vec = Vec::new(); + let ema30_30m_option = ema30_30m_data.iter().position(|x| *x.0 == element.0); + let ema30_30m_option_c = ema30_30m_option.clone(); + let ema150_30m_option = ema150_30m_data.iter().position(|x| *x.0 == element.0); + let ema150_30m_option_c = ema150_30m_option.clone(); + let element_c = element.clone(); + let filtered_4th_symbols_arc_c = Arc::clone(&filtered_4th_symbols_arc); + + if ema30_30m_option_c.is_some() && ema150_30m_option_c.is_some() { + ema30_30m_vec = ema30_30m_data[ema30_30m_option.unwrap()].1.clone(); + ema150_30m_vec = ema150_30m_data[ema150_30m_option.unwrap()].1.clone(); + + if ema30_30m_vec.len() >= 10 && ema150_30m_vec.len() >= 10 { + let ema30_30m_vec_c = ema30_30m_vec.clone(); + let ema150_30m_vec_c = ema150_30m_vec.clone(); + + task_vec.push(tokio::spawn(async move { + let ema30_search_result = ema30_30m_vec_c.binary_search_by_key( + &element_c.1, + |&EmaData { + ema_value, + close_time, + }| close_time, + ); + let ema150_search_result = ema150_30m_vec_c.binary_search_by_key( + &element_c.1, + |&EmaData { + ema_value, + close_time, + }| close_time, + ); + + if ema30_search_result.is_ok() && ema150_search_result.is_ok() { + if ema30_30m_vec_c[ema30_search_result.unwrap()-9].ema_value < ema150_30m_vec_c[ema150_search_result.unwrap()-9].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-8].ema_value < ema150_30m_vec_c[ema150_search_result.unwrap()-8].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-7].ema_value < ema150_30m_vec_c[ema150_search_result.unwrap()-7].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-6].ema_value < ema150_30m_vec_c[ema150_search_result.unwrap()-6].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-5].ema_value < ema150_30m_vec_c[ema150_search_result.unwrap()-5].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-4].ema_value < ema150_30m_vec_c[ema150_search_result.unwrap()-4].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-3].ema_value < ema150_30m_vec_c[ema150_search_result.unwrap()-3].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-2].ema_value < ema150_30m_vec_c[ema150_search_result.unwrap()-2].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-1].ema_value < ema150_30m_vec_c[ema150_search_result.unwrap()-1].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()].ema_value >= ema150_30m_vec_c[ema150_search_result.unwrap()].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()].ema_value > ema30_30m_vec_c[ema30_search_result.unwrap()-1].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-1].ema_value > ema30_30m_vec_c[ema30_search_result.unwrap()-2].ema_value && + ema30_30m_vec_c[ema30_search_result.unwrap()-2].ema_value > ema30_30m_vec_c[ema30_search_result.unwrap()-3].ema_value + { + let mut filtered_4th_symbols_lock = + filtered_4th_symbols_arc_c.lock().await; + filtered_4th_symbols_lock.push(element_c); + } + } + })); + } + } + } + try_join_all(task_vec).await?; + + // 4th filtering: heatmap volume(MA length 10, std length 10, 30m close price), the current candle should be Normal or Low. + let filtered_4th_symbols_c = filtered_4th_symbols_arc.lock().await.clone(); + let mut filtered_5th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) + for element in filtered_4th_symbols_c { + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.0); + if opclo_30m_option.is_some() { + let opclo_30m_vec = rt_price_30m_vec_c[opclo_30m_option.unwrap()].1.clone(); + + if opclo_30m_vec.len() >= 3 { + let heatmap_volume_option = + heatmap_volume(&element.0, &rt_price_30m_vec_c, 10, 10, 4.0, 2.5, 1.0, -0.5) + .await; + if heatmap_volume_option.is_some() { + let heatmap_volume_vec = heatmap_volume_option.unwrap(); + let heatmap_search_result = heatmap_volume_vec.binary_search_by_key( + &element.1, + |HeatmapVolumeData { + heatmap_value, + heatmap_level, + close_time, + }| *close_time, + ); + if heatmap_search_result.is_ok() { + if (heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level + == HeatMapLevel::Low + || + heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level + == HeatMapLevel::Normal) && + (heatmap_volume_vec[heatmap_search_result.unwrap()-1].heatmap_level + == HeatMapLevel::Low + || + heatmap_volume_vec[heatmap_search_result.unwrap()-1].heatmap_level + == HeatMapLevel::Normal + ) + { + filtered_5th_symbols.push(element); + } + } + } + } + } + } + + // final job: adding price information to filtered results + let mut filtered_symbols: Vec<(String, i64, f64)> = Vec::new(); // (symbol, closetime, current price) + let mut filtered_symbols_arc = Arc::new(Mutex::new(filtered_symbols)); + let mut task_vec = Vec::new(); + for element in filtered_5th_symbols { + let mut filtered_symbols_arc_c = Arc::clone(&filtered_symbols_arc); + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + + let elememt_c = element.clone(); + task_vec.push(tokio::spawn(async move { + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.0); + if opclo_30m_option.is_some() { + if rt_price_30m_vec_c[opclo_30m_option.unwrap()] + .1 + .last() + .is_some() + { + let mut filtered_symbols_lock: tokio::sync::MutexGuard< + '_, + Vec<(String, i64, f64)>, + > = filtered_symbols_arc_c.lock().await; + filtered_symbols_lock.push(( + elememt_c.0, + elememt_c.1, + rt_price_30m_vec_c[opclo_30m_option.unwrap()] + .1 + .last() + .unwrap() + .close_price, + )); + } + } + })); + } + + try_join_all(task_vec).await?; + + let a = filtered_symbols_arc.lock().await.clone(); + insert_pre_suggested_coins(4, false, &a, alldata).await; + + Ok(()) +} + +pub async fn strategist_005( + alldata: &AllData, +) -> Result<(), Box> { + // print rt_price for debugging + // let a = alldata.rt_price_30m_vec.iter().position(|a| a.0 == "BTCUSDT"); + // println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap()); + + // 1st filtering: supertrend(ATR period 30, multiplier: 6.0, 30m close price), the area should be in UP area. + let mut filtered_2nd_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_2nd_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_2nd_symbols)); // (symbol, closetime) + let mut task_vec = Vec::new(); + let valid_symbol_vec_c = alldata.valid_symbol_vec.clone(); + for symbol in valid_symbol_vec_c { + let mut opclo_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_2nd_symbols_arc_c = Arc::clone(&filtered_2nd_symbols_arc); + task_vec.push(tokio::spawn(async move { + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == symbol); + let supertrend_option_30m = + supertrend(&symbol, &rt_price_30m_vec_c, 30, 6.0, true).await; + + if opclo_30m_option.is_some() && supertrend_option_30m.is_some() { + opclo_30m_vec = rt_price_30m_vec_c[opclo_30m_option.unwrap()].1.clone(); + supertrend_vec = supertrend_option_30m.unwrap(); + + if opclo_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 { + let supertrend_search_result = supertrend_vec.binary_search_by_key( + &opclo_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()] + .signal.as_ref().is_some_and(|signal| signal.contains("BUY")) + { + let mut filtered_2nd_symbols_lock = + filtered_2nd_symbols_arc_c.lock().await; + filtered_2nd_symbols_lock + .push((symbol.clone(), opclo_30m_vec.last().unwrap().close_time)); + } + } + } + } + })); + } + try_join_all(task_vec).await?; + + // 2nd filtering: lookup tables if the tradepair is already there + let inspect_table_name_1 = String::from("buy_ordered_coin_list"); + let inspect_table_name_2 = String::from("sell_ordered_coin_list"); + let inspect_table_name_3 = String::from("pre_suggested_coin_list"); + let inspect_table_name_4 = String::from("suggested_coin_list"); + + let mut filtered_3rd_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_3rd_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_3rd_symbols)); // (symbol, closetime) + let mut task_vec = Vec::new(); + + let filtered_2nd_iter = filtered_2nd_symbols_arc.lock().await.clone().into_iter(); + for element in filtered_2nd_iter { + let mut exists_condition_build = String::from("symbol=\'"); + exists_condition_build.push_str(element.0.as_str()); + exists_condition_build.push_str("\' AND registerer="); + exists_condition_build.push_str(5.to_string().as_str()); + // exists_condition_build.push_str("\' AND close_time="); + // exists_condition_build.push_str(element.1.to_string().as_str()); + let exists_condition = Some(exists_condition_build); + let exists_condition_c = exists_condition.clone(); + let inspect_table_name_1_c = inspect_table_name_1.clone(); + let inspect_table_name_2_c = inspect_table_name_2.clone(); + let inspect_table_name_3_c = inspect_table_name_3.clone(); + let inspect_table_name_4_c = inspect_table_name_4.clone(); + let element_c = element.clone(); + let filtered_3rd_symbols_arc_c = Arc::clone(&filtered_3rd_symbols_arc); + task_vec.push(tokio::spawn(async move { + let inspect_result_1 = + exists_record(&inspect_table_name_1_c, &exists_condition_c).await; + let inspect_result_2 = + exists_record(&inspect_table_name_2_c, &exists_condition_c).await; + let inspect_result_3 = + exists_record(&inspect_table_name_3_c, &exists_condition_c).await; + let inspect_result_4 = + exists_record(&inspect_table_name_4_c, &exists_condition_c).await; + + if inspect_result_1 == false + && inspect_result_2 == false + && inspect_result_3 == false + && inspect_result_4 == false + { + let mut filtered_3rd_symbols_lock = filtered_3rd_symbols_arc_c.lock().await; + filtered_3rd_symbols_lock.push(element_c); + } + })); + } + try_join_all(task_vec).await?; + + // 3rd filtering: heatmap volume(MA length 10, std length 10, 30m close price), the current candle should be Normal or Low. + let filtered_3rd_symbols_c = filtered_3rd_symbols_arc.lock().await.clone(); + let mut filtered_4th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) + for element in filtered_3rd_symbols_c { + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.0); + if opclo_30m_option.is_some() { + let opclo_30m_vec = rt_price_30m_vec_c[opclo_30m_option.unwrap()].1.clone(); + + if opclo_30m_vec.len() >= 3 { + let heatmap_volume_option = + heatmap_volume(&element.0, &rt_price_30m_vec_c, 10, 10, 4.0, 2.5, 1.0, -0.5) + .await; + if heatmap_volume_option.is_some() { + let heatmap_volume_vec = heatmap_volume_option.unwrap(); + let heatmap_search_result = heatmap_volume_vec.binary_search_by_key( + &element.1, + |HeatmapVolumeData { + heatmap_value, + heatmap_level, + close_time, + }| *close_time, + ); + if heatmap_search_result.is_ok() { + if (heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level + == HeatMapLevel::Low + || + heatmap_volume_vec[heatmap_search_result.unwrap()].heatmap_level + == HeatMapLevel::Normal) && + (heatmap_volume_vec[heatmap_search_result.unwrap()-1].heatmap_level + == HeatMapLevel::Low + || + heatmap_volume_vec[heatmap_search_result.unwrap()-1].heatmap_level + == HeatMapLevel::Normal) && + (heatmap_volume_vec[heatmap_search_result.unwrap()-2].heatmap_level + == HeatMapLevel::Low + || + heatmap_volume_vec[heatmap_search_result.unwrap()-2].heatmap_level + == HeatMapLevel::Normal) + { + filtered_4th_symbols.push(element); + } + } + } + } + } + } + + // final job: adding price information to filtered results + let mut filtered_symbols: Vec<(String, i64, f64)> = Vec::new(); // (symbol, closetime, current price) + let mut filtered_symbols_arc = Arc::new(Mutex::new(filtered_symbols)); + let mut task_vec = Vec::new(); + for element in filtered_4th_symbols { + let mut filtered_symbols_arc_c = Arc::clone(&filtered_symbols_arc); + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + + let elememt_c = element.clone(); + task_vec.push(tokio::spawn(async move { + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.0); + if opclo_30m_option.is_some() { + if rt_price_30m_vec_c[opclo_30m_option.unwrap()] + .1 + .last() + .is_some() + { + let mut filtered_symbols_lock: tokio::sync::MutexGuard< + '_, + Vec<(String, i64, f64)>, + > = filtered_symbols_arc_c.lock().await; + filtered_symbols_lock.push(( + elememt_c.0, + elememt_c.1, + rt_price_30m_vec_c[opclo_30m_option.unwrap()] + .1 + .last() + .unwrap() + .close_price, + )); + } + } + })); + } + + try_join_all(task_vec).await?; + + let a = filtered_symbols_arc.lock().await.clone(); + insert_pre_suggested_coins(5, false, &a, alldata).await; + + Ok(()) +} + +pub async fn strategist_006( + alldata: &AllData, +) -> Result<(), Box> { + // print rt_price for debugging + // let a = alldata.rt_price_30m_vec.iter().position(|a| a.0 == "BTCUSDT"); + // println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap()); + + // 1st filtering: making basic form + let mut filtered_2nd_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_2nd_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_2nd_symbols)); // (symbol, closetime) + let mut task_vec = Vec::new(); + let valid_symbol_vec_c = alldata.valid_symbol_vec.clone(); + for symbol in valid_symbol_vec_c { + let mut opclo_30m_vec: Vec = Vec::new(); + + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + let filtered_2nd_symbols_arc_c = Arc::clone(&filtered_2nd_symbols_arc); + task_vec.push(tokio::spawn(async move { + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == symbol); + + if opclo_30m_option.is_some() { + opclo_30m_vec = rt_price_30m_vec_c[opclo_30m_option.unwrap()].1.clone(); + + if opclo_30m_vec.len() >= 3 { + let mut filtered_2nd_symbols_lock = + filtered_2nd_symbols_arc_c.lock().await; + filtered_2nd_symbols_lock + .push((symbol.clone(), opclo_30m_vec.last().unwrap().close_time)); + } + } + })); + } + try_join_all(task_vec).await?; + + // 2nd filtering: lookup tables if the tradepair is already there + let inspect_table_name_1 = String::from("buy_ordered_coin_list"); + let inspect_table_name_2 = String::from("sell_ordered_coin_list"); + let inspect_table_name_3 = String::from("pre_suggested_coin_list"); + let inspect_table_name_4 = String::from("suggested_coin_list"); + + let mut filtered_3rd_symbols: Vec<(String, i64)> = Vec::new(); + let mut filtered_3rd_symbols_arc: Arc>> = + Arc::new(Mutex::new(filtered_3rd_symbols)); // (symbol, closetime) + let mut task_vec = Vec::new(); + + let filtered_2nd_iter = filtered_2nd_symbols_arc.lock().await.clone().into_iter(); + for element in filtered_2nd_iter { + let mut exists_condition_build = String::from("symbol=\'"); + exists_condition_build.push_str(element.0.as_str()); + exists_condition_build.push_str("\' AND registerer="); + exists_condition_build.push_str(6.to_string().as_str()); + // exists_condition_build.push_str("\' AND close_time="); + // exists_condition_build.push_str(element.1.to_string().as_str()); + let exists_condition = Some(exists_condition_build); + let exists_condition_c = exists_condition.clone(); + let inspect_table_name_1_c = inspect_table_name_1.clone(); + let inspect_table_name_2_c = inspect_table_name_2.clone(); + let inspect_table_name_3_c = inspect_table_name_3.clone(); + let inspect_table_name_4_c = inspect_table_name_4.clone(); + let element_c = element.clone(); + let filtered_3rd_symbols_arc_c = Arc::clone(&filtered_3rd_symbols_arc); + task_vec.push(tokio::spawn(async move { + let inspect_result_1 = + exists_record(&inspect_table_name_1_c, &exists_condition_c).await; + let inspect_result_2 = + exists_record(&inspect_table_name_2_c, &exists_condition_c).await; + let inspect_result_3 = + exists_record(&inspect_table_name_3_c, &exists_condition_c).await; + let inspect_result_4 = + exists_record(&inspect_table_name_4_c, &exists_condition_c).await; + + if inspect_result_1 == false + && inspect_result_2 == false + && inspect_result_3 == false + && inspect_result_4 == false + { + let mut filtered_3rd_symbols_lock = filtered_3rd_symbols_arc_c.lock().await; + filtered_3rd_symbols_lock.push(element_c); + } + })); + } + try_join_all(task_vec).await?; + + // 6th filtering: StochRSI (RSI length: 10, Stoch length: 10, smooth k: 3, smooth d: 3) smooth kn > kn-1 + let filtered_3rd_symbol_c = filtered_3rd_symbols_arc.lock().await.clone(); + let mut rsi10_1d_data: Vec<(String, Vec)> = rsi( + 10, + &alldata.rt_price_1d_vec, + &filtered_3rd_symbol_c, + ) + .await?; + let stoch_rsi_data = stoch_rsi(&rsi10_1d_data, 10, 3, 3).await?; + let mut stoch_rsi10_1d_vec: Vec = Vec::new(); + let mut filtered_4th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) + for element in filtered_3rd_symbol_c { + let stoch_rsi10_1d_option = stoch_rsi_data.iter().position(|x| *x.0 == element.0); + + if stoch_rsi10_1d_option.is_some() { + stoch_rsi10_1d_vec = stoch_rsi_data[stoch_rsi10_1d_option.unwrap()].1.clone(); + + if stoch_rsi10_1d_vec.len() >= 3 { + let stoch_rsi_search_result = stoch_rsi10_1d_vec.binary_search_by_key( + &element.1, + |&StochRsiData { + k, + d, + close_time, + }| close_time, + ); + if stoch_rsi_search_result.is_ok() { + if stoch_rsi10_1d_vec[stoch_rsi_search_result.unwrap()].k > stoch_rsi10_1d_vec[stoch_rsi_search_result.unwrap()-1].k && + stoch_rsi10_1d_vec[stoch_rsi_search_result.unwrap()].k < 90.0 && + stoch_rsi10_1d_vec[stoch_rsi_search_result.unwrap()-1].k > 10.0 { + filtered_4th_symbols.push(element); + } + } + } + } + } + + // 6th filtering condition: MACD + let mut opclo_30m_vec: Vec = Vec::new(); + let mut ema3_1d_vec: &Vec = &Vec::new(); + let mut ema10_1d_vec: &Vec = &Vec::new(); + + let ema3_1d_data: Vec<(String, Vec)> = ema( + 3, + &alldata.rt_price_1d_vec, + &filtered_4th_symbols, + ) + .await?; + let ema10_1d_data: Vec<(String, Vec)> = ema( + 10, + &alldata.rt_price_1d_vec, + &filtered_4th_symbols, + ) + .await?; + + let mut filtered_5th_symbols: Vec<(String, i64)> = Vec::new(); // (symbol, closetime) + for element in filtered_4th_symbols { + let ema3_1d_option = ema3_1d_data.iter().position(|x| *x.0 == *element.0); + let ema10_1d_option = ema10_1d_data.iter().position(|x| *x.0 == *element.0); + + if ema3_1d_option.is_some() && ema10_1d_option.is_some() { + ema3_1d_vec = &ema3_1d_data[ema3_1d_option.unwrap()].1; + ema10_1d_vec = &ema10_1d_data[ema10_1d_option.unwrap()].1; + + if ema3_1d_vec.len() > 20 && ema10_1d_vec.len() > 20 { + let macd_vec = ema_macd(&ema3_1d_vec, &ema10_1d_vec, 10).await?; + // let macd_search_result = macd_vec.binary_search_by_key(&element.1, |&EmaMacd{macd_value, close_time}|close_time); + + // if macd_search_result.is_ok() { + if macd_vec.last().unwrap().macd_value > macd_vec[macd_vec.len() -1].macd_value { + filtered_5th_symbols.push(element); + } + // } + } + } + } + + // final job: adding price information to filtered results + let mut filtered_symbols: Vec<(String, i64, f64)> = Vec::new(); // (symbol, closetime, current price) + let mut filtered_symbols_arc = Arc::new(Mutex::new(filtered_symbols)); + let mut task_vec = Vec::new(); + for element in filtered_5th_symbols { + let mut filtered_symbols_arc_c = Arc::clone(&filtered_symbols_arc); + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + + let elememt_c = element.clone(); + task_vec.push(tokio::spawn(async move { + let opclo_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.0); + if opclo_30m_option.is_some() { + if rt_price_30m_vec_c[opclo_30m_option.unwrap()] + .1 + .last() + .is_some() + { + let mut filtered_symbols_lock: tokio::sync::MutexGuard< + '_, + Vec<(String, i64, f64)>, + > = filtered_symbols_arc_c.lock().await; + filtered_symbols_lock.push(( + elememt_c.0, + elememt_c.1, + rt_price_30m_vec_c[opclo_30m_option.unwrap()] + .1 + .last() + .unwrap() + .close_price, + )); + } + } + })); + } + + try_join_all(task_vec).await?; + + let a = filtered_symbols_arc.lock().await.clone(); + insert_pre_suggested_coins(6, true, &a, alldata).await; Ok(()) } @@ -5976,6 +7145,7 @@ pub async fn get_current_price( async fn insert_pre_suggested_coins( registerer: i32, + is_long: bool, filtered_symbols: &Vec<(String, i64, f64)>, alldata: &AllData, ) -> Result<(), Box> { @@ -6000,6 +7170,7 @@ async fn insert_pre_suggested_coins( "minimum_profit_percent", "maximum_profit_percent", "registerer", + "is_long", ]; if exists_result1 == true && exists_result2 == true && exists_result3 == true { @@ -6081,7 +7252,7 @@ async fn insert_pre_suggested_coins( } if is_dupe == false { - let insert_values = vec![ + let mut insert_values = vec![ filtered_element.0.clone(), // symbol filtered_element.1.to_string(), // close_time filtered_element.2.to_string(), // suggested_price @@ -6092,6 +7263,13 @@ async fn insert_pre_suggested_coins( 0.0.to_string(), // maximum_profit_percent registerer.to_string(), // registerer ]; + + if is_long == true { + insert_values.push(1.to_string()); // is_long + } else { + insert_values.push(0.to_string()); // is_long + } + insert_one_record(&insert_table_name, &insert_columns, &insert_values).await; } } @@ -6158,7 +7336,7 @@ async fn insert_pre_suggested_coins( } if is_dupe == false { - let insert_values = vec![ + let mut insert_values = vec![ filtered_element.0.clone(), // symbol filtered_element.1.to_string(), // close_time filtered_element.2.to_string(), // suggested_price @@ -6169,6 +7347,13 @@ async fn insert_pre_suggested_coins( 0.0.to_string(), // maximum_profit_percent registerer.to_string(), // registerer ]; + + if is_long == true { + insert_values.push(1.to_string()); // is_long + } else { + insert_values.push(0.to_string()); // is_long + } + insert_one_record(&insert_table_name, &insert_columns, &insert_values).await; } } @@ -6225,7 +7410,7 @@ async fn insert_pre_suggested_coins( } if is_dupe == false { - let insert_values = vec![ + let mut insert_values = vec![ filtered_element.0.clone(), // symbol filtered_element.1.to_string(), // close_time filtered_element.2.to_string(), // suggested_price @@ -6236,6 +7421,13 @@ async fn insert_pre_suggested_coins( 0.0.to_string(), // maximum_profit_percent registerer.to_string(), // registerer ]; + + if is_long == true { + insert_values.push(1.to_string()); // is_long + } else { + insert_values.push(0.to_string()); // is_long + } + insert_one_record(&insert_table_name, &insert_columns, &insert_values).await; } } @@ -6276,7 +7468,7 @@ async fn insert_pre_suggested_coins( } if is_dupe == false { - let insert_values = vec![ + let mut insert_values = vec![ filtered_element.0.clone(), // symbol filtered_element.1.to_string(), // close_time filtered_element.2.to_string(), // suggested_price @@ -6287,6 +7479,13 @@ async fn insert_pre_suggested_coins( 0.0.to_string(), // maximum_profit_percent registerer.to_string(), // registerer ]; + + if is_long == true { + insert_values.push(1.to_string()); // is_long + } else { + insert_values.push(0.to_string()); // is_long + } + insert_one_record(&insert_table_name, &insert_columns, &insert_values).await; } } @@ -6353,7 +7552,7 @@ async fn insert_pre_suggested_coins( } if is_dupe == false { - let insert_values = vec![ + let mut insert_values = vec![ filtered_element.0.clone(), // symbol filtered_element.1.to_string(), // close_time filtered_element.2.to_string(), // suggested_price @@ -6364,6 +7563,13 @@ async fn insert_pre_suggested_coins( 0.0.to_string(), // maximum_profit_percent registerer.to_string(), // registerer ]; + + if is_long == true { + insert_values.push(1.to_string()); // is_long + } else { + insert_values.push(0.to_string()); // is_long + } + insert_one_record(&insert_table_name, &insert_columns, &insert_values).await; } } @@ -6414,7 +7620,7 @@ async fn insert_pre_suggested_coins( } if is_dupe == false { - let insert_values = vec![ + let mut insert_values = vec![ filtered_element.0.clone(), // symbol filtered_element.1.to_string(), // close_time filtered_element.2.to_string(), // suggested_price @@ -6425,6 +7631,13 @@ async fn insert_pre_suggested_coins( 0.0.to_string(), // maximum_profit_percent registerer.to_string(), // registerer ]; + + if is_long == true { + insert_values.push(1.to_string()); // is_long + } else { + insert_values.push(0.to_string()); // is_long + } + insert_one_record(&insert_table_name, &insert_columns, &insert_values).await; } } @@ -6465,7 +7678,7 @@ async fn insert_pre_suggested_coins( } if is_dupe == false { - let insert_values = vec![ + let mut insert_values = vec![ filtered_element.0.clone(), // symbol filtered_element.1.to_string(), // close_time filtered_element.2.to_string(), // suggested_price @@ -6476,12 +7689,19 @@ async fn insert_pre_suggested_coins( 0.0.to_string(), // maximum_profit_percent registerer.to_string(), // registerer ]; + + if is_long == true { + insert_values.push(1.to_string()); // is_long + } else { + insert_values.push(0.to_string()); // is_long + } + insert_one_record(&insert_table_name, &insert_columns, &insert_values).await; } } } else { for filtered_element in filtered_symbols { - let insert_values = vec![ + let mut insert_values = vec![ filtered_element.0.clone(), // symbol filtered_element.1.to_string(), // close_time filtered_element.2.to_string(), // suggested_price @@ -6492,6 +7712,13 @@ async fn insert_pre_suggested_coins( 0.0.to_string(), // maximum_profit_percent registerer.to_string(), // registerer ]; + + if is_long == true { + insert_values.push(1.to_string()); // is_long + } else { + insert_values.push(0.to_string()); // is_long + } + insert_one_record(&insert_table_name, &insert_columns, &insert_values).await; } }