From 8b8cbb0dcebf0198c9cf01e1c19df67797164820 Mon Sep 17 00:00:00 2001 From: Sik Yoon Date: Sun, 23 Jun 2024 16:50:23 +0900 Subject: [PATCH] Update filtering --- src/strategy_team/future_strategy_long.rs | 207 ++++++++++++++++++--- src/strategy_team/future_strategy_short.rs | 205 +++++++++++++++++--- 2 files changed, 358 insertions(+), 54 deletions(-) diff --git a/src/strategy_team/future_strategy_long.rs b/src/strategy_team/future_strategy_long.rs index 1a05876..f24948b 100644 --- a/src/strategy_team/future_strategy_long.rs +++ b/src/strategy_team/future_strategy_long.rs @@ -1,3 +1,5 @@ +use rust_decimal::prelude::Signed; + use crate::value_estimation_team::{datapoints::price_data::CandleType, indicators::wiliams_percent_r}; use super::{ @@ -9,7 +11,7 @@ use super::{ FilteredDataValue, HashMap, HashSet, HeatMapLevel, HeatmapVolumeData, MacdData, Mutex, RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal, SupertrendData, TemaData, ToPrimitive, TradeFee, WiliamsPercentR, future_duplicate_filter, insert_future_coins, get_current_price_decimal, - sma, sma_open, LrData, linear_regression + sma, sma_open, LrData, linear_regression, bollingerband }; use crate::future::{Position, FuturesExchangeInfo}; @@ -35,19 +37,21 @@ pub async fn list_up_for_buy( // current lr > prev lr, current r_squared <= 0.01 let mut keys_to_remove: HashSet = HashSet::new(); - let lr_map = linear_regression(10, 0, &alldata.rt_price_30m_vec, &filtered_data).await?; - let sma_map = sma(10, &alldata.rt_price_30m_vec, &filtered_data).await?; + let lr_map = linear_regression(30, 0, &alldata.rt_price_30m_vec, &filtered_data).await?; + let lr50_map = linear_regression(50, 0, &alldata.rt_price_30m_vec, &filtered_data).await?; + let sma_map = sma(30, &alldata.rt_price_30m_vec, &filtered_data).await?; for (symbol, values) in &mut filtered_data { let mut do_buy = false; - if let (Some(lr_vec), Some(sma_vec), Some(current_info)) = (lr_map.get(symbol), sma_map.get(symbol), get_current_price_decimal(&symbol, &alldata.rt_price_30m_vec).await) { + if let (Some(lr_vec), Some(lr50_vec), Some(sma_vec), Some(current_info)) = (lr_map.get(symbol), lr50_map.get(symbol), sma_map.get(symbol), get_current_price_decimal(&symbol, &alldata.rt_price_30m_vec).await) { if lr_vec.len() > 10 + && lr50_vec.len() > 10 && sma_vec.len() > 10 && lr_vec.last().is_some_and(|x| x.close_time > server_epoch) && sma_vec.last().is_some_and(|x| x.close_time > server_epoch) && lr_vec[lr_vec.len()-1].lr_value > lr_vec[lr_vec.len()-2].lr_value && lr_vec[lr_vec.len()-2].lr_value > lr_vec[lr_vec.len()-3].lr_value - && lr_vec.last().unwrap().r_squared <= 0.15 - && lr_vec[lr_vec.len()-1].lr_value >= sma_vec[sma_vec.len()-1].sma_value + && lr_vec.last().unwrap().r_squared <= 0.02 + && lr_vec[lr_vec.len()-1].lr_value > sma_vec[sma_vec.len()-1].sma_value && lr_vec[lr_vec.len()-2].lr_value <= sma_vec[sma_vec.len()-2].sma_value { values.closetime = current_info.1; @@ -116,7 +120,7 @@ pub async fn list_up_for_buy( // supertrend(ATR period 30, multiplier: 2.0, 30m close price) let mut keys_to_remove: HashSet = HashSet::new(); let supertrend_1m_map = - supertrend(100, 2.5, true, &alldata.rt_price_1m_vec, &filtered_data).await?; + supertrend(10, 1.5, true, &alldata.rt_price_30m_vec, &filtered_data).await?; for (symbol, values) in &mut filtered_data { let mut do_buy = false; if let Some(supertrend_vec) = supertrend_1m_map.get(symbol) @@ -135,6 +139,46 @@ pub async fn list_up_for_buy( } remove_keys(&mut filtered_data, keys_to_remove).await; + // BollingerBand (len:30, multiplier 3) 5 previous high price < BB upper + let mut keys_to_remove: HashSet = HashSet::new(); + let bollingerband_map = + bollingerband(30, 3.0, &alldata.rt_price_30m_vec, &filtered_data).await?; + for (symbol, filtered_data) in &mut filtered_data { + let mut do_buy = false; + if let (Some(bb_vec), Some(rt_30m_vec)) = ( + bollingerband_map.get(symbol), + alldata.rt_price_30m_vec.get(symbol), + ) { + if rt_30m_vec.len() >= 10 + && bb_vec.len() >= 10 + && rt_30m_vec.last().unwrap().close_time > server_epoch + { + if let Ok(bb_search_result) = bb_vec.binary_search_by_key( + &rt_30m_vec.last().unwrap().close_time, + |BollingerBandData { + sma, + upperband, + lowerband, + close_time, + }| *close_time, + ) { + if bb_vec[bb_search_result].upperband > rt_30m_vec[rt_30m_vec.len() - 1].high_price + && bb_vec[bb_search_result-1].upperband > rt_30m_vec[rt_30m_vec.len() - 2].high_price + && bb_vec[bb_search_result-2].upperband > rt_30m_vec[rt_30m_vec.len() - 3].high_price + && bb_vec[bb_search_result-3].upperband > rt_30m_vec[rt_30m_vec.len() - 4].high_price + && bb_vec[bb_search_result-4].upperband > rt_30m_vec[rt_30m_vec.len() - 5].high_price + { + do_buy = true; + } + } + } + } + if do_buy == false { + keys_to_remove.insert(symbol.clone()); + } + } + remove_keys(&mut filtered_data, keys_to_remove).await; + // set target_price and stop_loss // let mut keys_to_remove: HashSet = HashSet::new(); // for (symbol, values) in &mut filtered_data { @@ -176,7 +220,7 @@ pub async fn list_up_for_buy( if let Some(wpr100_vec) = wpr100_map.get(symbol) { if wpr100_vec.len() > 15 && wpr100_vec.last().unwrap().close_time > server_epoch - && wpr100_vec.last().unwrap().r_value < -70.0 { + && wpr100_vec.last().unwrap().r_value < -80.0 { do_buy = true; } } @@ -265,7 +309,12 @@ pub async fn list_up_for_buy( || (heatmap_volume_vec[heatmap_volume_vec.len()-2].heatmap_level == HeatMapLevel::ExtraHigh && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-2].close_time).is_some_and(|x| x.candle_type == CandleType::UP)) || (heatmap_volume_vec[heatmap_volume_vec.len()-3].heatmap_level == HeatMapLevel::ExtraHigh && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-3].close_time).is_some_and(|x| x.candle_type == CandleType::UP)) || (heatmap_volume_vec[heatmap_volume_vec.len()-4].heatmap_level == HeatMapLevel::ExtraHigh && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-4].close_time).is_some_and(|x| x.candle_type == CandleType::UP)) - || (heatmap_volume_vec[heatmap_volume_vec.len()-5].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-5].close_time).is_some_and(|x| x.candle_type == CandleType::UP)) + || (heatmap_volume_vec[heatmap_volume_vec.len()-5].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-5].close_time).is_some_and(|x| x.candle_type == CandleType::UP) + || (heatmap_volume_vec[heatmap_volume_vec.len()-6].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-6].close_time).is_some_and(|x| x.candle_type == CandleType::UP) + || (heatmap_volume_vec[heatmap_volume_vec.len()-7].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-7].close_time).is_some_and(|x| x.candle_type == CandleType::UP) + || (heatmap_volume_vec[heatmap_volume_vec.len()-8].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-8].close_time).is_some_and(|x| x.candle_type == CandleType::UP) + || (heatmap_volume_vec[heatmap_volume_vec.len()-9].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-9].close_time).is_some_and(|x| x.candle_type == CandleType::UP) + || (heatmap_volume_vec[heatmap_volume_vec.len()-10].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-10].close_time).is_some_and(|x| x.candle_type == CandleType::UP)) { do_buy = false; } @@ -384,15 +433,74 @@ pub async fn list_up_for_sell(all_data: &AllData, futures_exchange_info_map: &Ha for element in &filled_positions { filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new()); } - let lr_map = linear_regression(10, 0, &all_data.rt_price_30m_vec, &filtered_symbols).await?; - // let supertrend_30m_map = - // supertrend(100, 1.5, true, &all_data.rt_price_30m_vec, &filtered_symbols).await?; + let lr_map = linear_regression(30, 0, &all_data.rt_price_30m_vec, &filtered_symbols).await?; + let sma_map = sma(30, &all_data.rt_price_30m_vec, &filtered_symbols).await?; + let heatmap_30m_map = heatmap_volume( + 30, + 30, + 4.0, + 1.5, + 0.5, + -0.5, + &filtered_symbols, + &all_data.rt_price_30m_vec, + ) + .await?; + let heatmap_1m_map = heatmap_volume( + 100, + 100, + 5.0, + 1.5, + 0.5, + -0.5, + &filtered_symbols, + &all_data.rt_price_1m_vec, + ) + .await?; + let bollingerband_30m_map = bollingerband(30, 3.0, &all_data.rt_price_30m_vec, &filtered_symbols).await?; + let bollingerband_1m_map = bollingerband(30, 4.5, &all_data.rt_price_1m_vec, &filtered_symbols).await?; + let supertrend_30m_map = + supertrend(10, 1.5, true, &all_data.rt_price_30m_vec, &filtered_symbols).await?; // let adx_vec = adx(15, 15, &all_data.rt_price_1m_vec, &filtered_symbols).await?; for element in filled_positions { let mut is_sell = false; - - if let Some(lr_vec) = lr_map.get(&element.symbol) { - if !element.current_price.is_zero() && lr_vec.len() > 10 && lr_vec.last().is_some_and(|x| x.close_time > server_epoch) { + if let (Some(lr_vec), + Some(sma_vec), + Some(heatmap_30m_vec), + Some(heatmap_1m_vec), + Some(bb_30m_vec), + Some(bb_1m_vec), + Some(rt_price_30m_vec), + Some(rt_price_1m_vec), + Some(supertrend_vec)) + = (lr_map.get(&element.symbol), + sma_map.get(&element.symbol), + heatmap_30m_map.get(&element.symbol), + heatmap_1m_map.get(&element.symbol), + bollingerband_30m_map.get(&element.symbol), + bollingerband_1m_map.get(&element.symbol), + all_data.rt_price_30m_vec.get(&element.symbol), + all_data.rt_price_1m_vec.get(&element.symbol), + supertrend_30m_map.get(&element.symbol)) { + if !element.current_price.is_zero() + && lr_vec.len() > 10 + && heatmap_30m_vec.len() > 10 + && heatmap_1m_vec.len() > 10 + && rt_price_30m_vec.len() > 10 + && rt_price_1m_vec.len() > 10 + && bb_30m_vec.len() > 10 + && bb_1m_vec.len() > 10 + && sma_vec.len() > 10 + && supertrend_vec.len() > 10 + && lr_vec.last().is_some_and(|x| x.close_time > server_epoch) + && sma_vec.last().is_some_and(|x| x.close_time > server_epoch) + && heatmap_30m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && heatmap_1m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && bb_30m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && bb_1m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && rt_price_30m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && rt_price_1m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && supertrend_vec.last().is_some_and(|x| x.close_time > server_epoch) { // if element.pure_profit_percent >= element.target_percent { // is_sell = true; @@ -400,24 +508,73 @@ pub async fn list_up_for_sell(all_data: &AllData, futures_exchange_info_map: &Ha // is_sell = true; // } else - if element.pure_profit_percent.is_sign_positive() && lr_vec[lr_vec.len()-2].r_squared >= 0.60 { - is_sell = true; - } else if server_epoch - element.close_time > 900_000 - && lr_vec[lr_vec.len()-1].lr_value < lr_vec[lr_vec.len()-2].lr_value { + if element.pure_profit_percent.is_sign_positive() && lr_vec.last().is_some_and(|x| x.r_squared >= 0.6) { is_sell = true; } else if server_epoch - element.close_time > 900_000 && lr_vec[lr_vec.len()-1].r_squared < lr_vec[lr_vec.len()-2].r_squared && lr_vec[lr_vec.len()-2].r_squared > lr_vec[lr_vec.len()-3].r_squared && lr_vec[lr_vec.len()-3].r_squared > lr_vec[lr_vec.len()-4].r_squared { is_sell = true; - } else if element.pure_profit_percent <= -0.8 { + } else if server_epoch - element.close_time > 1_800_000 + && lr_vec.last().unwrap().close_time == sma_vec.last().unwrap().close_time + && lr_vec[lr_vec.len()-1].lr_value < sma_vec[sma_vec.len()-1].sma_value + && lr_vec[lr_vec.len()-2].lr_value > sma_vec[sma_vec.len()-2].sma_value { is_sell = true; - } else if element.pure_profit_percent >= 2.0 { + } else if element.pure_profit_percent.is_sign_positive() && heatmap_30m_vec.last().is_some_and(|x| x.heatmap_level == HeatMapLevel::ExtraHigh) { + is_sell = true; + } else if element.pure_profit_percent.is_sign_positive() + && (heatmap_1m_vec.last().is_some_and(|x| x.heatmap_level == HeatMapLevel::ExtraHigh) + || heatmap_1m_vec[heatmap_1m_vec.len()-2].heatmap_level == HeatMapLevel::ExtraHigh) { + is_sell = true; + } else if element.pure_profit_percent.is_sign_negative() && element.pure_profit_percent <= -5.0 { + is_sell = true; + } else if supertrend_vec.last().is_some_and(|x| x.signal.as_ref().is_some_and(|a| *a == SuperTrendSignal::SELL)) { is_sell = true; } - let minimum_candles = 5; - let maximum_candles = 20; + if is_sell == false { + if let Ok(bb_search_result) = bb_30m_vec.binary_search_by_key( + &rt_price_30m_vec.last().unwrap().close_time, + |BollingerBandData { + sma, + upperband, + lowerband, + close_time, + }| *close_time, + ) { + if element.pure_profit_percent.is_sign_positive() + && bb_30m_vec[bb_search_result].upperband <= rt_price_30m_vec[rt_price_30m_vec.len() - 1].high_price + && bb_30m_vec[bb_search_result-1].upperband <= rt_price_30m_vec[rt_price_30m_vec.len() - 2].high_price + { + is_sell = true; + } + } + + if let Ok(bb_search_result) = bb_1m_vec.binary_search_by_key( + &rt_price_1m_vec.last().unwrap().close_time, + |BollingerBandData { + sma, + upperband, + lowerband, + close_time, + }| *close_time, + ) { + if element.pure_profit_percent.is_sign_positive() + && bb_1m_vec[bb_search_result].upperband <= rt_price_1m_vec[rt_price_1m_vec.len() - 1].high_price + && bb_1m_vec[bb_search_result-1].upperband <= rt_price_1m_vec[rt_price_1m_vec.len() - 2].high_price + { + is_sell = true; + } + } + + let minimum_candles = 5; + let maximum_candles = 30; + + if server_epoch - element.close_time > 1_800_000 * maximum_candles { + is_sell = true; + } + } + // for count_candles in minimum_candles..=maximum_candles { // if count_candles < maximum_candles // && server_epoch - element.transact_time @@ -442,9 +599,7 @@ pub async fn list_up_for_sell(all_data: &AllData, futures_exchange_info_map: &Ha // } // } - if server_epoch - element.close_time > 1_800_000 * maximum_candles { - is_sell = true; - } + //} else if server_epoch - element.close_time > 300_000 // && adx_vec.get(&element.symbol).is_some_and(|a| a.len() > 10 && a.last().is_some_and(|b| b.close_time > server_epoch && b.adx < 15.0)) { diff --git a/src/strategy_team/future_strategy_short.rs b/src/strategy_team/future_strategy_short.rs index 631ad49..c54ead3 100644 --- a/src/strategy_team/future_strategy_short.rs +++ b/src/strategy_team/future_strategy_short.rs @@ -9,7 +9,7 @@ use super::{ FilteredDataValue, HashMap, HashSet, HeatMapLevel, HeatmapVolumeData, MacdData, Mutex, RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal, SupertrendData, TemaData, ToPrimitive, TradeFee, WiliamsPercentR, future_duplicate_filter, insert_future_coins, get_current_price_decimal, - sma, sma_open, LrData, linear_regression + sma, sma_open, LrData, linear_regression, bollingerband }; use crate::future::{Position, FuturesExchangeInfo}; @@ -35,21 +35,22 @@ pub async fn list_up_for_buy( // current lr < prev lr, current r_squared <= 0.01 let mut keys_to_remove: HashSet = HashSet::new(); - let lr_map = linear_regression(10, 0, &alldata.rt_price_30m_vec, &filtered_data).await?; - let sma10_map = sma(10, &alldata.rt_price_30m_vec, &filtered_data).await?; + let lr_map = linear_regression(30, 0, &alldata.rt_price_30m_vec, &filtered_data).await?; + let lr50_map = linear_regression(50, 0, &alldata.rt_price_30m_vec, &filtered_data).await?; + let sma10_map = sma(30, &alldata.rt_price_30m_vec, &filtered_data).await?; for (symbol, values) in &mut filtered_data { let mut do_buy = false; - if let (Some(lr_vec), Some(sma_vec), Some(current_info)) = (lr_map.get(symbol), sma10_map.get(symbol), get_current_price_decimal(&symbol, &alldata.rt_price_30m_vec).await) { + if let (Some(lr_vec), Some(lr50_vec), Some(sma_vec), Some(current_info)) = (lr_map.get(symbol), lr50_map.get(symbol), sma10_map.get(symbol), get_current_price_decimal(&symbol, &alldata.rt_price_30m_vec).await) { if lr_vec.len() > 10 + && lr50_vec.len() > 10 && sma_vec.len() > 10 && lr_vec.last().is_some_and(|x| x.close_time > server_epoch) && sma_vec.last().is_some_and(|x| x.close_time > server_epoch) && lr_vec[lr_vec.len()-1].lr_value < lr_vec[lr_vec.len()-2].lr_value && lr_vec[lr_vec.len()-2].lr_value < lr_vec[lr_vec.len()-3].lr_value - && lr_vec.last().unwrap().r_squared <= 0.15 - && lr_vec[lr_vec.len()-1].lr_value <= sma_vec[sma_vec.len()-1].sma_value + && lr_vec.last().unwrap().r_squared <= 0.02 + && lr_vec[lr_vec.len()-1].lr_value < sma_vec[sma_vec.len()-1].sma_value && lr_vec[lr_vec.len()-2].lr_value >= sma_vec[sma_vec.len()-2].sma_value - { values.closetime = current_info.1; do_buy = true; @@ -115,7 +116,7 @@ pub async fn list_up_for_buy( // supertrend(ATR period 30, multiplier: 2.0, 30m close price) let mut keys_to_remove: HashSet = HashSet::new(); let supertrend_1m_map = - supertrend(100, 2.5, true, &alldata.rt_price_1m_vec, &filtered_data).await?; + supertrend(10, 1.5, true, &alldata.rt_price_30m_vec, &filtered_data).await?; for (symbol, values) in &mut filtered_data { let mut do_buy = false; if let Some(supertrend_vec) = supertrend_1m_map.get(symbol) @@ -134,6 +135,46 @@ pub async fn list_up_for_buy( } remove_keys(&mut filtered_data, keys_to_remove).await; + // BollingerBand (len:30, multiplier 3) 5 previous high price < BB upper + let mut keys_to_remove: HashSet = HashSet::new(); + let bollingerband_map = + bollingerband(30, 3.0, &alldata.rt_price_30m_vec, &filtered_data).await?; + for (symbol, filtered_data) in &mut filtered_data { + let mut do_buy = false; + if let (Some(bb_vec), Some(rt_30m_vec)) = ( + bollingerband_map.get(symbol), + alldata.rt_price_30m_vec.get(symbol), + ) { + if rt_30m_vec.len() >= 10 + && bb_vec.len() >= 10 + && rt_30m_vec.last().unwrap().close_time > server_epoch + { + if let Ok(bb_search_result) = bb_vec.binary_search_by_key( + &rt_30m_vec.last().unwrap().close_time, + |BollingerBandData { + sma, + upperband, + lowerband, + close_time, + }| *close_time, + ) { + if bb_vec[bb_search_result].lowerband < rt_30m_vec[rt_30m_vec.len() - 1].low_price + && bb_vec[bb_search_result-1].lowerband < rt_30m_vec[rt_30m_vec.len() - 2].low_price + && bb_vec[bb_search_result-2].lowerband < rt_30m_vec[rt_30m_vec.len() - 3].low_price + && bb_vec[bb_search_result-3].lowerband < rt_30m_vec[rt_30m_vec.len() - 4].low_price + && bb_vec[bb_search_result-4].lowerband < rt_30m_vec[rt_30m_vec.len() - 5].low_price + { + do_buy = true; + } + } + } + } + if do_buy == false { + keys_to_remove.insert(symbol.clone()); + } + } + remove_keys(&mut filtered_data, keys_to_remove).await; + // set target_price and stop_loss // let mut keys_to_remove: HashSet = HashSet::new(); // for (symbol, values) in &mut filtered_data { @@ -175,7 +216,7 @@ pub async fn list_up_for_buy( if let Some(wpr100_vec) = wpr100_map.get(symbol) { if wpr100_vec.len() > 15 && wpr100_vec.last().unwrap().close_time > server_epoch - && wpr100_vec.last().unwrap().r_value > -30.0 { + && wpr100_vec.last().unwrap().r_value > -20.0 { do_buy = true; } } @@ -264,7 +305,12 @@ pub async fn list_up_for_buy( || (heatmap_volume_vec[heatmap_volume_vec.len()-2].heatmap_level == HeatMapLevel::ExtraHigh && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-2].close_time).is_some_and(|x| x.candle_type == CandleType::DOWN)) || (heatmap_volume_vec[heatmap_volume_vec.len()-3].heatmap_level == HeatMapLevel::ExtraHigh && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-3].close_time).is_some_and(|x| x.candle_type == CandleType::DOWN)) || (heatmap_volume_vec[heatmap_volume_vec.len()-4].heatmap_level == HeatMapLevel::ExtraHigh && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-4].close_time).is_some_and(|x| x.candle_type == CandleType::DOWN)) - || (heatmap_volume_vec[heatmap_volume_vec.len()-5].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-5].close_time).is_some_and(|x| x.candle_type == CandleType::DOWN)) + || (heatmap_volume_vec[heatmap_volume_vec.len()-5].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-5].close_time).is_some_and(|x| x.candle_type == CandleType::DOWN) + || (heatmap_volume_vec[heatmap_volume_vec.len()-6].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-6].close_time).is_some_and(|x| x.candle_type == CandleType::DOWN) + || (heatmap_volume_vec[heatmap_volume_vec.len()-7].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-7].close_time).is_some_and(|x| x.candle_type == CandleType::DOWN) + || (heatmap_volume_vec[heatmap_volume_vec.len()-8].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-8].close_time).is_some_and(|x| x.candle_type == CandleType::DOWN) + || (heatmap_volume_vec[heatmap_volume_vec.len()-9].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-9].close_time).is_some_and(|x| x.candle_type == CandleType::DOWN) + || (heatmap_volume_vec[heatmap_volume_vec.len()-10].heatmap_level == HeatMapLevel::ExtraHigh) && rt_price_vec.iter().find(|x| x.close_time == heatmap_volume_vec[heatmap_volume_vec.len()-10].close_time).is_some_and(|x| x.candle_type == CandleType::DOWN)) { do_buy = false; } @@ -382,9 +428,33 @@ pub async fn list_up_for_sell(all_data: &AllData, futures_exchange_info_map: &Ha for element in &filled_positions { filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new()); } - let lr_map = linear_regression(10, 0, &all_data.rt_price_30m_vec, &filtered_symbols).await?; - // let supertrend_30m_map = - // supertrend(100, 1.5, true, &all_data.rt_price_30m_vec, &filtered_symbols).await?; + let lr_map = linear_regression(30, 0, &all_data.rt_price_30m_vec, &filtered_symbols).await?; + let sma_map: HashMap> = sma(30, &all_data.rt_price_30m_vec, &filtered_symbols).await?; + let heatmap_30m_map = heatmap_volume( + 30, + 30, + 4.0, + 1.5, + 0.5, + -0.5, + &filtered_symbols, + &all_data.rt_price_30m_vec, + ) + .await?; + let heatmap_1m_map = heatmap_volume( + 100, + 100, + 5.0, + 1.5, + 0.5, + -0.5, + &filtered_symbols, + &all_data.rt_price_1m_vec, + ) + .await?; + let bollingerband_30m_map = bollingerband(30, 3.0, &all_data.rt_price_30m_vec, &filtered_symbols).await?; + let bollingerband_1m_map = bollingerband(30, 4.5, &all_data.rt_price_1m_vec, &filtered_symbols).await?; + let supertrend_30m_map = supertrend(10, 1.5, true, &all_data.rt_price_30m_vec, &filtered_symbols).await?; // let adx_vec = adx(15, 15, &all_data.rt_price_1m_vec, &filtered_symbols).await?; for element in filled_positions { let mut is_sell = false; @@ -396,33 +466,115 @@ pub async fn list_up_for_sell(all_data: &AllData, futures_exchange_info_map: &Ha // RoundingStrategy::ToZero, // ); // TODO: BNB 코인이 없으면 - - if let Some(lr_vec) = lr_map.get(&element.symbol) { - if !element.current_price.is_zero() && lr_vec.len() > 10 && lr_vec.last().is_some_and(|x| x.close_time > server_epoch) { - + if let (Some(lr_vec), + Some(sma_vec), + Some(heatmap_30m_vec), + Some(heatmap_1m_vec), + Some(bb_30m_vec), + Some(bb_1m_vec), + Some(rt_price_30m_vec), + Some(rt_price_1m_vec), + Some(supertrend_vec)) + = (lr_map.get(&element.symbol), + sma_map.get(&element.symbol), + heatmap_30m_map.get(&element.symbol), + heatmap_1m_map.get(&element.symbol), + bollingerband_30m_map.get(&element.symbol), + bollingerband_1m_map.get(&element.symbol), + all_data.rt_price_30m_vec.get(&element.symbol), + all_data.rt_price_1m_vec.get(&element.symbol), + supertrend_30m_map.get(&element.symbol)) { + if !element.current_price.is_zero() + && lr_vec.len() > 10 + && heatmap_30m_vec.len() > 10 + && heatmap_1m_vec.len() > 10 + && rt_price_30m_vec.len() > 10 + && rt_price_1m_vec.len() > 10 + && bb_30m_vec.len() > 10 + && bb_1m_vec.len() > 10 + && sma_vec.len() > 10 + && supertrend_vec.len() > 10 + && lr_vec.last().is_some_and(|x| x.close_time > server_epoch) + && sma_vec.last().is_some_and(|x| x.close_time > server_epoch) + && heatmap_30m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && heatmap_1m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && bb_30m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && bb_1m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && rt_price_30m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && rt_price_1m_vec.last().is_some_and(|x| x.close_time > server_epoch) + && supertrend_vec.last().is_some_and(|x| x.close_time > server_epoch) { // if element.pure_profit_percent >= element.target_percent { // is_sell = true; // } else if element.pure_profit_percent <= element.stoploss_percent { // is_sell = true; // } else - if element.pure_profit_percent.is_sign_positive() && lr_vec[lr_vec.len()-2].r_squared >= 0.60 { - is_sell = true; - } else if server_epoch - element.close_time > 900_000 - && lr_vec[lr_vec.len()-1].lr_value > lr_vec[lr_vec.len()-2].lr_value { + + if element.pure_profit_percent.is_sign_positive() && lr_vec.last().is_some_and(|x| x.r_squared >= 0.6) { is_sell = true; } else if server_epoch - element.close_time > 900_000 && lr_vec[lr_vec.len()-1].r_squared < lr_vec[lr_vec.len()-2].r_squared && lr_vec[lr_vec.len()-2].r_squared > lr_vec[lr_vec.len()-3].r_squared && lr_vec[lr_vec.len()-3].r_squared > lr_vec[lr_vec.len()-4].r_squared { is_sell = true; - } else if element.pure_profit_percent <= -0.8 { + } else if server_epoch - element.close_time > 1_800_000 + && lr_vec.last().unwrap().close_time == sma_vec.last().unwrap().close_time + && lr_vec[lr_vec.len()-1].lr_value > sma_vec[sma_vec.len()-1].sma_value + && lr_vec[lr_vec.len()-2].lr_value < sma_vec[sma_vec.len()-2].sma_value { is_sell = true; - } else if element.pure_profit_percent >= 2.0 { + } else if element.pure_profit_percent.is_sign_positive() && heatmap_30m_vec.last().is_some_and(|x| x.heatmap_level == HeatMapLevel::ExtraHigh) { + is_sell = true; + } else if element.pure_profit_percent.is_sign_positive() + && (heatmap_1m_vec.last().is_some_and(|x| x.heatmap_level == HeatMapLevel::ExtraHigh) + || heatmap_1m_vec[heatmap_1m_vec.len()-2].heatmap_level == HeatMapLevel::ExtraHigh) { + is_sell = true; + } else if element.pure_profit_percent.is_sign_negative() && element.pure_profit_percent <= -5.0 { + is_sell = true; + } else if supertrend_vec.last().is_some_and(|x| x.signal.as_ref().is_some_and(|a| *a == SuperTrendSignal::BUY)) { is_sell = true; } + + if is_sell == false { + if let Ok(bb_search_result) = bb_30m_vec.binary_search_by_key( + &rt_price_30m_vec.last().unwrap().close_time, + |BollingerBandData { + sma, + upperband, + lowerband, + close_time, + }| *close_time, + ) { + if element.pure_profit_percent.is_sign_positive() + && bb_30m_vec[bb_search_result].lowerband >= rt_price_30m_vec[rt_price_30m_vec.len() - 1].low_price + && bb_30m_vec[bb_search_result-1].lowerband >= rt_price_30m_vec[rt_price_30m_vec.len() - 2].low_price + { + is_sell = true; + } + } + + if let Ok(bb_search_result) = bb_1m_vec.binary_search_by_key( + &rt_price_1m_vec.last().unwrap().close_time, + |BollingerBandData { + sma, + upperband, + lowerband, + close_time, + }| *close_time, + ) { + if element.pure_profit_percent.is_sign_positive() + && bb_1m_vec[bb_search_result].lowerband >= rt_price_1m_vec[rt_price_1m_vec.len() - 1].low_price + && bb_1m_vec[bb_search_result-1].lowerband >= rt_price_1m_vec[rt_price_1m_vec.len() - 2].low_price + { + is_sell = true; + } + } - let minimum_candles = 5; - let maximum_candles = 20; + let minimum_candles = 5; + let maximum_candles = 30; + + if server_epoch - element.close_time > 1_800_000 * maximum_candles { + is_sell = true; + } + } // for count_candles in minimum_candles..=maximum_candles { // if count_candles < maximum_candles // && server_epoch - element.transact_time @@ -447,9 +599,6 @@ pub async fn list_up_for_sell(all_data: &AllData, futures_exchange_info_map: &Ha // } // } - if server_epoch - element.close_time > 1_800_000 * maximum_candles { - is_sell = true; - } //} else if server_epoch - element.close_time > 300_000 // && adx_vec.get(&element.symbol).is_some_and(|a| a.len() > 10 && a.last().is_some_and(|b| b.close_time > server_epoch && b.adx < 15.0)) {