From dc0cc8234ab65cb529e9220200db87bb5d212da4 Mon Sep 17 00:00:00 2001 From: Sik Yoon Date: Sun, 19 Nov 2023 01:27:51 +0900 Subject: [PATCH] Separate selling function --- src/coex/exchange_team.rs | 2 +- src/coex/order_team.rs | 196 ++--------------- src/main.rs | 296 +++++++++++++++----------- src/strategy_team/mod.rs | 5 + src/strategy_team/strategy_003.rs | 165 +++++++++++++- src/strategy_team/strategy_manager.rs | 13 +- 6 files changed, 363 insertions(+), 314 deletions(-) diff --git a/src/coex/exchange_team.rs b/src/coex/exchange_team.rs index 6242c84..3a426e1 100644 --- a/src/coex/exchange_team.rs +++ b/src/coex/exchange_team.rs @@ -576,7 +576,7 @@ pub async fn monitoring_scoreboard( let mut update_condition: Vec<(String, String)> = Vec::new(); let mut update_condition2: Vec<(String, String)> = Vec::new(); - let filled_buy_orders = select_filled_buy_orders().await?; + let filled_buy_orders = select_filled_buy_orders(0).await?; if filled_buy_orders.is_empty() { // initialization of table diff --git a/src/coex/order_team.rs b/src/coex/order_team.rs index a6b4854..cee5091 100644 --- a/src/coex/order_team.rs +++ b/src/coex/order_team.rs @@ -516,27 +516,21 @@ pub async fn monitoring_open_buy_order( Ok(()) } -pub async fn monitoring_filled_buy_order( - all_data: &AllData, +pub async fn update_price_of_filled_buy_order( coin_price_vec: &Vec, exchange_info_vec: &Vec, trade_fee_vec: &Vec, ) -> Result<(), Box> { - let index_list = select_marketcap().await; - // let scoreboard_list = select_scoreboard().await; - // let signal_decision = select_signal_decision().await; - - let filled_buy_orders = select_filled_buy_orders().await?; + let filled_buy_orders = select_filled_buy_orders(0).await?; if !filled_buy_orders.is_empty() { // 심볼들을 2개씩 청스로 나누어 테스크를 생성하고 각 태스크 별로 병렬로 처리한다. // update real-time current price to each record through chunks - let chunks: std::slice::Chunks<'_, BuyOrderedCoinList> = filled_buy_orders.chunks(2); + let chunks: std::slice::Chunks<'_, BuyOrderedCoinList> = filled_buy_orders.chunks(3); let mut task_vec = Vec::new(); for chunk in chunks { let chunk_vec = chunk.to_vec(); - let interval_clone = interval.clone(); let coin_price_vec_c = coin_price_vec.clone(); let exchange_info_vec_c = exchange_info_vec.clone(); let trade_fee_vec_c = trade_fee_vec.clone(); @@ -550,179 +544,7 @@ pub async fn monitoring_filled_buy_order( .await; })); } - - let result = try_join_all(task_vec).await; - - // sell coin if its sell condition is satisfied - let filled_buy_orders = select_filled_buy_orders().await?; - let client = ClientBuilder::new() - .timeout(tokio::time::Duration::from_millis(5000)) - .build() - .unwrap(); - let instant = Instant::now(); - let server_epoch = server_epoch().await; - - let mut sell_order_count = 0; - for element in filled_buy_orders { - if element.used_usdt >= dec!(10.0) { - // ignore coins having 10 usdt below because of not traded - let sell_percent_for_uptrend = |z: f64| 0.94 * z - 0.5; - - let lot_step_size_option = exchange_info_vec - .iter() - .find(|ExchangeInfo| ExchangeInfo.symbol == element.symbol); - let quote_commission_precision_option = exchange_info_vec - .iter() - .find(|ExchangeInfo| ExchangeInfo.symbol == element.symbol); - - let opclo_30m_option = all_data - .rt_price_30m_vec - .iter() - .position(|x| *x.0 == element.symbol); - - if lot_step_size_option.is_some() - && quote_commission_precision_option.is_some() - && opclo_30m_option.is_some() - { - let lot_step_size = lot_step_size_option.unwrap().stepsize; - let quote_commission_precision = quote_commission_precision_option - .unwrap() - .quote_commission_precision; - let base_qty_to_be_ordered = - element.base_qty_fee_adjusted.round_dp_with_strategy( - lot_step_size.normalize().scale(), - RoundingStrategy::ToZero, - ); - - let mut opclo_30m_vec = all_data.rt_price_30m_vec[opclo_30m_option.unwrap()] - .1 - .clone(); - - opclo_30m_vec.pop(); - opclo_30m_vec.reverse(); - let mut opclo_sample_length: usize = 50; // 50 candle samsples - let nbr_of_exclusive: usize = 5; - opclo_30m_vec.truncate(opclo_sample_length); - opclo_30m_vec.sort_by(|a, b| (a.high_price-a.low_price).total_cmp(&(b.high_price-b.low_price))); - opclo_30m_vec.truncate(opclo_sample_length - nbr_of_exclusive); - opclo_sample_length -= nbr_of_exclusive; - - let mut sum_amplitude_candles = 0.0; - let mut sum_ratio_amp_body = 0.0; - for element in &opclo_30m_vec { - sum_amplitude_candles += - ((element.high_price / element.low_price) - 1.0) * 100.0; - sum_ratio_amp_body += (element.close_price - element.open_price).abs() - / (element.high_price - element.low_price); - } - let average_amplitude = sum_amplitude_candles / opclo_sample_length as f64; // percent unit - let average_ratio_amp_body = sum_ratio_amp_body / opclo_sample_length as f64; - - let mut amplitude_variance = 0.0; - for element in &opclo_30m_vec { - amplitude_variance += ((((element.high_price / element.low_price) - 1.0) - * 100.0) - - average_amplitude) - .powi(2); - } - amplitude_variance = amplitude_variance / (opclo_sample_length - 1) as f64; - let standard_deviation_amplitude = amplitude_variance.sqrt(); - - // let target_profit_percent = average_amplitude + (standard_deviation_amplitude * (average_ratio_amp_body)); - let target_profit_percent = |multiplier: f64| -> f64 { - if multiplier < 0.0 { - ((average_amplitude) * multiplier) - (standard_deviation_amplitude * 2.0) // 2.0 sigma (recommand: 0.5 ~ 2.0(patient & greedy)) - } else { - ((average_amplitude) * multiplier) + (standard_deviation_amplitude * 2.0) // 2.0 sigma (recommand: 0.5 ~ 2.0(patient & greedy)) - } - }; - - - if element.is_long == 0 || element.is_long == 1 { - if element.pure_profit_percent >= 0.0 { - let mut is_sell = false; - if element.maximum_profit_percent >= target_profit_percent(5.0) + 0.2 - && element.pure_profit_percent >= target_profit_percent(5.0) + 0.2 - { - println!( - "Selling {} 500% target_profit_percent: {:.3}", - element.symbol, - element.pure_profit_percent - ); - is_sell = true; - } else if element.pure_profit_percent >= 7.0 - { - println!( - "Selling {} 7% profit_percent", - element.symbol - ); - is_sell = true; - } else if server_epoch - element.close_time >= (3_600_000 * 24) && element.pure_profit_percent >= 0.2 // (1hr * 24) - { - println!( - "selling {} due to time up {:.3}", - element.symbol, - element.pure_profit_percent - ); - is_sell = true; - } - - if is_sell == true { - // let mut sell_price_ahead: Decimal = Decimal::new(14, 8); - // sell_price_ahead = decimal_mul(decimal_add(decimal_mul(decimal_mul(rust_decimal::Decimal::from_f64(element.pure_profit_percent).unwrap(), dec!(0.01)), dec!(0.97)), dec!(1)), element.buy_price).round_dp_with_strategy(2, RoundingStrategy::ToZero); - limit_order_sell( - &element, - element.current_price, - base_qty_to_be_ordered, - &client, - &exchange_info_vec, - &trade_fee_vec, - ) - .await; - } - } else { - let mut is_sell = false; - if element.pure_profit_percent <= target_profit_percent(-2.5) - 0.2 // -0.2 means about total trade fees. - { - println!( - "Selling {} -250% target_profit_percent: {:.3}", - element.symbol, - element.pure_profit_percent - ); - is_sell = true; - } else if element.pure_profit_percent <= -5.0 - { - println!( - "selling {} -5.0% profit", - element.symbol - ); - is_sell = true; - } - - if is_sell == true { - limit_order_sell( - &element, - element.current_price, - base_qty_to_be_ordered, - &client, - &exchange_info_vec, - &trade_fee_vec, - ) - .await; - } - } - } - } - } - - if sell_order_count == 25 { - // to avoid Limit of order: LIMIT 50 for 10 secs - sleep(Duration::from_secs(10)).await; - sell_order_count = 0; - } - } } - Ok(()) } @@ -832,7 +654,6 @@ async fn update_repeat_task( update_record.push(update_record_build.clone()); } } - } } @@ -2267,10 +2088,17 @@ async fn get_timestamp() -> String { timestamp } -pub async fn select_filled_buy_orders() -> Result, Box> { +// parameter 0: select all registerers +pub async fn select_filled_buy_orders(registerer: u32) -> Result, Box> { let select_table_name = String::from("buy_ordered_coin_list"); let select_columns = String::from("*"); - let select_condition = Some(String::from("WHERE status = 'FILLED' or status = 'SIMUL'")); + let mut select_condition_build = String::from("WHERE (status = 'FILLED' or status = 'SIMUL')"); + if registerer > 0 { + select_condition_build.push_str(" and registerer = "); + select_condition_build.push_str(registerer.to_string().as_str()); + } + let select_condition = Some(select_condition_build); + let data_struct = BuyOrderedCoinList::new(); let select_result = try_select_record( diff --git a/src/main.rs b/src/main.rs index a98df64..c326124 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,6 +58,8 @@ async fn main() -> Result<(), Box> { let tx_task7 = tx_task1.clone(); // for Task#7 let tx_task8 = tx_task1.clone(); // for Task#8 let tx_task9 = tx_task1.clone(); // for Task#9 + let tx_task10 = tx_task1.clone(); // for Task#10 + let tx_task11 = tx_task1.clone(); // for Task#11 let tx_task12 = tx_task1.clone(); // for Task#12 let tx_task13 = tx_task1.clone(); // for Task#13 let tx_task14 = tx_task1.clone(); // for Task#14 @@ -73,7 +75,6 @@ async fn main() -> Result<(), Box> { let tx_task24 = tx_task1.clone(); // for Task#24 let tx_task25 = tx_task1.clone(); // for Task#25 let tx_task26 = tx_task1.clone(); // for Task#26 - let tx_task27 = tx_task1.clone(); // for Task#27 let (tx1, mut rx1_1) = watch::channel(0); // local_epoch let mut rx1_2 = rx1_1.clone(); @@ -90,6 +91,7 @@ async fn main() -> Result<(), Box> { let mut rx2_tradefee_vec = rx_tradefee_vec.clone(); let mut rx3_tradefee_vec = rx_tradefee_vec.clone(); let mut rx4_tradefee_vec = rx_tradefee_vec.clone(); + let mut rx5_tradefee_vec = rx_tradefee_vec.clone(); // valid usdt trade data let mut valid_usdt_trade_vec: Vec = Vec::new(); // symbol @@ -97,6 +99,7 @@ async fn main() -> Result<(), Box> { watch::channel(valid_usdt_trade_vec); let mut rx2_valid_usdt_trade_vec = rx_valid_usdt_trade_vec.clone(); let mut rx3_valid_usdt_trade_vec = rx_valid_usdt_trade_vec.clone(); + let mut rx4_valid_usdt_trade_vec = rx_valid_usdt_trade_vec.clone(); // price per second data and channels let mut price_vec: Vec = Vec::new(); // (symbol, price) @@ -126,27 +129,32 @@ async fn main() -> Result<(), Box> { let mut rx2_rt_price_1m_vec = rx_rt_price_1m_vec.clone(); let mut rx3_rt_price_1m_vec = rx_rt_price_1m_vec.clone(); let mut rx4_rt_price_1m_vec = rx_rt_price_1m_vec.clone(); + let mut rx5_rt_price_1m_vec = rx_rt_price_1m_vec.clone(); let mut rt_price_30m_vec: Vec<(String, Vec)> = Vec::new(); let (tx_rt_price_30m_vec, mut rx_rt_price_30m_vec) = watch::channel(rt_price_30m_vec); let mut rx2_rt_price_30m_vec = rx_rt_price_30m_vec.clone(); let mut rx3_rt_price_30m_vec = rx_rt_price_30m_vec.clone(); let mut rx4_rt_price_30m_vec = rx_rt_price_30m_vec.clone(); + let mut rx5_rt_price_30m_vec = rx_rt_price_30m_vec.clone(); let mut rt_price_1d_vec: Vec<(String, Vec)> = Vec::new(); let (tx_rt_price_1d_vec, mut rx_rt_price_1d_vec) = watch::channel(rt_price_1d_vec); let mut rx2_rt_price_1d_vec = rx_rt_price_1d_vec.clone(); let mut rx3_rt_price_1d_vec = rx_rt_price_1d_vec.clone(); + let mut rx4_rt_price_1d_vec = rx_rt_price_1d_vec.clone(); let mut rt_price_1w_vec: Vec<(String, Vec)> = Vec::new(); let (tx_rt_price_1w_vec, mut rx_rt_price_1w_vec) = watch::channel(rt_price_1w_vec); let mut rx2_rt_price_1w_vec = rx_rt_price_1w_vec.clone(); let mut rx3_rt_price_1w_vec = rx_rt_price_1w_vec.clone(); + let mut rx4_rt_price_1w_vec = rx_rt_price_1w_vec.clone(); let mut rt_price_1mon_vec: Vec<(String, Vec)> = Vec::new(); let (tx_rt_price_1mon_vec, mut rx_rt_price_1mon_vec) = watch::channel(rt_price_1mon_vec); let mut rx2_rt_price_1mon_vec = rx_rt_price_1mon_vec.clone(); let mut rx3_rt_price_1mon_vec = rx_rt_price_1mon_vec.clone(); + let mut rx4_rt_price_1mon_vec = rx_rt_price_1mon_vec.clone(); // TEMA data // let mut tema3_1m_data: Vec<(String, Vec<(f64, i64)>)> = Vec::new(); // Vec<(symbol, Vec<(price, closetime)>)> @@ -189,6 +197,7 @@ async fn main() -> Result<(), Box> { let mut rx3_exchange_info_data = rx_exchange_info_data.clone(); let mut rx4_exchange_info_data = rx_exchange_info_data.clone(); let mut rx5_exchange_info_data = rx_exchange_info_data.clone(); + let mut rx6_exchange_info_data = rx_exchange_info_data.clone(); { if RUNNING_MODE == RunningMode::REAL { @@ -259,103 +268,99 @@ async fn main() -> Result<(), Box> { match result { Some(1) => { - print!("\r1[■] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[■] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(2) => { - print!("\r1[ ] 2[■] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[■] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(3) => { - print!("\r1[ ] 2[ ] 3[■] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[■] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(4) => { - print!("\r1[ ] 2[ ] 3[ ] 4[■] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[■] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(5) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[■] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[■] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(6) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[■] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[■] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(7) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[■] 8[] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[■] 8[] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(8) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[■ 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[■ 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(9) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[■] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[■] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(12) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[■] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[■] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(13) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[■] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[■] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(14) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[■] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[■] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(15) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[■] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[■] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(16) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[■] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[■] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(17) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[■] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[■] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(18) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[■] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[■] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(19) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[■] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[■] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(20) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[■] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[■] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(21) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[■] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[■] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(22) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[■] 23[ ] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[■] 23[ ] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(23) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[■] 24[ ] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[■] 24[ ] 25[ ] 26[ ]"); io::stdout().flush(); } Some(24) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[■] 25[ ] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[■] 25[ ] 26[ ]"); io::stdout().flush(); } Some(25) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[■] 26[ ] 27[ ]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[■] 26[ ]"); io::stdout().flush(); } Some(26) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[■] 27[ ]"); - io::stdout().flush(); - } - Some(27) => { - print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[ ] 27[■]"); + print!("\r1[ ] 2[ ] 3[ ] 4[ ] 5[ ] 6[ ] 7[ ] 8[ ] 9[ ] 12[ ] 13[ ] 14[ ] 15[ ] 16[ ] 17[ ] 18[ ] 19[ ] 20[ ] 21[ ] 22[ ] 23[ ] 24[ ] 25[ ] 26[■]"); io::stdout().flush(); } Some(_) => {} @@ -524,7 +529,7 @@ async fn main() -> Result<(), Box> { } }); - // Task#13: request lot stepsize and ticksize + // Task#3: request lot stepsize and ticksize tokio::task::spawn(async move { let client = ClientBuilder::new() .timeout(tokio::time::Duration::from_millis(3000)) @@ -551,8 +556,8 @@ async fn main() -> Result<(), Box> { match result { Ok(T) => { tx_exchange_info_data.send_modify(|vec| *vec = exchange_info_data_temp); - tx_task13 - .send(13) + tx_task3 + .send(3) .expect("The mpsc channel has been closed."); } Err(E) => {} @@ -561,7 +566,7 @@ async fn main() -> Result<(), Box> { } }); - // Task#3: request 24h price changes, + // Task#4: request 24h price changes, // pick valid USDT Trades, // filtering stop USDT Trades, // monitor total_24h_change_profit_index, @@ -588,7 +593,7 @@ async fn main() -> Result<(), Box> { Ok(T) => { tx_valid_usdt_trade_vec .send_modify(|vec| *vec = valid_usdt_trade_vec_temp); - tx_task3.send(3).expect("The mpsc channel has been closed."); + tx_task4.send(4).expect("The mpsc channel has been closed."); } Err(E) => {} } @@ -636,7 +641,7 @@ async fn main() -> Result<(), Box> { } }); - // Task#4: price per second + // Task#5: price per second tokio::task::spawn(async move { sleep(Duration::from_secs(20)).await; let client = ClientBuilder::new() @@ -655,7 +660,7 @@ async fn main() -> Result<(), Box> { Ok(T) => { price_vec_temp_c = price_vec_temp.clone(); tx_price_vec.send_modify(|vec| *vec = price_vec_temp); - tx_task4.send(4).expect("The mpsc channel has been closed."); + tx_task5.send(5).expect("The mpsc channel has been closed."); } Err(E) => {} } @@ -788,7 +793,7 @@ async fn main() -> Result<(), Box> { } }); - // Task#5: fetch candle 1m + // Task#6: fetch candle 1m tokio::task::spawn(async move { let mut elapsed_time = 0; let interval = String::from("1m"); @@ -801,7 +806,7 @@ async fn main() -> Result<(), Box> { match result { Ok(T) => { tx_candle_1m_vec.send_modify(|vec| *vec = candle_1m_vec_temp); - tx_task5.send(5).expect("The mpsc channel has been closed."); + tx_task6.send(6).expect("The mpsc channel has been closed."); } Err(E) => {} } @@ -814,7 +819,7 @@ async fn main() -> Result<(), Box> { } }); - // Task#6: fetch candle 30m + // Task#7: fetch candle 30m tokio::task::spawn(async move { let mut elapsed_time = 0; let interval = String::from("30m"); @@ -829,7 +834,7 @@ async fn main() -> Result<(), Box> { match result { Ok(T) => { tx_candle_30m_vec.send_modify(|vec| *vec = candle_30m_vec_temp); - tx_task6.send(6).expect("The mpsc channel has been closed."); + tx_task7.send(7).expect("The mpsc channel has been closed."); } Err(E) => {} } @@ -841,7 +846,7 @@ async fn main() -> Result<(), Box> { } }); - // Task#7: fetch candle 1d + // Task#8: fetch candle 1d tokio::task::spawn(async move { let mut elapsed_time = 0; let interval = String::from("1d"); @@ -855,7 +860,7 @@ async fn main() -> Result<(), Box> { match result { Ok(T) => { tx_candle_1d_vec.send_modify(|vec| *vec = candle_1d_vec_temp); - tx_task7.send(7).expect("The mpsc channel has been closed."); + tx_task8.send(8).expect("The mpsc channel has been closed."); } Err(E) => {} } @@ -867,7 +872,7 @@ async fn main() -> Result<(), Box> { } }); - // // Task#8: fetch candle 1w + // // Task#9: fetch candle 1w // tokio::task::spawn(async move{ // let interval = String::from("1w"); // sleep(Duration::from_secs(600)).await; @@ -878,14 +883,14 @@ async fn main() -> Result<(), Box> { // match result { // Ok(T) => { // tx_candle_1w_vec.send_modify(|vec| *vec = candle_1w_vec_temp); - // tx_task8.send(8).expect("The mpsc channel has been closed."); + // tx_task9.send(9).expect("The mpsc channel has been closed."); // } // Err(E) => {} // } // } // }); - // // Task#9: fetch candle 1mon + // // Task#10: fetch candle 1mon // tokio::task::spawn(async move{ // let interval = String::from("1mon"); // sleep(Duration::from_secs(600)).await; @@ -896,22 +901,22 @@ async fn main() -> Result<(), Box> { // match result { // Ok(T) => { // tx_candle_1mon_vec.send_modify(|vec| *vec = candle_1mon_vec_temp); - // tx_task9.send(9).expect("The mpsc channel has been closed."); + // tx_task10.send(10).expect("The mpsc channel has been closed."); // } // Err(E) => {} // } // } // }); - // Task#12: monitoring total market cap + // Task#11: monitoring total market cap if RUNNING_MODE == REAL || RUNNING_MODE == SIMUL || RUNNING_MODE == TEST { tokio::task::spawn(async move { loop { let result = signal_association::coinmarketcap::market_cap_index().await; match result { Ok(T) => { - tx_task12 - .send(12) + tx_task11 + .send(11) .expect("The mpsc channel has been closed."); } Err(E) => {} @@ -920,15 +925,15 @@ async fn main() -> Result<(), Box> { }); } - // Task#14: monitoring foreign exchange rate + // Task#12: monitoring foreign exchange rate if RUNNING_MODE == REAL || RUNNING_MODE == SIMUL { tokio::task::spawn(async move { loop { let result = signal_association::exchange_rate::monitoring_fx_rate_index().await; match result { Ok(T) => { - tx_task14 - .send(14) + tx_task12 + .send(12) .expect("The mpsc channel has been closed."); } Err(E) => {} @@ -938,14 +943,14 @@ async fn main() -> Result<(), Box> { }); } - // // // Task#15: monitoring dollar index + // // // Task#13: monitoring dollar index // // tokio::task::spawn(async move { // // loop // // { // // let result = signal_association::dollar_index::monitoring_dollar_index().await; // // match result { // // Ok(T) => { - // // tx_task15.send(15).expect("The mpsc channel has been closed."); + // // tx_task13.send(13).expect("The mpsc channel has been closed."); // // } // // Err(E) => {} // // } @@ -953,7 +958,7 @@ async fn main() -> Result<(), Box> { // // } // // }); - // Task#16: monitoring signal decision + // Task#14: monitoring signal decision if RUNNING_MODE == REAL || RUNNING_MODE == SIMUL || RUNNING_MODE == TEST { tokio::task::spawn(async move { loop { @@ -961,8 +966,8 @@ async fn main() -> Result<(), Box> { signal_association::signal_decision::monitoring_signal_decision().await; match result { Ok(T) => { - tx_task16 - .send(16) + tx_task14 + .send(14) .expect("The mpsc channel has been closed."); } Err(E) => {} @@ -973,15 +978,15 @@ async fn main() -> Result<(), Box> { }); } - // Task#17: monitoring future ratio + // Task#15: monitoring future ratio if RUNNING_MODE == REAL || RUNNING_MODE == SIMUL || RUNNING_MODE == TEST { tokio::task::spawn(async move { loop { let result = signal_association::future_ratio::monitoring_future_ratio().await; match result { Ok(T) => { - tx_task17 - .send(17) + tx_task15 + .send(15) .expect("The mpsc channel has been closed."); } Err(E) => {} @@ -993,7 +998,7 @@ async fn main() -> Result<(), Box> { } // COEX part - // Task#18: strategists + // Task#16: execute strategis for buy if RUNNING_MODE == REAL || RUNNING_MODE == SIMUL { tokio::task::spawn(async move { sleep(Duration::from_secs(40)).await; @@ -1007,15 +1012,15 @@ async fn main() -> Result<(), Box> { all_data.rt_price_1m_vec = rx3_rt_price_1m_vec.borrow().clone(); all_data.rt_price_30m_vec = rx3_rt_price_30m_vec.borrow().clone(); all_data.rt_price_1d_vec = rx3_rt_price_1d_vec.borrow().clone(); - // all_data.rt_price_1w_vec = rx3_rt_price_1w_vec.borrow().clone(); - // all_data.rt_price_1mon_vec = rx3_rt_price_1mon_vec.borrow().clone(); + all_data.rt_price_1w_vec = rx3_rt_price_1w_vec.borrow().clone(); + all_data.rt_price_1mon_vec = rx3_rt_price_1mon_vec.borrow().clone(); let result = strategy_team::strategy_manager::execute_list_up_for_buy(&all_data).await; match result { Ok(T) => { - tx_task18 - .send(18) + tx_task16 + .send(16) .expect("The mpsc channel has been closed."); } Err(E) => { @@ -1049,8 +1054,8 @@ async fn main() -> Result<(), Box> { // match result { // Ok(T) => { - // tx_task18 - // .send(18) + // tx_task16 + // .send(16) // .expect("The mpsc channel has been closed."); // } // Err(E) => {} @@ -1065,7 +1070,49 @@ async fn main() -> Result<(), Box> { }); } - // Task#19: monitoring pre-suggested coins + // Task#17: execute strategis for sell + if RUNNING_MODE == REAL || RUNNING_MODE == SIMUL { + tokio::task::spawn(async move { + sleep(Duration::from_secs(40)).await; + let mut all_data = AllData::new(); + let mut exchange_info_vec: Vec = Vec::new(); + let mut trade_fee_vec: Vec = Vec::new(); + let mut elapsed_time = 0; + loop { + let instant = Instant::now(); + all_data.valid_symbol_vec = rx4_valid_usdt_trade_vec.borrow().clone(); + exchange_info_vec = rx6_exchange_info_data.borrow().clone(); + trade_fee_vec = rx5_tradefee_vec.borrow().clone(); + // realtime price data + all_data.rt_price_1m_vec = rx5_rt_price_1m_vec.borrow().clone(); + all_data.rt_price_30m_vec = rx5_rt_price_30m_vec.borrow().clone(); + all_data.rt_price_1d_vec = rx4_rt_price_1d_vec.borrow().clone(); + all_data.rt_price_1w_vec = rx4_rt_price_1w_vec.borrow().clone(); + all_data.rt_price_1mon_vec = rx4_rt_price_1mon_vec.borrow().clone(); + + let result = strategy_team::strategy_manager::execute_list_up_for_sell(&all_data, &exchange_info_vec, &trade_fee_vec).await; + + match result { + Ok(T) => { + tx_task17 + .send(17) + .expect("The mpsc channel has been closed."); + } + Err(E) => { + // eprintln!("Couldn't execute strategists."); + } + } + + // sleep as much as the loop recurs per 1 second if all operation finished within 1 second. + elapsed_time = instant.elapsed().as_millis(); + if 250 > elapsed_time { + sleep(Duration::from_millis((250 - elapsed_time) as u64)).await; + } + } + }); + } + + // Task#18: monitoring pre-suggested coins tokio::task::spawn(async move { sleep(Duration::from_secs(30)).await; let mut elapsed_time = 0; @@ -1077,8 +1124,8 @@ async fn main() -> Result<(), Box> { // send Task#0 a message to notify running on match result { Ok(T) => { - tx_task19 - .send(19) + tx_task18 + .send(18) .expect("The mpsc channel has been closed."); } Err(E) => {} @@ -1092,7 +1139,7 @@ async fn main() -> Result<(), Box> { } }); - // Task#20: buy_coin + // Task#19: buy_coin if RUNNING_MODE == REAL || RUNNING_MODE == SIMUL || RUNNING_MODE == TEST { tokio::task::spawn(async move { sleep(Duration::from_secs(30)).await; @@ -1111,8 +1158,8 @@ async fn main() -> Result<(), Box> { // send Task#0 a message to notify running on match result { Ok(T) => { - tx_task20 - .send(20) + tx_task19 + .send(19) .expect("The mpsc channel has been closed."); } Err(E) => { @@ -1145,8 +1192,8 @@ async fn main() -> Result<(), Box> { // send Task#0 a message to notify running on match result { Ok(T) => { - tx_task20 - .send(20) + tx_task19 + .send(19) .expect("The mpsc channel has been closed."); } Err(E) => {} @@ -1160,7 +1207,7 @@ async fn main() -> Result<(), Box> { }); } - // Task#21: monitoring_open_buy_order + // Task#20: monitoring_open_buy_order if RUNNING_MODE == REAL || RUNNING_MODE == TEST { tokio::task::spawn(async move { if RUNNING_MODE == REAL { @@ -1187,8 +1234,8 @@ async fn main() -> Result<(), Box> { // send Task#0 a message to notify running on match result { Ok(T) => { - tx_task21 - .send(21) + tx_task20 + .send(20) .expect("The mpsc channel has been closed."); } Err(E) => {} @@ -1203,7 +1250,7 @@ async fn main() -> Result<(), Box> { }); } - // Task#22: monitoring_filled_buy_order + // Task#21: update_price_of_filled_buy_order tokio::task::spawn(async move { if RUNNING_MODE == TEST { sleep(Duration::from_secs(10)).await; @@ -1211,18 +1258,13 @@ async fn main() -> Result<(), Box> { sleep(Duration::from_secs(30)).await; } let mut elapsed_time = 0; - let mut all_data = AllData::new(); loop { let instant = Instant::now(); let coin_price_vec = rx5_price_vec.borrow().clone(); let exchange_info_vec = rx2_exchange_info_data.borrow().clone(); let trade_fee_vec = rx3_tradefee_vec.borrow().clone(); - // realtime price data - all_data.rt_price_30m_vec = rx4_rt_price_30m_vec.borrow().clone(); - - let result = coex::order_team::monitoring_filled_buy_order( - &all_data, + let result = coex::order_team::update_price_of_filled_buy_order( &coin_price_vec, &exchange_info_vec, &trade_fee_vec, @@ -1232,8 +1274,8 @@ async fn main() -> Result<(), Box> { // send Task#0 a message to notify running on match result { Ok(T) => { - tx_task22 - .send(22) + tx_task21 + .send(21) .expect("The mpsc channel has been closed."); } Err(E) => {} @@ -1248,7 +1290,7 @@ async fn main() -> Result<(), Box> { } }); - // Task#23: monitoring_open_sell_order + // Task#22: monitoring_open_sell_order if RUNNING_MODE == REAL || RUNNING_MODE == TEST { tokio::task::spawn(async move { if RUNNING_MODE == REAL { @@ -1275,8 +1317,8 @@ async fn main() -> Result<(), Box> { // send Task#0 a message to notify running on match result { Ok(T) => { - tx_task23 - .send(23) + tx_task22 + .send(22) .expect("The mpsc channel has been closed."); } Err(E) => {} @@ -1291,7 +1333,7 @@ async fn main() -> Result<(), Box> { }); } - // Task#24: monitoring_filled_sell_order + // Task#23: monitoring_filled_sell_order tokio::task::spawn(async move { let client = ClientBuilder::new() .timeout(tokio::time::Duration::from_millis(3000)) @@ -1302,6 +1344,36 @@ async fn main() -> Result<(), Box> { let instant = Instant::now(); let result = coex::order_team::monitoring_filled_sell_order(&client).await; + // send Task#0 a message to notify running on + match result { + Ok(T) => { + tx_task23 + .send(23) + .expect("The mpsc channel has been closed."); + } + Err(E) => {} + } + + // sleep as much as the loop recurs per 1 second if all operation finished within 1 second. + elapsed_time = instant.elapsed().as_millis(); + if 200 > elapsed_time { + sleep(Duration::from_millis((200 - elapsed_time) as u64)).await; + } + } + }); + + // Task#24: monitoring_scoreboard + tokio::task::spawn(async move { + let mut elapsed_time = 0; + let mut all_data = AllData::new(); + loop { + let instant = Instant::now(); + + // realtime price data + all_data.rt_price_1m_vec = rx4_rt_price_1m_vec.borrow().clone(); + + let result = coex::exchange_team::monitoring_scoreboard(&all_data).await; + // send Task#0 a message to notify running on match result { Ok(T) => { @@ -1320,37 +1392,7 @@ async fn main() -> Result<(), Box> { } }); - // Task#25: monitoring_scoreboard - tokio::task::spawn(async move { - let mut elapsed_time = 0; - let mut all_data = AllData::new(); - loop { - let instant = Instant::now(); - - // realtime price data - all_data.rt_price_1m_vec = rx4_rt_price_1m_vec.borrow().clone(); - - let result = coex::exchange_team::monitoring_scoreboard(&all_data).await; - - // send Task#0 a message to notify running on - match result { - Ok(T) => { - tx_task25 - .send(25) - .expect("The mpsc channel has been closed."); - } - Err(E) => {} - } - - // sleep as much as the loop recurs per 1 second if all operation finished within 1 second. - elapsed_time = instant.elapsed().as_millis(); - if 200 > elapsed_time { - sleep(Duration::from_millis((200 - elapsed_time) as u64)).await; - } - } - }); - - // Task#26: update current_total_usdt and available_usdt + // Task#25: update current_total_usdt and available_usdt tokio::task::spawn(async move { let client = ClientBuilder::new() .timeout(tokio::time::Duration::from_millis(3000)) @@ -1367,8 +1409,8 @@ async fn main() -> Result<(), Box> { // send Task#0 a message to notify running on match result { Ok(T) => { - tx_task26 - .send(26) + tx_task25 + .send(25) .expect("The mpsc channel has been closed."); } Err(E) => { @@ -1384,7 +1426,7 @@ async fn main() -> Result<(), Box> { } }); - // Task#27: update kelly_criterion + // Task#26: update kelly_criterion tokio::task::spawn(async move { let mut elapsed_time = 0; loop { @@ -1395,8 +1437,8 @@ async fn main() -> Result<(), Box> { // send Task#0 a message to notify running on match result { Ok(T) => { - tx_task27 - .send(27) + tx_task26 + .send(26) .expect("The mpsc channel has been closed."); } Err(E) => { diff --git a/src/strategy_team/mod.rs b/src/strategy_team/mod.rs index 7467a9f..a5cf0e7 100644 --- a/src/strategy_team/mod.rs +++ b/src/strategy_team/mod.rs @@ -19,7 +19,12 @@ use crate::value_estimation_team::indicators::supertrend::{supertrend, Supertren use crate::value_estimation_team::indicators::heatmap_volume::{ heatmap_volume, HeatMapLevel, HeatmapVolumeData, }; +use crate::coex::order_team::{limit_order_sell, select_filled_buy_orders}; +use crate::coin_health_check_team::request_others::{ExchangeInfo, TradeFee}; use futures::future::try_join_all; +use reqwest::{Client, ClientBuilder}; +use rust_decimal::{prelude::FromPrimitive, prelude::ToPrimitive, Decimal, RoundingStrategy}; +use rust_decimal_macros::dec; use sqlx::FromRow; use tokio::sync::Mutex; diff --git a/src/strategy_team/strategy_003.rs b/src/strategy_team/strategy_003.rs index 9ae9897..fa6fa71 100644 --- a/src/strategy_team/strategy_003.rs +++ b/src/strategy_team/strategy_003.rs @@ -1,4 +1,4 @@ -use super::{AllData, RealtimePriceData, Mutex, Arc, try_join_all, exists_record, StochRsiData, EmaData, SupertrendData, RsiData, stoch_rsi, ema, rsi, supertrend}; +use super::{limit_order_sell, AllData, RealtimePriceData, Mutex, Arc, try_join_all, exists_record, StochRsiData, EmaData, SupertrendData, RsiData, stoch_rsi, ema, rsi, supertrend, select_filled_buy_orders, ExchangeInfo, TradeFee, Client, ClientBuilder, dec, RoundingStrategy}; pub async fn list_up_for_buy( alldata: &AllData, @@ -282,5 +282,168 @@ pub async fn list_up_for_buy( let a = filtered_symbols_arc.lock().await.clone(); super::strategy_manager::insert_pre_suggested_coins(3, false, &a, alldata).await; + Ok(()) +} + +pub async fn list_up_for_sell( + all_data: &AllData, + exchange_info_vec: &Vec, + trade_fee_vec: &Vec, +) -> Result<(), Box> { + let filled_buy_orders = select_filled_buy_orders(3).await?; + + if !filled_buy_orders.is_empty() { + let client = ClientBuilder::new() + .timeout(tokio::time::Duration::from_millis(5000)) + .build() + .unwrap(); + + let mut sell_order_count = 0; + for element in filled_buy_orders { + if element.used_usdt >= dec!(10.0) { + // ignore coins having 10 usdt below because of not traded + let sell_percent_for_uptrend = |z: f64| 0.94 * z - 0.5; + + let lot_step_size_option = exchange_info_vec + .iter() + .find(|ExchangeInfo| ExchangeInfo.symbol == element.symbol); + let quote_commission_precision_option = exchange_info_vec + .iter() + .find(|ExchangeInfo| ExchangeInfo.symbol == element.symbol); + + let opclo_30m_option = all_data + .rt_price_30m_vec + .iter() + .position(|x| *x.0 == element.symbol); + + if lot_step_size_option.is_some() + && quote_commission_precision_option.is_some() + && opclo_30m_option.is_some() + { + let lot_step_size = lot_step_size_option.unwrap().stepsize; + let quote_commission_precision = quote_commission_precision_option + .unwrap() + .quote_commission_precision; + let base_qty_to_be_ordered = + element.base_qty_fee_adjusted.round_dp_with_strategy( + lot_step_size.normalize().scale(), + RoundingStrategy::ToZero, + ); + + let mut opclo_30m_vec = all_data.rt_price_30m_vec[opclo_30m_option.unwrap()] + .1 + .clone(); + + opclo_30m_vec.pop(); + opclo_30m_vec.reverse(); + let mut opclo_sample_length: usize = 50; // 50 candle samsples + let nbr_of_exclusive: usize = 5; + opclo_30m_vec.truncate(opclo_sample_length); + opclo_30m_vec.sort_by(|a, b| (a.high_price-a.low_price).total_cmp(&(b.high_price-b.low_price))); + opclo_30m_vec.truncate(opclo_sample_length - nbr_of_exclusive); + opclo_sample_length -= nbr_of_exclusive; + + let mut sum_amplitude_candles = 0.0; + let mut sum_ratio_amp_body = 0.0; + for element in &opclo_30m_vec { + sum_amplitude_candles += + ((element.high_price / element.low_price) - 1.0) * 100.0; + sum_ratio_amp_body += (element.close_price - element.open_price).abs() + / (element.high_price - element.low_price); + } + let average_amplitude = sum_amplitude_candles / opclo_sample_length as f64; // percent unit + let average_ratio_amp_body = sum_ratio_amp_body / opclo_sample_length as f64; + + let mut amplitude_variance = 0.0; + for element in &opclo_30m_vec { + amplitude_variance += ((((element.high_price / element.low_price) - 1.0) + * 100.0) + - average_amplitude) + .powi(2); + } + amplitude_variance = amplitude_variance / (opclo_sample_length - 1) as f64; + let standard_deviation_amplitude = amplitude_variance.sqrt(); + + // let target_profit_percent = average_amplitude + (standard_deviation_amplitude * (average_ratio_amp_body)); + let target_profit_percent = |multiplier: f64| -> f64 { + if multiplier < 0.0 { + ((average_amplitude) * multiplier) - (standard_deviation_amplitude * 2.0) // 2.0 sigma (recommand: 0.5 ~ 2.0(patient & greedy)) + } else { + ((average_amplitude) * multiplier) + (standard_deviation_amplitude * 2.0) // 2.0 sigma (recommand: 0.5 ~ 2.0(patient & greedy)) + } + }; + + + if element.is_long == 0 || element.is_long == 1 { + if element.pure_profit_percent >= 0.0 { + let mut is_sell = false; + if element.maximum_profit_percent >= target_profit_percent(5.0) + 0.2 + && element.pure_profit_percent >= target_profit_percent(5.0) + 0.2 + { + println!( + "Selling {} 500% target_profit_percent: {:.3}", + element.symbol, + element.pure_profit_percent + ); + is_sell = true; + } else if element.pure_profit_percent >= 7.0 + { + println!( + "Selling {} 7% profit_percent", + element.symbol + ); + is_sell = true; + } + + if is_sell == true { + // let mut sell_price_ahead: Decimal = Decimal::new(14, 8); + // sell_price_ahead = decimal_mul(decimal_add(decimal_mul(decimal_mul(rust_decimal::Decimal::from_f64(element.pure_profit_percent).unwrap(), dec!(0.01)), dec!(0.97)), dec!(1)), element.buy_price).round_dp_with_strategy(2, RoundingStrategy::ToZero); + limit_order_sell( + &element, + element.current_price, + base_qty_to_be_ordered, + &client, + &exchange_info_vec, + &trade_fee_vec, + ) + .await; + } + } else { + let mut is_sell = false; + if element.pure_profit_percent <= target_profit_percent(-2.5) - 0.2 // -0.2 means about total trade fees. + { + println!( + "Selling {} -250% target_profit_percent: {:.3}", + element.symbol, + element.pure_profit_percent + ); + is_sell = true; + } else if element.pure_profit_percent <= -5.0 + { + println!( + "selling {} -5.0% profit", + element.symbol + ); + is_sell = true; + } + + if is_sell == true { + limit_order_sell( + &element, + element.current_price, + base_qty_to_be_ordered, + &client, + &exchange_info_vec, + &trade_fee_vec, + ) + .await; + } + } + } + } + } + } + } + Ok(()) } \ No newline at end of file diff --git a/src/strategy_team/strategy_manager.rs b/src/strategy_team/strategy_manager.rs index 6cde5b5..1fb931b 100644 --- a/src/strategy_team/strategy_manager.rs +++ b/src/strategy_team/strategy_manager.rs @@ -8,7 +8,7 @@ use serde::Deserialize; use tokio::time::{sleep, Duration, Instant}; use crate::signal_association::signal_decision::*; -use super::{AllData, RealtimePriceData, exists_record, try_select_record, insert_one_record, FromRow}; +use super::{AllData, RealtimePriceData, exists_record, try_select_record, insert_one_record, FromRow, ExchangeInfo, TradeFee}; #[derive(Debug, FromRow)] struct ServerEpoch { @@ -38,6 +38,17 @@ pub async fn execute_list_up_for_buy( Ok(()) } +pub async fn execute_list_up_for_sell( + all_data: &AllData, + exchange_info_vec: &Vec, + trade_fee_vec: &Vec +) -> Result<(), Box> { + + crate::strategy_team::strategy_003::list_up_for_sell(all_data, exchange_info_vec, trade_fee_vec).await?; + + Ok(()) +} + // useful functions for strategists pub async fn get_current_price( symbol: &String,