tradingbot/src/strategy_team/strategy_003.rs
2024-01-07 03:14:45 +09:00

259 lines
13 KiB
Rust

use crate::value_estimation_team::indicators::bollingerband::bollingerband;
use super::{
dec, decimal_add, decimal_sub, decimal_div, ema, ema_opclo, sma_opclo, exists_record, insert_pre_suggested_coins,
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredData, Mutex, SmaData,
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, server_epoch, MacdData, ema_macd,
BollingerBandData, ToPrimitive
};
// BUY: 30m SMA5 (opclo_price) < 30m EMA3 (opclo_price)
// SELL: 30m SMA5 (opclo_price) > 30m EMA3 (opclo_price)
pub async fn list_up_for_buy(
alldata: AllData,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
// print rt_price for debugging
// let a = alldata.rt_price_30m_vec.iter().position(|a| a.0 == "BTCUSDT");
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
// 1st filtering: lookup tables if the tradepair is already there
let inspect_table_name_1 = String::from("buy_ordered_coin_list");
let inspect_table_name_2 = String::from("sell_ordered_coin_list");
let inspect_table_name_3 = String::from("pre_suggested_coin_list");
let inspect_table_name_4 = String::from("suggested_coin_list");
let mut filtered_data_1st: Vec<FilteredData> = Vec::new();
let mut filtered_data_1st_arc: Arc<Mutex<Vec<FilteredData>>> =
Arc::new(Mutex::new(filtered_data_1st));
let mut task_vec = Vec::new();
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(3.to_string().as_str());
// exists_condition_build.push_str("\' AND close_time=");
// exists_condition_build.push_str(element.1.to_string().as_str());
let exists_condition = Some(exists_condition_build);
let exists_condition_c = exists_condition.clone();
let inspect_table_name_1_c = inspect_table_name_1.clone();
let inspect_table_name_2_c = inspect_table_name_2.clone();
let inspect_table_name_3_c = inspect_table_name_3.clone();
let inspect_table_name_4_c = inspect_table_name_4.clone();
let 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;
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?;
// 2nd filtering: SMA5 (opclo_price) < EMA3 (opclo_price)
let filtered_data_1st = filtered_data_1st_arc.lock().await.clone();
let mut filtered_data_2nd: Vec<FilteredData> = Vec::new();
let mut filtered_data_2nd_arc: Arc<Mutex<Vec<FilteredData>>> =
Arc::new(Mutex::new(filtered_data_2nd));
let mut task_vec = Vec::new();
let sma_opclos = sma_opclo(5, &alldata.rt_price_30m_vec, &filtered_data_1st).await?;
let ema_opclos = ema_opclo(3, &alldata.rt_price_30m_vec, &filtered_data_1st).await?;
for element in filtered_data_1st {
let mut rt_30m_vec: Vec<RealtimePriceData> = Vec::new();
let mut sma_vec: Vec<SmaData> = Vec::new();
let mut ema_vec: Vec<EmaData> = Vec::new();
let rt_price_30m_vec_c: Vec<(String, Vec<RealtimePriceData>)> = alldata.rt_price_30m_vec.clone();
let sma_opclos_c = sma_opclos.clone();
let ema_opclos_c = ema_opclos.clone();
let filtered_data_2nd_arc_c = Arc::clone(&filtered_data_2nd_arc);
task_vec.push(tokio::spawn(async move {
let rt_30m_option = rt_price_30m_vec_c
.iter()
.position(|x: &(String, Vec<RealtimePriceData>)| *x.0 == element.symbol);
let sma_option_30m = sma_opclos_c.iter().position(|x| x.0 == element.symbol);
let ema_option_30m = ema_opclos_c.iter().position(|x| x.0 == element.symbol);
if rt_30m_option.is_some() && sma_option_30m.is_some() && ema_option_30m.is_some() {
rt_30m_vec = rt_price_30m_vec_c[rt_30m_option.unwrap()].1.clone();
sma_vec = sma_opclos_c[sma_option_30m.unwrap()].1.clone();
ema_vec = ema_opclos_c[ema_option_30m.unwrap()].1.clone();
let server_epoch = server_epoch().await;
if rt_30m_vec.len() >= 3 && sma_vec.len() >= 3 && ema_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
let sma_search_result = sma_vec.binary_search_by_key(
&rt_30m_vec.last().unwrap().close_time,
|SmaData {
sma_value,
close_time,
}| *close_time,
);
let ema_search_result = ema_vec.binary_search_by_key(
&rt_30m_vec.last().unwrap().close_time,
|EmaData {
ema_value,
close_time,
}| *close_time,
);
if sma_search_result.is_ok() && ema_search_result.is_ok() {
if sma_vec[sma_search_result.unwrap()].sma_value < ema_vec[ema_search_result.unwrap()].ema_value &&
sma_vec[sma_search_result.unwrap()-1].sma_value > ema_vec[ema_search_result.unwrap()-1].ema_value {
let mut filtered_data_2nd_lock = filtered_data_2nd_arc_c.lock().await;
let mut filtered_data = FilteredData::new();
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?;
// 3rd filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
let filtered_data_2nd_c = filtered_data_2nd_arc.lock().await.clone();
let mut filtered_data_3rd: Vec<FilteredData> = Vec::new();
let mut filtered_data_3rd_arc: Arc<Mutex<Vec<FilteredData>>> =
Arc::new(Mutex::new(filtered_data_3rd));
let mut task_vec = Vec::new();
for element in filtered_data_2nd_c {
let mut supertrend_vec: Vec<SupertrendData> = 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 position_idx = rt_price_30m_vec_c.iter().position(|elem| elem.0 == element.symbol);
if position_idx.is_some() {
let vec_len = rt_price_30m_vec_c[position_idx.unwrap()].1.len();
if vec_len >= 11 {
let candles = rt_price_30m_vec_c[position_idx.unwrap()].1.get(vec_len-12..vec_len-1).unwrap();
let windows = candles.windows(2);
let mut average_amplitude = 0.0;
for window in windows {
average_amplitude += (window.last().unwrap().high_price - window.last().unwrap().low_price) / window.first().unwrap().close_price;
}
average_amplitude /= 10.0;
if 0.005 <= average_amplitude && average_amplitude <= 0.01 {
let mut filtered_data_3rd_lock = filtered_data_3rd_arc_c.lock().await;
let mut filtered_data = FilteredData::new();
filtered_data.symbol = element.symbol.clone();
filtered_data.closetime = element.closetime;
filtered_data.current_price = element.current_price;
filtered_data.stoploss = element.stoploss;
filtered_data.target_price = element.target_price;
filtered_data_3rd_lock.push(filtered_data);
}
}
}
}));
}
try_join_all(task_vec).await?;
let final_filtered_data = filtered_data_3rd_arc.lock().await.clone();
insert_pre_suggested_coins(3, false, &final_filtered_data, &alldata).await;
Ok(())
}
pub async fn list_up_for_sell(
all_data: &AllData,
exchange_info_vec: &Vec<ExchangeInfo>,
trade_fee_vec: &Vec<TradeFee>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
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 supertrend_vec: Vec<SupertrendData> = Vec::new();
let server_epoch = server_epoch().await;
let mut filtered_symbol_vec: Vec<FilteredData> = Vec::new();
for element in &filled_buy_orders {
let filltered_data = FilteredData{
symbol: element.symbol.clone(),
closetime: 0,
stoploss: dec!(0),
target_price: dec!(0),
current_price: dec!(0),
};
filtered_symbol_vec.push(filltered_data);
}
let sma_opclos = sma_opclo(5, &all_data.rt_price_30m_vec, &filtered_symbol_vec).await?;
let ema_opclos = ema_opclo(3, &all_data.rt_price_30m_vec, &filtered_symbol_vec).await?;
for element in filled_buy_orders {
let sma_result = sma_opclos.iter().position(|x| x.0 == element.symbol);
let ema_result = ema_opclos.iter().position(|x| x.0 == element.symbol);
if sma_result.is_some() && ema_result.is_some() && element.used_usdt >= dec!(10.0) {
let lot_step_size_option = exchange_info_vec
.iter()
.position(|exchange_info| exchange_info.symbol == element.symbol);
let quote_commission_precision_option = exchange_info_vec
.iter()
.position(|exchange_info| exchange_info.symbol == element.symbol);
if lot_step_size_option.is_some()
&& quote_commission_precision_option.is_some()
{
let lot_step_size = exchange_info_vec[lot_step_size_option.unwrap()].stepsize;
let quote_commission_precision = exchange_info_vec
[quote_commission_precision_option.unwrap()]
.quote_commission_precision;
let base_qty_to_be_ordered =
element.base_qty_ordered.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 sma_opclos[sma_result.unwrap()].1.last().unwrap().sma_value > ema_opclos[ema_result.unwrap()].1.last().unwrap().ema_value &&
sma_opclos[sma_result.unwrap()].1[sma_opclos.len()-2].sma_value < ema_opclos[ema_result.unwrap()].1[ema_opclos.len()-2].ema_value
{
limit_order_sell(
&element,
element.current_price,
base_qty_to_be_ordered,
&client,
&exchange_info_vec,
&trade_fee_vec,
)
.await;
}
}
}
}
}
}
Ok(())
}