From 689a3cd8a726b3862f9642bbb92f0414c162539f Mon Sep 17 00:00:00 2001 From: Sik Yoon Date: Sun, 19 Nov 2023 23:29:56 +0900 Subject: [PATCH] Define FilteredData struct --- src/strategy_team/mod.rs | 26 +- src/strategy_team/strategy_004.rs | 538 ++++++++++++++------------ src/strategy_team/strategy_manager.rs | 184 +++++---- 3 files changed, 416 insertions(+), 332 deletions(-) diff --git a/src/strategy_team/mod.rs b/src/strategy_team/mod.rs index cc3cb47..56d8196 100644 --- a/src/strategy_team/mod.rs +++ b/src/strategy_team/mod.rs @@ -24,11 +24,13 @@ 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 crate::decimal_funcs::*; use sqlx::FromRow; use std::sync::Arc; use tokio::sync::Mutex; +use strategy_manager::insert_pre_suggested_coins; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct AllData { pub valid_symbol_vec: Vec, pub rt_price_1m_vec: Vec<(String, Vec)>, @@ -61,3 +63,25 @@ pub struct TimeData { pub last_server_epoch: u64, pub last_server_ymdhs: String, } + +#[derive(Clone)] +pub struct FilteredData { + pub symbol: String, + pub closetime: i64, + pub stoploss: Decimal, + pub target_price: Decimal, + pub current_price: Decimal, +} + +impl FilteredData { + fn new() -> FilteredData { + let a = FilteredData { + symbol: String::new(), + closetime: 0, + stoploss: Decimal::new(0, 8), + target_price: Decimal::new(0, 8), + current_price: Decimal::new(0, 8), + }; + a + } +} \ No newline at end of file diff --git a/src/strategy_team/strategy_004.rs b/src/strategy_team/strategy_004.rs index aee0bc3..9820270 100644 --- a/src/strategy_team/strategy_004.rs +++ b/src/strategy_team/strategy_004.rs @@ -1,268 +1,310 @@ -// 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()); +use super::{ + dec, ema, exists_record, limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, + supertrend, try_join_all, AllData, Arc, Client, ClientBuilder, EmaData, ExchangeInfo, Mutex, + RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, + insert_pre_suggested_coins, Decimal, FilteredData, decimal_add, decimal_sub +}; -// // 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; +// Triple SuperTrend strategy +// SuperTrend length: 10, multiplier: 5, already up area +// SuperTrend length: 10, multiplier: 3, already up area +// SuperTrend length: 10, multiplier: 1.2, buy signal +pub async fn list_up_for_buy( + 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()); -// 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(); + // 1st 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"); -// 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?; + let mut filtered_data_1st: Vec = Vec::new(); + let mut filtered_data_1st_arc: Arc>> = + Arc::new(Mutex::new(filtered_data_1st)); + let mut task_vec = Vec::new(); -// // 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"); + for symbol in &alldata.valid_symbol_vec { + let mut exists_condition_build = String::from("symbol=\'"); + exists_condition_build.push_str(symbol.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 symbol_c = symbol.clone(); + let filtered_data_1st_arc_c = Arc::clone(&filtered_data_1st_arc); + task_vec.push(tokio::spawn(async move { + let mut filtered_data = FilteredData::new(); + 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; -// 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(); + if inspect_result_1 == false + && inspect_result_2 == false + && inspect_result_3 == false + && inspect_result_4 == false + { + let mut filtered_data_1st_lock = filtered_data_1st_arc_c.lock().await; + + filtered_data.symbol = symbol_c; + + filtered_data_1st_lock.push(filtered_data); + } + })); + } + try_join_all(task_vec).await?; -// 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; + // 2nd filtering: supertrend(ATR period 10, multiplier: 5.0, 30m close price), the area should be in UP area. + let filtered_data_1st = filtered_data_1st_arc.lock().await.clone(); + let mut filtered_data_2nd: Vec = Vec::new(); + let mut filtered_data_2nd_arc: Arc>> = + Arc::new(Mutex::new(filtered_data_2nd)); + let mut task_vec = Vec::new(); + + for element in filtered_data_1st { + let mut rt_30m_vec: Vec = Vec::new(); + let mut supertrend_vec: Vec = Vec::new(); + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + let filtered_data_2nd_arc_c = Arc::clone(&filtered_data_2nd_arc); + task_vec.push(tokio::spawn(async move { + let mut filtered_data = FilteredData::new(); + let rt_30m_option = rt_price_30m_vec_c.iter().position(|x| *x.0 == element.symbol); + let supertrend_option_30m = + supertrend(&element.symbol, &rt_price_30m_vec_c, 10, 5.0, true).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?; + if rt_30m_option.is_some() && supertrend_option_30m.is_some() { + rt_30m_vec = rt_price_30m_vec_c[rt_30m_option.unwrap()].1.clone(); + supertrend_vec = supertrend_option_30m.unwrap(); -// // 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?; + if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 { + let supertrend_search_result = supertrend_vec.binary_search_by_key( + &rt_30m_vec.last().unwrap().close_time, + |SupertrendData { + band_value, + signal, + area, + close_time, + }| *close_time, + ); + if supertrend_search_result.is_ok() { + if supertrend_vec[supertrend_search_result.unwrap()] + .area + .contains("UP") + { + let mut filtered_data_2nd_lock = + filtered_data_2nd_arc_c.lock().await; + + filtered_data.symbol = element.symbol.clone(); + filtered_data.closetime = rt_30m_vec.last().unwrap().close_time; + filtered_data.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_30m_vec.last().unwrap().close_price).unwrap(); + filtered_data_2nd_lock + .push(filtered_data); + } + } + } + } + })); + } + try_join_all(task_vec).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); + // 3rd filtering: supertrend(ATR period 10, multiplier: 3.0, 30m close price), the area should be in UP area. + let filtered_data_2nd = filtered_data_2nd_arc.lock().await.clone(); + let mut filtered_data_3rd: Vec = Vec::new(); + let mut filtered_data_3rd_arc: Arc>> = + Arc::new(Mutex::new(filtered_data_3rd)); + let mut task_vec = Vec::new(); + let valid_symbol_vec_c = alldata.valid_symbol_vec.clone(); + for element in filtered_data_2nd { + 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_data_3rd_arc_c = Arc::clone(&filtered_data_3rd_arc); + task_vec.push(tokio::spawn(async move { + let mut filtered_data = FilteredData::new(); + let supertrend_option_30m = + supertrend(&element.symbol, &rt_price_30m_vec_c, 10, 3.0, true).await; -// 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 supertrend_option_30m.is_some() { + supertrend_vec = supertrend_option_30m.unwrap(); -// 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 supertrend_vec.len() >= 3 { + let supertrend_search_result = supertrend_vec.binary_search_by_key( + &element.closetime, + |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_3rd_symbols_lock = + filtered_data_3rd_arc_c.lock().await; + + filtered_data.symbol = element.symbol.clone(); + filtered_data.closetime = element.closetime; + filtered_data.current_price = element.current_price; + + filtered_3rd_symbols_lock + .push(filtered_data); + } + } + } + } + })); + } + try_join_all(task_vec).await?; -// 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, -// ); + // 4th filtering: supertrend(ATR period 10, multiplier: 1.2, 30m close price), the area should be in UP area. + // set stoploss and target_price + let filtered_data_3rd_c = filtered_data_3rd_arc.lock().await.clone(); + let mut filtered_data_4th: Vec = Vec::new(); + let mut filtered_data_4th_arc: Arc>> = + Arc::new(Mutex::new(filtered_data_4th)); + let mut task_vec = Vec::new(); + for element in filtered_data_3rd_c { + let mut supertrend_vec: Vec = Vec::new(); + let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone(); + let filtered_data_4th_arc_c = Arc::clone(&filtered_data_4th_arc); + + task_vec.push(tokio::spawn(async move { + let supertrend_option_30m = + supertrend(&element.symbol, &rt_price_30m_vec_c, 10, 1.2, true).await; + let mut filtered_data = FilteredData::new(); + if supertrend_option_30m.is_some() { + supertrend_vec = supertrend_option_30m.unwrap(); -// 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?; + if supertrend_vec.len() >= 3 { + let supertrend_search_result = supertrend_vec.binary_search_by_key( + &element.closetime, + |SupertrendData { + band_value, + signal, + area, + close_time, + }| *close_time, + ); + if supertrend_search_result.is_ok() { + let supertrend_prev_element = supertrend_vec[supertrend_search_result.unwrap()-1].clone(); + let supertrend_element = supertrend_vec[supertrend_search_result.unwrap()].clone(); + if supertrend_element.signal.is_some_and(|x| x.contains("BUY")) + && element.current_price < rust_decimal::prelude::FromPrimitive::from_f64(supertrend_prev_element.band_value * 1.003).unwrap() + { + let mut filtered_data_4th_lock = + filtered_data_4th_arc_c.lock().await; + + filtered_data.symbol = element.symbol.clone(); + filtered_data.closetime = element.closetime; + filtered_data.current_price = element.current_price; + filtered_data.stoploss = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_element.band_value).unwrap(); + let target_price = decimal_add(element.current_price, decimal_sub(element.current_price, filtered_data.stoploss)); + filtered_data.target_price = target_price; + + filtered_data_4th_lock + .push(filtered_data); + } + } + } + } + })); + } + 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(); + let final_filtered_data = filtered_data_4th_arc.lock().await.clone(); + insert_pre_suggested_coins(4, false, &final_filtered_data, &alldata).await; + + Ok(()) +} -// 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); -// } -// } -// } -// } -// } -// } +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(4).await?; -// // 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(); + if !filled_buy_orders.is_empty() { + let client = ClientBuilder::new() + .timeout(tokio::time::Duration::from_millis(5000)) + .build() + .unwrap(); -// 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, -// )); -// } -// } -// })); -// } + for element in filled_buy_orders { + if element.used_usdt >= dec!(10.0) { -// try_join_all(task_vec).await?; + let lot_step_size_option = exchange_info_vec + .iter() + .find(|exchange_info| exchange_info.symbol == element.symbol); + let quote_commission_precision_option = exchange_info_vec + .iter() + .find(|exchange_info| exchange_info.symbol == element.symbol); -// let a = filtered_symbols_arc.lock().await.clone(); -// insert_pre_suggested_coins(4, false, &a, alldata).await; + let opclo_30m_option = all_data + .rt_price_30m_vec + .iter() + .position(|x| *x.0 == element.symbol); -// Ok(()) -// } + 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, + ); + + if (element.is_long == 0 || element.is_long == 1) && !element.current_price.is_zero() { + if element.current_price >= element.target_price { + println!("target selling {} {}", element.symbol, element.pure_profit_percent); + limit_order_sell( + &element, + element.current_price, + base_qty_to_be_ordered, + &client, + &exchange_info_vec, + &trade_fee_vec, + ) + .await; + } else if element.current_price <= element.stoploss { + println!("stoploss selling {} {}", element.symbol, element.pure_profit_percent); + 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 22c95ce..7bd05fb 100644 --- a/src/strategy_team/strategy_manager.rs +++ b/src/strategy_team/strategy_manager.rs @@ -8,7 +8,7 @@ use serde::Deserialize; use super::{ exists_record, insert_one_record, try_select_record, AllData, ExchangeInfo, FromRow, - RealtimePriceData, TradeFee, + RealtimePriceData, TradeFee, FilteredData, try_join_all }; use crate::signal_association::signal_decision::*; use tokio::time::{sleep, Duration, Instant}; @@ -31,13 +31,22 @@ struct Record { pub async fn execute_list_up_for_buy( all_data: &AllData, ) -> Result<(), Box> { + let mut task_vec = Vec::new(); + // let all_data_c3 = all_data.clone(); + let all_data_c4 = all_data.clone(); // strategist_001(all_data).await?; // strategist_002(all_data).await?; - crate::strategy_team::strategy_003::list_up_for_buy(all_data).await?; + // task_vec.push(tokio::spawn(async move { + // crate::strategy_team::strategy_003::list_up_for_buy(all_data_c3).await; + // })); + task_vec.push(tokio::spawn(async move { + crate::strategy_team::strategy_004::list_up_for_buy(all_data_c4).await; + })); // strategist_004(all_data).await?; // strategist_005(all_data).await?; // strategist_006(all_data).await?; + try_join_all(task_vec).await?; Ok(()) } @@ -46,7 +55,8 @@ pub async fn execute_list_up_for_sell( exchange_info_vec: &Vec, trade_fee_vec: &Vec, ) -> Result<(), Box> { - crate::strategy_team::strategy_003::list_up_for_sell( + + crate::strategy_team::strategy_004::list_up_for_sell( all_data, exchange_info_vec, trade_fee_vec, @@ -77,9 +87,8 @@ pub async fn get_current_price( pub async fn insert_pre_suggested_coins( registerer: i32, is_long: bool, - filtered_symbols: &Vec<(String, i64, f64)>, + filtered_coins: &Vec, alldata: &AllData, - target_price: Decimal ) -> Result<(), Box> { // Check the existance of record that is registered by this strategist let mut dest_table_name = String::from("suggested_coin_list"); @@ -97,6 +106,7 @@ pub async fn insert_pre_suggested_coins( "close_time", "suggested_price", "current_price", + "stoploss", "target_price", "registered_server_epoch", "profit_percent", @@ -154,12 +164,12 @@ pub async fn insert_pre_suggested_coins( .await?; // insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list] - for filtered_element in filtered_symbols { + for filtered_coin in filtered_coins { let mut is_dupe = false; // initialize for list_element in &suggested_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -167,8 +177,8 @@ pub async fn insert_pre_suggested_coins( } for list_element in &ordered_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -176,8 +186,8 @@ pub async fn insert_pre_suggested_coins( } for list_element in &pre_suggested_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -186,11 +196,12 @@ pub async fn insert_pre_suggested_coins( if is_dupe == false { let mut insert_values = vec![ - filtered_element.0.clone(), // symbol - filtered_element.1.to_string(), // close_time - filtered_element.2.to_string(), // suggested_price - filtered_element.2.to_string(), // current_price - target_price.to_string(), // target_price + filtered_coin.symbol.clone(), // symbol + filtered_coin.closetime.to_string(), // close_time + filtered_coin.current_price.to_string(), // suggested_price + filtered_coin.current_price.to_string(), // current_price + filtered_coin.stoploss.to_string(), // stoploss + filtered_coin.target_price.to_string(), // target_price server_epoch().await.to_string(), // registered_server_epoch 0.0.to_string(), // profit_percent 0.0.to_string(), // minimum_profit_percent @@ -248,12 +259,12 @@ pub async fn insert_pre_suggested_coins( .await?; // insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list] - for filtered_element in filtered_symbols { + for filtered_coin in filtered_coins { let mut is_dupe = false; // initialize for list_element in &suggested_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -261,8 +272,8 @@ pub async fn insert_pre_suggested_coins( } for list_element in &ordered_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -271,11 +282,12 @@ pub async fn insert_pre_suggested_coins( if is_dupe == false { let mut insert_values = vec![ - filtered_element.0.clone(), // symbol - filtered_element.1.to_string(), // close_time - filtered_element.2.to_string(), // suggested_price - filtered_element.2.to_string(), // current_price - target_price.to_string(), // target_price + filtered_coin.symbol.clone(), // symbol + filtered_coin.closetime.to_string(), // close_time + filtered_coin.current_price.to_string(), // suggested_price + filtered_coin.current_price.to_string(), // current_price + filtered_coin.stoploss.to_string(), // stoploss + filtered_coin.target_price.to_string(), // target_price server_epoch().await.to_string(), // registered_server_epoch 0.0.to_string(), // profit_percent 0.0.to_string(), // minimum_profit_percent @@ -323,12 +335,12 @@ pub async fn insert_pre_suggested_coins( .await?; // insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list] - for filtered_element in filtered_symbols { + for filtered_coin in filtered_coins { let mut is_dupe = false; // initialize for list_element in &suggested_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -336,8 +348,8 @@ pub async fn insert_pre_suggested_coins( } for list_element in &pre_suggested_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -346,11 +358,12 @@ pub async fn insert_pre_suggested_coins( if is_dupe == false { let mut insert_values = vec![ - filtered_element.0.clone(), // symbol - filtered_element.1.to_string(), // close_time - filtered_element.2.to_string(), // suggested_price - filtered_element.2.to_string(), // current_price - target_price.to_string(), // target_price + filtered_coin.symbol.clone(), // symbol + filtered_coin.closetime.to_string(), // close_time + filtered_coin.current_price.to_string(), // suggested_price + filtered_coin.current_price.to_string(), // current_price + filtered_coin.stoploss.to_string(), // stoploss + filtered_coin.target_price.to_string(), // target_price server_epoch().await.to_string(), // registered_server_epoch 0.0.to_string(), // profit_percent 0.0.to_string(), // minimum_profit_percent @@ -391,12 +404,12 @@ pub async fn insert_pre_suggested_coins( .await?; // insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list] - for filtered_element in filtered_symbols { + for filtered_coin in filtered_coins { let mut is_dupe = false; // initialize for list_element in &suggested_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -405,11 +418,12 @@ pub async fn insert_pre_suggested_coins( if is_dupe == false { let mut insert_values = vec![ - filtered_element.0.clone(), // symbol - filtered_element.1.to_string(), // close_time - filtered_element.2.to_string(), // suggested_price - filtered_element.2.to_string(), // current_price - target_price.to_string(), // target_price + filtered_coin.symbol.clone(), // symbol + filtered_coin.closetime.to_string(), // close_time + filtered_coin.current_price.to_string(), // suggested_price + filtered_coin.current_price.to_string(), // current_price + filtered_coin.stoploss.to_string(), // stoploss + filtered_coin.target_price.to_string(), // target_price server_epoch().await.to_string(), // registered_server_epoch 0.0.to_string(), // profit_percent 0.0.to_string(), // minimum_profit_percent @@ -467,12 +481,12 @@ pub async fn insert_pre_suggested_coins( .await?; // insert record without duplicate(registerer, close_time, symbol) into [pre_suggested_coin_list] - for filtered_element in filtered_symbols { + for filtered_coin in filtered_coins { let mut is_dupe = false; // initialize for list_element in &ordered_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -480,8 +494,8 @@ pub async fn insert_pre_suggested_coins( } for list_element in &pre_suggested_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -490,11 +504,12 @@ pub async fn insert_pre_suggested_coins( if is_dupe == false { let mut insert_values = vec![ - filtered_element.0.clone(), // symbol - filtered_element.1.to_string(), // close_time - filtered_element.2.to_string(), // suggested_price - filtered_element.2.to_string(), // current_price - target_price.to_string(), // target_price + filtered_coin.symbol.clone(), // symbol + filtered_coin.closetime.to_string(), // close_time + filtered_coin.current_price.to_string(), // suggested_price + filtered_coin.current_price.to_string(), // current_price + filtered_coin.stoploss.to_string(), // stoploss + filtered_coin.target_price.to_string(), // target_price server_epoch().await.to_string(), // registered_server_epoch 0.0.to_string(), // profit_percent 0.0.to_string(), // minimum_profit_percent @@ -545,12 +560,12 @@ pub async fn insert_pre_suggested_coins( .await?; // insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list] - for filtered_element in filtered_symbols { + for filtered_coin in filtered_coins { let mut is_dupe = false; // initialize for list_element in &ordered_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -559,11 +574,12 @@ pub async fn insert_pre_suggested_coins( if is_dupe == false { let mut insert_values = vec![ - filtered_element.0.clone(), // symbol - filtered_element.1.to_string(), // close_time - filtered_element.2.to_string(), // suggested_price - filtered_element.2.to_string(), // current_price - target_price.to_string(), // target_price + filtered_coin.symbol.clone(), // symbol + filtered_coin.closetime.to_string(), // close_time + filtered_coin.current_price.to_string(), // suggested_price + filtered_coin.current_price.to_string(), // current_price + filtered_coin.stoploss.to_string(), // stoploss + filtered_coin.target_price.to_string(), // target_price server_epoch().await.to_string(), // registered_server_epoch 0.0.to_string(), // profit_percent 0.0.to_string(), // minimum_profit_percent @@ -604,12 +620,12 @@ pub async fn insert_pre_suggested_coins( .await?; // insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list] - for filtered_element in filtered_symbols { + for filtered_coin in filtered_coins { let mut is_dupe = false; // initialize for list_element in &pre_suggested_coin_list { - if (filtered_element.0 == list_element.symbol) - && (filtered_element.1 == list_element.close_time) + if (filtered_coin.symbol == list_element.symbol) + && (filtered_coin.closetime == list_element.close_time) { is_dupe = true; break; @@ -618,11 +634,12 @@ pub async fn insert_pre_suggested_coins( if is_dupe == false { let mut insert_values = vec![ - filtered_element.0.clone(), // symbol - filtered_element.1.to_string(), // close_time - filtered_element.2.to_string(), // suggested_price - filtered_element.2.to_string(), // current_price - target_price.to_string(), // target_price + filtered_coin.symbol.clone(), // symbol + filtered_coin.closetime.to_string(), // close_time + filtered_coin.current_price.to_string(), // suggested_price + filtered_coin.current_price.to_string(), // current_price + filtered_coin.stoploss.to_string(), // stoploss + filtered_coin.target_price.to_string(), // target_price server_epoch().await.to_string(), // registered_server_epoch 0.0.to_string(), // profit_percent 0.0.to_string(), // minimum_profit_percent @@ -640,19 +657,20 @@ pub async fn insert_pre_suggested_coins( } } } else { - for filtered_element in filtered_symbols { + for filtered_coin in filtered_coins { let mut insert_values = vec![ - filtered_element.0.clone(), // symbol - filtered_element.1.to_string(), // close_time - filtered_element.2.to_string(), // suggested_price - filtered_element.2.to_string(), // current_price - target_price.to_string(), // target_price - server_epoch().await.to_string(), // registered_server_epoch - 0.0.to_string(), // profit_percent - 0.0.to_string(), // minimum_profit_percent - 0.0.to_string(), // maximum_profit_percent - registerer.to_string(), // registerer - ]; + filtered_coin.symbol.clone(), // symbol + filtered_coin.closetime.to_string(), // close_time + filtered_coin.current_price.to_string(), // suggested_price + filtered_coin.current_price.to_string(), // current_price + filtered_coin.stoploss.to_string(), // stoploss + filtered_coin.target_price.to_string(), // target_price + server_epoch().await.to_string(), // registered_server_epoch + 0.0.to_string(), // profit_percent + 0.0.to_string(), // minimum_profit_percent + 0.0.to_string(), // maximum_profit_percent + registerer.to_string(), // registerer + ]; if is_long == true { insert_values.push(1.to_string()); // is_long