// assets_managing_team manages [asset_manage_announcement] and [wallet] ([wallet_testnet] as well) use crate::coex::exchange_team::*; use crate::database_control::*; use crate::decimal_funcs::*; use crate::RunningMode::*; use crate::RUNNING_MODE; use reqwest::Client; use rust_decimal::{prelude::ToPrimitive, Decimal, RoundingStrategy}; use rust_decimal_macros::dec; use serde_json::{Result, Value}; use sqlx::FromRow; use crate::coex::order_team::DBlist; #[derive(Debug, FromRow)] pub struct AssetInfo { pub initial_usdt: Decimal, pub current_total_usdt: Decimal, pub profit: Decimal, pub realtime_expected_total_usdt: f64, pub realtime_profit: f64, pub available_usdt: Decimal, pub is_tradable: u8, pub unit_trade_usdt: Decimal, } impl DBlist for AssetInfo { fn new() -> AssetInfo { let a = AssetInfo { initial_usdt: Decimal::new(0, 8), current_total_usdt: Decimal::new(0, 8), profit: Decimal::new(0, 8), realtime_expected_total_usdt: 0.0, realtime_profit: 0.0, available_usdt: Decimal::new(0, 8), is_tradable: 0, unit_trade_usdt: Decimal::new(0, 8), }; a } } #[derive(Debug, FromRow)] pub struct WalletInfo { pub asset: String, pub free: Decimal, pub locked: Decimal, } impl DBlist for WalletInfo { fn new() -> WalletInfo { let a = WalletInfo { asset: String::new(), free: Decimal::new(0, 8), locked: Decimal::new(0, 8), }; a } } // set unit_trade_usdt pub async fn set_unit_usdt() { let asset_info = select_asset_manage_announcement().await; let mut set_unit_trade_usdt = Decimal::new(0, 8); if RUNNING_MODE == SIMUL { set_unit_trade_usdt = dec!(100.0); // $100 for each trade } else if RUNNING_MODE == REAL { // define protect_rate and unit_trade_usdt as high as total_usdt_amount if dec!(0.0) <= asset_info.current_total_usdt && asset_info.current_total_usdt < dec!(1000.0) { set_unit_trade_usdt = dec!(50.0); // $100 for each trade // set_unit_trade_usdt = decimal_mul(asset_info.current_total_usdt, dec!(0.8)); // 80% of total usdt } else if dec!(1000.0) <= asset_info.current_total_usdt { // set_unit_trade_usdt = dec!(150.0); // $150 for each trade set_unit_trade_usdt = decimal_mul(asset_info.current_total_usdt, dec!(0.05)); if set_unit_trade_usdt <= dec!(20) { set_unit_trade_usdt = dec!(0); } else { let truncated = decimal_mul(decimal_mul(set_unit_trade_usdt, dec!(0.1)).trunc(), dec!(10)); let difference = decimal_sub(set_unit_trade_usdt, truncated); if difference >= dec!(5) { set_unit_trade_usdt = decimal_add(truncated, dec!(5)); } else { set_unit_trade_usdt = truncated; } } } } // update fields in [asset_manage_announcement] table let update_table_name = String::from("asset_manage_announcement"); let update_values = vec![( String::from("unit_trade_usdt"), set_unit_trade_usdt.to_string(), )]; let update_condition = vec![(String::from("id"), String::from("1"))]; update_record3(&update_table_name, &update_values, &update_condition) .await .unwrap(); } // add extra usdt to initial usdt pub async fn add_extra_usdt(extra_usdt: Decimal) { // update fields in [asset_manage_announcement] table let update_table_name = String::from("asset_manage_announcement"); let mut value_build = String::from("initial_usdt + "); value_build.push_str( extra_usdt .round_dp_with_strategy(8, RoundingStrategy::ToZero) .to_string() .as_str(), ); let update_values = vec![(String::from("initial_usdt"), value_build)]; let update_condition = vec![(String::from("id"), String::from("1"))]; update_record3(&update_table_name, &update_values, &update_condition) .await .unwrap(); let mut value_build = String::from("current_total_usdt + "); value_build.push_str( extra_usdt .round_dp_with_strategy(8, RoundingStrategy::ToZero) .to_string() .as_str(), ); let update_values = vec![(String::from("current_total_usdt"), value_build)]; let update_condition = vec![(String::from("id"), String::from("1"))]; update_record3(&update_table_name, &update_values, &update_condition) .await .unwrap(); add_available_usdt(extra_usdt.round_dp_with_strategy(8, RoundingStrategy::ToZero)).await; // add additional_usdt into [wallet_simul] let mut update_table_name = String::new(); if RUNNING_MODE == SIMUL { let update_table_name = String::from("wallet"); let mut value_build = String::from("free + "); value_build.push_str(extra_usdt.to_string().as_str()); let update_values = vec![(String::from("free"), value_build)]; let update_condition = vec![(String::from("asset"), String::from("USDT"))]; update_record3(&update_table_name, &update_values, &update_condition) .await .unwrap(); } println!("add_extra_usdt 완료"); } // update current_total_usdt and profit of asset pub async fn update_current_total_usdt() { let mut update_values: Vec<(String, String)> = Vec::new(); if RUNNING_MODE == REAL || RUNNING_MODE == TEST { let free_usdt = fetch_free_usdt().await; let initial_usdt = select_asset_manage_announcement().await.initial_usdt; // println!("update_current_total_usdt실행 free_usdt: {}, initial_usdt: {}", free_usdt, initial_usdt); let mut profit: Decimal; if initial_usdt.is_zero() { profit = dec!(0.0); } else { profit = decimal_sub(decimal_div(free_usdt, initial_usdt), dec!(1)); } update_values = vec![ (String::from("current_total_usdt"), free_usdt.to_string()), (String::from("profit"), profit.to_string()), ( String::from("realtime_expected_total_usdt"), 0.0.to_string(), ), (String::from("realtime_profit"), 0.0.to_string()), ]; } else { let asset_info = select_asset_manage_announcement().await; let mut profit: Decimal; if asset_info.initial_usdt.is_zero() { profit = dec!(0.0); } else { profit = decimal_sub( decimal_div(asset_info.current_total_usdt, asset_info.initial_usdt), dec!(1), ); } update_values = vec![ ( String::from("current_total_usdt"), asset_info.available_usdt.to_string(), ), (String::from("profit"), profit.to_string()), ( String::from("realtime_expected_total_usdt"), 0.0.to_string(), ), (String::from("realtime_profit"), 0.0.to_string()), ]; } let update_table_name = String::from("asset_manage_announcement"); let update_condition = vec![(String::from("id"), String::from("1"))]; update_record3(&update_table_name, &update_values, &update_condition) .await .unwrap(); set_unit_usdt().await; } // monitor whether [buy_ordered_coin_list] is empty to update current_total_usdt and available_usdt in [asset_manage_announcement] pub async fn monitoring_asset_usdt(previous_result: &mut bool, client: &Client) -> Result<()> { let table_name = String::from("buy_ordered_coin_list"); let condition = None; let buy_list_result = exists_record(&table_name, &condition).await; let table_name = String::from("sell_ordered_coin_list"); let condition = None; let sell_list_result = exists_record(&table_name, &condition).await; if buy_list_result == false && sell_list_result == false { if buy_list_result == false && sell_list_result == false && *previous_result == true && (RUNNING_MODE == TEST || RUNNING_MODE == REAL) { let mut result = crate::coex::order_team::account_information(&client).await; // (/api, Weight(IP) 10) loop { if result.is_ok() { break; } else { println!("retry account_information()"); tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; result = crate::coex::order_team::account_information(&client).await; // (/api, Weight(IP) 10) } } update_current_total_usdt().await; set_available_usdt().await; } else if buy_list_result == false && sell_list_result == false && *previous_result == true && (RUNNING_MODE == SIMUL) { update_current_total_usdt().await; set_is_tradable().await; } *previous_result = false; } else { update_realtime_asset().await; *previous_result = true; } Ok(()) } // update realtime_expected_total_usdt and realtime_profit pub async fn update_realtime_asset() { let asset_info = select_asset_manage_announcement().await; let scoreboard_list = select_scoreboard().await; let scoreboard_short = scoreboard_list.first().unwrap(); let scoreboard_long = scoreboard_list.last().unwrap(); if scoreboard_short.total_number_of_coin != 0 || scoreboard_long.total_number_of_coin != 0 { // calculate expect_realtime_asset let available_usdt = asset_info.available_usdt.to_f64().unwrap(); let total_used_usdt = scoreboard_short.total_used_usdt + scoreboard_long.total_used_usdt; let current_pos_profit_usdt = scoreboard_short.total_pos_profit_usdt + scoreboard_long.total_pos_profit_usdt; let current_neg_profit_usdt = scoreboard_short.total_neg_profit_usdt + scoreboard_long.total_neg_profit_usdt; let expect_realtime_expected_total_usdt = available_usdt + total_used_usdt + current_pos_profit_usdt + current_neg_profit_usdt; // calculate realtime_profit let mut realtime_profit = 0.0; let current_total_usdt = asset_info.current_total_usdt; if current_total_usdt.is_zero() { realtime_profit = 0.0; } else { realtime_profit = ((expect_realtime_expected_total_usdt / current_total_usdt.to_f64().unwrap()) - 1.0) * 100.0; } // update record let update_table_name = String::from("asset_manage_announcement"); let update_values = vec![ ( String::from("realtime_expected_total_usdt"), expect_realtime_expected_total_usdt.to_string(), ), (String::from("realtime_profit"), realtime_profit.to_string()), ]; let update_condition = vec![(String::from("id"), String::from("1"))]; update_record3(&update_table_name, &update_values, &update_condition) .await .unwrap(); } } // set available_usdt pub async fn set_available_usdt() { let update_table_name = String::from("asset_manage_announcement"); // fetch current_total_usdt let mut asset_info = select_asset_manage_announcement().await; let available_usdt = asset_info.current_total_usdt; let unit_trade_usdt = asset_info.unit_trade_usdt; // set available_usdt with current_total_usdt and update is_tradable let update_value = { if available_usdt > unit_trade_usdt { vec![ (String::from("available_usdt"), available_usdt.to_string()), (String::from("is_tradable"), (String::from("1"))), ] } else { vec![ (String::from("available_usdt"), available_usdt.to_string()), (String::from("is_tradable"), (String::from("0"))), ] } }; let update_condition = vec![(String::from("id"), String::from("1"))]; update_record3(&update_table_name, &update_value, &update_condition) .await .unwrap(); } // get available_usdt pub async fn get_available_usdt() -> Decimal { let update_table_name = String::from("asset_manage_announcement"); let mut asset_info = select_asset_manage_announcement().await; asset_info.available_usdt } // add available_usdt pub async fn add_available_usdt(add_usdt: Decimal) { let update_table_name = String::from("asset_manage_announcement"); let mut value_build = String::from("available_usdt + "); value_build.push_str(add_usdt.to_string().as_str()); let update_values = vec![(String::from("available_usdt"), value_build)]; let update_condition = vec![(String::from("id"), String::from("1"))]; update_record3(&update_table_name, &update_values, &update_condition) .await .unwrap(); } // subtract available_usdt pub async fn sub_available_usdt(sub_usdt: Decimal) { let update_table_name = String::from("asset_manage_announcement"); let mut value_build = String::from("available_usdt - "); value_build.push_str(sub_usdt.to_string().as_str()); let update_values = vec![(String::from("available_usdt"), value_build)]; let update_condition = vec![(String::from("id"), String::from("1"))]; update_record3(&update_table_name, &update_values, &update_condition) .await .unwrap(); } // set is_tradable as available_usdt pub async fn set_is_tradable() { let update_table_name = String::from("asset_manage_announcement"); let mut asset_info = select_asset_manage_announcement().await; let unit_trade_usdt = asset_info.unit_trade_usdt; let available_usdt = asset_info.available_usdt; let update_value = { if available_usdt > unit_trade_usdt { vec![(String::from("is_tradable"), (String::from("1")))] } else { vec![(String::from("is_tradable"), (String::from("0")))] } }; let update_condition = vec![(String::from("id"), String::from("1"))]; update_record3(&update_table_name, &update_value, &update_condition) .await .unwrap(); } // get is_tradable pub async fn get_is_tradable() -> bool { let asset_info = select_asset_manage_announcement().await; let is_tradable = asset_info.is_tradable; if asset_info.is_tradable == 1 { true } else { false } } pub async fn get_unit_trade_usdt() -> Decimal { let asset_info = select_asset_manage_announcement().await; asset_info.unit_trade_usdt } pub async fn select_asset_manage_announcement() -> AssetInfo { let mut asset_info = AssetInfo::new(); let table_name = String::from("asset_manage_announcement"); let columns = String::from("*"); let condition = None; let select_result = select_record(&table_name, &columns, &condition, &asset_info) .await .unwrap(); let result_vec = select_result.first().unwrap(); asset_info.initial_usdt = result_vec.initial_usdt; asset_info.current_total_usdt = result_vec.current_total_usdt; asset_info.profit = result_vec.profit; asset_info.realtime_expected_total_usdt = result_vec.realtime_expected_total_usdt; asset_info.realtime_profit = result_vec.realtime_profit; asset_info.available_usdt = result_vec.available_usdt; asset_info.is_tradable = result_vec.is_tradable; asset_info.unit_trade_usdt = result_vec.unit_trade_usdt; asset_info } // fetch free usdt from wallet pub async fn fetch_free_usdt() -> Decimal { let wallet_info = WalletInfo::new(); let select_table_name = { if RUNNING_MODE == SIMUL || RUNNING_MODE == REAL { String::from("wallet") } else { String::from("wallet_testnet") } }; let select_columns_name = String::from("*"); let condition = Some(String::from("WHERE asset = 'USDT'")); let mut select_result = select_record( &select_table_name, &select_columns_name, &condition, &wallet_info, ) .await .unwrap(); select_result.first().unwrap().free }