Replace Vec with HashMap (#3)
All vec operation was replaced with HashMap. Increase outstanding performance. Co-authored-by: Sik Yoon <younxxxx@gmail.com> Reviewed-on: http://192.168.1.100:3000/Sik/tradingbot/pulls/3
This commit is contained in:
parent
6adf6cab88
commit
223c6760c1
|
|
@ -1,14 +1,16 @@
|
|||
use crate::coex::assets_managing_team::*;
|
||||
use crate::coex::order_team::*;
|
||||
use crate::coin_health_check_team::request_others::{CoinPriceData, ExchangeInfo, TradeFee};
|
||||
use crate::coin_health_check_team::request_others::{ExchangeInfo, TradeFee};
|
||||
use crate::database_control::*;
|
||||
use crate::decimal_funcs::{decimal, decimal_add, decimal_div, decimal_mul, decimal_sub};
|
||||
use crate::signal_association::signal_decision::*;
|
||||
use crate::strategy_team::AllData;
|
||||
use hmac_sha256::Hash;
|
||||
use reqwest::{Client, ClientBuilder};
|
||||
use rust_decimal::{prelude::FromPrimitive, prelude::ToPrimitive, Decimal, RoundingStrategy};
|
||||
use rust_decimal_macros::dec;
|
||||
use sqlx::FromRow;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, FromRow)]
|
||||
struct IsTradableInfo {
|
||||
|
|
@ -219,13 +221,13 @@ impl DBlist for MarketCapIndex {
|
|||
|
||||
// buy coin
|
||||
pub async fn buy_coin(
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut suggested_coin = get_suggested_coin_list().await;
|
||||
|
||||
if !suggested_coin.is_empty() && exchange_info_vec.len() != 0 && trade_fee_vec.len() != 0 {
|
||||
let server_epoch = server_epoch().await;
|
||||
if !suggested_coin.is_empty() && exchange_info_map.len() != 0 && trade_fee_map.len() != 0 {
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let mut filtered_suggested_coin_vec: Vec<&SuggestedCoin> = Vec::new();
|
||||
let mut is_exist_delete_symbol: bool = false;
|
||||
let mut delete_condition = String::from("WHERE ");
|
||||
|
|
@ -255,22 +257,12 @@ pub async fn buy_coin(
|
|||
.unwrap();
|
||||
for element in &filtered_suggested_coin_vec {
|
||||
if is_tradable == true {
|
||||
let exchange_info_result = exchange_info_vec
|
||||
.iter()
|
||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
||||
|
||||
let trade_fee_result = trade_fee_vec
|
||||
.iter()
|
||||
.position(|trade_fee| trade_fee.symbol == element.symbol);
|
||||
|
||||
if exchange_info_result.is_some() && trade_fee_result.is_some() {
|
||||
let lot_step_size =
|
||||
exchange_info_vec[exchange_info_result.unwrap()].stepsize;
|
||||
let tick_size = exchange_info_vec[exchange_info_result.unwrap()].ticksize;
|
||||
let base_commission_precision = exchange_info_vec
|
||||
[exchange_info_result.unwrap()]
|
||||
.base_commission_precision;
|
||||
let trade_fee = trade_fee_vec[trade_fee_result.unwrap()].takercommission;
|
||||
if exchange_info_map.contains_key(&element.symbol) && trade_fee_map.contains_key(&element.symbol) {
|
||||
let exchange_info = exchange_info_map.get(&element.symbol).unwrap();
|
||||
let lot_step_size = exchange_info.stepsize;
|
||||
let tick_size = exchange_info.ticksize;
|
||||
let base_commission_precision = exchange_info.base_commission_precision;
|
||||
let trade_fee = trade_fee_map.get(&element.symbol).unwrap().takercommission;
|
||||
|
||||
// buy the suggested coin and transfer it into [buy_ordered_coin_list]
|
||||
let mut base_qty_ordered = Decimal::new(0, 8);
|
||||
|
|
@ -312,7 +304,7 @@ pub async fn buy_coin(
|
|||
// order the symbol based on base_qty_ordered and current_price
|
||||
limit_order_buy(
|
||||
element,
|
||||
exchange_info_vec,
|
||||
exchange_info_map,
|
||||
trade_fee,
|
||||
TimeInForce::Gtc,
|
||||
element.suggested_price,
|
||||
|
|
@ -348,7 +340,6 @@ pub async fn buy_coin(
|
|||
delete_record(&suggested_coin_list_table_name, &delete_condition)
|
||||
.await
|
||||
.unwrap();
|
||||
println!("Delete suggested coin list");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -358,16 +349,15 @@ pub async fn buy_coin(
|
|||
// buy coin for test
|
||||
pub async fn buy_coin_for_test(
|
||||
client: &Client,
|
||||
coin_price_vec: &Vec<CoinPriceData>,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut suggested_coin = get_suggested_coin_list().await;
|
||||
let mut delete_condition = String::from("WHERE ");
|
||||
|
||||
let unit_trade_usdt = get_unit_trade_usdt().await;
|
||||
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let mut filtered_suggested_coin_vec: Vec<&SuggestedCoin> = Vec::new();
|
||||
|
||||
for element in &suggested_coin {
|
||||
|
|
@ -385,26 +375,11 @@ pub async fn buy_coin_for_test(
|
|||
|
||||
let insert_table_name = String::from("buy_ordered_coin_list");
|
||||
for element in &filtered_suggested_coin_vec {
|
||||
let lot_step_size = exchange_info_vec
|
||||
.iter()
|
||||
.find(|exchange_info| exchange_info.symbol == element.symbol)
|
||||
.unwrap()
|
||||
.stepsize;
|
||||
let tick_size = exchange_info_vec
|
||||
.iter()
|
||||
.find(|exchange_info| exchange_info.symbol == element.symbol)
|
||||
.unwrap()
|
||||
.ticksize;
|
||||
let base_commission_precision = exchange_info_vec
|
||||
.iter()
|
||||
.find(|exchange_info| exchange_info.symbol == element.symbol)
|
||||
.unwrap()
|
||||
.base_commission_precision;
|
||||
let trade_fee = trade_fee_vec
|
||||
.iter()
|
||||
.find(|trade_fee| trade_fee.symbol == element.symbol)
|
||||
.unwrap()
|
||||
.takercommission;
|
||||
if exchange_info_map.contains_key(&element.symbol) && trade_fee_map.contains_key(&element.symbol){
|
||||
let lot_step_size = exchange_info_map.get(&element.symbol).unwrap().stepsize;
|
||||
let tick_size = exchange_info_map.get(&element.symbol).unwrap().ticksize;
|
||||
let base_commission_precision = exchange_info_map.get(&element.symbol).unwrap().base_commission_precision;
|
||||
let trade_fee = trade_fee_map.get(&element.symbol).unwrap().takercommission;
|
||||
|
||||
// buy the suggested coin and transfer it into [buy_ordered_coin_list]
|
||||
// let price_index = coin_price_vec.iter().position(|x| *x.symbol == element.symbol);
|
||||
|
|
@ -435,7 +410,7 @@ pub async fn buy_coin_for_test(
|
|||
// order the symbol based on base_qty_ordered and current_price
|
||||
limit_order_buy(
|
||||
element,
|
||||
exchange_info_vec,
|
||||
exchange_info_map,
|
||||
trade_fee,
|
||||
TimeInForce::Gtc,
|
||||
order_price,
|
||||
|
|
@ -447,12 +422,13 @@ pub async fn buy_coin_for_test(
|
|||
.await;
|
||||
println!(" buy coin 완료");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
// monitoring the price change of pre-suggested coins before suggesting them and move them when conditions are agree
|
||||
pub async fn monitoring_pre_suggested_coins(
|
||||
coin_price_vec: &Vec<CoinPriceData>,
|
||||
coin_price_map: &HashMap<String, f64>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let select_table_name = String::from("pre_suggested_coin_list");
|
||||
let pre_suggested_coin_list = select_pre_suggested_coin_list().await;
|
||||
|
|
@ -468,14 +444,8 @@ pub async fn monitoring_pre_suggested_coins(
|
|||
let mut update_condition: Vec<(String, String)> = Vec::new();
|
||||
|
||||
for element in pre_suggested_coin_list {
|
||||
let price_index = coin_price_vec
|
||||
.iter()
|
||||
.position(|x| *x.symbol == element.symbol);
|
||||
if price_index.is_some() {
|
||||
price = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
coin_price_vec[price_index.unwrap()].current_price,
|
||||
)
|
||||
.unwrap();
|
||||
if let Some(current_price) = coin_price_map.get(&element.symbol) {
|
||||
price = rust_decimal::prelude::FromPrimitive::from_f64(*current_price).unwrap();
|
||||
profit_percent = ((price - element.suggested_price) / element.suggested_price)
|
||||
.to_f64()
|
||||
.unwrap()
|
||||
|
|
@ -561,7 +531,7 @@ pub async fn monitoring_pre_suggested_coins(
|
|||
insert_values.push(element.stoploss.to_string()); // stoploss
|
||||
insert_values.push(element.target_price.to_string()); // target_price
|
||||
insert_values.push(element.close_time.to_string()); // close_time
|
||||
insert_values.push(server_epoch().await.to_string()); // registered_server_epoch
|
||||
insert_values.push(get_server_epoch().await.to_string()); // registered_server_epoch
|
||||
insert_values.push(element.registerer.to_string()); // registerer
|
||||
insert_values.push(element.is_long.to_string()); // is_long
|
||||
insert_values.push(0.to_string()); // already_buy
|
||||
|
|
@ -626,7 +596,7 @@ pub async fn monitoring_scoreboard(
|
|||
let scoreboard_list = select_scoreboard().await;
|
||||
let mut count_short_coins = 0;
|
||||
let mut count_long_coins = 0;
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let mut timer_check = false;
|
||||
|
||||
for element in &filled_buy_orders {
|
||||
|
|
@ -756,12 +726,9 @@ pub async fn monitoring_scoreboard(
|
|||
let mut base_profit_percent = 0.0;
|
||||
let mut target_profit_percent = 0.0;
|
||||
|
||||
let opclo_1m_option = all_data
|
||||
.rt_price_1m_vec
|
||||
.iter()
|
||||
.position(|x| *x.0 == String::from("BTCUSDT"));
|
||||
if opclo_1m_option.is_some() {
|
||||
let mut opclo_1m_vec = all_data.rt_price_1m_vec[opclo_1m_option.unwrap()].1.clone();
|
||||
let symbol = String::from("BTCUSDT");
|
||||
if let Some(rt_price_1m_vec) = all_data.rt_price_1m_vec.get(&symbol) {
|
||||
let mut opclo_1m_vec = rt_price_1m_vec.clone();
|
||||
let opclo_sample_length: usize = 5; // 10 candle samsples
|
||||
opclo_1m_vec.pop();
|
||||
opclo_1m_vec.reverse();
|
||||
|
|
@ -949,7 +916,7 @@ async fn get_suggested_coin_list() -> Vec<SuggestedCoin> {
|
|||
select_result
|
||||
}
|
||||
|
||||
pub async fn server_epoch() -> i64 {
|
||||
pub async fn get_server_epoch() -> i64 {
|
||||
let table_name = String::from("time");
|
||||
let columns = String::from("*");
|
||||
let condition = None;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use crate::URL_TEST;
|
|||
// use crates
|
||||
use crate::coex::assets_managing_team::*;
|
||||
use crate::coex::exchange_team::*;
|
||||
use crate::coin_health_check_team::request_others::{CoinPriceData, ExchangeInfo, TradeFee};
|
||||
use crate::coin_health_check_team::request_others::{ExchangeInfo, TradeFee};
|
||||
use crate::database_control::*;
|
||||
use crate::decimal_funcs::*;
|
||||
use crate::signal_association::signal_decision::*;
|
||||
|
|
@ -30,6 +30,7 @@ use rust_decimal_macros::dec;
|
|||
use serde_json::Value;
|
||||
use sqlx::FromRow;
|
||||
use tokio::time::*;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub enum OrderSide {
|
||||
Buy,
|
||||
|
|
@ -298,7 +299,7 @@ pub async fn limit_order_buy_test(
|
|||
|
||||
pub async fn limit_order_buy(
|
||||
element: &SuggestedCoin,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee: Decimal,
|
||||
tif: TimeInForce,
|
||||
order_price: Decimal,
|
||||
|
|
@ -331,7 +332,7 @@ pub async fn limit_order_buy(
|
|||
];
|
||||
let mut insert_values: Vec<Vec<String>> = Vec::new();
|
||||
let mut insert_value_container: Vec<String> = Vec::new();
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
if RUNNING_MODE == SIMUL {
|
||||
insert_value_container.push(element.symbol.clone()); // symbol
|
||||
insert_value_container.push(0.to_string()); // order_id
|
||||
|
|
@ -350,7 +351,6 @@ pub async fn limit_order_buy(
|
|||
insert_value_container.push(0.0.to_string()); // pure_profit_percent
|
||||
insert_value_container.push(0.0.to_string()); // minimum_profit_percent
|
||||
insert_value_container.push(0.0.to_string()); // maximum_profit_percent
|
||||
insert_value_container.push(0.to_string()); // registerer
|
||||
insert_value_container.push(element.registerer.to_string()); // registerer
|
||||
insert_value_container.push(0.to_string()); // is_long
|
||||
|
||||
|
|
@ -498,13 +498,12 @@ pub async fn limit_order_buy(
|
|||
|
||||
pub async fn monitoring_open_buy_order(
|
||||
client: &Client,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let open_buy_orders = select_open_buy_orders().await;
|
||||
|
||||
if !open_buy_orders.is_empty() {
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let orders_outdated = open_buy_orders
|
||||
.iter()
|
||||
.filter(|&element| server_epoch - element.transact_time >= 600_000)
|
||||
|
|
@ -517,14 +516,14 @@ pub async fn monitoring_open_buy_order(
|
|||
// cancel orders outdated over 3mins and delete the records in [buy_ordered_coin_list]
|
||||
if !orders_outdated.is_empty() {
|
||||
for element in orders_outdated {
|
||||
cancel_buy_order(element, &client, exchange_info_vec, trade_fee_vec).await;
|
||||
cancel_buy_order(element, &client, trade_fee_map).await;
|
||||
sleep(Duration::from_millis(500)).await; // Use max 30 LIMIT/min
|
||||
}
|
||||
}
|
||||
|
||||
if !orders_to_be_queried.is_empty() {
|
||||
for element in orders_to_be_queried {
|
||||
query_buy_order(element, &client, exchange_info_vec, trade_fee_vec).await;
|
||||
query_buy_order(element, &client, trade_fee_map).await;
|
||||
sleep(Duration::from_millis(500)).await; // Use max 30 LIMIT/min
|
||||
}
|
||||
}
|
||||
|
|
@ -534,9 +533,9 @@ pub async fn monitoring_open_buy_order(
|
|||
}
|
||||
|
||||
pub async fn update_price_of_filled_buy_order(
|
||||
coin_price_vec: &Vec<CoinPriceData>,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
coin_price_map: &HashMap<String, f64>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let filled_buy_orders = select_filled_buy_orders(0).await?;
|
||||
|
||||
|
|
@ -548,9 +547,9 @@ pub async fn update_price_of_filled_buy_order(
|
|||
|
||||
for chunk in chunks {
|
||||
let chunk_vec = chunk.to_vec();
|
||||
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();
|
||||
let coin_price_vec_c = coin_price_map.clone();
|
||||
let exchange_info_vec_c = exchange_info_map.clone();
|
||||
let trade_fee_vec_c = trade_fee_map.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
update_repeat_task(
|
||||
chunk_vec,
|
||||
|
|
@ -567,16 +566,16 @@ pub async fn update_price_of_filled_buy_order(
|
|||
|
||||
async fn update_repeat_task(
|
||||
buy_ordered_coin_vec: Vec<BuyOrderedCoinList>,
|
||||
coin_price_vec: &Vec<CoinPriceData>,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
coin_price_map: &HashMap<String, f64>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let mut update_values: Vec<(String, String)> = Vec::new();
|
||||
let mut update_condition: Vec<(String, String)> = Vec::new();
|
||||
let mut price = Decimal::new(0, 8);
|
||||
let mut profit_percent = 0.0;
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
|
||||
let update_colums = vec![
|
||||
"current_price",
|
||||
|
|
@ -594,37 +593,13 @@ async fn update_repeat_task(
|
|||
for element in buy_ordered_coin_vec {
|
||||
// build update values
|
||||
update_record_build.clear();
|
||||
let price_index_option = coin_price_vec
|
||||
.iter()
|
||||
.position(|x| *x.symbol == element.symbol);
|
||||
let lot_step_size_result = exchange_info_vec
|
||||
.iter()
|
||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
||||
let quote_commission_precision_result = exchange_info_vec
|
||||
.iter()
|
||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
||||
let trade_fee_result = trade_fee_vec
|
||||
.iter()
|
||||
.position(|trade_fee| trade_fee.symbol == element.symbol);
|
||||
|
||||
if price_index_option.is_some()
|
||||
&& lot_step_size_result.is_some()
|
||||
&& quote_commission_precision_result.is_some()
|
||||
&& trade_fee_result.is_some()
|
||||
{
|
||||
let price_result: Option<Decimal> = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
coin_price_vec[price_index_option.unwrap()].current_price,
|
||||
);
|
||||
|
||||
if price_result.is_some() {
|
||||
price = price_result.unwrap();
|
||||
if coin_price_map.contains_key(&element.symbol) && exchange_info_map.contains_key(&element.symbol) && trade_fee_map.contains_key(&element.symbol) {
|
||||
price = rust_decimal::prelude::FromPrimitive::from_f64(*coin_price_map.get(&element.symbol).unwrap()).unwrap();
|
||||
if !price.is_zero() {
|
||||
// to get quote_commission_precision
|
||||
let trade_fee = trade_fee_vec[trade_fee_result.unwrap()].takercommission;
|
||||
let lot_step_size = exchange_info_vec[lot_step_size_result.unwrap()].stepsize;
|
||||
let quote_commission_precision = exchange_info_vec
|
||||
[quote_commission_precision_result.unwrap()]
|
||||
.quote_commission_precision;
|
||||
let trade_fee = trade_fee_map.get(&element.symbol).unwrap().takercommission;
|
||||
let lot_step_size = exchange_info_map.get(&element.symbol).unwrap().stepsize;
|
||||
let quote_commission_precision = exchange_info_map.get(&element.symbol).unwrap().quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_fee_adjusted.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
|
|
@ -686,7 +661,6 @@ async fn update_repeat_task(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_records(&update_table_name, &update_record, &update_colums).await;
|
||||
|
||||
|
|
@ -698,8 +672,8 @@ pub async fn limit_order_sell(
|
|||
sell_base_price: Decimal,
|
||||
sell_base_quantity: Decimal,
|
||||
client: &Client,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let insert_table_name = String::from("sell_ordered_coin_list");
|
||||
let insert_columns = vec![
|
||||
|
|
@ -724,18 +698,11 @@ pub async fn limit_order_sell(
|
|||
];
|
||||
let mut insert_values: Vec<Vec<String>> = Vec::new();
|
||||
let mut insert_value_container: Vec<String> = Vec::new();
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
if RUNNING_MODE == SIMUL && buy_ordered_coin.status == "SIMUL" {
|
||||
let quote_asset_precision_option = exchange_info_vec
|
||||
.iter()
|
||||
.position(|exchange_info| exchange_info.symbol == buy_ordered_coin.symbol);
|
||||
let trade_fee_option = trade_fee_vec
|
||||
.iter()
|
||||
.position(|trade_fee| trade_fee.symbol == buy_ordered_coin.symbol);
|
||||
if quote_asset_precision_option.is_some() && trade_fee_option.is_some() {
|
||||
let quote_asset_precision =
|
||||
exchange_info_vec[quote_asset_precision_option.unwrap()].quote_asset_precision;
|
||||
let trade_fee = trade_fee_vec[trade_fee_option.unwrap()].takercommission;
|
||||
if exchange_info_map.contains_key(&buy_ordered_coin.symbol) && trade_fee_map.contains_key(&buy_ordered_coin.symbol) {
|
||||
let quote_asset_precision = exchange_info_map.get(&buy_ordered_coin.symbol).unwrap().quote_asset_precision;
|
||||
let trade_fee = trade_fee_map.get(&buy_ordered_coin.symbol).unwrap().takercommission;
|
||||
|
||||
let get_usdt = decimal_mul(sell_base_quantity, sell_base_price)
|
||||
.round_dp_with_strategy(quote_asset_precision, RoundingStrategy::ToZero);
|
||||
|
|
@ -839,17 +806,9 @@ pub async fn limit_order_sell(
|
|||
.push(T.get("status").unwrap().as_str().unwrap().to_string()); // status
|
||||
insert_value_container.push(buy_ordered_coin.used_usdt.to_string()); // used_usdt
|
||||
|
||||
let quote_asset_precision_option = exchange_info_vec
|
||||
.iter()
|
||||
.position(|exchange_info| exchange_info.symbol == buy_ordered_coin.symbol);
|
||||
let trade_fee_option = trade_fee_vec
|
||||
.iter()
|
||||
.position(|trade_fee| trade_fee.symbol == buy_ordered_coin.symbol);
|
||||
if quote_asset_precision_option.is_some() && trade_fee_option.is_some() {
|
||||
let quote_asset_precision = exchange_info_vec
|
||||
[quote_asset_precision_option.unwrap()]
|
||||
.quote_asset_precision;
|
||||
let trade_fee = trade_fee_vec[trade_fee_option.unwrap()].takercommission;
|
||||
if exchange_info_map.contains_key(&buy_ordered_coin.symbol) && trade_fee_map.contains_key(&buy_ordered_coin.symbol) {
|
||||
let quote_asset_precision = exchange_info_map.get(&buy_ordered_coin.symbol).unwrap().quote_asset_precision;
|
||||
let trade_fee = trade_fee_map.get(&buy_ordered_coin.symbol).unwrap().takercommission;
|
||||
let get_usdt = rust_decimal::prelude::FromStr::from_str(
|
||||
T.get("cummulativeQuoteQty").unwrap().as_str().unwrap(),
|
||||
)
|
||||
|
|
@ -932,13 +891,13 @@ pub async fn limit_order_sell(
|
|||
|
||||
pub async fn monitoring_open_sell_order(
|
||||
client: &Client,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let open_sell_orders = select_open_sell_orders().await;
|
||||
|
||||
if !open_sell_orders.is_empty() {
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let orders_outdated = open_sell_orders
|
||||
.iter()
|
||||
.filter(|&element| server_epoch - element.transact_time >= 5_000)
|
||||
|
|
@ -951,14 +910,14 @@ pub async fn monitoring_open_sell_order(
|
|||
// cancel orders outdated over 30secs, delete its records in [sell_ordered_coin_list], and move them into [buy_ordered_coin_list]
|
||||
if !orders_outdated.is_empty() {
|
||||
for element in orders_outdated {
|
||||
cancel_sell_order(element, &client, exchange_info_vec, trade_fee_vec).await;
|
||||
cancel_sell_order(element, &client, exchange_info_map, trade_fee_map).await;
|
||||
sleep(Duration::from_millis(200)).await; // Use max 30 LIMIT/min
|
||||
}
|
||||
}
|
||||
|
||||
if !orders_to_be_queried.is_empty() {
|
||||
for element in orders_to_be_queried {
|
||||
query_sell_order(element, &client, exchange_info_vec, trade_fee_vec).await;
|
||||
query_sell_order(element, &client, exchange_info_map, trade_fee_map).await;
|
||||
sleep(Duration::from_millis(300)).await; // Use max 30 LIMIT/min
|
||||
}
|
||||
}
|
||||
|
|
@ -991,7 +950,7 @@ pub async fn monitoring_filled_sell_order(
|
|||
let mut insert_value_build: Vec<String> = Vec::new();
|
||||
|
||||
let update_table_name = String::from("achievement_evaluation");
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let mut total_get_usdt = Decimal::new(0, 8);
|
||||
|
||||
for element in filled_sell_orders {
|
||||
|
|
@ -1119,8 +1078,7 @@ pub async fn market_order(
|
|||
pub async fn cancel_buy_order(
|
||||
order: &BuyOrderedCoinList,
|
||||
client: &Client,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
// building URL and API-keys
|
||||
let mut url = String::new();
|
||||
|
|
@ -1195,18 +1153,8 @@ pub async fn cancel_buy_order(
|
|||
status_value_build.push('\'');
|
||||
|
||||
// calculate values to be updated
|
||||
let trade_fee_option = trade_fee_vec
|
||||
.iter()
|
||||
.position(|trade_fee| trade_fee.symbol == order.symbol);
|
||||
|
||||
let base_asset_precision_option = exchange_info_vec
|
||||
.iter()
|
||||
.position(|exchange_info| exchange_info.symbol == order.symbol);
|
||||
|
||||
if trade_fee_option.is_some() && base_asset_precision_option.is_some() {
|
||||
let trade_fee =
|
||||
trade_fee_vec[trade_fee_option.unwrap()].takercommission;
|
||||
|
||||
if trade_fee_map.contains_key(&order.symbol) {
|
||||
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||
let base_qty_ordered = rust_decimal::prelude::FromStr::from_str(
|
||||
T.get("executedQty").unwrap().as_str().unwrap(),
|
||||
)
|
||||
|
|
@ -1214,10 +1162,6 @@ pub async fn cancel_buy_order(
|
|||
|
||||
let base_qty_fee_adjusted =
|
||||
decimal_mul(base_qty_ordered, decimal_sub(dec!(1), trade_fee));
|
||||
|
||||
let base_asset_precision = exchange_info_vec
|
||||
[base_asset_precision_option.unwrap()]
|
||||
.base_asset_precision;
|
||||
let buy_price = decimal_div(cummulative_quote_qty, base_qty_ordered)
|
||||
.round_dp_with_strategy(8, RoundingStrategy::ToZero);
|
||||
|
||||
|
|
@ -1261,11 +1205,11 @@ pub async fn cancel_buy_order(
|
|||
} else if T.get("code").is_some() {
|
||||
// case that the order isn't canceled because the order completes while canceling
|
||||
// update record in ordered_coin_list
|
||||
query_buy_order(order, &client, exchange_info_vec, trade_fee_vec).await;
|
||||
query_buy_order(order, &client, trade_fee_map).await;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
query_buy_order(order, &client, exchange_info_vec, trade_fee_vec).await;
|
||||
query_buy_order(order, &client, trade_fee_map).await;
|
||||
// println!("cancel order buy failed!: {}", body);
|
||||
}
|
||||
}
|
||||
|
|
@ -1277,8 +1221,8 @@ pub async fn cancel_buy_order(
|
|||
pub async fn cancel_sell_order(
|
||||
order: &SellOrderedCoinList,
|
||||
client: &Client,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
// building URL and API-keys
|
||||
let mut url = String::new();
|
||||
|
|
@ -1364,7 +1308,7 @@ pub async fn cancel_sell_order(
|
|||
// insert record in [buy_ordered_coin_list]
|
||||
let mut insert_values: Vec<Vec<String>> = Vec::new();
|
||||
let mut insert_value_container: Vec<String> = Vec::new();
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
insert_value_container.push(order.symbol.clone()); // symbol
|
||||
insert_value_container.push(order.buy_order_id.to_string()); // order_id
|
||||
insert_value_container.push(order.transact_time.to_string()); // transact_time
|
||||
|
|
@ -1388,19 +1332,9 @@ pub async fn cancel_sell_order(
|
|||
insert_values.push(insert_value_container.clone());
|
||||
insert_records(&insert_table_name, &insert_columns, &insert_values).await;
|
||||
} else {
|
||||
let quote_asset_precision_option = exchange_info_vec
|
||||
.iter()
|
||||
.position(|exchange_info| exchange_info.symbol == order.symbol);
|
||||
let trade_fee_option = trade_fee_vec
|
||||
.iter()
|
||||
.position(|trade_fee| trade_fee.symbol == order.symbol);
|
||||
|
||||
if quote_asset_precision_option.is_some() && trade_fee_option.is_some() {
|
||||
let quote_asset_precision = exchange_info_vec
|
||||
[quote_asset_precision_option.unwrap()]
|
||||
.quote_asset_precision;
|
||||
let trade_fee =
|
||||
trade_fee_vec[trade_fee_option.unwrap()].takercommission;
|
||||
if exchange_info_map.contains_key(&order.symbol) && trade_fee_map.contains_key(&order.symbol) {
|
||||
let quote_asset_precision = exchange_info_map.get(&order.symbol).unwrap().quote_asset_precision;
|
||||
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||
if base_qty_executed == base_qty_ordered {
|
||||
// FILLED case
|
||||
// update status FILLED
|
||||
|
|
@ -1514,7 +1448,7 @@ pub async fn cancel_sell_order(
|
|||
decimal_mul(rest_base_qty, decimal_sub(dec!(1), trade_fee));
|
||||
let mut insert_values: Vec<Vec<String>> = Vec::new();
|
||||
let mut insert_value_container: Vec<String> = Vec::new();
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
insert_value_container.push(order.symbol.clone()); // symbol
|
||||
insert_value_container.push(order.buy_order_id.to_string()); // order_id
|
||||
insert_value_container.push(server_epoch.to_string()); // transact_time
|
||||
|
|
@ -1542,12 +1476,12 @@ pub async fn cancel_sell_order(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
query_sell_order(&order, &client, exchange_info_vec, trade_fee_vec).await;
|
||||
query_sell_order(&order, &client, exchange_info_map, trade_fee_map).await;
|
||||
}
|
||||
} else if T.get("code").is_some() {
|
||||
// case that the order isn't canceled because the order completes while canceling
|
||||
// update record in ordered_coin_list
|
||||
query_sell_order(&order, &client, exchange_info_vec, trade_fee_vec).await;
|
||||
query_sell_order(&order, &client, exchange_info_map, trade_fee_map).await;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
@ -1626,8 +1560,7 @@ pub async fn all_orders(
|
|||
pub async fn query_buy_order(
|
||||
order: &BuyOrderedCoinList,
|
||||
client: &Client,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
// building URL and API-keys
|
||||
let mut url = String::new();
|
||||
|
|
@ -1687,18 +1620,8 @@ pub async fn query_buy_order(
|
|||
value_build.push('\'');
|
||||
|
||||
// calculate values to be updated
|
||||
let trade_fee_option = trade_fee_vec
|
||||
.iter()
|
||||
.position(|trade_fee| trade_fee.symbol == order.symbol);
|
||||
let base_asset_precision_option = exchange_info_vec
|
||||
.iter()
|
||||
.position(|exchange_info| exchange_info.symbol == order.symbol);
|
||||
|
||||
if trade_fee_option.is_some() && base_asset_precision_option.is_some() {
|
||||
let trade_fee = trade_fee_vec[trade_fee_option.unwrap()].takercommission;
|
||||
let base_asset_precision = exchange_info_vec
|
||||
[base_asset_precision_option.unwrap()]
|
||||
.base_asset_precision;
|
||||
if trade_fee_map.contains_key(&order.symbol) {
|
||||
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||
let base_qty_ordered = rust_decimal::prelude::FromStr::from_str(
|
||||
T.get("executedQty").unwrap().as_str().unwrap(),
|
||||
)
|
||||
|
|
@ -1773,8 +1696,8 @@ pub async fn query_buy_order(
|
|||
pub async fn query_sell_order(
|
||||
order: &SellOrderedCoinList,
|
||||
client: &Client,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
// building URL and API-keys
|
||||
let mut url = String::new();
|
||||
|
|
@ -1817,18 +1740,9 @@ pub async fn query_sell_order(
|
|||
if T.get("status").is_some_and(|a| a.as_str().unwrap() == "FILLED")
|
||||
|| T.get("status").is_some_and(|a| a.as_str().unwrap() == "PARTIALLY_FILLED")
|
||||
{
|
||||
let quote_asset_precision_option = exchange_info_vec
|
||||
.iter()
|
||||
.position(|exchange_info| exchange_info.symbol == order.symbol);
|
||||
let trade_fee_option = trade_fee_vec
|
||||
.iter()
|
||||
.position(|trade_fee| trade_fee.symbol == order.symbol);
|
||||
|
||||
if quote_asset_precision_option.is_some() && trade_fee_option.is_some() {
|
||||
let quote_asset_precision = exchange_info_vec
|
||||
[quote_asset_precision_option.unwrap()]
|
||||
.quote_asset_precision;
|
||||
let trade_fee = trade_fee_vec[trade_fee_option.unwrap()].takercommission;
|
||||
if exchange_info_map.contains_key(&order.symbol) && trade_fee_map.contains_key(&order.symbol) {
|
||||
let quote_asset_precision = exchange_info_map.get(&order.symbol).unwrap().quote_asset_precision;
|
||||
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||
let get_usdt = rust_decimal::prelude::FromStr::from_str(
|
||||
T.get("cummulativeQuoteQty").unwrap().as_str().unwrap(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ use sqlx::{Error, FromRow};
|
|||
use std::borrow::{Borrow, BorrowMut};
|
||||
use std::sync::Arc;
|
||||
use tokio::{join, sync::Mutex, time::*};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Debug, FromRow)]
|
||||
struct AllCoinProfitChangeAvgList {
|
||||
|
|
@ -85,8 +86,8 @@ pub async fn initialize_valid_usde_trade() -> Result<(), Box<dyn std::error::Err
|
|||
|
||||
// filter valid USDT trades from all24hstatistics table in database
|
||||
pub async fn collect_valid_usde_trade(
|
||||
valid_usdt_trade_vec: &mut Vec<String>,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
valid_usdt_trade_vec: &mut HashSet<String>,
|
||||
exchange_info_vec: &HashMap<String, ExchangeInfo>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
#[derive(Debug, FromRow)]
|
||||
struct UsdtTrades {
|
||||
|
|
@ -138,27 +139,23 @@ pub async fn collect_valid_usde_trade(
|
|||
select_record(&fetch_table_name, &column_name, &condition, &usdt_trades).await?;
|
||||
|
||||
// filtering usdt trades
|
||||
let mut filtered_usdt_trades: Vec<String> = Vec::new();
|
||||
let mut excluded_usdt_trades: Vec<String> = Vec::new();
|
||||
let mut filtered_usdt_trades: HashSet<String> = HashSet::new();
|
||||
let mut excluded_usdt_trades: HashSet<String> = HashSet::new();
|
||||
for usdt_trade in usdt_trades {
|
||||
// build update values
|
||||
let step_size_result = exchange_info_vec
|
||||
.iter()
|
||||
.position(|exchange_info| exchange_info.symbol == usdt_trade.symbol);
|
||||
|
||||
if step_size_result.is_some() {
|
||||
if let Some(value) = exchange_info_vec.get(&usdt_trade.symbol) {
|
||||
let avg_price: Decimal =
|
||||
rust_decimal::prelude::FromPrimitive::from_f64(usdt_trade.weightedavgprice)
|
||||
.unwrap();
|
||||
let step_size = exchange_info_vec[step_size_result.unwrap()].stepsize;
|
||||
let step_size = value.stepsize;
|
||||
let step_price = decimal_mul(step_size, avg_price);
|
||||
let unit_trade_usdt = crate::coex::assets_managing_team::get_unit_trade_usdt().await;
|
||||
|
||||
// exclude USDT trades whose step_price is over than 1% of unit_trade_usdt
|
||||
if step_price > decimal_mul(unit_trade_usdt, dec!(0.01)) {
|
||||
excluded_usdt_trades.push(usdt_trade.symbol.clone());
|
||||
excluded_usdt_trades.insert(usdt_trade.symbol.clone());
|
||||
} else {
|
||||
filtered_usdt_trades.push(usdt_trade.symbol.clone());
|
||||
filtered_usdt_trades.insert(usdt_trade.symbol.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -188,74 +185,6 @@ pub async fn collect_valid_usde_trade(
|
|||
delete_all_rows(&table_name).await?;
|
||||
insert_records(&table_name, &columns, &value_wrapper).await?;
|
||||
|
||||
// major trades
|
||||
// if RUNNING_MODE == TEST || RUNNING_MODE == REAL || RUNNING_MODE == SIMUL {
|
||||
// let table_name = String::from("valid_usdt_trades");
|
||||
// let columns = vec!["symbol"];
|
||||
// let mut symbol_vec: Vec<String> = Vec::new();
|
||||
// let mut value_wrapper: Vec<Vec<String>> = Vec::new();
|
||||
|
||||
// value_wrapper.push(vec![String::from("BTCUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("ETHUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("XRPUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("DOGEUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("LTCUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("TRXUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("DOTUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("LINKUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("AVAXUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("BCHUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("SHIBUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("APTUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("ARBUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("ETCUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("XMRUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("HBARUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("UNIUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("XLMUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("VETUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("QNTUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("GRTUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("AAVEUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("EGLDUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("LDOUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("STXUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("MKRUSDT")]);
|
||||
// value_wrapper.push(vec![String::from("OPUSDT")]);
|
||||
|
||||
// symbol_vec.push(String::from("BTCUSDT"));
|
||||
// symbol_vec.push(String::from("ETHUSDT"));
|
||||
// symbol_vec.push(String::from("XRPUSDT"));
|
||||
// symbol_vec.push(String::from("DOGEUSDT"));
|
||||
// symbol_vec.push(String::from("LTCUSDT"));
|
||||
// symbol_vec.push(String::from("TRXUSDT"));
|
||||
// symbol_vec.push(String::from("DOTUSDT"));
|
||||
// symbol_vec.push(String::from("LINKUSDT"));
|
||||
// symbol_vec.push(String::from("AVAXUSDT"));
|
||||
// symbol_vec.push(String::from("BCHUSDT"));
|
||||
// symbol_vec.push(String::from("SHIBUSDT"));
|
||||
// symbol_vec.push(String::from("APTUSDT"));
|
||||
// symbol_vec.push(String::from("ARBUSDT"));
|
||||
// symbol_vec.push(String::from("ETCUSDT"));
|
||||
// symbol_vec.push(String::from("XMRUSDT"));
|
||||
// symbol_vec.push(String::from("HBARUSDT"));
|
||||
// symbol_vec.push(String::from("UNIUSDT"));
|
||||
// symbol_vec.push(String::from("XLMUSDT"));
|
||||
// symbol_vec.push(String::from("VETUSDT"));
|
||||
// symbol_vec.push(String::from("QNTUSDT"));
|
||||
// symbol_vec.push(String::from("GRTUSDT"));
|
||||
// symbol_vec.push(String::from("AAVEUSDT"));
|
||||
// symbol_vec.push(String::from("EGLDUSDT"));
|
||||
// symbol_vec.push(String::from("LDOUSDT"));
|
||||
// symbol_vec.push(String::from("STXUSDT"));
|
||||
// symbol_vec.push(String::from("MKRUSDT"));
|
||||
// symbol_vec.push(String::from("OPUSDT"));
|
||||
|
||||
// *valid_usdt_trade_vec = symbol_vec;
|
||||
// delete_all_rows(&table_name).await?;
|
||||
// insert_records(&table_name, &columns, &value_wrapper).await?;
|
||||
// }
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use sqlx::{Error, FromRow};
|
|||
use std::borrow::{Borrow, BorrowMut};
|
||||
use std::sync::Arc;
|
||||
use tokio::{join, sync::Mutex, time::*};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CandleData {
|
||||
|
|
@ -25,6 +26,26 @@ pub struct CandleData {
|
|||
pub ignore_this: f64,
|
||||
}
|
||||
|
||||
impl CandleData {
|
||||
fn new() -> CandleData {
|
||||
let candle_data = CandleData {
|
||||
open_time: 0,
|
||||
open_price: 0.0,
|
||||
high_price: 0.0,
|
||||
low_price: 0.0,
|
||||
close_price: 0.0,
|
||||
volume: 0.0,
|
||||
close_time: 0,
|
||||
quote_asset_volume: 0.0,
|
||||
number_of_trades: 0,
|
||||
taker_buy_base_asset_volume: 0.0,
|
||||
taker_buy_quote_asset_volume: 0.0,
|
||||
ignore_this: 0.0,
|
||||
};
|
||||
candle_data
|
||||
}
|
||||
}
|
||||
|
||||
// fetch the list of valid usdt trades
|
||||
#[derive(Debug, FromRow, Clone)]
|
||||
struct Symbols {
|
||||
|
|
@ -37,7 +58,7 @@ async fn request_candlestick_data(
|
|||
symbol: String,
|
||||
interval: &String,
|
||||
client: &Client,
|
||||
candle_set: &mut Vec<(String, Vec<CandleData>)>,
|
||||
candle_set: &mut HashMap<String, Vec<CandleData>>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut query = String::from("https://api.binance.com/api/v3/klines?");
|
||||
query.push_str("&symbol=");
|
||||
|
|
@ -67,7 +88,7 @@ async fn de_candle_json(
|
|||
symbol: String,
|
||||
interval: &String,
|
||||
body: &String,
|
||||
candle_set: &mut Vec<(String, Vec<CandleData>)>,
|
||||
candle_map: &mut HashMap<String, Vec<CandleData>>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let v: Value = serde_json::from_str(body.as_str())?;
|
||||
let mut into_vec = v.as_array();
|
||||
|
|
@ -75,21 +96,8 @@ async fn de_candle_json(
|
|||
return Err("Err")?;
|
||||
}
|
||||
|
||||
let mut candle_data = CandleData {
|
||||
open_time: 0,
|
||||
open_price: 0.0,
|
||||
high_price: 0.0,
|
||||
low_price: 0.0,
|
||||
close_price: 0.0,
|
||||
volume: 0.0,
|
||||
close_time: 0,
|
||||
quote_asset_volume: 0.0,
|
||||
number_of_trades: 0,
|
||||
taker_buy_base_asset_volume: 0.0,
|
||||
taker_buy_quote_asset_volume: 0.0,
|
||||
ignore_this: 0.0,
|
||||
};
|
||||
let mut candle_vec: Vec<CandleData> = Vec::new();
|
||||
let mut candle_data = CandleData::new();
|
||||
for element in into_vec.unwrap() {
|
||||
let inner_into_vec = element.as_array().unwrap();
|
||||
candle_data.open_time = element[0].as_i64().unwrap();
|
||||
|
|
@ -110,7 +118,7 @@ async fn de_candle_json(
|
|||
candle_vec.push(candle_data.clone());
|
||||
}
|
||||
|
||||
candle_set.push((symbol, candle_vec));
|
||||
candle_map.insert(symbol, candle_vec);
|
||||
// let search_result = candle_set.iter().position(|x| x.0 == symbol);
|
||||
// match search_result {
|
||||
// Some(T) => {
|
||||
|
|
@ -127,7 +135,7 @@ async fn de_candle_json2(
|
|||
symbol: String,
|
||||
interval: &String,
|
||||
body: &String,
|
||||
candle_set: &mut Vec<(String, Vec<CandleData>)>,
|
||||
candle_map: &mut HashMap<String, Vec<CandleData>>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let v: Value = serde_json::from_str(body.as_str())?;
|
||||
let mut into_vec = v.as_array();
|
||||
|
|
@ -135,21 +143,8 @@ async fn de_candle_json2(
|
|||
return Err("Err")?;
|
||||
}
|
||||
|
||||
let mut candle_data = CandleData {
|
||||
open_time: 0,
|
||||
open_price: 0.0,
|
||||
high_price: 0.0,
|
||||
low_price: 0.0,
|
||||
close_price: 0.0,
|
||||
volume: 0.0,
|
||||
close_time: 0,
|
||||
quote_asset_volume: 0.0,
|
||||
number_of_trades: 0,
|
||||
taker_buy_base_asset_volume: 0.0,
|
||||
taker_buy_quote_asset_volume: 0.0,
|
||||
ignore_this: 0.0,
|
||||
};
|
||||
let mut candle_vec: Vec<CandleData> = Vec::new();
|
||||
let mut candle_data = CandleData::new();
|
||||
for element in into_vec.unwrap() {
|
||||
let inner_into_vec = element.as_array().unwrap();
|
||||
candle_data.open_time = element[0].as_i64().unwrap();
|
||||
|
|
@ -170,14 +165,10 @@ async fn de_candle_json2(
|
|||
candle_vec.push(candle_data.clone());
|
||||
}
|
||||
|
||||
let search_result = candle_set.iter().position(|x| x.0 == symbol);
|
||||
match search_result {
|
||||
Some(T) => {
|
||||
candle_set[T].1 = candle_vec;
|
||||
}
|
||||
None => {
|
||||
candle_set.push((symbol, candle_vec));
|
||||
}
|
||||
if let Some(value) = candle_map.get_mut(&symbol) {
|
||||
*value = candle_vec;
|
||||
} else {
|
||||
candle_map.insert(symbol, candle_vec);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -262,7 +253,7 @@ pub async fn request_candlestick_initial(
|
|||
symbol: String,
|
||||
interval: &String,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut candle_set: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let mut candle_set: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(tokio::time::Duration::from_millis(20000))
|
||||
.build()
|
||||
|
|
@ -449,7 +440,7 @@ pub async fn create_candle_table(
|
|||
// for fetching 1m and 30m candle
|
||||
pub async fn fetch_candle_parallel(
|
||||
interval: &String,
|
||||
candle_vec: &mut Vec<(String, Vec<CandleData>)>,
|
||||
candle_map: &mut HashMap<String, Vec<CandleData>>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let instant = Instant::now();
|
||||
let fetch_table_name = String::from("valid_usdt_trades");
|
||||
|
|
@ -466,10 +457,10 @@ pub async fn fetch_candle_parallel(
|
|||
let chunks = select_result.chunks(20);
|
||||
let nbr_chunks = chunks.len();
|
||||
|
||||
let mut candle_vec_arc_wrapper: Vec<Arc<Mutex<Vec<(String, Vec<CandleData>)>>>> = Vec::new();
|
||||
let mut candle_vec_arc_wrapper: Vec<Arc<Mutex<HashMap<String, Vec<CandleData>>>>> = Vec::new();
|
||||
for _ in 0..nbr_chunks {
|
||||
let mut candle_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let mut candle_vec_arc = Arc::new(Mutex::new(candle_vec_temp));
|
||||
let mut candle_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let mut candle_vec_arc = Arc::new(Mutex::new(candle_map_temp));
|
||||
candle_vec_arc_wrapper.push(candle_vec_arc);
|
||||
}
|
||||
|
||||
|
|
@ -490,15 +481,15 @@ pub async fn fetch_candle_parallel(
|
|||
|
||||
match result {
|
||||
Ok(T) => {
|
||||
let mut candle_buffer: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let mut candle_buffer: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
for element in candle_vec_arc_wrapper {
|
||||
let a = element.lock().await.clone();
|
||||
for element in a {
|
||||
candle_buffer.push(element);
|
||||
for (symbol, candle_data) in a {
|
||||
candle_buffer.insert(symbol, candle_data);
|
||||
}
|
||||
}
|
||||
|
||||
*candle_vec = candle_buffer;
|
||||
*candle_map = candle_buffer;
|
||||
// println!(" candle {} 완료 elapsed:{:.2}s", interval.as_str(), instant.elapsed().as_secs_f32());
|
||||
}
|
||||
Err(E) => {
|
||||
|
|
@ -512,7 +503,7 @@ pub async fn fetch_candle_parallel(
|
|||
async fn repeat_task(
|
||||
interval: String,
|
||||
symbol_vec: Vec<Symbols>,
|
||||
my_count: Arc<Mutex<Vec<(String, Vec<CandleData>)>>>,
|
||||
my_count: Arc<Mutex<HashMap<String, Vec<CandleData>>>>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(tokio::time::Duration::from_millis(5000))
|
||||
|
|
@ -531,7 +522,7 @@ async fn repeat_task(
|
|||
// for fetching 1d, 1w, and 1mon candle
|
||||
pub async fn fetch_candle_delay(
|
||||
interval: &String,
|
||||
candle_vec: &mut Vec<(String, Vec<CandleData>)>,
|
||||
candle_vec: &mut HashMap<String, Vec<CandleData>>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let instant_func = Instant::now();
|
||||
let server_epoch = server_epoch().await;
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ use serde_json::Value;
|
|||
use sqlx::{Error, FromRow};
|
||||
use std::borrow::{Borrow, BorrowMut};
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use tokio::{join, sync::Mutex, time::*};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TradeFee {
|
||||
pub symbol: String,
|
||||
pub makercommission: Decimal,
|
||||
pub takercommission: Decimal,
|
||||
}
|
||||
|
|
@ -20,7 +20,6 @@ pub struct TradeFee {
|
|||
impl TradeFee {
|
||||
fn new() -> TradeFee {
|
||||
let a = TradeFee {
|
||||
symbol: String::new(),
|
||||
makercommission: Decimal::new(0, 8),
|
||||
takercommission: Decimal::new(0, 8),
|
||||
};
|
||||
|
|
@ -30,7 +29,6 @@ impl TradeFee {
|
|||
|
||||
#[derive(Debug, FromRow, Clone)]
|
||||
pub struct ExchangeInfo {
|
||||
pub symbol: String,
|
||||
pub stepsize: Decimal,
|
||||
pub ticksize: Decimal,
|
||||
pub base_asset_precision: u32,
|
||||
|
|
@ -42,7 +40,6 @@ pub struct ExchangeInfo {
|
|||
impl ExchangeInfo {
|
||||
fn new() -> ExchangeInfo {
|
||||
let a = ExchangeInfo {
|
||||
symbol: String::new(),
|
||||
stepsize: Decimal::new(0, 8),
|
||||
ticksize: Decimal::new(0, 8),
|
||||
base_asset_precision: 0,
|
||||
|
|
@ -54,27 +51,12 @@ impl ExchangeInfo {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct CoinPriceData {
|
||||
pub symbol: String,
|
||||
pub current_price: f64,
|
||||
}
|
||||
|
||||
impl CoinPriceData {
|
||||
fn new() -> CoinPriceData {
|
||||
let a = CoinPriceData {
|
||||
symbol: String::new(),
|
||||
current_price: 0.0,
|
||||
};
|
||||
a
|
||||
}
|
||||
}
|
||||
// request all coin price (/api, Weight(IP) 2)
|
||||
// request_all_coin_price -> de_all_coin_price_json -> store_coin_price_db
|
||||
// pub async fn request_all_coin_price(client: &Client, price_vec: &Arc<Mutex<Vec<(String, f64)>>>) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
pub async fn request_all_coin_price(
|
||||
client: &Client,
|
||||
price_vec: &mut Vec<CoinPriceData>,
|
||||
price_vec: &mut HashMap<String, f64>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let url = "https://api.binance.com/api/v3/ticker/price";
|
||||
let mut response = client.get(url).send().await?;
|
||||
|
|
@ -88,7 +70,7 @@ pub async fn request_all_coin_price(
|
|||
|
||||
async fn de_all_coin_price_json(
|
||||
body: &String,
|
||||
price_vec: &mut Vec<CoinPriceData>,
|
||||
price_vec: &mut HashMap<String, f64>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let v: Value = serde_json::from_str(body.as_str())?;
|
||||
let into_vec = v.as_array();
|
||||
|
|
@ -97,27 +79,23 @@ async fn de_all_coin_price_json(
|
|||
}
|
||||
let mut object_map = &serde_json::map::Map::new();
|
||||
|
||||
let mut de_price_vec: Vec<CoinPriceData> = Vec::new();
|
||||
let mut data_temp = CoinPriceData::new();
|
||||
|
||||
let mut symbol = String::new();
|
||||
let mut price = 0.0;
|
||||
for element in into_vec.unwrap() {
|
||||
object_map = element.as_object().unwrap();
|
||||
let mut object_map_iter = object_map.iter();
|
||||
|
||||
for element in object_map_iter {
|
||||
match element.0.as_str() {
|
||||
"symbol" => data_temp.symbol = element.1.as_str().unwrap().to_string(),
|
||||
"price" => {
|
||||
data_temp.current_price = element.1.as_str().unwrap().parse::<f64>().unwrap()
|
||||
}
|
||||
"symbol" => symbol = element.1.as_str().unwrap().to_string(),
|
||||
"price" => price = element.1.as_str().unwrap().parse::<f64>().unwrap(),
|
||||
_ => {
|
||||
println!("Elements in body msg are changed. Please update both your coinprices table and vectors.");
|
||||
}
|
||||
}
|
||||
price_vec.insert(symbol.clone(), price);
|
||||
}
|
||||
de_price_vec.push(data_temp.clone());
|
||||
}
|
||||
*price_vec = de_price_vec;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -129,7 +107,7 @@ pub async fn request_trade_fee(
|
|||
local_epoch: u128,
|
||||
difference_epoch: i64,
|
||||
client: &Client,
|
||||
tradefee_vec: &mut Vec<TradeFee>,
|
||||
tradefee_vec: &mut HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut base_url = String::from("https://api.binance.com/sapi/v1/asset/tradeFee?");
|
||||
|
||||
|
|
@ -188,7 +166,7 @@ pub async fn request_trade_fee(
|
|||
|
||||
async fn de_trade_fee_json(
|
||||
body: &String,
|
||||
tradefee_vec: &mut Vec<TradeFee>,
|
||||
tradefee_map: &mut HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let v: Value = serde_json::from_str(body.as_str())?;
|
||||
|
||||
|
|
@ -197,9 +175,9 @@ async fn de_trade_fee_json(
|
|||
return Err("Err")?;
|
||||
}
|
||||
let mut object_map = &serde_json::map::Map::new();
|
||||
let mut de_tradefee_vec: Vec<TradeFee> = Vec::new();
|
||||
let mut tradefee_map_build: HashMap<String, TradeFee> = HashMap::new();
|
||||
let mut symbol = String::new();
|
||||
let mut tradefee_data = TradeFee::new();
|
||||
|
||||
for element in into_vec.unwrap() {
|
||||
object_map = element.as_object().unwrap();
|
||||
|
||||
|
|
@ -207,7 +185,7 @@ async fn de_trade_fee_json(
|
|||
|
||||
for element in object_map_iter {
|
||||
match element.0.as_str() {
|
||||
"symbol" => tradefee_data.symbol = element.1.as_str().unwrap().to_string(),
|
||||
"symbol" => symbol = element.1.as_str().unwrap().to_string(),
|
||||
"makerCommission" => {
|
||||
tradefee_data.makercommission =
|
||||
rust_decimal::prelude::FromStr::from_str(element.1.as_str().unwrap())
|
||||
|
|
@ -223,10 +201,9 @@ async fn de_trade_fee_json(
|
|||
}
|
||||
}
|
||||
}
|
||||
de_tradefee_vec.push(tradefee_data.clone());
|
||||
tradefee_map_build.insert(symbol.clone(), tradefee_data.clone());
|
||||
}
|
||||
tradefee_vec.clear();
|
||||
*tradefee_vec = de_tradefee_vec;
|
||||
*tradefee_map = tradefee_map_build;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -354,7 +331,7 @@ async fn store_24h_change_db(
|
|||
// request exchange information. (/api, Weight(IP) 10)
|
||||
pub async fn request_exchange_infomation(
|
||||
client: &Client,
|
||||
exchange_info_data: &mut Vec<ExchangeInfo>,
|
||||
exchange_info_map: &mut HashMap<String, ExchangeInfo>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
// building URL and API-keys
|
||||
let mut url = String::new();
|
||||
|
|
@ -380,8 +357,9 @@ pub async fn request_exchange_infomation(
|
|||
return Err("Err")?;
|
||||
}
|
||||
|
||||
let mut data_temp = ExchangeInfo::new();
|
||||
let mut data_temp_vec: Vec<ExchangeInfo> = Vec::new();
|
||||
let mut symbol = String::new();
|
||||
let mut exchange_info = ExchangeInfo::new();
|
||||
let mut data_map_temp: HashMap<String, ExchangeInfo> = HashMap::new();
|
||||
|
||||
for element in into_vec.unwrap() {
|
||||
if element.0.contains("symbols") {
|
||||
|
|
@ -394,23 +372,23 @@ pub async fn request_exchange_infomation(
|
|||
.unwrap()
|
||||
.ends_with("USDT")
|
||||
{
|
||||
data_temp.symbol =
|
||||
symbol =
|
||||
(element.get("symbol").unwrap().as_str().unwrap().to_string());
|
||||
data_temp.base_asset_precision =
|
||||
exchange_info.base_asset_precision =
|
||||
(element.get("baseAssetPrecision").unwrap().as_u64().unwrap()) as u32;
|
||||
data_temp.base_commission_precision = (element
|
||||
exchange_info.base_commission_precision = (element
|
||||
.get("baseCommissionPrecision")
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap())
|
||||
as u32;
|
||||
data_temp.quote_asset_precision = (element
|
||||
exchange_info.quote_asset_precision = (element
|
||||
.get("quoteAssetPrecision")
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap())
|
||||
as u32;
|
||||
data_temp.quote_commission_precision = (element
|
||||
exchange_info.quote_commission_precision = (element
|
||||
.get("quoteCommissionPrecision")
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
|
|
@ -426,7 +404,7 @@ pub async fn request_exchange_infomation(
|
|||
.unwrap()
|
||||
.starts_with("LOT_SIZE")
|
||||
{
|
||||
data_temp.stepsize = rust_decimal::prelude::FromStr::from_str(
|
||||
exchange_info.stepsize = rust_decimal::prelude::FromStr::from_str(
|
||||
element.get("stepSize").unwrap().as_str().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
|
@ -439,20 +417,20 @@ pub async fn request_exchange_infomation(
|
|||
.unwrap()
|
||||
.starts_with("PRICE_FILTER")
|
||||
{
|
||||
data_temp.ticksize = rust_decimal::prelude::FromStr::from_str(
|
||||
exchange_info.ticksize = rust_decimal::prelude::FromStr::from_str(
|
||||
element.get("tickSize").unwrap().as_str().unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
data_temp_vec.push(data_temp.clone());
|
||||
data_map_temp.insert(symbol.clone(), exchange_info.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*exchange_info_data = data_temp_vec;
|
||||
*exchange_info_map = data_map_temp;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ pub enum RunningMode {
|
|||
TEST,
|
||||
REAL,
|
||||
}
|
||||
pub const RUNNING_MODE: RunningMode = RunningMode::REAL;
|
||||
pub const RUNNING_MODE: RunningMode = RunningMode::SIMUL;
|
||||
|
||||
pub mod coex;
|
||||
pub mod coin_health_check_team;
|
||||
|
|
|
|||
406
src/main.rs
406
src/main.rs
|
|
@ -3,13 +3,15 @@
|
|||
|
||||
use crate::coin_health_check_team::*;
|
||||
use crate::request_candles::CandleData;
|
||||
use crate::request_others::{CoinPriceData, ExchangeInfo, TradeFee};
|
||||
use crate::request_others::{ExchangeInfo, TradeFee};
|
||||
use crate::server_health_check_team::ServerHealth;
|
||||
use crate::strategy_team::AllData;
|
||||
use crate::time_checking_team::UserTime;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use reqwest::{Client, ClientBuilder};
|
||||
use rust_decimal::Decimal;
|
||||
use sqlx::{mysql::*, Connection, Executor, FromRow, Row};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
sync::Arc,
|
||||
|
|
@ -80,88 +82,88 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let (tx2, mut rx2) = watch::channel(0); // epoch_difference
|
||||
|
||||
// trade fee data
|
||||
let mut tradefee_vec: Vec<TradeFee> = Vec::new(); // (symbol, makerCommission, takerCommission)
|
||||
let (tx_tradefee_vec, mut rx_tradefee_vec) = watch::channel(tradefee_vec);
|
||||
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();
|
||||
let mut tradefee_vec_capacity = rx_tradefee_vec.clone();
|
||||
let mut tradefee_map: HashMap<String, TradeFee> = HashMap::new(); // <symbol, TradeFee>
|
||||
let (tx_tradefee_map, mut rx_tradefee_map) = watch::channel(tradefee_map);
|
||||
let mut rx2_tradefee_map = rx_tradefee_map.clone();
|
||||
let mut rx3_tradefee_map = rx_tradefee_map.clone();
|
||||
let mut rx4_tradefee_map = rx_tradefee_map.clone();
|
||||
let mut rx5_tradefee_map = rx_tradefee_map.clone();
|
||||
let mut tradefee_map_capacity = rx_tradefee_map.clone();
|
||||
|
||||
// valid usdt trade data
|
||||
let mut valid_usdt_trade_vec: Vec<String> = Vec::new(); // symbol
|
||||
let (tx_valid_usdt_trade_vec, mut rx_valid_usdt_trade_vec) =
|
||||
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();
|
||||
let mut valid_usdt_trade_vec_capacity = rx_valid_usdt_trade_vec.clone();
|
||||
let mut valid_usdt_trade_set: HashSet<String> = HashSet::new(); // symbol
|
||||
let (tx_valid_usdt_trade_set, mut rx_valid_usdt_trade_set) =
|
||||
watch::channel(valid_usdt_trade_set);
|
||||
let mut rx2_valid_usdt_trade_set = rx_valid_usdt_trade_set.clone();
|
||||
let mut rx3_valid_usdt_trade_set = rx_valid_usdt_trade_set.clone();
|
||||
let mut rx4_valid_usdt_trade_set = rx_valid_usdt_trade_set.clone();
|
||||
let mut valid_usdt_trade_set_capacity = rx_valid_usdt_trade_set.clone();
|
||||
|
||||
// price per second data and channels
|
||||
let mut price_vec: Vec<CoinPriceData> = Vec::new(); // (symbol, price)
|
||||
let (tx_price_vec, mut rx_price_vec) = watch::channel(price_vec);
|
||||
let mut rx3_price_vec = rx_price_vec.clone();
|
||||
let mut rx5_price_vec = rx_price_vec.clone();
|
||||
let mut price_vec_capacity = rx_price_vec.clone();
|
||||
let mut price_map: HashMap<String, f64> = HashMap::new(); // <symbol, price>
|
||||
let (tx_price_map, mut rx_price_map) = watch::channel(price_map);
|
||||
let mut rx3_price_map = rx_price_map.clone();
|
||||
let mut rx5_price_map = rx_price_map.clone();
|
||||
let mut price_map_capacity = rx_price_map.clone();
|
||||
|
||||
// candle data from endpoint and channels
|
||||
let mut candle_1m_vec: Vec<(String, Vec<CandleData>)> = Vec::new(); // (symbol, Vec<CandleData)>
|
||||
let (tx_candle_1m_vec, mut rx_candle_1m_vec) = watch::channel(candle_1m_vec);
|
||||
let mut candle_1m_vec_capacity = rx_candle_1m_vec.clone();
|
||||
let mut candle_1m_map: HashMap<String, Vec<CandleData>> = HashMap::new(); // <symbol, Vec<CandleData>>
|
||||
let (tx_candle_1m_map, mut rx_candle_1m_map) = watch::channel(candle_1m_map);
|
||||
let mut candle_1m_map_capacity = rx_candle_1m_map.clone();
|
||||
|
||||
let mut candle_30m_vec: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let (tx_candle_30m_vec, mut rx_candle_30m_vec) = watch::channel(candle_30m_vec);
|
||||
let mut candle_30m_vec_capacity = rx_candle_30m_vec.clone();
|
||||
let mut candle_30m_map: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let (tx_candle_30m_map, mut rx_candle_30m_map) = watch::channel(candle_30m_map);
|
||||
let mut candle_30m_map_capacity = rx_candle_30m_map.clone();
|
||||
|
||||
let mut candle_1d_vec: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let (tx_candle_1d_vec, mut rx_candle_1d_vec) = watch::channel(candle_1d_vec);
|
||||
let mut candle_1d_vec_capacity = rx_candle_1d_vec.clone();
|
||||
let mut candle_1d_map: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let (tx_candle_1d_map, mut rx_candle_1d_map) = watch::channel(candle_1d_map);
|
||||
let mut candle_1d_map_capacity = rx_candle_1d_map.clone();
|
||||
|
||||
let mut candle_1w_vec: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let (tx_candle_1w_vec, mut rx_candle_1w_vec) = watch::channel(candle_1w_vec);
|
||||
let mut candle_1w_vec_capacity = rx_candle_1w_vec.clone();
|
||||
let mut candle_1w_map: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let (tx_candle_1w_map, mut rx_candle_1w_map) = watch::channel(candle_1w_map);
|
||||
let mut candle_1w_map_capacity = rx_candle_1w_map.clone();
|
||||
|
||||
let mut candle_1mon_vec: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let (tx_candle_1mon_vec, mut rx_candle_1mon_vec) = watch::channel(candle_1mon_vec);
|
||||
let mut candle_1mon_vec_capacity = rx_candle_1mon_vec.clone();
|
||||
let mut candle_1mon_map: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let (tx_candle_1mon_map, mut rx_candle_1mon_map) = watch::channel(candle_1mon_map);
|
||||
let mut candle_1mon_map_capacity = rx_candle_1mon_map.clone();
|
||||
|
||||
// real-time reflected price data and channels
|
||||
let mut rt_price_1m_vec: Vec<(String, Vec<RealtimePriceData>)> = Vec::new(); // (symbol, Vec<RealtimePriceData)>
|
||||
let (tx_rt_price_1m_vec, mut rx_rt_price_1m_vec) = watch::channel(rt_price_1m_vec);
|
||||
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_1m_vec_capacity = rx_rt_price_1m_vec.clone();
|
||||
let mut rt_price_1m_map: HashMap<String, Vec<RealtimePriceData>> = HashMap::new(); // <symbol, Vec<RealtimePriceData>>
|
||||
let (tx_rt_price_1m_map, mut rx_rt_price_1m_map) = watch::channel(rt_price_1m_map);
|
||||
let mut rx2_rt_price_1m_map = rx_rt_price_1m_map.clone();
|
||||
let mut rx3_rt_price_1m_map = rx_rt_price_1m_map.clone();
|
||||
let mut rx4_rt_price_1m_map = rx_rt_price_1m_map.clone();
|
||||
let mut rx5_rt_price_1m_map = rx_rt_price_1m_map.clone();
|
||||
let mut rt_price_1m_map_capacity = rx_rt_price_1m_map.clone();
|
||||
|
||||
let mut rt_price_30m_vec: Vec<(String, Vec<RealtimePriceData>)> = 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_30m_vec_capacity = rx_rt_price_30m_vec.clone();
|
||||
let mut rt_price_30m_map: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let (tx_rt_price_30m_map, mut rx_rt_price_30m_map) = watch::channel(rt_price_30m_map);
|
||||
let mut rx2_rt_price_30m_map = rx_rt_price_30m_map.clone();
|
||||
let mut rx3_rt_price_30m_map = rx_rt_price_30m_map.clone();
|
||||
let mut rx4_rt_price_30m_map = rx_rt_price_30m_map.clone();
|
||||
let mut rx5_rt_price_30m_map = rx_rt_price_30m_map.clone();
|
||||
let mut rt_price_30m_map_capacity = rx_rt_price_30m_map.clone();
|
||||
|
||||
let mut rt_price_1d_vec: Vec<(String, Vec<RealtimePriceData>)> = 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_1d_vec_capacity = rx_rt_price_1d_vec.clone();
|
||||
let mut rt_price_1d_map: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let (tx_rt_price_1d_map, mut rx_rt_price_1d_map) = watch::channel(rt_price_1d_map);
|
||||
let mut rx2_rt_price_1d_map = rx_rt_price_1d_map.clone();
|
||||
let mut rx3_rt_price_1d_map = rx_rt_price_1d_map.clone();
|
||||
let mut rx4_rt_price_1d_map = rx_rt_price_1d_map.clone();
|
||||
let mut rt_price_1d_map_capacity = rx_rt_price_1d_map.clone();
|
||||
|
||||
let mut rt_price_1w_vec: Vec<(String, Vec<RealtimePriceData>)> = 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_1w_vec_capacity = rx_rt_price_1w_vec.clone();
|
||||
let mut rt_price_1w_map: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let (tx_rt_price_1w_map, mut rx_rt_price_1w_map) = watch::channel(rt_price_1w_map);
|
||||
let mut rx2_rt_price_1w_map = rx_rt_price_1w_map.clone();
|
||||
let mut rx3_rt_price_1w_map = rx_rt_price_1w_map.clone();
|
||||
let mut rx4_rt_price_1w_map = rx_rt_price_1w_map.clone();
|
||||
let mut rt_price_1w_map_capacity = rx_rt_price_1w_map.clone();
|
||||
|
||||
let mut rt_price_1mon_vec: Vec<(String, Vec<RealtimePriceData>)> = 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();
|
||||
let mut rt_price_1mon_vec_capacity = rx_rt_price_1mon_vec.clone();
|
||||
let mut rt_price_1mon_map: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let (tx_rt_price_1mon_map, mut rx_rt_price_1mon_map) = watch::channel(rt_price_1mon_map);
|
||||
let mut rx2_rt_price_1mon_map = rx_rt_price_1mon_map.clone();
|
||||
let mut rx3_rt_price_1mon_map = rx_rt_price_1mon_map.clone();
|
||||
let mut rx4_rt_price_1mon_map = rx_rt_price_1mon_map.clone();
|
||||
let mut rt_price_1mon_map_capacity = rx_rt_price_1mon_map.clone();
|
||||
|
||||
// TEMA data
|
||||
// let mut tema3_1m_data: Vec<(String, Vec<(f64, i64)>)> = Vec::new(); // Vec<(symbol, Vec<(price, closetime)>)>
|
||||
|
|
@ -198,14 +200,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
// let (tx_tema30_1mon_data, mut rx_tema30_1mon_data) = watch::channel(tema30_1mon_data);
|
||||
|
||||
// Exchange Information data
|
||||
let mut exchange_info_data: Vec<ExchangeInfo> = Vec::new();
|
||||
let (tx_exchange_info_data, mut rx_exchange_info_data) = watch::channel(exchange_info_data);
|
||||
let mut rx2_exchange_info_data = rx_exchange_info_data.clone();
|
||||
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();
|
||||
let mut exchange_info_data_capacity = rx_exchange_info_data.clone();
|
||||
let mut exchange_info_map: HashMap<String, ExchangeInfo> = HashMap::new();
|
||||
let (tx_exchange_info_map, mut rx_exchange_info_map) = watch::channel(exchange_info_map);
|
||||
let mut rx2_exchange_info_map = rx_exchange_info_map.clone();
|
||||
let mut rx3_exchange_info_map = rx_exchange_info_map.clone();
|
||||
let mut rx4_exchange_info_map = rx_exchange_info_map.clone();
|
||||
let mut rx5_exchange_info_map = rx_exchange_info_map.clone();
|
||||
let mut rx6_exchange_info_map = rx_exchange_info_map.clone();
|
||||
let mut exchange_info_map_capacity = rx_exchange_info_map.clone();
|
||||
|
||||
{
|
||||
if RUNNING_MODE == RunningMode::REAL {
|
||||
|
|
@ -225,20 +227,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let interval_1w = String::from("1w");
|
||||
let interval_1mon = String::from("1mon");
|
||||
|
||||
let mut candle_30m_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let mut candle_1d_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let mut candle_1w_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let mut candle_1mon_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let mut candle_30m_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let mut candle_1d_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let mut candle_1w_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let mut candle_1mon_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
|
||||
request_candles::fetch_candle_parallel(&interval_30m, &mut candle_30m_vec_temp).await;
|
||||
request_candles::fetch_candle_parallel(&interval_1d, &mut candle_1d_vec_temp).await;
|
||||
request_candles::fetch_candle_parallel(&interval_1w, &mut candle_1w_vec_temp).await;
|
||||
request_candles::fetch_candle_parallel(&interval_1mon, &mut candle_1mon_vec_temp).await;
|
||||
request_candles::fetch_candle_parallel(&interval_30m, &mut candle_30m_map_temp).await;
|
||||
request_candles::fetch_candle_parallel(&interval_1d, &mut candle_1d_map_temp).await;
|
||||
request_candles::fetch_candle_parallel(&interval_1w, &mut candle_1w_map_temp).await;
|
||||
request_candles::fetch_candle_parallel(&interval_1mon, &mut candle_1mon_map_temp).await;
|
||||
|
||||
tx_candle_30m_vec.send_modify(|vec| *vec = candle_30m_vec_temp);
|
||||
tx_candle_1d_vec.send_modify(|vec| *vec = candle_1d_vec_temp);
|
||||
tx_candle_1w_vec.send_modify(|vec| *vec = candle_1w_vec_temp);
|
||||
tx_candle_1mon_vec.send_modify(|vec| *vec = candle_1mon_vec_temp);
|
||||
tx_candle_30m_map.send_modify(|map| *map = candle_30m_map_temp);
|
||||
tx_candle_1d_map.send_modify(|map| *map = candle_1d_map_temp);
|
||||
tx_candle_1w_map.send_modify(|map| *map = candle_1w_map_temp);
|
||||
tx_candle_1mon_map.send_modify(|map| *map = candle_1mon_map_temp);
|
||||
|
||||
// sleep as much as the loop recurs per 60 seconds, expecting child threads will have finished within 60 seconds.
|
||||
println!("Ok..");
|
||||
|
|
@ -515,10 +517,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
match tx1_changed {
|
||||
Ok(T) => match tx2_changed {
|
||||
Ok(T) => {
|
||||
let mut tradefee_vec_temp: Vec<TradeFee> = Vec::new();
|
||||
let mut result;
|
||||
let mut tradefee_vec_temp: HashMap<String, TradeFee> = HashMap::new();
|
||||
loop {
|
||||
result = request_others::request_trade_fee(
|
||||
let result = request_others::request_trade_fee(
|
||||
API_KEY,
|
||||
SECRET_KEY,
|
||||
local_epoch,
|
||||
|
|
@ -535,13 +536,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
}
|
||||
}
|
||||
|
||||
match result {
|
||||
Ok(T) => {
|
||||
tx_tradefee_vec.send_modify(|vec| *vec = tradefee_vec_temp);
|
||||
tx_tradefee_map.send_modify(|vec| *vec = tradefee_vec_temp);
|
||||
tx_task2.send(2).expect("The mpsc channel has been closed.");
|
||||
}
|
||||
Err(E) => {}
|
||||
}
|
||||
|
||||
}
|
||||
Err(E) => {
|
||||
panic!("tx2-rx2 channel has been closed.")
|
||||
|
|
@ -567,30 +564,27 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let mut exchange_info_data_temp: Vec<ExchangeInfo> = Vec::new();
|
||||
let mut exchange_info_map_temp: HashMap<String, ExchangeInfo> = HashMap::new();
|
||||
let mut result;
|
||||
loop {
|
||||
result = coin_health_check_team::request_others::request_exchange_infomation(
|
||||
&client,
|
||||
&mut exchange_info_data_temp,
|
||||
&mut exchange_info_map_temp,
|
||||
)
|
||||
.await;
|
||||
|
||||
// retry
|
||||
if exchange_info_data_temp.len() == 0 {
|
||||
if exchange_info_map_temp.len() == 0 {
|
||||
sleep(Duration::from_secs(3)).await;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
match result {
|
||||
Ok(T) => {
|
||||
tx_exchange_info_data.send_modify(|vec| *vec = exchange_info_data_temp);
|
||||
|
||||
tx_exchange_info_map.send_modify(|vec| *vec = exchange_info_map_temp);
|
||||
tx_task3.send(3).expect("The mpsc channel has been closed.");
|
||||
}
|
||||
Err(E) => {}
|
||||
}
|
||||
|
||||
sleep(Duration::from_secs(300)).await; // sleep for 5 mins
|
||||
}
|
||||
});
|
||||
|
|
@ -613,23 +607,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let result = request_others::request_24hr_ticker_price_change_statistics(&client).await;
|
||||
match result {
|
||||
Ok(T) => {
|
||||
let exchange_info_vec = rx5_exchange_info_data.borrow().clone();
|
||||
let mut valid_usdt_trade_vec_temp: Vec<String> = Vec::new();
|
||||
let result = monitors::collect_valid_usde_trade(
|
||||
&mut valid_usdt_trade_vec_temp,
|
||||
&exchange_info_vec,
|
||||
let exchange_info_map = rx5_exchange_info_map.borrow().clone();
|
||||
let mut valid_usdt_trade_set_temp: HashSet<String> = HashSet::new();
|
||||
monitors::collect_valid_usde_trade(
|
||||
&mut valid_usdt_trade_set_temp,
|
||||
&exchange_info_map,
|
||||
)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(T) => {
|
||||
tx_valid_usdt_trade_vec
|
||||
.send_modify(|vec| *vec = valid_usdt_trade_vec_temp);
|
||||
tx_valid_usdt_trade_set
|
||||
.send_modify(|vec| *vec = valid_usdt_trade_set_temp);
|
||||
tx_task4.send(4).expect("The mpsc channel has been closed.");
|
||||
}
|
||||
Err(E) => {}
|
||||
}
|
||||
}
|
||||
Err(E) => {
|
||||
println!(">>> Failed to monitor usdt_24h_change_profit_index.");
|
||||
}
|
||||
|
|
@ -676,7 +665,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
// Task#5: price per second
|
||||
tokio::task::spawn(async move {
|
||||
sleep(Duration::from_secs(20)).await;
|
||||
let mut server_epoch = 0;
|
||||
let mut elapsed_time = 0;
|
||||
loop {
|
||||
let instant = Instant::now();
|
||||
|
|
@ -684,101 +672,85 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.timeout(tokio::time::Duration::from_millis(1000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let mut price_vec_temp: Vec<CoinPriceData> = Vec::new();
|
||||
let result = request_others::request_all_coin_price(&client, &mut price_vec_temp).await;
|
||||
let mut price_vec_temp_c: Vec<CoinPriceData> = Vec::new();
|
||||
match result {
|
||||
Ok(T) => {
|
||||
let mut price_vec_temp: HashMap<String, f64> = HashMap::new();
|
||||
let mut price_vec_temp_c: HashMap<String, f64> = HashMap::new();
|
||||
request_others::request_all_coin_price(&client, &mut price_vec_temp).await;
|
||||
price_vec_temp_c = price_vec_temp.clone();
|
||||
tx_price_vec.send_modify(|vec| *vec = price_vec_temp);
|
||||
tx_price_map.send_modify(|vec| *vec = price_vec_temp);
|
||||
tx_task5.send(5).expect("The mpsc channel has been closed.");
|
||||
}
|
||||
Err(E) => {}
|
||||
}
|
||||
|
||||
// Task#10: make realtime price data of 1m, 30m, 1d, 1w and 1mon
|
||||
let valid_usdt_trade_vec = rx_valid_usdt_trade_vec.borrow().clone();
|
||||
let valid_usdt_trade_set = rx_valid_usdt_trade_set.borrow().clone();
|
||||
// 1m
|
||||
let interval = String::from("1m");
|
||||
let candle_1m_vec = rx_candle_1m_vec.borrow().clone();
|
||||
let rt_price_1m_vec_read_temp: Vec<(String, Vec<RealtimePriceData>)> = Vec::new();
|
||||
let mut rt_price_1m_vec_write_temp: Vec<(String, Vec<RealtimePriceData>)> = Vec::new();
|
||||
let candle_1m_vec = rx_candle_1m_map.borrow().clone();
|
||||
let dummy_data: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let mut rt_price_1m_map_write_temp: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let mut rt_price_1m_map_write_temp_c: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let result = value_estimation_team::datapoints::price_data::update_realtime_price_data(
|
||||
&interval,
|
||||
&candle_1m_vec,
|
||||
&rt_price_1m_vec_read_temp,
|
||||
&mut rt_price_1m_vec_write_temp,
|
||||
&dummy_data,
|
||||
&mut rt_price_1m_map_write_temp,
|
||||
&price_vec_temp_c,
|
||||
&valid_usdt_trade_vec,
|
||||
&valid_usdt_trade_set,
|
||||
)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(T) => {
|
||||
if tx_rt_price_1m_vec.is_closed() {
|
||||
rt_price_1m_map_write_temp_c = rt_price_1m_map_write_temp.clone();
|
||||
if tx_rt_price_1m_map.is_closed() {
|
||||
eprintln!("tx_rt_price_1m_vec has been closed!");
|
||||
} else {
|
||||
tx_rt_price_1m_vec.send_modify(|vec| *vec = rt_price_1m_vec_write_temp);
|
||||
}
|
||||
}
|
||||
Err(E) => {}
|
||||
tx_rt_price_1m_map.send_modify(|vec| *vec = rt_price_1m_map_write_temp);
|
||||
}
|
||||
|
||||
// 30m
|
||||
let interval = String::from("30m");
|
||||
let candle_30m_vec = rx_candle_30m_vec.borrow().clone();
|
||||
let rt_price_1m_vec = rx_rt_price_1m_vec.borrow().clone();
|
||||
let mut rt_price_30m_vec_write_temp: Vec<(String, Vec<RealtimePriceData>)> = Vec::new();
|
||||
|
||||
if !rt_price_1m_vec.is_empty() {
|
||||
let candle_30m_map = rx_candle_30m_map.borrow().clone();
|
||||
let mut rt_price_30m_map_write_temp: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let mut rt_price_30m_map_write_temp_c: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
if !rt_price_1m_map_write_temp_c.is_empty() {
|
||||
let result =
|
||||
value_estimation_team::datapoints::price_data::update_realtime_price_data(
|
||||
&interval,
|
||||
&candle_30m_vec,
|
||||
&rt_price_1m_vec,
|
||||
&mut rt_price_30m_vec_write_temp,
|
||||
&candle_30m_map,
|
||||
&rt_price_1m_map_write_temp_c,
|
||||
&mut rt_price_30m_map_write_temp,
|
||||
&price_vec_temp_c,
|
||||
&valid_usdt_trade_vec,
|
||||
&valid_usdt_trade_set,
|
||||
)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(T) => {
|
||||
if tx_rt_price_30m_vec.is_closed() {
|
||||
rt_price_30m_map_write_temp_c = rt_price_30m_map_write_temp.clone();
|
||||
if tx_rt_price_30m_map.is_closed() {
|
||||
eprintln!("tx_rt_price_30m_vec has been closed!");
|
||||
} else {
|
||||
tx_rt_price_30m_vec
|
||||
.send_modify(|vec| *vec = rt_price_30m_vec_write_temp);
|
||||
}
|
||||
}
|
||||
Err(E) => {}
|
||||
tx_rt_price_30m_map
|
||||
.send_modify(|map: &mut HashMap<String, Vec<RealtimePriceData>>| *map = rt_price_30m_map_write_temp);
|
||||
}
|
||||
}
|
||||
|
||||
// 1d
|
||||
let interval = String::from("1d");
|
||||
let candle_1d_vec = rx_candle_1d_vec.borrow().clone();
|
||||
let rt_price_30m_vec = rx_rt_price_30m_vec.borrow().clone();
|
||||
let mut rt_price_1d_vec_write_temp: Vec<(String, Vec<RealtimePriceData>)> = Vec::new();
|
||||
let candle_1d_vec = rx_candle_1d_map.borrow().clone();
|
||||
let mut rt_price_1d_map_write_temp: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
|
||||
if !rt_price_30m_vec.is_empty() {
|
||||
if !rt_price_30m_map_write_temp_c.is_empty() {
|
||||
let result =
|
||||
value_estimation_team::datapoints::price_data::update_realtime_price_data(
|
||||
&interval,
|
||||
&candle_1d_vec,
|
||||
&rt_price_30m_vec,
|
||||
&mut rt_price_1d_vec_write_temp,
|
||||
&rt_price_30m_map_write_temp_c,
|
||||
&mut rt_price_1d_map_write_temp,
|
||||
&price_vec_temp_c,
|
||||
&valid_usdt_trade_vec,
|
||||
&valid_usdt_trade_set,
|
||||
)
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(T) => {
|
||||
if tx_rt_price_1d_vec.is_closed() {
|
||||
if tx_rt_price_1d_map.is_closed() {
|
||||
eprintln!("tx_rt_price_1d_vec has been closed!");
|
||||
} else {
|
||||
tx_rt_price_1d_vec.send_modify(|vec| *vec = rt_price_1d_vec_write_temp);
|
||||
tx_rt_price_1d_map.send_modify(|map| *map = rt_price_1d_map_write_temp);
|
||||
}
|
||||
}
|
||||
Err(E) => {}
|
||||
|
|
@ -831,13 +803,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let interval = String::from("1m");
|
||||
loop {
|
||||
let instant = Instant::now();
|
||||
let mut candle_1m_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let mut candle_1m_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let result =
|
||||
request_candles::fetch_candle_parallel(&interval, &mut candle_1m_vec_temp).await;
|
||||
request_candles::fetch_candle_parallel(&interval, &mut candle_1m_map_temp).await;
|
||||
|
||||
match result {
|
||||
Ok(T) => {
|
||||
tx_candle_1m_vec.send_modify(|vec| *vec = candle_1m_vec_temp);
|
||||
tx_candle_1m_map.send_modify(|vec| *vec = candle_1m_map_temp);
|
||||
tx_task6.send(6).expect("The mpsc channel has been closed.");
|
||||
}
|
||||
Err(E) => {}
|
||||
|
|
@ -858,14 +830,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let interval = String::from("30m");
|
||||
loop {
|
||||
let instant = Instant::now();
|
||||
let mut candle_30m_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let mut candle_30m_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let result =
|
||||
request_candles::fetch_candle_delay(&interval, &mut candle_30m_vec_temp).await;
|
||||
request_candles::fetch_candle_delay(&interval, &mut candle_30m_map_temp).await;
|
||||
// request_candles::fetch_candle_parallel(&interval, &mut candle_30m_vec_temp).await;
|
||||
|
||||
match result {
|
||||
Ok(T) => {
|
||||
tx_candle_30m_vec.send_modify(|vec| *vec = candle_30m_vec_temp);
|
||||
tx_candle_30m_map.send_modify(|vec| *vec = candle_30m_map_temp);
|
||||
tx_task7.send(7).expect("The mpsc channel has been closed.");
|
||||
}
|
||||
Err(E) => {}
|
||||
|
|
@ -886,13 +858,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
sleep(Duration::from_secs(600)).await;
|
||||
loop {
|
||||
let instant = Instant::now();
|
||||
let mut candle_1d_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::new();
|
||||
let mut candle_1d_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||
let result =
|
||||
request_candles::fetch_candle_delay(&interval, &mut candle_1d_vec_temp).await;
|
||||
request_candles::fetch_candle_delay(&interval, &mut candle_1d_map_temp).await;
|
||||
|
||||
match result {
|
||||
Ok(T) => {
|
||||
tx_candle_1d_vec.send_modify(|vec| *vec = candle_1d_vec_temp);
|
||||
tx_candle_1d_map.send_modify(|vec| *vec = candle_1d_map_temp);
|
||||
tx_task8.send(8).expect("The mpsc channel has been closed.");
|
||||
}
|
||||
Err(E) => {}
|
||||
|
|
@ -1039,14 +1011,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
loop {
|
||||
let instant = Instant::now();
|
||||
let mut all_data = AllData::new();
|
||||
all_data.valid_symbol_vec = rx3_valid_usdt_trade_vec.borrow().clone();
|
||||
all_data.valid_symbol_vec = rx3_valid_usdt_trade_set.borrow().clone();
|
||||
|
||||
// realtime price data
|
||||
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_1m_vec = rx3_rt_price_1m_map.borrow().clone();
|
||||
all_data.rt_price_30m_vec = rx3_rt_price_30m_map.borrow().clone();
|
||||
all_data.rt_price_1d_vec = rx3_rt_price_1d_map.borrow().clone();
|
||||
all_data.rt_price_1w_vec = rx3_rt_price_1w_map.borrow().clone();
|
||||
all_data.rt_price_1mon_vec = rx3_rt_price_1mon_map.borrow().clone();
|
||||
|
||||
let result =
|
||||
strategy_team::strategy_manager::execute_list_up_for_buy(&all_data).await;
|
||||
|
|
@ -1076,13 +1048,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let mut all_data = AllData::new();
|
||||
loop {
|
||||
let instant = Instant::now();
|
||||
all_data.valid_symbol_vec = rx3_valid_usdt_trade_vec.borrow().clone();
|
||||
all_data.valid_symbol_vec = rx3_valid_usdt_trade_set.borrow().clone();
|
||||
// realtime price data
|
||||
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_1m_vec = rx3_rt_price_1m_map.borrow().clone();
|
||||
all_data.rt_price_30m_vec = rx3_rt_price_30m_map.borrow().clone();
|
||||
all_data.rt_price_1d_vec = rx3_rt_price_1d_map.borrow().clone();
|
||||
all_data.rt_price_1w_vec = rx3_rt_price_1w_map.borrow().clone();
|
||||
all_data.rt_price_1mon_vec = rx3_rt_price_1mon_map.borrow().clone();
|
||||
|
||||
// let result = coex::strategy_team::execute_strategist_for_test(&all_data).await;
|
||||
|
||||
|
|
@ -1112,23 +1084,23 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
loop {
|
||||
let instant = Instant::now();
|
||||
let mut all_data = AllData::new();
|
||||
let mut exchange_info_vec: Vec<ExchangeInfo> = Vec::new();
|
||||
let mut trade_fee_vec: Vec<TradeFee> = Vec::new();
|
||||
let mut exchange_info_map: HashMap<String, ExchangeInfo> = HashMap::new();
|
||||
let mut trade_fee_map: HashMap<String, TradeFee> = HashMap::new();
|
||||
|
||||
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();
|
||||
all_data.valid_symbol_vec = rx4_valid_usdt_trade_set.borrow().clone();
|
||||
exchange_info_map = rx6_exchange_info_map.borrow().clone();
|
||||
trade_fee_map = rx5_tradefee_map.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();
|
||||
all_data.rt_price_1m_vec = rx5_rt_price_1m_map.borrow().clone();
|
||||
all_data.rt_price_30m_vec = rx5_rt_price_30m_map.borrow().clone();
|
||||
all_data.rt_price_1d_vec = rx4_rt_price_1d_map.borrow().clone();
|
||||
all_data.rt_price_1w_vec = rx4_rt_price_1w_map.borrow().clone();
|
||||
all_data.rt_price_1mon_vec = rx4_rt_price_1mon_map.borrow().clone();
|
||||
|
||||
let result = strategy_team::strategy_manager::execute_list_up_for_sell(
|
||||
&all_data,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
@ -1158,7 +1130,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let mut elapsed_time = 0;
|
||||
loop {
|
||||
let instant = Instant::now();
|
||||
let coin_price_vec = rx3_price_vec.borrow().clone();
|
||||
let coin_price_vec = rx3_price_map.borrow().clone();
|
||||
let result = coex::exchange_team::monitoring_pre_suggested_coins(&coin_price_vec).await;
|
||||
|
||||
// send Task#0 a message to notify running on
|
||||
|
|
@ -1187,10 +1159,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let mut elapsed_time = 0;
|
||||
loop {
|
||||
let instant = Instant::now();
|
||||
let exchange_info_vec = rx_exchange_info_data.borrow().clone();
|
||||
let trade_fee_vec = rx_tradefee_vec.borrow().clone();
|
||||
let exchange_info_map = rx_exchange_info_map.borrow().clone();
|
||||
let trade_fee_map = rx_tradefee_map.borrow().clone();
|
||||
let result =
|
||||
coex::exchange_team::buy_coin(&exchange_info_vec, &trade_fee_vec).await;
|
||||
coex::exchange_team::buy_coin(&exchange_info_map, &trade_fee_map).await;
|
||||
|
||||
// send Task#0 a message to notify running on
|
||||
match result {
|
||||
|
|
@ -1217,8 +1189,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let mut elapsed_time = 0;
|
||||
|
||||
let instant = Instant::now();
|
||||
let exchange_info_vec = rx_exchange_info_data.borrow().clone();
|
||||
let trade_fee_vec = rx_tradefee_vec.borrow().clone();
|
||||
let exchange_info_vec = rx_exchange_info_map.borrow().clone();
|
||||
let trade_fee_vec = rx_tradefee_map.borrow().clone();
|
||||
// let result = coex::exchange_team::buy_coin_for_test(&client, &coin_price_vec, &exchange_info_vec, &trade_fee_vec).await;
|
||||
let result = coex::exchange_team::buy_coin(&exchange_info_vec, &trade_fee_vec).await;
|
||||
|
||||
|
|
@ -1255,12 +1227,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let exchange_info_vec = rx3_exchange_info_data.borrow().clone();
|
||||
let trade_fee_vec = rx2_tradefee_vec.borrow().clone();
|
||||
let trade_fee_map = rx2_tradefee_map.borrow().clone();
|
||||
let result = coex::order_team::monitoring_open_buy_order(
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
@ -1293,9 +1263,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let mut elapsed_time = 0;
|
||||
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();
|
||||
let coin_price_vec = rx5_price_map.borrow().clone();
|
||||
let exchange_info_vec = rx2_exchange_info_map.borrow().clone();
|
||||
let trade_fee_vec = rx3_tradefee_map.borrow().clone();
|
||||
|
||||
let result = coex::order_team::update_price_of_filled_buy_order(
|
||||
&coin_price_vec,
|
||||
|
|
@ -1338,8 +1308,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let exchange_info_vec = rx4_exchange_info_data.borrow().clone();
|
||||
let trade_fee_vec = rx4_tradefee_vec.borrow().clone();
|
||||
let exchange_info_vec = rx4_exchange_info_map.borrow().clone();
|
||||
let trade_fee_vec = rx4_tradefee_map.borrow().clone();
|
||||
let result = coex::order_team::monitoring_open_sell_order(
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
|
|
@ -1403,7 +1373,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let mut all_data = AllData::new();
|
||||
|
||||
// realtime price data
|
||||
all_data.rt_price_1m_vec = rx4_rt_price_1m_vec.borrow().clone();
|
||||
all_data.rt_price_1m_vec = rx4_rt_price_1m_map.borrow().clone();
|
||||
|
||||
let result = coex::exchange_team::monitoring_scoreboard(&all_data).await;
|
||||
|
||||
|
|
|
|||
|
|
@ -3,16 +3,16 @@ pub mod strategy_002;
|
|||
pub mod strategy_003;
|
||||
pub mod strategy_004;
|
||||
pub mod strategy_005;
|
||||
pub mod strategy_006;
|
||||
pub mod strategy_test;
|
||||
// pub mod strategy_006;
|
||||
// pub mod strategy_test;
|
||||
pub mod strategy_manager;
|
||||
|
||||
use crate::coex::order_team::{limit_order_sell, select_filled_buy_orders};
|
||||
use crate::coex::exchange_team::server_epoch;
|
||||
use crate::coex::exchange_team::get_server_epoch;
|
||||
use crate::coin_health_check_team::request_others::{ExchangeInfo, TradeFee};
|
||||
use crate::database_control::*;
|
||||
use crate::decimal_funcs::*;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use crate::value_estimation_team::datapoints::price_data::{RealtimePriceData, CandleType};
|
||||
use crate::value_estimation_team::indicators::bollingerband::{bollingerband, BollingerBandData};
|
||||
use crate::value_estimation_team::indicators::ema::{ema, ema_opclo, EmaData};
|
||||
use crate::value_estimation_team::indicators::heatmap_volume::{
|
||||
|
|
@ -22,7 +22,7 @@ use crate::value_estimation_team::indicators::macd::{ema_macd, MacdData};
|
|||
use crate::value_estimation_team::indicators::rsi::{rsi, RsiData};
|
||||
use crate::value_estimation_team::indicators::sma::{sma, sma_opclo, SmaData};
|
||||
use crate::value_estimation_team::indicators::stoch_rsi::{stoch_rsi, StochRsiData};
|
||||
use crate::value_estimation_team::indicators::supertrend::{supertrend, SupertrendData};
|
||||
use crate::value_estimation_team::indicators::supertrend::{supertrend, SupertrendData, SuperTrendArea, SuperTrendSignal};
|
||||
use crate::value_estimation_team::indicators::adx::{AdxData, adx};
|
||||
use futures::future::try_join_all;
|
||||
use reqwest::{Client, ClientBuilder};
|
||||
|
|
@ -32,25 +32,26 @@ use sqlx::FromRow;
|
|||
use std::sync::Arc;
|
||||
use strategy_manager::insert_pre_suggested_coins;
|
||||
use tokio::sync::Mutex;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AllData {
|
||||
pub valid_symbol_vec: Vec<String>,
|
||||
pub rt_price_1m_vec: Vec<(String, Vec<RealtimePriceData>)>,
|
||||
pub rt_price_30m_vec: Vec<(String, Vec<RealtimePriceData>)>,
|
||||
pub rt_price_1d_vec: Vec<(String, Vec<RealtimePriceData>)>,
|
||||
pub rt_price_1w_vec: Vec<(String, Vec<RealtimePriceData>)>,
|
||||
pub rt_price_1mon_vec: Vec<(String, Vec<RealtimePriceData>)>,
|
||||
pub valid_symbol_vec: HashSet<String>,
|
||||
pub rt_price_1m_vec: HashMap<String, Vec<RealtimePriceData>>,
|
||||
pub rt_price_30m_vec: HashMap<String, Vec<RealtimePriceData>>,
|
||||
pub rt_price_1d_vec: HashMap<String, Vec<RealtimePriceData>>,
|
||||
pub rt_price_1w_vec: HashMap<String, Vec<RealtimePriceData>>,
|
||||
pub rt_price_1mon_vec: HashMap<String, Vec<RealtimePriceData>>,
|
||||
}
|
||||
impl AllData {
|
||||
pub fn new() -> AllData {
|
||||
let a = AllData {
|
||||
valid_symbol_vec: Vec::new(),
|
||||
rt_price_1m_vec: Vec::new(),
|
||||
rt_price_30m_vec: Vec::new(),
|
||||
rt_price_1d_vec: Vec::new(),
|
||||
rt_price_1w_vec: Vec::new(),
|
||||
rt_price_1mon_vec: Vec::new(),
|
||||
valid_symbol_vec: HashSet::new(),
|
||||
rt_price_1m_vec: HashMap::new(),
|
||||
rt_price_30m_vec: HashMap::new(),
|
||||
rt_price_1d_vec: HashMap::new(),
|
||||
rt_price_1w_vec: HashMap::new(),
|
||||
rt_price_1mon_vec: HashMap::new(),
|
||||
};
|
||||
a
|
||||
}
|
||||
|
|
@ -68,18 +69,16 @@ pub struct TimeData {
|
|||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FilteredData {
|
||||
pub symbol: String,
|
||||
pub struct FilteredDataValue {
|
||||
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(),
|
||||
impl FilteredDataValue {
|
||||
fn new() -> FilteredDataValue {
|
||||
let a = FilteredDataValue {
|
||||
closetime: 0,
|
||||
stoploss: Decimal::new(0, 8),
|
||||
target_price: Decimal::new(0, 8),
|
||||
|
|
@ -89,22 +88,22 @@ impl FilteredData {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn duplicate_filter(registerer: i32, original_filtered_data: &Vec<FilteredData>)
|
||||
-> Result<Vec<FilteredData>, Box<dyn std::error::Error + Send + Sync>>
|
||||
pub async fn duplicate_filter(registerer: i32, original_filtered_data: &HashMap<String, FilteredDataValue>)
|
||||
-> Result<HashMap<String, FilteredDataValue>, Box<dyn std::error::Error + Send + Sync>>
|
||||
{
|
||||
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: Vec<FilteredData> = Vec::new();
|
||||
let mut filtered_data_arc: Arc<Mutex<Vec<FilteredData>>> =
|
||||
let mut filtered_data: HashMap<String, FilteredDataValue> = HashMap::new();
|
||||
let mut filtered_data_arc: Arc<Mutex<HashMap<String, FilteredDataValue>>> =
|
||||
Arc::new(Mutex::new(filtered_data));
|
||||
let mut task_vec = Vec::new();
|
||||
|
||||
for element in original_filtered_data {
|
||||
for (symbol, filtered_data) in original_filtered_data {
|
||||
let mut exists_condition_build = String::from("symbol=\'");
|
||||
exists_condition_build.push_str(element.symbol.as_str());
|
||||
exists_condition_build.push_str(symbol.as_str());
|
||||
exists_condition_build.push_str("\' AND registerer=");
|
||||
exists_condition_build.push_str(registerer.to_string().as_str());
|
||||
// exists_condition_build.push_str("\' AND close_time=");
|
||||
|
|
@ -115,7 +114,8 @@ pub async fn duplicate_filter(registerer: i32, original_filtered_data: &Vec<Filt
|
|||
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 symbol_c = symbol.clone();
|
||||
let filtered_data_c = filtered_data.clone();
|
||||
let filtered_data_arc_c = Arc::clone(&filtered_data_arc);
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let inspect_result_1 =
|
||||
|
|
@ -133,7 +133,7 @@ pub async fn duplicate_filter(registerer: i32, original_filtered_data: &Vec<Filt
|
|||
&& inspect_result_4 == false
|
||||
{
|
||||
let mut filtered_data_lock = filtered_data_arc_c.lock().await;
|
||||
filtered_data_lock.push(element_c);
|
||||
filtered_data_lock.insert(symbol_c, filtered_data_c);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
@ -141,3 +141,30 @@ pub async fn duplicate_filter(registerer: i32, original_filtered_data: &Vec<Filt
|
|||
let filtered_data_c = filtered_data_arc.lock().await.clone();
|
||||
Ok(filtered_data_c)
|
||||
}
|
||||
|
||||
pub async fn remove_keys(filtered_data: &mut HashMap<String, FilteredDataValue>, keys_to_remove: HashSet<String>) {
|
||||
let len_prev = filtered_data.len();
|
||||
// remove key-value in filtered_data
|
||||
for symbol in keys_to_remove {
|
||||
filtered_data.remove(&symbol);
|
||||
}
|
||||
let len_now = filtered_data.len();
|
||||
|
||||
// shrink capacity of filtered_data
|
||||
if len_now != len_prev {
|
||||
filtered_data.shrink_to_fit();
|
||||
}
|
||||
}
|
||||
|
||||
// useful functions for strategists
|
||||
pub async fn get_current_price(
|
||||
symbol: &String,
|
||||
rt_price_map: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
) -> Option<f64> {
|
||||
if let Some(rt_vec) = rt_price_map.get(symbol) {
|
||||
if rt_vec.last().is_some() {
|
||||
return Some(rt_vec.last().unwrap().close_price);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
|||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, ema, 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,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
||||
};
|
||||
|
||||
// BB lowerband + SuperTrend + StochRSI
|
||||
|
|
@ -19,115 +19,19 @@ pub async fn list_up_for_buy(
|
|||
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
|
||||
|
||||
// 1st filtering: filtering valid trade pair
|
||||
let mut filtered_data_1st: Vec<FilteredData> = Vec::new();
|
||||
let mut filtered_data: HashMap<String, FilteredDataValue> = HashMap::new();
|
||||
for symbol in &alldata.valid_symbol_vec {
|
||||
let mut filtered_data = FilteredData::new();
|
||||
filtered_data.symbol = symbol.clone();
|
||||
filtered_data_1st.push(filtered_data);
|
||||
}
|
||||
|
||||
// 2nd filtering: supertrend(ATR period 20, multiplier: 2, 30m close price)
|
||||
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();
|
||||
|
||||
for element in filtered_data_1st {
|
||||
let mut rt_30m_vec: Vec<RealtimePriceData> = Vec::new();
|
||||
let mut supertrend_vec: Vec<SupertrendData> = 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 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, 20, 2.0, true).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();
|
||||
let server_epoch = server_epoch().await;
|
||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
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() {
|
||||
let current_price: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(rt_30m_vec.last().unwrap().close_price).unwrap();
|
||||
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 = current_price;
|
||||
|
||||
if supertrend_vec[supertrend_search_result.unwrap()].area.contains("DOWN")
|
||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value > element.current_price.to_f64().unwrap()
|
||||
{
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec[supertrend_search_result.unwrap()].band_value).unwrap();
|
||||
let stop_loss = decimal_sub(filtered_data.current_price, decimal_div(decimal_sub(band_value, filtered_data.current_price), dec!(2)));
|
||||
filtered_data.stoploss = stop_loss;
|
||||
|
||||
filtered_data_2nd_lock.push(filtered_data);
|
||||
} else if supertrend_vec[supertrend_search_result.unwrap()].area.contains("UP")
|
||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value < element.current_price.to_f64().unwrap()
|
||||
{
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec[supertrend_search_result.unwrap()].band_value).unwrap();
|
||||
filtered_data.stoploss = band_value;
|
||||
|
||||
filtered_data_2nd_lock.push(filtered_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
|
||||
// 3rd filtering: the latest 5 30m candle close prices > EMA 200
|
||||
let filtered_data_2nd = filtered_data_2nd_arc.lock().await.clone();
|
||||
let mut filtered_data_3rd: Vec<FilteredData> = Vec::new();
|
||||
let ema_vec = ema(200, &alldata.rt_price_30m_vec, &filtered_data_2nd).await?;
|
||||
for element in filtered_data_2nd {
|
||||
let ema_search_result = ema_vec.iter().position(|x| x.0 == element.symbol);
|
||||
let candle_search_result = alldata.rt_price_30m_vec.iter().position(|x| x.0 == element.symbol);
|
||||
if ema_search_result.is_some() && candle_search_result.is_some() {
|
||||
let search_result = ema_vec[ema_search_result.unwrap()].1.binary_search_by_key(
|
||||
&alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.last().unwrap().close_time,
|
||||
|EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| *close_time);
|
||||
if search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-1].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-2].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-2].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-3].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-3].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-4].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-4].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-5].close_price) {
|
||||
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.push(filtered_data);
|
||||
}
|
||||
}
|
||||
filtered_data.insert(symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
|
||||
// 4th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
|
||||
let mut filtered_data_4th: Vec<FilteredData> = Vec::new();
|
||||
for element in filtered_data_3rd {
|
||||
let position_idx = alldata.rt_price_30m_vec.iter().position(|elem| elem.0 == element.symbol);
|
||||
if position_idx.is_some() {
|
||||
let vec_len = alldata.rt_price_30m_vec[position_idx.unwrap()].1.len();
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if alldata.rt_price_30m_vec.contains_key(symbol) {
|
||||
let rt_price_30m = alldata.rt_price_30m_vec.get(symbol).unwrap();
|
||||
let vec_len = rt_price_30m.len();
|
||||
if vec_len >= 11 {
|
||||
let candles = alldata.rt_price_30m_vec[position_idx.unwrap()].1.get(vec_len-12..vec_len-1).unwrap();
|
||||
let candles = rt_price_30m.get(vec_len-12..vec_len-1).unwrap();
|
||||
let windows = candles.windows(2);
|
||||
let mut average_amplitude = 0.0;
|
||||
|
||||
|
|
@ -137,41 +41,143 @@ pub async fn list_up_for_buy(
|
|||
average_amplitude /= 10.0;
|
||||
|
||||
if 0.005 <= average_amplitude && average_amplitude <= 0.01 {
|
||||
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;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
filtered_data_4th.push(filtered_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2nd filtering: supertrend(ATR period 20, multiplier: 2, 30m close price)
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let supertrend_30m_map = supertrend(20, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_30m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
// input closetime, current_price
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
|
||||
// 5th filtering: 30m StochRSI (RSI_len: 10, StochRSI_len: 10, K: 3, D: 3) previous K < 5 && current K > previous K
|
||||
let mut filtered_data_5th: Vec<FilteredData> = Vec::new();
|
||||
let stoch_rsis = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data_4th).await?;
|
||||
for element in filtered_data_4th {
|
||||
let position_idx = stoch_rsis.iter().position(|elem| elem.0 == element.symbol);
|
||||
if position_idx.is_some() {
|
||||
let stoch_rsi_vec = stoch_rsis[position_idx.unwrap()].1.clone();
|
||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == element.closetime);
|
||||
// input stoploss
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN &&
|
||||
supertrend_vec.last().unwrap().band_value > values.current_price.to_f64().unwrap()
|
||||
{
|
||||
values.stoploss = decimal_sub(values.current_price, decimal_sub(band_value, values.current_price));
|
||||
|
||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
||||
supertrend_vec.last().unwrap().band_value < values.current_price.to_f64().unwrap()
|
||||
{
|
||||
values.stoploss = band_value;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// filtering: the latest 5 30m candle close prices > EMA 200
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let emas = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if emas.contains_key(symbol) && alldata.rt_price_30m_vec.contains_key(symbol) {
|
||||
let ema = emas.get(symbol).unwrap();
|
||||
let rt_price_30m = alldata.rt_price_30m_vec.get(symbol).unwrap();
|
||||
let rt_price_30m_len = rt_price_30m.len();
|
||||
let search_result = ema.binary_search_by_key(
|
||||
&alldata.rt_price_30m_vec.get(symbol).unwrap().last().unwrap().close_time,
|
||||
|EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| *close_time);
|
||||
if search_result.is_ok_and(|x| ema[search_result.unwrap()].ema_value < rt_price_30m[rt_price_30m_len-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-1].ema_value < rt_price_30m[rt_price_30m_len-2].close_price) &&
|
||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-2].ema_value < rt_price_30m[rt_price_30m_len-3].close_price) &&
|
||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-3].ema_value < rt_price_30m[rt_price_30m_len-4].close_price) &&
|
||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-4].ema_value < rt_price_30m[rt_price_30m_len-5].close_price) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// filtering: 30m StochRSI (RSI_len: 10, StochRSI_len: 10, K: 3, D: 3) previous K < 5 && current K > previous K
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let stoch_rsis = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if alldata.rt_price_30m_vec.contains_key(symbol) && stoch_rsis.contains_key(symbol) {
|
||||
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == values.closetime);
|
||||
if search_result.is_some_and(|a| stoch_rsi_vec[a-1].k < 5.0 && stoch_rsi_vec[a].k > stoch_rsi_vec[a-1].k) {
|
||||
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;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
filtered_data_5th.push(filtered_data);
|
||||
}
|
||||
// filtering: 1d MACD (3, 7, 30) current MACD-signal > prev MACD-signal
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if macd_vec[macd_vec.len()-1].macd_value - macd_vec[macd_vec.len()-1].signal_value > macd_vec[macd_vec.len()-2].macd_value - macd_vec[macd_vec.len()-2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
let final_filtered_data = duplicate_filter(1, &filtered_data_5th).await?;
|
||||
// filtering: the 2 previous ADX(10, 10)s decrease
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let adx_vec = adx(10, 10, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(adx_vec) = adx_vec.get(symbol) {
|
||||
if let Some(last_idx) = adx_vec.iter().position(|elem| elem.close_time == values.closetime) {
|
||||
if
|
||||
adx_vec[last_idx].adx < adx_vec[last_idx-1].adx &&
|
||||
adx_vec[last_idx-1].adx < adx_vec[last_idx-2].adx {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
let final_filtered_data = duplicate_filter(1, &filtered_data).await?;
|
||||
insert_pre_suggested_coins(1, false, &final_filtered_data, &alldata).await;
|
||||
|
||||
Ok(())
|
||||
|
|
@ -179,8 +185,8 @@ pub async fn list_up_for_buy(
|
|||
|
||||
pub async fn list_up_for_sell(
|
||||
all_data: &AllData,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let filled_buy_orders = select_filled_buy_orders(1).await?;
|
||||
|
||||
|
|
@ -190,47 +196,21 @@ pub async fn list_up_for_sell(
|
|||
.build()
|
||||
.unwrap();
|
||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
|
||||
let mut filtered_symbol_vec: Vec<FilteredData> = Vec::new();
|
||||
let mut filtered_symbols: HashMap<String, FilteredDataValue> = HashMap::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);
|
||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
let stoch_rsis = stoch_rsi(10, 10, 3, 3, &all_data.rt_price_30m_vec, &filtered_symbol_vec).await?;
|
||||
let supertrend_30m = supertrend(20, 2.0, true, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
||||
let stoch_rsis = stoch_rsi(10, 10, 3, 3, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
||||
for element in filled_buy_orders {
|
||||
if 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);
|
||||
let search_result = stoch_rsis.iter().position(|x| x.0 == element.symbol);
|
||||
|
||||
let opclo_30m_option = all_data
|
||||
.rt_price_30m_vec
|
||||
.iter()
|
||||
.position(|x| *x.0 == element.symbol);
|
||||
let supertrend_option_30m =
|
||||
supertrend(&element.symbol, &all_data.rt_price_30m_vec, 20, 2.0, true).await;
|
||||
|
||||
if lot_step_size_option.is_some()
|
||||
&& quote_commission_precision_option.is_some()
|
||||
&& search_result.is_some()
|
||||
&& opclo_30m_option.is_some()
|
||||
&& supertrend_option_30m.is_some()
|
||||
{
|
||||
if let (Some(exchange_info), Some(tradefee), Some(stoch_rsi), Some(supertrend_vec)) =
|
||||
(exchange_info_map.get(&element.symbol), trade_fee_map.get(&element.symbol), stoch_rsis.get(&element.symbol), supertrend_30m.get(&element.symbol)) {
|
||||
// update stoploss
|
||||
supertrend_vec = supertrend_option_30m.unwrap();
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
||||
if supertrend_vec.last().unwrap().area.contains("UP")
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP
|
||||
&& band_value > element.stoploss {
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![
|
||||
|
|
@ -242,19 +222,17 @@ pub async fn list_up_for_sell(
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
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 lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let stoch_rsi_k = stoch_rsis[search_result.unwrap()].1.last().unwrap().k;
|
||||
let stoch_rsi_k_prev = stoch_rsis[search_result.unwrap()].1[stoch_rsis[search_result.unwrap()].1.len()-2].k;
|
||||
let stoch_rsi_d = stoch_rsis[search_result.unwrap()].1.last().unwrap().d;
|
||||
let stoch_rsi_d_prev = stoch_rsis[search_result.unwrap()].1[stoch_rsis[search_result.unwrap()].1.len()-2].d;
|
||||
let stoch_rsi_k = stoch_rsi.last().unwrap().k;
|
||||
let stoch_rsi_k_prev = stoch_rsi[stoch_rsi.len()-2].k;
|
||||
let stoch_rsi_d = stoch_rsi.last().unwrap().d;
|
||||
let stoch_rsi_d_prev = stoch_rsi[stoch_rsi.len()-2].d;
|
||||
if (element.is_long == 0 || element.is_long == 1)
|
||||
&& !element.current_price.is_zero()
|
||||
{
|
||||
|
|
@ -264,49 +242,40 @@ pub async fn list_up_for_sell(
|
|||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if server_epoch - element.transact_time > (1_800_000) * 20 {
|
||||
} else if server_epoch - element.transact_time > (1_800_000) * 15 {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if element.pure_profit_percent > 5.0 {
|
||||
} else if element.pure_profit_percent > 3.0 {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if stoch_rsi_k >= 95.0 {
|
||||
} else if stoch_rsi_k >= 90.0 &&
|
||||
(stoch_rsi_k < stoch_rsi_d &&
|
||||
stoch_rsi_k_prev > stoch_rsi_d_prev) {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
)
|
||||
.await;
|
||||
} else if stoch_rsi_k < stoch_rsi_d &&
|
||||
stoch_rsi_k_prev >= stoch_rsi_d_prev {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
@ -336,6 +305,7 @@ pub async fn list_up_for_sell(
|
|||
// }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
|||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, ema, 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,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
||||
};
|
||||
|
||||
// BB 30m lowerband + BB 1m lowerband
|
||||
|
|
@ -18,39 +18,46 @@ pub async fn list_up_for_buy(
|
|||
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
|
||||
|
||||
// 1st filtering: filtering valid trade pair
|
||||
let mut filtered_data_1st: Vec<FilteredData> = Vec::new();
|
||||
let mut filtered_data: HashMap<String, FilteredDataValue> = HashMap::new();
|
||||
for symbol in &alldata.valid_symbol_vec {
|
||||
let mut filtered_data = FilteredData::new();
|
||||
filtered_data.symbol = symbol.clone();
|
||||
filtered_data_1st.push(filtered_data);
|
||||
filtered_data.insert(symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
|
||||
// 5th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let Some(rt_price_30m_vec) = alldata.rt_price_30m_vec.get(symbol) {
|
||||
let vec_len = rt_price_30m_vec.len();
|
||||
if vec_len >= 11 {
|
||||
let candles = rt_price_30m_vec.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 {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 2nd filtering: BollingerBand (len:10, multiplier 2.5) previous_30m_price (close or low price) < lower_band
|
||||
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 bollingerbands_30m = bollingerband(10, 2.5, &alldata.rt_price_30m_vec, &filtered_data_1st).await?;
|
||||
let bollingerbands_1m = bollingerband(30, 3.0, &alldata.rt_price_1m_vec, &filtered_data_1st).await?;
|
||||
for element in filtered_data_1st {
|
||||
let mut rt_30m_vec: Vec<RealtimePriceData> = Vec::new();
|
||||
let mut bb_30m_vec: Vec<BollingerBandData> = Vec::new();
|
||||
let mut bb_1m_vec: Vec<BollingerBandData> = Vec::new();
|
||||
let rt_price_30m_vec_c: Vec<(String, Vec<RealtimePriceData>)> = alldata.rt_price_30m_vec.clone();
|
||||
let bollingerbands_30m_c = bollingerbands_30m.clone();
|
||||
let bollingerbands_1m_c = bollingerbands_1m.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| *x.0 == element.symbol);
|
||||
let bb_option_30m = bollingerbands_30m_c.iter().position(|x| x.0 == element.symbol);
|
||||
let bb_option_1m = bollingerbands_1m_c.iter().position(|x| x.0 == element.symbol);
|
||||
if rt_30m_option.is_some() && bb_option_30m.is_some() && bb_option_1m.is_some() {
|
||||
rt_30m_vec = rt_price_30m_vec_c[rt_30m_option.unwrap()].1.clone();
|
||||
bb_30m_vec = bollingerbands_30m_c[bb_option_30m.unwrap()].1.clone();
|
||||
bb_1m_vec = bollingerbands_1m_c[bb_option_1m.unwrap()].1.clone();
|
||||
let server_epoch = server_epoch().await;
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let bollingerbands_30m_map = bollingerband(10, 2.5, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let bollingerbands_1m_map = bollingerband(30, 3.0, &alldata.rt_price_1m_vec, &filtered_data).await?;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(bb_30m_vec), Some(bb_1m_vec), Some(rt_30m_vec)) = (bollingerbands_30m_map.get(symbol), bollingerbands_1m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
if rt_30m_vec.len() >= 3 && bb_30m_vec.len() >= 3 && bb_1m_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
let bb_30m_search_result = bb_30m_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|
|
@ -65,35 +72,29 @@ pub async fn list_up_for_buy(
|
|||
if bb_30m_vec[bb_30m_search_result.unwrap()].lowerband > rt_30m_vec[rt_30m_vec.len()-1].close_price &&
|
||||
bb_1m_vec.last().unwrap().lowerband > rt_30m_vec[rt_30m_vec.len()-1].close_price
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 3rd filtering: supertrend(ATR period 7, multiplier: 1.5, 30m close price), area should be DOWN
|
||||
let filtered_data_2nd = filtered_data_2nd_arc.lock().await.clone();
|
||||
let mut filtered_data_3rd: Vec<FilteredData> = Vec::new();
|
||||
|
||||
for element in filtered_data_2nd {
|
||||
let rt_30m_option = alldata.rt_price_30m_vec
|
||||
.iter()
|
||||
.position(|x| *x.0 == element.symbol);
|
||||
let supertrend_option_30m =
|
||||
supertrend(&element.symbol, &alldata.rt_price_30m_vec, 7, 1.5, true).await;
|
||||
|
||||
if rt_30m_option.is_some() && supertrend_option_30m.is_some() {
|
||||
let rt_30m_vec = alldata.rt_price_30m_vec[rt_30m_option.unwrap()].1.clone();
|
||||
let supertrend_vec = supertrend_option_30m.unwrap();
|
||||
let server_epoch = server_epoch().await;
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let supertrend_30m_map = supertrend( 7, 1.5, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(rt_30m_vec), Some(supertrend_vec)) = (alldata.rt_price_30m_vec.get(symbol), supertrend_30m_map.get(symbol)) {
|
||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|
|
@ -105,88 +106,76 @@ pub async fn list_up_for_buy(
|
|||
}| *close_time,
|
||||
);
|
||||
if supertrend_search_result.is_ok() {
|
||||
if supertrend_vec[supertrend_search_result.unwrap()].area.contains("DOWN")
|
||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value > element.current_price.to_f64().unwrap()
|
||||
if supertrend_vec[supertrend_search_result.unwrap()].area == SuperTrendArea::DOWN
|
||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value > filtered_data.current_price.to_f64().unwrap()
|
||||
{
|
||||
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.target_price = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec[supertrend_search_result.unwrap()].band_value).unwrap();
|
||||
let stop_loss = decimal_sub(filtered_data.current_price, decimal_div(decimal_sub(filtered_data.target_price, filtered_data.current_price), dec!(2)));
|
||||
filtered_data.stoploss = stop_loss;
|
||||
|
||||
filtered_data_3rd.push(filtered_data);
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 4th filtering: the latest 5 30m candle close prices > EMA 200
|
||||
let mut filtered_data_4th: Vec<FilteredData> = Vec::new();
|
||||
let ema_vec = ema(200, &alldata.rt_price_30m_vec, &filtered_data_3rd).await?;
|
||||
for element in filtered_data_3rd {
|
||||
let mut opclo_30m_vec = alldata.rt_price_30m_vec.clone();
|
||||
let ema_search_result = ema_vec.iter().position(|x| x.0 == element.symbol);
|
||||
let candle_search_result = alldata.rt_price_30m_vec.iter().position(|x| x.0 == element.symbol);
|
||||
if ema_search_result.is_some() && candle_search_result.is_some() {
|
||||
let search_result = ema_vec[ema_search_result.unwrap()].1.binary_search_by_key(
|
||||
&alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.last().unwrap().close_time,
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let ema_map = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(ema_vec), Some(rt_30m_vec)) = (ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
let search_result = ema_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| *close_time);
|
||||
if search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-1].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-2].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-2].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-3].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-3].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-4].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-4].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-5].close_price) {
|
||||
if search_result.is_ok_and(|x| ema_vec[x].ema_value < rt_30m_vec[rt_30m_vec.len()-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[x-1].ema_value < rt_30m_vec[rt_30m_vec.len()-2].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[x-2].ema_value < rt_30m_vec[rt_30m_vec.len()-3].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[x-3].ema_value < rt_30m_vec[rt_30m_vec.len()-4].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[x-4].ema_value < rt_30m_vec[rt_30m_vec.len()-5].close_price) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).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;
|
||||
// filtering: 1d MACD (3, 7, 30) current MACD-signal > prev MACD-signal
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if macd_vec[macd_vec.len()-1].macd_value - macd_vec[macd_vec.len()-1].signal_value > macd_vec[macd_vec.len()-2].macd_value - macd_vec[macd_vec.len()-2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
filtered_data_4th.push(filtered_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
|
||||
let mut filtered_data_5th: Vec<FilteredData> = Vec::new();
|
||||
for element in filtered_data_4th {
|
||||
let position_idx = alldata.rt_price_30m_vec.iter().position(|elem| elem.0 == element.symbol);
|
||||
if position_idx.is_some() {
|
||||
let vec_len = alldata.rt_price_30m_vec[position_idx.unwrap()].1.len();
|
||||
if vec_len >= 11 {
|
||||
let candles = alldata.rt_price_30m_vec[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 = 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_5th.push(filtered_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let final_filtered_data = duplicate_filter(2, &filtered_data_5th).await?;
|
||||
let final_filtered_data = duplicate_filter(2, &filtered_data).await?;
|
||||
insert_pre_suggested_coins(2, false, &final_filtered_data, &alldata).await;
|
||||
|
||||
Ok(())
|
||||
|
|
@ -194,8 +183,8 @@ pub async fn list_up_for_buy(
|
|||
|
||||
pub async fn list_up_for_sell(
|
||||
all_data: &AllData,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let filled_buy_orders = select_filled_buy_orders(2).await?;
|
||||
|
||||
|
|
@ -204,24 +193,12 @@ pub async fn list_up_for_sell(
|
|||
.timeout(tokio::time::Duration::from_millis(5000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for element in filled_buy_orders {
|
||||
if 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;
|
||||
if let Some(exchange_info) = exchange_info_map.get(&element.symbol) {
|
||||
let lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
|
|
@ -238,8 +215,8 @@ pub async fn list_up_for_sell(
|
|||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if element.current_price <= element.stoploss {
|
||||
|
|
@ -248,8 +225,8 @@ pub async fn list_up_for_sell(
|
|||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if server_epoch - element.transact_time > (1_800_000) * 20 {
|
||||
|
|
@ -258,8 +235,8 @@ pub async fn list_up_for_sell(
|
|||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,188 +3,129 @@ use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
|||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, ema, ema_opclo, sma, 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, duplicate_filter
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex, SmaData,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
||||
};
|
||||
|
||||
// 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,
|
||||
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: filtering valid trade pair
|
||||
let mut filtered_data_1st: Vec<FilteredData> = Vec::new();
|
||||
let mut filtered_data: HashMap<String, FilteredDataValue> = HashMap::new();
|
||||
for symbol in &alldata.valid_symbol_vec {
|
||||
let mut filtered_data = FilteredData::new();
|
||||
filtered_data.symbol = symbol.clone();
|
||||
filtered_data_1st.push(filtered_data);
|
||||
filtered_data.insert(symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
|
||||
// 2nd filtering: SMA5 (opclo_price) < EMA3 (opclo_price) && 5 previous MA > current MA
|
||||
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_close = sma(5, &alldata.rt_price_30m_vec, &filtered_data_1st).await?;
|
||||
let ema_close = ema(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_close.clone();
|
||||
let ema_opclos_c = ema_close.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(
|
||||
// 3rd filtering: supertrend(ATR period 20, multiplier: 4.0, 30m close price), area should be UP
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let supertrend_30m_map = supertrend(20, 4.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(rt_30m_vec), Some(supertrend_vec)) = (alldata.rt_price_30m_vec.get(symbol), supertrend_30m_map.get(symbol)) {
|
||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|SmaData {
|
||||
sma_value,
|
||||
|SupertrendData {
|
||||
band_value,
|
||||
signal,
|
||||
area,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
);
|
||||
let ema_search_result = ema_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
if supertrend_search_result.is_ok() {
|
||||
if supertrend_vec[supertrend_search_result.unwrap()].area == SuperTrendArea::UP
|
||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value < filtered_data.current_price.to_f64().unwrap()
|
||||
{
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 5th filtering: 30m StochRSI (RSI_len: 30, StochRSI_len: 30, K: 3, D: 3) previous K, D / current K, D < 10 && current K > current D
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let stoch_rsis = stoch_rsi(30, 30, 3, 3, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if alldata.rt_price_30m_vec.contains_key(symbol) && stoch_rsis.contains_key(symbol) {
|
||||
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == values.closetime);
|
||||
if search_result.is_some_and(|a| stoch_rsi_vec[a-1].k < 10.0 && stoch_rsi_vec[a].k < 10.0
|
||||
&& stoch_rsi_vec[a-1].d < 10.0 && stoch_rsi_vec[a].d< 10.0 &&
|
||||
stoch_rsi_vec[a-1].k <= stoch_rsi_vec[a-1].d && stoch_rsi_vec[a].k > stoch_rsi_vec[a].d) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 3rd filtering: the latest 5 30m candle close prices > EMA 200
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let emas = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if emas.contains_key(symbol) && alldata.rt_price_30m_vec.contains_key(symbol) {
|
||||
let ema = emas.get(symbol).unwrap();
|
||||
let rt_price_30m = alldata.rt_price_30m_vec.get(symbol).unwrap();
|
||||
let rt_price_30m_len = rt_price_30m.len();
|
||||
let search_result = ema.binary_search_by_key(
|
||||
&alldata.rt_price_30m_vec.get(symbol).unwrap().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 &&
|
||||
sma_vec[sma_search_result.unwrap()-4].sma_value > sma_vec[sma_search_result.unwrap()].sma_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);
|
||||
}| *close_time);
|
||||
if search_result.is_ok_and(|x| ema[search_result.unwrap()].ema_value < rt_price_30m[rt_price_30m_len-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-1].ema_value < rt_price_30m[rt_price_30m_len-2].close_price) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).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?;
|
||||
|
||||
// 4th filtering: BollingerBand (len:20, multiplier 2) 5 previous_30m_price (close or low price) < lower_band
|
||||
let filtered_data_3rd = filtered_data_3rd_arc.lock().await.clone();
|
||||
let mut filtered_data_4th: Vec<FilteredData> = Vec::new();
|
||||
let mut filtered_data_4th_arc: Arc<Mutex<Vec<FilteredData>>> =
|
||||
Arc::new(Mutex::new(filtered_data_4th));
|
||||
let mut task_vec = Vec::new();
|
||||
let bollingerbands = bollingerband(20, 2.0, &alldata.rt_price_30m_vec, &filtered_data_3rd).await?;
|
||||
for element in filtered_data_3rd {
|
||||
let mut rt_30m_vec: Vec<RealtimePriceData> = Vec::new();
|
||||
let mut bb_vec: Vec<BollingerBandData> = Vec::new();
|
||||
let rt_price_30m_vec_c: Vec<(String, Vec<RealtimePriceData>)> = alldata.rt_price_30m_vec.clone();
|
||||
let bollingerbands_c = bollingerbands.clone();
|
||||
let filtered_data_4th_arc_c = Arc::clone(&filtered_data_4th_arc);
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let rt_30m_option = rt_price_30m_vec_c
|
||||
.iter()
|
||||
.position(|x| *x.0 == element.symbol);
|
||||
let bb_option_30m = bollingerbands_c.iter().position(|x| x.0 == element.symbol);
|
||||
|
||||
if rt_30m_option.is_some() && bb_option_30m.is_some() {
|
||||
rt_30m_vec = rt_price_30m_vec_c[rt_30m_option.unwrap()].1.clone();
|
||||
bb_vec = bollingerbands_c[bb_option_30m.unwrap()].1.clone();
|
||||
let server_epoch = server_epoch().await;
|
||||
if rt_30m_vec.len() >= 6 && bb_vec.len() >= 6 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
let 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_search_result.is_ok() {
|
||||
if bb_vec[bb_search_result.unwrap()-1].lowerband > rt_30m_vec[rt_30m_vec.len()-2].low_price ||
|
||||
bb_vec[bb_search_result.unwrap()-2].lowerband > rt_30m_vec[rt_30m_vec.len()-3].low_price ||
|
||||
bb_vec[bb_search_result.unwrap()-3].lowerband > rt_30m_vec[rt_30m_vec.len()-4].low_price ||
|
||||
bb_vec[bb_search_result.unwrap()-4].lowerband > rt_30m_vec[rt_30m_vec.len()-5].low_price ||
|
||||
bb_vec[bb_search_result.unwrap()-5].lowerband > rt_30m_vec[rt_30m_vec.len()-6].low_price
|
||||
// filtering: 1d MACD (3, 7, 30) current MACD-signal > prev MACD-signal
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if macd_vec[macd_vec.len()-1].macd_value - macd_vec[macd_vec.len()-1].signal_value > macd_vec[macd_vec.len()-2].macd_value - macd_vec[macd_vec.len()-2].signal_value
|
||||
{
|
||||
let mut filtered_data_4th_lock = filtered_data_4th_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_4th_lock.push(filtered_data);
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
let final_filtered_data = duplicate_filter(3, &filtered_data_4th_arc.lock().await.clone()).await?;
|
||||
let final_filtered_data = duplicate_filter(3, &filtered_data).await?;
|
||||
insert_pre_suggested_coins(3, false, &final_filtered_data, &alldata).await;
|
||||
|
||||
Ok(())
|
||||
|
|
@ -192,8 +133,8 @@ pub async fn list_up_for_buy(
|
|||
|
||||
pub async fn list_up_for_sell(
|
||||
all_data: &AllData,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let filled_buy_orders = select_filled_buy_orders(3).await?;
|
||||
|
||||
|
|
@ -202,62 +143,110 @@ pub async fn list_up_for_sell(
|
|||
.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();
|
||||
let mut filtered_symbols: HashMap<String, FilteredDataValue> = HashMap::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);
|
||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
let sma_close = sma(5, &all_data.rt_price_30m_vec, &filtered_symbol_vec).await?;
|
||||
let ema_close = ema(3, &all_data.rt_price_30m_vec, &filtered_symbol_vec).await?;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let stoch_rsis = stoch_rsi(30, 30, 3, 3, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
||||
for element in filled_buy_orders {
|
||||
let sma_result = sma_close.iter().position(|x| x.0 == element.symbol);
|
||||
let ema_result = ema_close.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;
|
||||
if element.used_usdt >= dec!(10.0) {
|
||||
if let (Some(exchange_info), Some(stoch_rsi)) = (exchange_info_map.get(&element.symbol), stoch_rsis.get(&element.symbol)) {
|
||||
let lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let stoch_rsi_k = stoch_rsi.last().unwrap().k;
|
||||
let stoch_rsi_k_prev = stoch_rsi[stoch_rsi.len()-2].k;
|
||||
let stoch_rsi_d = stoch_rsi.last().unwrap().d;
|
||||
let stoch_rsi_d_prev = stoch_rsi[stoch_rsi.len()-2].d;
|
||||
|
||||
if (element.is_long == 0 || element.is_long == 1)
|
||||
&& !element.current_price.is_zero()
|
||||
{
|
||||
if sma_close[sma_result.unwrap()].1.last().unwrap().sma_value > ema_close[ema_result.unwrap()].1.last().unwrap().ema_value &&
|
||||
sma_close[sma_result.unwrap()].1[sma_close.len()-2].sma_value < ema_close[ema_result.unwrap()].1[ema_close.len()-2].ema_value
|
||||
if element.current_price >= element.target_price
|
||||
{
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if element.current_price <= element.stoploss {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if server_epoch - element.transact_time > (1_800_000) * 35 {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if stoch_rsi_k >= 90.0 {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if stoch_rsi_k >= 20.0 && stoch_rsi_k >= 20.0 &&
|
||||
stoch_rsi_k_prev >= 20.0 && stoch_rsi_k_prev >= 20.0 &&
|
||||
stoch_rsi_k < stoch_rsi_d &&
|
||||
stoch_rsi_k_prev >= stoch_rsi_d_prev
|
||||
{
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
// TODO: sell_count가 1일 때 적용하기
|
||||
// else if (supertrend_vec
|
||||
// .last()
|
||||
// .unwrap()
|
||||
// .signal
|
||||
// .as_ref()
|
||||
// .is_some_and(|x| x.contains("SELL"))
|
||||
// || supertrend_vec.last().unwrap().area.contains("DOWN"))
|
||||
// && (supertrend_vec.last().unwrap().close_time > element.close_time)
|
||||
// {
|
||||
// println!(
|
||||
// "SELL signal selling {} {:.2}",
|
||||
// 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;
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
|||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, ema, 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,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, CandleType
|
||||
};
|
||||
|
||||
// BB lowerband + SuperTrend + StochRSI
|
||||
|
|
@ -19,35 +19,45 @@ pub async fn list_up_for_buy(
|
|||
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
|
||||
|
||||
// 1st filtering: filtering valid trade pair
|
||||
let mut filtered_data_1st: Vec<FilteredData> = Vec::new();
|
||||
let mut filtered_data: HashMap<String, FilteredDataValue> = HashMap::new();
|
||||
for symbol in &alldata.valid_symbol_vec {
|
||||
let mut filtered_data = FilteredData::new();
|
||||
filtered_data.symbol = symbol.clone();
|
||||
filtered_data_1st.push(filtered_data);
|
||||
filtered_data.insert(symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
|
||||
// 2nd filtering: BollingerBand (len:30, multiplier 3) previous_30m_price (close or low price) < lower_band
|
||||
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 bollingerbands = bollingerband(30, 3.0, &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 bb_vec: Vec<BollingerBandData> = Vec::new();
|
||||
let rt_price_30m_vec_c: Vec<(String, Vec<RealtimePriceData>)> = alldata.rt_price_30m_vec.clone();
|
||||
let bollingerbands_c = bollingerbands.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| *x.0 == element.symbol);
|
||||
let bb_option_30m = bollingerbands_c.iter().position(|x| x.0 == element.symbol);
|
||||
// 5th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let Some(rt_price_30m_vec) = alldata.rt_price_30m_vec.get(symbol) {
|
||||
let vec_len = rt_price_30m_vec.len();
|
||||
if vec_len >= 11 {
|
||||
let candles = rt_price_30m_vec.get(vec_len-12..vec_len-1).unwrap();
|
||||
let windows = candles.windows(2);
|
||||
let mut average_amplitude = 0.0;
|
||||
|
||||
if rt_30m_option.is_some() && bb_option_30m.is_some() {
|
||||
rt_30m_vec = rt_price_30m_vec_c[rt_30m_option.unwrap()].1.clone();
|
||||
bb_vec = bollingerbands_c[bb_option_30m.unwrap()].1.clone();
|
||||
let server_epoch = server_epoch().await;
|
||||
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 {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 2nd filtering: BollingerBand (len:30, multiplier 3) previous_30m_price (close or low price) < lower_band
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let bollingerband_map = bollingerband(30, 3.0, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
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() >= 3 && bb_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
let bb_search_result = bb_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|
|
@ -61,39 +71,32 @@ pub async fn list_up_for_buy(
|
|||
if bb_search_result.is_ok() {
|
||||
if bb_vec[bb_search_result.unwrap()-1].lowerband > rt_30m_vec[rt_30m_vec.len()-2].low_price &&
|
||||
rt_30m_vec[rt_30m_vec.len()-2].opclo_price > rt_30m_vec.last().unwrap().close_price &&
|
||||
rt_30m_vec[rt_30m_vec.len()-2].candle_type.contains("DOWN") &&
|
||||
rt_30m_vec[rt_30m_vec.len()-2].candle_type == CandleType::DOWN &&
|
||||
rt_30m_vec[rt_30m_vec.len()-2].high_price < bb_vec[bb_search_result.unwrap()-1].sma
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 3rd filtering: supertrend(ATR period 10, multiplier: 2, 30m close price), area should be DOWN
|
||||
let filtered_data_2nd = filtered_data_2nd_arc.lock().await.clone();
|
||||
let mut filtered_data_3rd: Vec<FilteredData> = Vec::new();
|
||||
for element in filtered_data_2nd {
|
||||
let mut rt_30m_vec: Vec<RealtimePriceData> = Vec::new();
|
||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
||||
let rt_30m_option = alldata.rt_price_30m_vec
|
||||
.iter()
|
||||
.position(|x| *x.0 == element.symbol);
|
||||
let supertrend_option_30m =
|
||||
supertrend(&element.symbol, &alldata.rt_price_30m_vec, 10, 2.0, true).await;
|
||||
|
||||
if rt_30m_option.is_some() && supertrend_option_30m.is_some() {
|
||||
rt_30m_vec = alldata.rt_price_30m_vec[rt_30m_option.unwrap()].1.clone();
|
||||
supertrend_vec = supertrend_option_30m.unwrap();
|
||||
let server_epoch = server_epoch().await;
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let supertrend_30m_map = supertrend( 10, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(supertrend_vec), Some(rt_30m_vec)) = (supertrend_30m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|
|
@ -105,106 +108,87 @@ pub async fn list_up_for_buy(
|
|||
}| *close_time,
|
||||
);
|
||||
if supertrend_search_result.is_ok_and(|x|
|
||||
supertrend_vec[x].area.contains("DOWN") && supertrend_vec[x].band_value > element.current_price.to_f64().unwrap()) {
|
||||
let mut filtered_data = FilteredData::new();
|
||||
filtered_data.symbol = element.symbol.clone();
|
||||
filtered_data.closetime = element.closetime;
|
||||
filtered_data.current_price = element.current_price;
|
||||
supertrend_vec[x].area == SuperTrendArea::DOWN && supertrend_vec[x].band_value > filtered_data.current_price.to_f64().unwrap()) {
|
||||
filtered_data.target_price = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec[supertrend_search_result.unwrap()].band_value).unwrap();
|
||||
let stop_loss = decimal_sub(filtered_data.current_price, decimal_div(decimal_sub(filtered_data.target_price, filtered_data.current_price), dec!(2)));
|
||||
filtered_data.stoploss = stop_loss;
|
||||
|
||||
filtered_data_3rd.push(filtered_data);
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 4th filtering: the latest 5 30m candle close prices > EMA 200
|
||||
let mut filtered_data_4th: Vec<FilteredData> = Vec::new();
|
||||
let ema_vec = ema(200, &alldata.rt_price_30m_vec, &filtered_data_3rd).await?;
|
||||
for element in filtered_data_3rd {
|
||||
let ema_search_result = ema_vec.iter().position(|x| x.0 == element.symbol);
|
||||
let candle_search_result = alldata.rt_price_30m_vec.iter().position(|x| x.0 == element.symbol);
|
||||
if ema_search_result.is_some() && candle_search_result.is_some() {
|
||||
let search_result = ema_vec[ema_search_result.unwrap()].1.binary_search_by_key(
|
||||
&alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.last().unwrap().close_time,
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let ema_map = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(ema_vec), Some(rt_30m_vec)) = (ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
let search_result = ema_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| *close_time);
|
||||
if search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-1].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-2].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-2].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-3].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-3].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-4].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[ema_search_result.unwrap()].1[search_result.unwrap()-4].ema_value < alldata.rt_price_30m_vec[candle_search_result.unwrap()].1[alldata.rt_price_30m_vec[candle_search_result.unwrap()].1.len()-5].close_price) {
|
||||
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_4th.push(filtered_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
|
||||
let mut filtered_data_5th: Vec<FilteredData> = Vec::new();
|
||||
for element in filtered_data_4th {
|
||||
let position_idx = alldata.rt_price_30m_vec.iter().position(|elem| elem.0 == element.symbol);
|
||||
|
||||
if position_idx.is_some() {
|
||||
let vec_len = alldata.rt_price_30m_vec[position_idx.unwrap()].1.len();
|
||||
if vec_len >= 11 {
|
||||
let candles = alldata.rt_price_30m_vec[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 = 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_5th.push(filtered_data);
|
||||
}
|
||||
}
|
||||
if search_result.is_ok_and(|x| ema_vec[search_result.unwrap()].ema_value < rt_30m_vec[rt_30m_vec.len()-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-1].ema_value < rt_30m_vec[rt_30m_vec.len()-2].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-2].ema_value < rt_30m_vec[rt_30m_vec.len()-3].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-3].ema_value < rt_30m_vec[rt_30m_vec.len()-4].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-4].ema_value < rt_30m_vec[rt_30m_vec.len()-5].close_price) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 6th filtering: 30m StochRSI (RSI_len: 10, StochRSI_len: 10, K: 3, D: 3) current K, D < 20
|
||||
let mut filtered_data_6th: Vec<FilteredData> = Vec::new();
|
||||
let stoch_rsis = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data_5th).await?;
|
||||
for element in filtered_data_5th {
|
||||
let position_idx = stoch_rsis.iter().position(|elem| elem.0 == element.symbol);
|
||||
|
||||
if position_idx.is_some() {
|
||||
let stoch_rsi_vec = stoch_rsis[position_idx.unwrap()].1.clone();
|
||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == element.closetime);
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let stoch_rsi_map = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let Some(stoch_rsi_vec) = stoch_rsi_map.get(symbol) {
|
||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == filtered_data.closetime);
|
||||
if search_result.is_some_and(|a| stoch_rsi_vec[a].k < 15.0 && stoch_rsi_vec[a].d < 15.0) {
|
||||
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;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
filtered_data_6th.push(filtered_data);
|
||||
}
|
||||
// filtering: 1d MACD (3, 7, 30) current MACD-signal > prev MACD-signal
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if macd_vec[macd_vec.len()-1].macd_value - macd_vec[macd_vec.len()-1].signal_value > macd_vec[macd_vec.len()-2].macd_value - macd_vec[macd_vec.len()-2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
let final_filtered_data = duplicate_filter(4, &filtered_data_6th).await?;
|
||||
let final_filtered_data = duplicate_filter(4, &filtered_data).await?;
|
||||
insert_pre_suggested_coins(4, false, &final_filtered_data, &alldata).await;
|
||||
|
||||
Ok(())
|
||||
|
|
@ -212,8 +196,8 @@ pub async fn list_up_for_buy(
|
|||
|
||||
pub async fn list_up_for_sell(
|
||||
all_data: &AllData,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let filled_buy_orders = select_filled_buy_orders(4).await?;
|
||||
|
||||
|
|
@ -223,23 +207,12 @@ pub async fn list_up_for_sell(
|
|||
.build()
|
||||
.unwrap();
|
||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for element in filled_buy_orders {
|
||||
if 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;
|
||||
if let Some(exchange_info) = exchange_info_map.get(&element.symbol) {
|
||||
let lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
|
|
@ -256,8 +229,8 @@ pub async fn list_up_for_sell(
|
|||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if element.current_price <= element.stoploss {
|
||||
|
|
@ -266,8 +239,8 @@ pub async fn list_up_for_sell(
|
|||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if server_epoch - element.transact_time > (1_800_000) * 20 {
|
||||
|
|
@ -276,8 +249,8 @@ pub async fn list_up_for_sell(
|
|||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,217 +1,163 @@
|
|||
use super::{
|
||||
dec, decimal_add, decimal_sub, ema, exists_record, insert_pre_suggested_coins,
|
||||
dec, decimal_add, decimal_sub, decimal_div, decimal_mul, ema, 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,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, server_epoch, MacdData, ema_macd,
|
||||
duplicate_filter
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, get_current_price
|
||||
};
|
||||
|
||||
// Triple SuperTrend strategy
|
||||
// SuperTrend length: 20, multiplier: 1.5, BUY signal
|
||||
// ADX(10, 10) < 25.0
|
||||
// the latest 5 candle close prices > EMA 200
|
||||
// BUY conditions
|
||||
// (1) 1d MACD (3, 7, 30) cross
|
||||
// (2) supertrend (30, 3): UP area
|
||||
// stoploss: (update) supertrend(10, 1.5) lowerband
|
||||
// target price: (fixed) stoploss inverse x 3 times profit
|
||||
pub async fn list_up_for_buy(
|
||||
alldata: AllData,
|
||||
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: filtering valid trade pair
|
||||
let mut filtered_data_1st: Vec<FilteredData> = Vec::new();
|
||||
let mut filtered_data: HashMap<String, FilteredDataValue> = HashMap::new();
|
||||
for symbol in &alldata.valid_symbol_vec {
|
||||
let mut filtered_data = FilteredData::new();
|
||||
filtered_data.symbol = symbol.clone();
|
||||
filtered_data_1st.push(filtered_data);
|
||||
filtered_data.insert(symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
|
||||
// 2nd filtering: supertrend(ATR period 20, multiplier: 1.5, 30m close price), signal should be BUY
|
||||
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();
|
||||
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP{
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
for element in filtered_data_1st {
|
||||
let mut rt_30m_vec: Vec<RealtimePriceData> = Vec::new();
|
||||
let mut supertrend_vec: Vec<SupertrendData> = 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 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, 20, 1.5, true).await;
|
||||
// 2nd filtering: 1d MACD (3, 5, 30) cross
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let macd_1d_map = ema_macd(3, 5, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if macd_vec[macd_vec.len()-1].macd_value > macd_vec[macd_vec.len()-1].signal_value &&
|
||||
macd_vec[macd_vec.len()-2].macd_value < macd_vec[macd_vec.len()-2].signal_value {
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).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();
|
||||
let server_epoch = server_epoch().await;
|
||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
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() {
|
||||
let current_price: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(rt_30m_vec.last().unwrap().close_price).unwrap();
|
||||
|
||||
if supertrend_vec[supertrend_search_result.unwrap()].signal.as_ref().is_some_and(|x| x.contains("BUY"))
|
||||
&& current_price
|
||||
< rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
supertrend_vec[supertrend_search_result.unwrap()-1].band_value * 1.002,
|
||||
)
|
||||
.unwrap()
|
||||
&& supertrend_vec[supertrend_search_result.unwrap()-1].band_value > supertrend_vec[supertrend_search_result.unwrap()].band_value
|
||||
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
// input stoploss, target_price
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN &&
|
||||
supertrend_vec.last().unwrap().band_value > values.current_price.to_f64().unwrap()
|
||||
{
|
||||
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 = supertrend_vec[supertrend_search_result.unwrap()].close_time;
|
||||
filtered_data.current_price = current_price;
|
||||
filtered_data.stoploss = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec[supertrend_search_result.unwrap()].band_value).unwrap();
|
||||
let target_price = decimal_add(
|
||||
filtered_data.current_price,
|
||||
decimal_sub(filtered_data.current_price, filtered_data.stoploss),
|
||||
);
|
||||
filtered_data.target_price = target_price;
|
||||
values.stoploss = decimal_sub(values.current_price, decimal_sub(band_value, values.current_price));
|
||||
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(2.0)), values.current_price);
|
||||
|
||||
filtered_data_2nd_lock.push(filtered_data);
|
||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
||||
supertrend_vec.last().unwrap().band_value < values.current_price.to_f64().unwrap()
|
||||
{
|
||||
values.stoploss = band_value;
|
||||
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(2.0)), values.current_price);
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 3rd filtering: ADX(10, 10) < 25.0
|
||||
let filtered_data_2nd = 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();
|
||||
let valid_symbol_vec_c = alldata.valid_symbol_vec.clone();
|
||||
let adx_vec = adx(10, 10, &alldata.rt_price_30m_vec, &filtered_data_2nd).await?;
|
||||
for element in filtered_data_2nd {
|
||||
let mut adx_vec_c = adx_vec.clone();
|
||||
let symbol = element.symbol.clone();
|
||||
let close_time = element.closetime;
|
||||
let idx_result = adx_vec.iter().position(|elem| elem.0 == symbol);
|
||||
let filtered_data_3rd_arc_c = Arc::clone(&filtered_data_3rd_arc);
|
||||
if idx_result.is_some(){
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let closetime_idx_result = adx_vec_c[idx_result.unwrap()].1.iter().position(|elem| elem.close_time==close_time);
|
||||
if closetime_idx_result.is_some() {
|
||||
if adx_vec_c[idx_result.unwrap()].1[closetime_idx_result.unwrap()].adx < 25.0 {
|
||||
let mut filtered_3rd_symbols_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;
|
||||
// filtering: the 1 previous ADX(3, 5)s increase
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let adx_vec = adx(3, 5, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(adx_vec) = adx_vec.get(symbol) {
|
||||
if let Some(last_idx) = adx_vec.iter().position(|elem| elem.close_time == values.closetime) {
|
||||
if
|
||||
adx_vec[last_idx].adx > adx_vec[last_idx-1].adx {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
filtered_3rd_symbols_lock.push(filtered_data);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
// limit buy price: 3 * abs(이전 3 개 중 최대값 제거 한 opclo 값 평균 - 현재 open 값) + 현재 open 값 > current_price
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(rt_price_vec) = alldata.rt_price_1d_vec.get(symbol) {
|
||||
if rt_price_vec.last().unwrap().close_time > server_epoch && rt_price_vec.len() >= 6 {
|
||||
let mut opclo_vec: Vec<f64> = Vec::new();
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-2].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-3].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-4].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-5].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-6].opclo_price);
|
||||
let max_idx = opclo_vec.iter().position(|&x| x == *opclo_vec.iter().max_by(|&a, &b| a.partial_cmp(b).unwrap()).unwrap());
|
||||
opclo_vec.remove(max_idx.unwrap());
|
||||
|
||||
// 4th filtering: the latest 5 30m candle close prices > EMA 200
|
||||
let filtered_data_3rd = filtered_data_3rd_arc.lock().await.clone();
|
||||
let mut filtered_data_4th: Vec<FilteredData> = Vec::new();
|
||||
let mut filtered_data_4th_arc: Arc<Mutex<Vec<FilteredData>>> =
|
||||
Arc::new(Mutex::new(filtered_data_4th));
|
||||
let mut task_vec = Vec::new();
|
||||
let ema_vec = ema(200, &alldata.rt_price_30m_vec, &filtered_data_3rd).await?;
|
||||
for element in filtered_data_3rd {
|
||||
let mut opclo_30m_vec = alldata.rt_price_30m_vec.clone();
|
||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
||||
let ema_vec_c = ema_vec.clone();
|
||||
let filtered_data_4th_arc_c = Arc::clone(&filtered_data_4th_arc);
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let ema_search_result = ema_vec_c.iter().position(|x| x.0 == element.symbol);
|
||||
let candle_search_result = opclo_30m_vec.iter().position(|x| x.0 == element.symbol);
|
||||
if ema_search_result.is_some() && candle_search_result.is_some() {
|
||||
let search_result = ema_vec_c[ema_search_result.unwrap()].1.binary_search_by_key(
|
||||
&opclo_30m_vec[candle_search_result.unwrap()].1.last().unwrap().close_time,
|
||||
|EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| *close_time);
|
||||
if search_result.is_ok_and(|x| ema_vec_c[ema_search_result.unwrap()].1[search_result.unwrap()].ema_value < opclo_30m_vec[candle_search_result.unwrap()].1[opclo_30m_vec[candle_search_result.unwrap()].1.len()-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec_c[ema_search_result.unwrap()].1[search_result.unwrap()-1].ema_value < opclo_30m_vec[candle_search_result.unwrap()].1[opclo_30m_vec[candle_search_result.unwrap()].1.len()-2].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec_c[ema_search_result.unwrap()].1[search_result.unwrap()-2].ema_value < opclo_30m_vec[candle_search_result.unwrap()].1[opclo_30m_vec[candle_search_result.unwrap()].1.len()-3].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec_c[ema_search_result.unwrap()].1[search_result.unwrap()-3].ema_value < opclo_30m_vec[candle_search_result.unwrap()].1[opclo_30m_vec[candle_search_result.unwrap()].1.len()-4].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec_c[ema_search_result.unwrap()].1[search_result.unwrap()-4].ema_value < opclo_30m_vec[candle_search_result.unwrap()].1[opclo_30m_vec[candle_search_result.unwrap()].1.len()-5].close_price) {
|
||||
let mut filtered_4th_symbols_lock =
|
||||
filtered_data_4th_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;
|
||||
let mut mean = 0.0;
|
||||
for element in &opclo_vec {
|
||||
mean += element;
|
||||
}
|
||||
mean /= opclo_vec.len() as f64;
|
||||
let current_price = rt_price_vec.last().unwrap().close_price;
|
||||
let difference = (mean - rt_price_vec.last().unwrap().open_price).abs();
|
||||
|
||||
filtered_4th_symbols_lock.push(filtered_data);
|
||||
if current_price < rt_price_vec.last().unwrap().open_price + (3.0 * difference) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 5th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
|
||||
let filtered_data_4th_c = filtered_data_4th_arc.lock().await.clone();
|
||||
let mut filtered_data_5th: Vec<FilteredData> = Vec::new();
|
||||
let mut filtered_data_5th_arc: Arc<Mutex<Vec<FilteredData>>> =
|
||||
Arc::new(Mutex::new(filtered_data_5th));
|
||||
let mut task_vec = Vec::new();
|
||||
for element in filtered_data_4th_c {
|
||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
||||
let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone();
|
||||
let filtered_data_5th_arc_c = Arc::clone(&filtered_data_5th_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_5th_lock = filtered_data_5th_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_5th_lock.push(filtered_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
|
||||
let final_filtered_data = duplicate_filter(5, &filtered_data_5th_arc.lock().await.clone()).await?;
|
||||
let final_filtered_data = duplicate_filter(5, &filtered_data).await?;
|
||||
insert_pre_suggested_coins(5, false, &final_filtered_data, &alldata).await;
|
||||
|
||||
Ok(())
|
||||
|
|
@ -219,8 +165,8 @@ pub async fn list_up_for_buy(
|
|||
|
||||
pub async fn list_up_for_sell(
|
||||
all_data: &AllData,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let filled_buy_orders = select_filled_buy_orders(5).await?;
|
||||
|
||||
|
|
@ -230,32 +176,19 @@ pub async fn list_up_for_sell(
|
|||
.build()
|
||||
.unwrap();
|
||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
||||
let server_epoch = server_epoch().await;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let mut filtered_symbols: HashMap<String, FilteredDataValue> = HashMap::new();
|
||||
for element in &filled_buy_orders {
|
||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
let supertrend_1d = supertrend(14, 1.2, true, &all_data.rt_price_1d_vec, &filtered_symbols).await?;
|
||||
for element in filled_buy_orders {
|
||||
if 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);
|
||||
|
||||
let opclo_30m_option = all_data
|
||||
.rt_price_30m_vec
|
||||
.iter()
|
||||
.position(|x| *x.0 == element.symbol);
|
||||
let supertrend_option_30m =
|
||||
supertrend(&element.symbol, &all_data.rt_price_30m_vec, 20, 1.5, true).await;
|
||||
|
||||
if lot_step_size_option.is_some()
|
||||
&& quote_commission_precision_option.is_some()
|
||||
&& opclo_30m_option.is_some()
|
||||
&& supertrend_option_30m.is_some()
|
||||
{
|
||||
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) =
|
||||
(exchange_info_map.get(&element.symbol), trade_fee_map.get(&element.symbol), supertrend_1d.get(&element.symbol)) {
|
||||
// update stoploss
|
||||
supertrend_vec = supertrend_option_30m.unwrap();
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
||||
if supertrend_vec.last().unwrap().area.contains("UP")
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP
|
||||
&& band_value > element.stoploss {
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![
|
||||
|
|
@ -267,10 +200,8 @@ pub async fn list_up_for_sell(
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
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 lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
|
|
@ -280,36 +211,24 @@ pub async fn list_up_for_sell(
|
|||
if (element.is_long == 0 || element.is_long == 1)
|
||||
&& !element.current_price.is_zero()
|
||||
{
|
||||
if element.current_price >= element.target_price
|
||||
&& element.pure_profit_percent >= 0.1
|
||||
{
|
||||
if element.current_price <= element.stoploss {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if element.current_price <= element.stoploss {
|
||||
} else if element.current_price >= element.target_price {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
)
|
||||
.await;
|
||||
} else if server_epoch - element.transact_time > (1_800_000) * 10 && element.pure_profit_percent.is_sign_positive() {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
base_qty_to_be_ordered,
|
||||
&client,
|
||||
&exchange_info_vec,
|
||||
&trade_fee_vec,
|
||||
&exchange_info_map,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
use crate::coex::exchange_team::*;
|
||||
use crate::coex::order_team::*;
|
||||
use crate::coin_health_check_team::request_others::CoinPriceData;
|
||||
use csv::{DeserializeRecordsIter, StringRecord};
|
||||
use rust_decimal::prelude::ToPrimitive;
|
||||
use rust_decimal::Decimal;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::strategy_test;
|
||||
// use super::strategy_test;
|
||||
use super::{
|
||||
exists_record, insert_one_record, try_join_all, try_select_record, AllData, ExchangeInfo,
|
||||
FilteredData, FromRow, RealtimePriceData, TradeFee,
|
||||
FilteredDataValue, FromRow, RealtimePriceData, TradeFee, HashMap
|
||||
};
|
||||
use crate::signal_association::signal_decision::*;
|
||||
use tokio::time::{sleep, Duration, Instant};
|
||||
|
|
@ -34,46 +33,31 @@ pub async fn execute_list_up_for_buy(
|
|||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
crate::strategy_team::strategy_001::list_up_for_buy(all_data).await;
|
||||
crate::strategy_team::strategy_002::list_up_for_buy(all_data).await;
|
||||
crate::strategy_team::strategy_003::list_up_for_buy(all_data).await;
|
||||
crate::strategy_team::strategy_004::list_up_for_buy(all_data).await;
|
||||
|
||||
crate::strategy_team::strategy_005::list_up_for_buy(all_data).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn execute_list_up_for_sell(
|
||||
all_data: &AllData,
|
||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
||||
trade_fee_vec: &Vec<TradeFee>,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
crate::strategy_team::strategy_001::list_up_for_sell(&all_data, &exchange_info_vec, &trade_fee_vec).await;
|
||||
crate::strategy_team::strategy_002::list_up_for_sell(&all_data, &exchange_info_vec, &trade_fee_vec).await;
|
||||
crate::strategy_team::strategy_004::list_up_for_sell(&all_data, &exchange_info_vec, &trade_fee_vec).await;
|
||||
crate::strategy_team::strategy_001::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||
crate::strategy_team::strategy_002::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||
crate::strategy_team::strategy_003::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||
crate::strategy_team::strategy_004::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||
crate::strategy_team::strategy_005::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// useful functions for strategists
|
||||
pub async fn get_current_price(
|
||||
symbol: &String,
|
||||
rt_price_vec: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
) -> Option<f64> {
|
||||
let index_result = rt_price_vec.iter().position(|x| *x.0 == *symbol);
|
||||
match index_result {
|
||||
Some(T) => {
|
||||
if rt_price_vec[T].1.last().is_some() {
|
||||
Some(rt_price_vec[T].1.last().unwrap().close_price)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn insert_pre_suggested_coins(
|
||||
registerer: i32,
|
||||
is_long: bool,
|
||||
filtered_coins: &Vec<FilteredData>,
|
||||
filtered_coins: &HashMap<String, FilteredDataValue>,
|
||||
alldata: &AllData,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
// Check the existance of record that is registered by this strategist
|
||||
|
|
@ -150,12 +134,12 @@ pub async fn insert_pre_suggested_coins(
|
|||
.await?;
|
||||
|
||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
||||
for filtered_coin in filtered_coins {
|
||||
for (symbol, filtered_data) in filtered_coins {
|
||||
let mut is_dupe = false; // initialize
|
||||
|
||||
for list_element in &suggested_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -163,8 +147,8 @@ pub async fn insert_pre_suggested_coins(
|
|||
}
|
||||
|
||||
for list_element in &ordered_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -172,8 +156,8 @@ pub async fn insert_pre_suggested_coins(
|
|||
}
|
||||
|
||||
for list_element in &pre_suggested_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -182,13 +166,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
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
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_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
|
||||
|
|
@ -245,12 +229,12 @@ pub async fn insert_pre_suggested_coins(
|
|||
.await?;
|
||||
|
||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
||||
for filtered_coin in filtered_coins {
|
||||
for (symbol, filtered_data) in filtered_coins {
|
||||
let mut is_dupe = false; // initialize
|
||||
|
||||
for list_element in &suggested_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -258,8 +242,8 @@ pub async fn insert_pre_suggested_coins(
|
|||
}
|
||||
|
||||
for list_element in &ordered_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -268,13 +252,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
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
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_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
|
||||
|
|
@ -321,12 +305,12 @@ pub async fn insert_pre_suggested_coins(
|
|||
.await?;
|
||||
|
||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
||||
for filtered_coin in filtered_coins {
|
||||
for (symbol, filtered_data) in filtered_coins {
|
||||
let mut is_dupe = false; // initialize
|
||||
|
||||
for list_element in &suggested_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -334,8 +318,8 @@ pub async fn insert_pre_suggested_coins(
|
|||
}
|
||||
|
||||
for list_element in &pre_suggested_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -344,13 +328,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
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
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_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
|
||||
|
|
@ -390,12 +374,12 @@ pub async fn insert_pre_suggested_coins(
|
|||
.await?;
|
||||
|
||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
||||
for filtered_coin in filtered_coins {
|
||||
for (symbol, filtered_data) in filtered_coins {
|
||||
let mut is_dupe = false; // initialize
|
||||
|
||||
for list_element in &suggested_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -404,13 +388,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
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
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_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
|
||||
|
|
@ -467,12 +451,12 @@ pub async fn insert_pre_suggested_coins(
|
|||
.await?;
|
||||
|
||||
// insert record without duplicate(registerer, close_time, symbol) into [pre_suggested_coin_list]
|
||||
for filtered_coin in filtered_coins {
|
||||
for (symbol, filtered_data) in filtered_coins {
|
||||
let mut is_dupe = false; // initialize
|
||||
|
||||
for list_element in &ordered_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -480,8 +464,8 @@ pub async fn insert_pre_suggested_coins(
|
|||
}
|
||||
|
||||
for list_element in &pre_suggested_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -490,13 +474,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
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
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_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
|
||||
|
|
@ -546,12 +530,12 @@ pub async fn insert_pre_suggested_coins(
|
|||
.await?;
|
||||
|
||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
||||
for filtered_coin in filtered_coins {
|
||||
for (symbol, filtered_data) in filtered_coins {
|
||||
let mut is_dupe = false; // initialize
|
||||
|
||||
for list_element in &ordered_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -560,13 +544,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
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
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_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
|
||||
|
|
@ -606,12 +590,12 @@ pub async fn insert_pre_suggested_coins(
|
|||
.await?;
|
||||
|
||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
||||
for filtered_coin in filtered_coins {
|
||||
for (symbol, filtered_data) in filtered_coins {
|
||||
let mut is_dupe = false; // initialize
|
||||
|
||||
for list_element in &pre_suggested_coin_list {
|
||||
if (filtered_coin.symbol == list_element.symbol)
|
||||
&& (filtered_coin.closetime == list_element.close_time)
|
||||
if (*symbol == list_element.symbol)
|
||||
&& (filtered_data.closetime == list_element.close_time)
|
||||
{
|
||||
is_dupe = true;
|
||||
break;
|
||||
|
|
@ -620,13 +604,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
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
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_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
|
||||
|
|
@ -643,15 +627,15 @@ pub async fn insert_pre_suggested_coins(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
for filtered_coin in filtered_coins {
|
||||
for (symbol, filtered_data) in filtered_coins {
|
||||
let mut insert_values = vec![
|
||||
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
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_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
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#![allow(warnings)]
|
||||
|
||||
use crate::coin_health_check_team::request_candles::CandleData;
|
||||
use crate::coin_health_check_team::request_others::CoinPriceData;
|
||||
use crate::database_control::*;
|
||||
use csv::{DeserializeRecordsIter, StringRecord};
|
||||
use rust_decimal::{prelude::ToPrimitive, Decimal};
|
||||
|
|
@ -10,6 +9,10 @@ use serde::Deserialize;
|
|||
use sqlx::FromRow;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, sync::Mutex, time::*};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum CandleType { UP, DOWN }
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct RealtimePriceData {
|
||||
|
|
@ -20,7 +23,7 @@ pub struct RealtimePriceData {
|
|||
pub low_price: f64,
|
||||
pub close_time: i64,
|
||||
pub quote_asset_volume: f64,
|
||||
pub candle_type: String,
|
||||
pub candle_type: CandleType,
|
||||
}
|
||||
|
||||
impl RealtimePriceData {
|
||||
|
|
@ -33,7 +36,7 @@ impl RealtimePriceData {
|
|||
low_price: 0.0,
|
||||
close_time: 0,
|
||||
quote_asset_volume: 0.0,
|
||||
candle_type: String::new(),
|
||||
candle_type: CandleType::DOWN,
|
||||
};
|
||||
data
|
||||
}
|
||||
|
|
@ -41,23 +44,20 @@ impl RealtimePriceData {
|
|||
|
||||
pub async fn update_realtime_price_data(
|
||||
interval: &String,
|
||||
read_candle_for_opclo: &Vec<(String, Vec<CandleData>)>,
|
||||
read_candle_for_rt: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
write_rt_data: &mut Vec<(String, Vec<RealtimePriceData>)>,
|
||||
read_price: &Vec<CoinPriceData>,
|
||||
read_symbol: &Vec<String>,
|
||||
read_candle: &HashMap<String, Vec<CandleData>>,
|
||||
read_candle_for_rt: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
write_rt_data: &mut HashMap<String, Vec<RealtimePriceData>>,
|
||||
read_price: &HashMap<String, f64>,
|
||||
read_symbol: &HashSet<String>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let instant = Instant::now();
|
||||
|
||||
let mut rt_price_vec: Vec<RealtimePriceData> = Vec::new();
|
||||
let mut rt_data_vec: Vec<(String, Vec<RealtimePriceData>)> = Vec::new();
|
||||
let mut rt_data_map: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
|
||||
for element in read_symbol {
|
||||
let candle_search_result = read_candle_for_opclo.iter().position(|x| x.0 == *element);
|
||||
|
||||
match candle_search_result {
|
||||
Some(T) => {
|
||||
for element in &read_candle_for_opclo[T].1 {
|
||||
if let Some(candle_data) = read_candle.get(element) {
|
||||
for element in candle_data {
|
||||
let mut realtime_price_data_builder = RealtimePriceData::new();
|
||||
realtime_price_data_builder.opclo_price =
|
||||
(element.open_price + element.close_price) / 2.0;
|
||||
|
|
@ -68,19 +68,17 @@ pub async fn update_realtime_price_data(
|
|||
realtime_price_data_builder.close_time = element.close_time;
|
||||
realtime_price_data_builder.quote_asset_volume = element.quote_asset_volume;
|
||||
if element.open_price < element.close_price {
|
||||
realtime_price_data_builder.candle_type = String::from("UP");
|
||||
realtime_price_data_builder.candle_type = CandleType::UP;
|
||||
} else {
|
||||
realtime_price_data_builder.candle_type = String::from("DOWN");
|
||||
realtime_price_data_builder.candle_type = CandleType::DOWN;
|
||||
}
|
||||
rt_price_vec.push(realtime_price_data_builder);
|
||||
}
|
||||
// reflect realtime data to the last element in rt_price_vec
|
||||
if interval.contains("1m") {
|
||||
let price_search_result = read_price.iter().position(|x| x.symbol == *element);
|
||||
if price_search_result.is_some() {
|
||||
if let Some(current_price) = read_price.get(element) {
|
||||
// update close_price
|
||||
rt_price_vec.last_mut().unwrap().close_price =
|
||||
read_price[price_search_result.unwrap()].current_price;
|
||||
rt_price_vec.last_mut().unwrap().close_price = *current_price;
|
||||
// update opclo_price
|
||||
rt_price_vec.last_mut().unwrap().opclo_price =
|
||||
(rt_price_vec.last_mut().unwrap().open_price
|
||||
|
|
@ -90,23 +88,21 @@ pub async fn update_realtime_price_data(
|
|||
if rt_price_vec.last_mut().unwrap().close_price
|
||||
>= rt_price_vec.last_mut().unwrap().open_price
|
||||
{
|
||||
rt_price_vec.last_mut().unwrap().candle_type = String::from("UP");
|
||||
rt_price_vec.last_mut().unwrap().candle_type = CandleType::UP;
|
||||
} else {
|
||||
rt_price_vec.last_mut().unwrap().candle_type = String::from("DOWN");
|
||||
rt_price_vec.last_mut().unwrap().candle_type = CandleType::DOWN;
|
||||
}
|
||||
// update high_price
|
||||
if rt_price_vec.last_mut().unwrap().high_price
|
||||
< read_price[price_search_result.unwrap()].current_price
|
||||
< *current_price
|
||||
{
|
||||
rt_price_vec.last_mut().unwrap().high_price =
|
||||
read_price[price_search_result.unwrap()].current_price;
|
||||
rt_price_vec.last_mut().unwrap().high_price = *current_price;
|
||||
}
|
||||
// update low_price
|
||||
if rt_price_vec.last_mut().unwrap().low_price
|
||||
> read_price[price_search_result.unwrap()].current_price
|
||||
> *current_price
|
||||
{
|
||||
rt_price_vec.last_mut().unwrap().low_price =
|
||||
read_price[price_search_result.unwrap()].current_price;
|
||||
rt_price_vec.last_mut().unwrap().low_price = *current_price;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -114,19 +110,9 @@ pub async fn update_realtime_price_data(
|
|||
// for 1d, uses 30m candle
|
||||
// for 1w, uses 1d candle
|
||||
// for 1mon, uses 1w candle
|
||||
|
||||
// search symbol
|
||||
let candle_search_result =
|
||||
read_candle_for_rt.iter().position(|x| x.0 == *element);
|
||||
match candle_search_result {
|
||||
Some(T) => {
|
||||
if read_candle_for_rt[T].1.len() >= 2 {
|
||||
let mut candle_vec_clone = read_candle_for_rt[T].1.clone();
|
||||
let mut rt_price_vec_clone = rt_price_vec.clone();
|
||||
rt_price_vec_clone.reverse();
|
||||
rt_price_vec_clone.truncate(2);
|
||||
rt_price_vec_clone.reverse();
|
||||
|
||||
if let Some(rt_vec) = read_candle_for_rt.get(element) {
|
||||
if rt_vec.len() >= 2 {
|
||||
let previous_close_time = rt_price_vec[rt_price_vec.len()-2].close_time;
|
||||
// update realtime information for the latest candle
|
||||
let mut update_closeprice = 0.0;
|
||||
let mut update_highprice = 0.0;
|
||||
|
|
@ -134,8 +120,8 @@ pub async fn update_realtime_price_data(
|
|||
let mut update_quote_asset_volume = 0.0;
|
||||
|
||||
// search close time
|
||||
let prev_closetime_result = candle_vec_clone.binary_search_by_key(
|
||||
&rt_price_vec_clone.first().unwrap().close_time,
|
||||
let prev_closetime_result = rt_vec.binary_search_by_key(
|
||||
&previous_close_time,
|
||||
|RealtimePriceData {
|
||||
opclo_price,
|
||||
open_price,
|
||||
|
|
@ -149,7 +135,7 @@ pub async fn update_realtime_price_data(
|
|||
);
|
||||
if prev_closetime_result.is_ok() {
|
||||
let result =
|
||||
candle_vec_clone.get(prev_closetime_result.unwrap() + 1..);
|
||||
rt_vec.get(prev_closetime_result.unwrap() + 1..);
|
||||
if result.is_some() {
|
||||
let update_highprice_result =
|
||||
result.unwrap().iter().max_by(|x, y| {
|
||||
|
|
@ -175,11 +161,8 @@ pub async fn update_realtime_price_data(
|
|||
}
|
||||
}
|
||||
|
||||
let price_search_result =
|
||||
read_price.iter().position(|x| x.symbol == *element);
|
||||
if price_search_result.is_some() {
|
||||
update_closeprice =
|
||||
read_price[price_search_result.unwrap()].current_price;
|
||||
if let Some(current_price) = read_price.get(element) {
|
||||
update_closeprice = *current_price;
|
||||
}
|
||||
|
||||
// update the latest candle with values
|
||||
|
|
@ -215,20 +198,16 @@ pub async fn update_realtime_price_data(
|
|||
}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
rt_data_vec.push((element.clone(), rt_price_vec.clone()));
|
||||
if let Some(price_vec) = write_rt_data.get_mut(element) {
|
||||
*price_vec = rt_price_vec.clone();
|
||||
} else {
|
||||
write_rt_data.insert(element.clone(), rt_price_vec.clone());
|
||||
}
|
||||
rt_price_vec.clear();
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
*write_rt_data = rt_data_vec;
|
||||
|
||||
// println!(" datapoints/price_{} 완료 elapsed:{:.2}s", interval, instant.elapsed().as_secs_f32());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{FilteredData, RealtimePriceData, try_join_all, Arc, Mutex};
|
||||
use super::{FilteredDataValue, RealtimePriceData, try_join_all, Arc, Mutex, HashMap};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AdxData {
|
||||
|
|
@ -19,25 +19,24 @@ struct DiData {
|
|||
close_time: i64,
|
||||
}
|
||||
|
||||
pub async fn adx(adx_len: usize, di_len: usize, input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
filtered_symbols: &Vec<FilteredData>,) -> Result<Vec<(String, Vec<AdxData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
pub async fn adx(adx_len: usize, di_len: usize, input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String, Vec<AdxData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
if filtered_symbols.is_empty() {
|
||||
Err(("Err"))?;
|
||||
}
|
||||
|
||||
let mut adx_vec: Vec<(String, Vec<AdxData>)> = Vec::new();
|
||||
let mut adx_vec: HashMap<String, Vec<AdxData>> = HashMap::new();
|
||||
let mut adx_vec_arc = Arc::new(Mutex::new(adx_vec));
|
||||
let mut task_vec = Vec::new();
|
||||
for element in filtered_symbols {
|
||||
let mut rt_data_vec = input_rt_data.clone();
|
||||
for (filtered_symbol, filtered_data) in filtered_symbols {
|
||||
let mut rt_data_map = input_rt_data.clone();
|
||||
let adx_vec_arc_c = Arc::clone(&adx_vec_arc);
|
||||
let symbol = element.symbol.clone();
|
||||
let symbol = filtered_symbol.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let idx_result = rt_data_vec.iter().position(|a| a.0 == symbol);
|
||||
|
||||
if idx_result.is_some() {
|
||||
if let Some(rt_price_data) = rt_data_map.get(&symbol) {
|
||||
if rt_price_data.len()-1 > adx_len && rt_price_data.len() > di_len {
|
||||
// step 1: calculate +DM, -DM, TR
|
||||
let windows = rt_data_vec[idx_result.unwrap()].1.windows(2);
|
||||
let windows = rt_price_data.windows(2);
|
||||
let mut basic_data_vec: Vec<BasicData> = Vec::new();
|
||||
for window in windows {
|
||||
let prev_rt_data = window.first().unwrap();
|
||||
|
|
@ -121,7 +120,8 @@ filtered_symbols: &Vec<FilteredData>,) -> Result<Vec<(String, Vec<AdxData>)>, Bo
|
|||
}
|
||||
|
||||
let mut adx_vec_arc_lock = adx_vec_arc_c.lock().await;
|
||||
adx_vec_arc_lock.push((symbol.clone(), smoothed_adx_vec.clone()));
|
||||
adx_vec_arc_lock.insert(symbol.clone(), smoothed_adx_vec.clone());
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,13 @@
|
|||
use crate::database_control::*;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use crate::value_estimation_team::indicators::sma::{SmaData, sma};
|
||||
use crate::strategy_team::FilteredData;
|
||||
use crate::strategy_team::FilteredDataValue;
|
||||
use futures::future::try_join_all;
|
||||
use serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use super::{HashMap};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BollingerBandData {
|
||||
|
|
@ -35,35 +36,31 @@ impl BollingerBandData {
|
|||
pub async fn bollingerband(
|
||||
period: usize,
|
||||
sd_factor: f64,
|
||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
filtered_symbols: &Vec<FilteredData>,
|
||||
) -> Result<Vec<(String, Vec<BollingerBandData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||
) -> Result<HashMap<String, Vec<BollingerBandData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
if filtered_symbols.is_empty() {
|
||||
Err(("Err"))?;
|
||||
}
|
||||
|
||||
let mut sma_data_vec: Vec<(String, Vec<SmaData>)> = sma(period, input_rt_data, filtered_symbols).await?;
|
||||
|
||||
let mut bb_data_wrapper: Vec<(String, Vec<BollingerBandData>)> = Vec::new();
|
||||
let mut sma_data_map: HashMap<String, Vec<SmaData>> = sma(period, input_rt_data, filtered_symbols).await?;
|
||||
let mut bb_data_wrapper: HashMap<String, Vec<BollingerBandData>> = HashMap::new();
|
||||
let mut bb_data_wrapper_arc = Arc::new(Mutex::new(bb_data_wrapper));
|
||||
let mut task_vec = Vec::new();
|
||||
for filtered_symbol in filtered_symbols {
|
||||
let filtered_symbol_c = filtered_symbol.clone();
|
||||
let rt_data_vec_c: Vec<(String, Vec<RealtimePriceData>)> = input_rt_data.clone();
|
||||
let sma_data_vec_c = sma_data_vec.clone();
|
||||
for (symbol, filtered_data) in filtered_symbols {
|
||||
if input_rt_data.contains_key(symbol) && sma_data_map.contains_key(symbol) {
|
||||
let symbol_c = symbol.clone();
|
||||
let rt_data_vec_c = input_rt_data.get(symbol).unwrap().clone();
|
||||
let sma_data_vec_c = sma_data_map.get(symbol).unwrap().clone();
|
||||
let bb_data_wrapper_arc_c = Arc::clone(&bb_data_wrapper_arc);
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let search_result1 = rt_data_vec_c.clone().iter().position(|x| x.0 == *filtered_symbol_c.symbol);
|
||||
let search_result2 = sma_data_vec_c.iter().position(|x| x.0 == *filtered_symbol_c.symbol);
|
||||
|
||||
if search_result1.is_some() && search_result2.is_some() {
|
||||
let mut bb_data = BollingerBandData::new();
|
||||
let mut bb_data_vec: Vec<BollingerBandData> = Vec::new();
|
||||
|
||||
// if the data has shorter than buffer
|
||||
if sma_data_vec_c[search_result2.unwrap()].1.len() > period {
|
||||
let result = rt_data_vec_c[search_result1.unwrap()].1.binary_search_by_key(
|
||||
&sma_data_vec_c[search_result2.unwrap()].1.first().unwrap().close_time,
|
||||
if sma_data_vec_c.len() > period {
|
||||
let result = rt_data_vec_c.binary_search_by_key(
|
||||
&sma_data_vec_c.first().unwrap().close_time,
|
||||
|RealtimePriceData {
|
||||
opclo_price,
|
||||
open_price,
|
||||
|
|
@ -80,12 +77,12 @@ pub async fn bollingerband(
|
|||
Ok(T) => {
|
||||
if T <= period - 1 {
|
||||
let mut read_data_iter =
|
||||
sma_data_vec_c[search_result2.unwrap()].1.iter();
|
||||
sma_data_vec_c.iter();
|
||||
for _ in T..period - 1 {
|
||||
read_data_iter.next();
|
||||
}
|
||||
let window_iter =
|
||||
rt_data_vec_c[search_result1.unwrap()].1.windows(period);
|
||||
rt_data_vec_c.windows(period);
|
||||
for buffer in window_iter {
|
||||
let mut sd_mean = 0.0;
|
||||
let mut standard_deviation = 0.0;
|
||||
|
|
@ -119,11 +116,11 @@ pub async fn bollingerband(
|
|||
}
|
||||
let mut bb_data_wrapper_lock = bb_data_wrapper_arc_c.lock().await;
|
||||
bb_data_wrapper_lock
|
||||
.push((filtered_symbol_c.symbol.clone(), bb_data_vec.clone()));
|
||||
}
|
||||
.insert(symbol_c, bb_data_vec.clone());
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
let a = bb_data_wrapper_arc.lock().await.to_owned();
|
||||
Ok(a)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ use serde::Deserialize;
|
|||
use sqlx::FromRow;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use super::FilteredData;
|
||||
use super::FilteredDataValue;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EmaData {
|
||||
|
|
@ -27,9 +28,9 @@ impl EmaData {
|
|||
// Binance EMA (closeprice)
|
||||
pub async fn ema(
|
||||
moving_number: usize,
|
||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
filtered_symbols: &Vec<FilteredData>,
|
||||
) -> Result<Vec<(String, Vec<EmaData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||
) -> Result<HashMap<String, Vec<EmaData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
if filtered_symbols.is_empty() {
|
||||
Err("Err")?;
|
||||
}
|
||||
|
|
@ -38,27 +39,24 @@ pub async fn ema(
|
|||
let mut ema_t: f64 = 0.0;
|
||||
let mut ema_prev: f64 = 0.0;
|
||||
|
||||
let mut ema_data_wrapper: Vec<(String, Vec<EmaData>)> = Vec::new();
|
||||
let mut ema_data_wrapper: HashMap<String, Vec<EmaData>> = HashMap::new();
|
||||
let mut ema_data_wrapper_arc = Arc::new(Mutex::new(ema_data_wrapper));
|
||||
let mut task_vec = Vec::new();
|
||||
for filtered_elem in filtered_symbols {
|
||||
let symbol_search_result = input_rt_data.iter().position(|x| x.0 == *filtered_elem.symbol);
|
||||
|
||||
match symbol_search_result {
|
||||
Some(T) => {
|
||||
for (symbol, filtered_data) in filtered_symbols {
|
||||
if let Some(rt_data_vec) = input_rt_data.get(symbol) {
|
||||
let ema_data_wrapper_arc_c = Arc::clone(&ema_data_wrapper_arc);
|
||||
let filtered_elem_c = filtered_elem.clone();
|
||||
let mut ema_data = EmaData::new();
|
||||
let mut ema_data_vec: Vec<EmaData> = Vec::new();
|
||||
let input_rt_data_c = input_rt_data.clone();
|
||||
let symbol_c = symbol.clone();
|
||||
let rt_data_vec_c = rt_data_vec.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
if input_rt_data_c[T].1.len() < moving_number {
|
||||
if rt_data_vec_c.len() < moving_number {
|
||||
ema_data.ema_value = 0.0;
|
||||
ema_data.close_time = 0;
|
||||
ema_data_vec.push(ema_data.clone());
|
||||
} else {
|
||||
let partial_vec1 = input_rt_data_c[T].1.get(..moving_number).unwrap();
|
||||
let partial_vec2 = input_rt_data_c[T].1.get(moving_number..).unwrap();
|
||||
let partial_vec1 = rt_data_vec_c.get(..moving_number).unwrap();
|
||||
let partial_vec2 = rt_data_vec_c.get(moving_number..).unwrap();
|
||||
|
||||
let mut sma_for_initial_value = 0.0;
|
||||
for element in partial_vec1 {
|
||||
|
|
@ -83,11 +81,9 @@ pub async fn ema(
|
|||
}
|
||||
}
|
||||
let mut ema_data_wrapper_lock = ema_data_wrapper_arc_c.lock().await;
|
||||
ema_data_wrapper_lock.push((filtered_elem_c.symbol.clone(), ema_data_vec.clone()));
|
||||
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
||||
}));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
let a = ema_data_wrapper_arc.lock().await.to_owned();
|
||||
|
|
@ -97,9 +93,9 @@ pub async fn ema(
|
|||
// Binance EMA ((open+close)/2)
|
||||
pub async fn ema_opclo(
|
||||
moving_number: usize,
|
||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
filtered_symbols: &Vec<FilteredData>,
|
||||
) -> Result<Vec<(String, Vec<EmaData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||
) -> Result<HashMap<String, Vec<EmaData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
if filtered_symbols.is_empty() {
|
||||
Err("Err")?;
|
||||
}
|
||||
|
|
@ -108,27 +104,24 @@ pub async fn ema_opclo(
|
|||
let mut ema_t: f64 = 0.0;
|
||||
let mut ema_prev: f64 = 0.0;
|
||||
|
||||
let mut ema_data_wrapper: Vec<(String, Vec<EmaData>)> = Vec::new();
|
||||
let mut ema_data_wrapper: HashMap<String, Vec<EmaData>> = HashMap::new();
|
||||
let mut ema_data_wrapper_arc = Arc::new(Mutex::new(ema_data_wrapper));
|
||||
let mut task_vec = Vec::new();
|
||||
for filtered_elem in filtered_symbols {
|
||||
let symbol_search_result = input_rt_data.iter().position(|x| x.0 == *filtered_elem.symbol);
|
||||
|
||||
match symbol_search_result {
|
||||
Some(T) => {
|
||||
for (symbol, filtered_data) in filtered_symbols {
|
||||
if let Some(rt_data_vec) = input_rt_data.get(symbol) {
|
||||
let ema_data_wrapper_arc_c = Arc::clone(&ema_data_wrapper_arc);
|
||||
let filtered_elem_c = filtered_elem.clone();
|
||||
let mut ema_data = EmaData::new();
|
||||
let mut ema_data_vec: Vec<EmaData> = Vec::new();
|
||||
let input_rt_data_c = input_rt_data.clone();
|
||||
let symbol_c = symbol.clone();
|
||||
let rt_data_vec_c = rt_data_vec.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
if input_rt_data_c[T].1.len() < moving_number {
|
||||
if rt_data_vec_c.len() < moving_number {
|
||||
ema_data.ema_value = 0.0;
|
||||
ema_data.close_time = 0;
|
||||
ema_data_vec.push(ema_data.clone());
|
||||
} else {
|
||||
let partial_vec1 = input_rt_data_c[T].1.get(..moving_number).unwrap();
|
||||
let partial_vec2 = input_rt_data_c[T].1.get(moving_number..).unwrap();
|
||||
let partial_vec1 = rt_data_vec_c.get(..moving_number).unwrap();
|
||||
let partial_vec2 = rt_data_vec_c.get(moving_number..).unwrap();
|
||||
|
||||
let mut sma_for_initial_value = 0.0;
|
||||
for element in partial_vec1 {
|
||||
|
|
@ -143,7 +136,7 @@ pub async fn ema_opclo(
|
|||
ema_prev = sma_for_initial_value;
|
||||
|
||||
for element in partial_vec2 {
|
||||
ema_t = (1.0 - alpha) * ema_prev + alpha * element.opclo_price;
|
||||
ema_t = (1.0 - alpha) * ema_prev + alpha * element.close_price;
|
||||
|
||||
ema_data.ema_value = ema_t;
|
||||
ema_data.close_time = element.close_time;
|
||||
|
|
@ -153,11 +146,9 @@ pub async fn ema_opclo(
|
|||
}
|
||||
}
|
||||
let mut ema_data_wrapper_lock = ema_data_wrapper_arc_c.lock().await;
|
||||
ema_data_wrapper_lock.push((filtered_elem_c.symbol.clone(), ema_data_vec.clone()));
|
||||
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
||||
}));
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
let a = ema_data_wrapper_arc.lock().await.to_owned();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use super::FilteredData;
|
||||
use super::FilteredDataValue;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use tokio::sync::Mutex;
|
||||
use futures::future::try_join_all;
|
||||
use super::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum HeatMapLevel {
|
||||
|
|
@ -28,20 +29,20 @@ pub async fn heatmap_volume(
|
|||
high_thold: f64,
|
||||
medium_thold: f64,
|
||||
normal_thold: f64,
|
||||
filtered_symbols: &Vec<FilteredData>,
|
||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
) -> Result<Vec<(String, Vec<HeatmapVolumeData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut heatmap_data_wrapper: Vec<(String, Vec<HeatmapVolumeData>)> = Vec::new();
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
) -> Result<HashMap<String, Vec<HeatmapVolumeData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut heatmap_data_wrapper: HashMap<String, Vec<HeatmapVolumeData>> = HashMap::new();
|
||||
let mut heatmap_data_wrapper_arc = Arc::new(Mutex::new(heatmap_data_wrapper));
|
||||
|
||||
let mut task_vec = Vec::new();
|
||||
for element in filtered_symbols {
|
||||
for (symbol, filtered_data) in filtered_symbols {
|
||||
if let Some(rt_price_vec) = input_rt_data.get(symbol) {
|
||||
let heatmap_data_wrapper_arc_c = Arc::clone(&heatmap_data_wrapper_arc);
|
||||
let element_c = element.clone();
|
||||
let input_rt_data_c = input_rt_data.clone();
|
||||
let symbol_c = symbol.clone();
|
||||
let rt_price_vec_c = rt_price_vec.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let search_result = input_rt_data_c.iter().position(|x| x.0 == element_c.symbol);
|
||||
if search_result.is_some_and(|a| input_rt_data_c[a].1.len() >= ma_len && input_rt_data_c[a].1.len() >= std_len) {
|
||||
if rt_price_vec_c.len() >= ma_len && rt_price_vec_c.len() >= std_len {
|
||||
// calc mean
|
||||
#[derive(Debug, Clone)]
|
||||
struct MeanData {
|
||||
|
|
@ -54,7 +55,7 @@ pub async fn heatmap_volume(
|
|||
mean_value: 0.0,
|
||||
close_time: 0,
|
||||
};
|
||||
let window = input_rt_data_c[search_result.unwrap()].1.windows(ma_len);
|
||||
let window = rt_price_vec_c.windows(ma_len);
|
||||
for buffer in window {
|
||||
// calculate SMA of volume
|
||||
mean_data.mean_value = 0.0;
|
||||
|
|
@ -82,7 +83,7 @@ pub async fn heatmap_volume(
|
|||
let mut mean = 0.0;
|
||||
let mut summation = 0.0;
|
||||
let mut sample_minus_mean = 0.0;
|
||||
let window = input_rt_data_c[search_result.unwrap()].1.windows(std_len);
|
||||
let window = rt_price_vec_c.windows(std_len);
|
||||
for buffer in window {
|
||||
pstdev_data.pstdev_value = 0.0;
|
||||
pstdev_data.close_time = 0;
|
||||
|
|
@ -115,7 +116,7 @@ pub async fn heatmap_volume(
|
|||
|
||||
if ma_len == std_len {
|
||||
let mut rt_data_trunc_vec =
|
||||
input_rt_data_c[search_result.unwrap()].1.get(ma_len - 1..).unwrap().iter();
|
||||
rt_price_vec_c.get(ma_len - 1..).unwrap().iter();
|
||||
|
||||
let zipped = mean_vec.iter().zip(pstdev_vec.iter());
|
||||
for element in zipped {
|
||||
|
|
@ -139,7 +140,7 @@ pub async fn heatmap_volume(
|
|||
}
|
||||
} else if ma_len > std_len {
|
||||
let mut rt_data_trunc_vec =
|
||||
input_rt_data_c[search_result.unwrap()].1.get(std_len - 1..).unwrap().iter();
|
||||
rt_price_vec_c.get(std_len - 1..).unwrap().iter();
|
||||
let mut mean_trunc_vec =
|
||||
mean_vec.get(mean_vec.len() - std_len..).unwrap().iter();
|
||||
let zipped = mean_trunc_vec.zip(pstdev_vec.iter());
|
||||
|
|
@ -153,7 +154,7 @@ pub async fn heatmap_volume(
|
|||
}
|
||||
} else {
|
||||
let mut rt_data_trunc_vec =
|
||||
input_rt_data_c[search_result.unwrap()].1.get(ma_len - 1..).unwrap().iter();
|
||||
rt_price_vec_c.get(ma_len - 1..).unwrap().iter();
|
||||
let mut pstdev_trunc_vec =
|
||||
pstdev_vec.get(pstdev_vec.len() - ma_len..).unwrap().iter();
|
||||
let zipped = mean_vec.iter().zip(pstdev_trunc_vec);
|
||||
|
|
@ -167,10 +168,12 @@ pub async fn heatmap_volume(
|
|||
} // level 구현
|
||||
}
|
||||
let mut heatmap_data_wrapper_lock = heatmap_data_wrapper_arc_c.lock().await;
|
||||
heatmap_data_wrapper_lock.push((element_c.symbol.clone(), heatmap_vol_vec.clone()));
|
||||
heatmap_data_wrapper_lock.insert(symbol_c, heatmap_vol_vec.clone());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
let a = heatmap_data_wrapper_arc.lock().await.to_owned();
|
||||
Ok(a)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::value_estimation_team::indicators::ema::{EmaData, ema};
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use super::FilteredData;
|
||||
use super::{FilteredDataValue, HashMap};
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use futures::future::try_join_all;
|
||||
|
|
@ -43,31 +43,28 @@ pub async fn ema_macd(
|
|||
fast_len: usize,
|
||||
slow_len: usize,
|
||||
signal_smoothing: usize,
|
||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
filtered_symbols: &Vec<FilteredData>
|
||||
) -> Result<Vec<(String, Vec<MacdData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut macd_oscil_vec: Vec<(String, Vec<MacdData>)> = Vec::new();
|
||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>
|
||||
) -> Result<HashMap<String, Vec<MacdData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut macd_oscil_vec: HashMap<String, Vec<MacdData>> = HashMap::new();
|
||||
|
||||
let fast_emas = ema(fast_len, input_rt_data, filtered_symbols).await?;
|
||||
let slow_emas = ema(slow_len, input_rt_data, filtered_symbols).await?;
|
||||
let mut macd_data_wrapper: Vec<(String, Vec<MacdData>)> = Vec::new();
|
||||
let mut macd_data_wrapper: HashMap<String, Vec<MacdData>> = HashMap::new();
|
||||
let mut macd_data_wrapper_arc = Arc::new(Mutex::new(macd_data_wrapper));
|
||||
let mut task_vec = Vec::new();
|
||||
for filtered_elem in filtered_symbols {
|
||||
for (symbol, filtered_data) in filtered_symbols {
|
||||
let fast_emas_c = fast_emas.clone();
|
||||
let slow_emas_c = slow_emas.clone();
|
||||
let filtered_elem_c = filtered_elem.clone();
|
||||
if let (Some(fast_ema_vec), Some(slow_ema_vec)) = (fast_emas.get(symbol), slow_emas_c.get(symbol)) {
|
||||
let symbol_c = symbol.clone();
|
||||
let fast_ema_vec_c = fast_ema_vec.clone();
|
||||
let slow_ema_vec_c = slow_ema_vec.clone();
|
||||
let macd_data_wrapper_arc_c = Arc::clone(&macd_data_wrapper_arc);
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let fast_search_result = fast_emas_c.iter().position(|x| x.0 == filtered_elem_c.symbol);
|
||||
let slow_search_result = slow_emas_c.iter().position(|x| x.0 == filtered_elem_c.symbol);
|
||||
|
||||
if fast_search_result.is_some_and(|a| fast_emas_c[a].1.len() >= signal_smoothing) &&
|
||||
slow_search_result.is_some_and(|a| slow_emas_c[a].1.len() >= signal_smoothing) {
|
||||
let fast_ema = fast_emas_c[fast_search_result.unwrap()].1.clone();
|
||||
let slow_ema = slow_emas_c[fast_search_result.unwrap()].1.clone();
|
||||
let result = fast_ema.binary_search_by_key(
|
||||
&slow_ema.first().unwrap().close_time,
|
||||
if fast_ema_vec_c.len() >= signal_smoothing && slow_ema_vec_c.len() >= signal_smoothing {
|
||||
let result = fast_ema_vec_c.binary_search_by_key(
|
||||
&slow_ema_vec_c.first().unwrap().close_time,
|
||||
|&EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
|
|
@ -75,8 +72,8 @@ pub async fn ema_macd(
|
|||
);
|
||||
if result.is_ok() {
|
||||
// making MACD
|
||||
let temp_vec = fast_ema.get(result.unwrap()..).unwrap();
|
||||
let zipped = temp_vec.iter().zip(slow_ema);
|
||||
let temp_vec = fast_ema_vec_c.get(result.unwrap()..).unwrap();
|
||||
let zipped = temp_vec.iter().zip(slow_ema_vec_c);
|
||||
let mut macd = TempData::new();
|
||||
let mut macd_vec: Vec<TempData> = Vec::new();
|
||||
for element in zipped {
|
||||
|
|
@ -147,13 +144,14 @@ pub async fn ema_macd(
|
|||
macd_vec.push(macd);
|
||||
}
|
||||
let mut macd_data_wrapper_lock = macd_data_wrapper_arc_c.lock().await;
|
||||
macd_data_wrapper_lock.push((filtered_elem_c.symbol.clone(), macd_vec.clone()));
|
||||
macd_data_wrapper_lock.insert(symbol_c, macd_vec.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
let a = macd_data_wrapper_arc.lock().await.to_owned();
|
||||
Ok(a)
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ pub mod stoch_rsi;
|
|||
pub mod supertrend;
|
||||
pub mod tema;
|
||||
|
||||
use crate::strategy_team::FilteredData;
|
||||
use crate::strategy_team::FilteredDataValue;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use futures::future::try_join_all;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use std::collections::HashMap;
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@
|
|||
|
||||
use crate::database_control::*;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use crate::strategy_team::FilteredData;
|
||||
use crate::strategy_team::FilteredDataValue;
|
||||
use futures::future::try_join_all;
|
||||
use serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::f64::NAN;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use super::HashMap;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RsiData {
|
||||
|
|
@ -29,21 +30,20 @@ impl RsiData {
|
|||
// Binance RSI (EMA, Closeprice, Wilder's weight, 150 candles)
|
||||
pub async fn rsi(
|
||||
rsi_number: usize,
|
||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
filtered_symbols: &Vec<FilteredData>,
|
||||
) -> Result<Vec<(String, Vec<RsiData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||
) -> Result<HashMap<String, Vec<RsiData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let instant = Instant::now();
|
||||
|
||||
let mut rsi_data_wrapper: Vec<(String, Vec<RsiData>)> = Vec::new();
|
||||
let mut rsi_data_wrapper: HashMap<String, Vec<RsiData>> = HashMap::new();
|
||||
let mut rsi_data_wrapper_arc = Arc::new(Mutex::new(rsi_data_wrapper));
|
||||
|
||||
let mut task_vec = Vec::new();
|
||||
for element in filtered_symbols {
|
||||
let element_c = element.clone();
|
||||
for (symbol, filtered_data) in filtered_symbols {
|
||||
if let Some(rt_price_vec) = input_rt_data.get(symbol) {
|
||||
let rsi_data_wrapper_arc_c = Arc::clone(&rsi_data_wrapper_arc);
|
||||
let search_result = input_rt_data.iter().position(|x| x.0 == *element_c.symbol);
|
||||
if search_result.is_some() {
|
||||
let input_rt_data_c = input_rt_data.clone();
|
||||
let symbol_c = symbol.clone();
|
||||
let mut input_rt_data_c = rt_price_vec.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let mut rsi_data_vec: Vec<RsiData> = Vec::new();
|
||||
let mut rsi_data = RsiData::new();
|
||||
|
|
@ -56,18 +56,17 @@ pub async fn rsi(
|
|||
let mut rsi: f64 = 0.0;
|
||||
let mut last_close_time = 0;
|
||||
|
||||
if input_rt_data_c[search_result.unwrap()].1.len() < rsi_number + 1 {
|
||||
if input_rt_data_c.len() < rsi_number + 1 {
|
||||
rsi_data.rsi_value = 0.0;
|
||||
rsi_data.close_time = 0;
|
||||
rsi_data_vec.push(rsi_data.clone());
|
||||
} else {
|
||||
read_data_vec = input_rt_data_c[search_result.unwrap()].1.clone();
|
||||
if read_data_vec.len() >= (150 + rsi_number) as usize {
|
||||
read_data_vec.reverse();
|
||||
read_data_vec.truncate((150 + rsi_number) as usize);
|
||||
read_data_vec.reverse();
|
||||
if input_rt_data_c.len() >= (150 + rsi_number) as usize {
|
||||
input_rt_data_c.reverse();
|
||||
input_rt_data_c.truncate((150 + rsi_number) as usize);
|
||||
input_rt_data_c.reverse();
|
||||
}
|
||||
let window_iter = read_data_vec.windows(rsi_number + 1);
|
||||
let window_iter = input_rt_data_c.windows(rsi_number + 1);
|
||||
|
||||
let mut prev_avg_ups: Option<f64> = None;
|
||||
let mut prev_avg_downs: Option<f64> = None;
|
||||
|
|
@ -143,7 +142,7 @@ pub async fn rsi(
|
|||
rsi_data_vec.push(rsi_data.clone());
|
||||
}
|
||||
let mut rsi_data_wrapper_lock = rsi_data_wrapper_arc_c.lock().await;
|
||||
rsi_data_wrapper_lock.push((element_c.symbol.clone(), rsi_data_vec.clone()));
|
||||
rsi_data_wrapper_lock.insert(symbol_c, rsi_data_vec.clone());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,13 @@
|
|||
|
||||
use crate::database_control::*;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use crate::strategy_team::FilteredData;
|
||||
use crate::strategy_team::FilteredDataValue;
|
||||
use futures::future::try_join_all;
|
||||
use serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use super::HashMap;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SmaData {
|
||||
|
|
@ -28,29 +29,28 @@ impl SmaData {
|
|||
// Binance MA (closeprice)
|
||||
pub async fn sma(
|
||||
moving_number: usize,
|
||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
filtered_symbols: &Vec<FilteredData>,
|
||||
) -> Result<Vec<(String, Vec<SmaData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||
) -> Result<HashMap<String, Vec<SmaData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
if filtered_symbols.is_empty() {
|
||||
Err("Err")?;
|
||||
}
|
||||
|
||||
let mut sma_data_wrapper: Vec<(String, Vec<SmaData>)> = Vec::new();
|
||||
let mut sma_data_wrapper: HashMap<String, Vec<SmaData>> = HashMap::new();
|
||||
let mut sma_data_wrapper_arc = Arc::new(Mutex::new(sma_data_wrapper));
|
||||
|
||||
let mut task_vec = Vec::new();
|
||||
for filtered_symbol in filtered_symbols {
|
||||
let filtered_symbol_c = filtered_symbol.clone();
|
||||
for (symbol, filtered_data) in filtered_symbols {
|
||||
if let Some(vec) = input_rt_data.get(symbol) {
|
||||
let sma_data_wrapper_arc_c = Arc::clone(&sma_data_wrapper_arc);
|
||||
let input_rt_data_c = input_rt_data.clone();
|
||||
let symbol_c = symbol.clone();
|
||||
let rt_price_data = vec.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let search_result = input_rt_data_c.iter().position(|x| x.0 == *filtered_symbol_c.symbol);
|
||||
if search_result.is_some() {
|
||||
let mut sma_data = SmaData::new();
|
||||
let mut sma_data_vec: Vec<SmaData> = Vec::new();
|
||||
|
||||
if input_rt_data_c[search_result.unwrap()].1.len() >= moving_number {
|
||||
let mut iter = input_rt_data_c[search_result.unwrap()].1.windows(moving_number);
|
||||
if rt_price_data.len() >= moving_number {
|
||||
let mut iter = rt_price_data.windows(moving_number);
|
||||
for buffer in iter {
|
||||
let mut avg = 0.0;
|
||||
for element in buffer {
|
||||
|
|
@ -64,10 +64,10 @@ pub async fn sma(
|
|||
}
|
||||
}
|
||||
let mut sma_data_wrapper_lock = sma_data_wrapper_arc_c.lock().await;
|
||||
sma_data_wrapper_lock.push((filtered_symbol_c.symbol.clone(), sma_data_vec.clone()));
|
||||
}
|
||||
sma_data_wrapper_lock.insert(symbol_c, sma_data_vec.clone());
|
||||
}));
|
||||
}
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
let a = sma_data_wrapper_arc.lock().await.to_owned();
|
||||
Ok(a)
|
||||
|
|
@ -76,29 +76,28 @@ pub async fn sma(
|
|||
// Binance MA ((open+close)/2)
|
||||
pub async fn sma_opclo(
|
||||
moving_number: usize,
|
||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
filtered_symbols: &Vec<FilteredData>,
|
||||
) -> Result<Vec<(String, Vec<SmaData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||
) -> Result<HashMap<String, Vec<SmaData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
if filtered_symbols.is_empty() {
|
||||
Err("Err")?;
|
||||
}
|
||||
|
||||
let mut sma_data_wrapper: Vec<(String, Vec<SmaData>)> = Vec::new();
|
||||
let mut sma_data_wrapper: HashMap<String, Vec<SmaData>> = HashMap::new();
|
||||
let mut sma_data_wrapper_arc = Arc::new(Mutex::new(sma_data_wrapper));
|
||||
|
||||
let mut task_vec = Vec::new();
|
||||
for filtered_symbol in filtered_symbols {
|
||||
let filtered_symbol_c = filtered_symbol.clone();
|
||||
for (symbol, filtered_data) in filtered_symbols {
|
||||
if let Some(vec) = input_rt_data.get(symbol) {
|
||||
let sma_data_wrapper_arc_c = Arc::clone(&sma_data_wrapper_arc);
|
||||
let input_rt_data_c = input_rt_data.clone();
|
||||
let symbol_c = symbol.clone();
|
||||
let rt_price_data = vec.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let search_result = input_rt_data_c.iter().position(|x| x.0 == *filtered_symbol_c.symbol);
|
||||
if search_result.is_some() {
|
||||
let mut sma_data = SmaData::new();
|
||||
let mut sma_data_vec: Vec<SmaData> = Vec::new();
|
||||
|
||||
if input_rt_data_c[search_result.unwrap()].1.len() >= moving_number {
|
||||
let mut iter = input_rt_data_c[search_result.unwrap()].1.windows(moving_number);
|
||||
if rt_price_data.len() >= moving_number {
|
||||
let mut iter = rt_price_data.windows(moving_number);
|
||||
for buffer in iter {
|
||||
let mut avg = 0.0;
|
||||
for element in buffer {
|
||||
|
|
@ -112,10 +111,10 @@ pub async fn sma_opclo(
|
|||
}
|
||||
}
|
||||
let mut sma_data_wrapper_lock = sma_data_wrapper_arc_c.lock().await;
|
||||
sma_data_wrapper_lock.push((filtered_symbol_c.symbol.clone(), sma_data_vec.clone()));
|
||||
}
|
||||
sma_data_wrapper_lock.insert(symbol_c, sma_data_vec.clone());
|
||||
}));
|
||||
}
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
let a = sma_data_wrapper_arc.lock().await.to_owned();
|
||||
Ok(a)
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@
|
|||
use crate::database_control::*;
|
||||
use crate::value_estimation_team::indicators::rsi::{RsiData, rsi};
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use crate::strategy_team::FilteredData;
|
||||
use crate::strategy_team::FilteredDataValue;
|
||||
use futures::{future::try_join_all, lock::Mutex};
|
||||
use serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::f64::NAN;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, time::*};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StochRsiData {
|
||||
|
|
@ -50,39 +51,31 @@ pub async fn stoch_rsi(
|
|||
stoch_rsi_length: usize,
|
||||
smooth_k: usize,
|
||||
smooth_d: usize,
|
||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
filtered_symbols: &Vec<FilteredData>
|
||||
) -> Result<Vec<(String, Vec<StochRsiData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut stoch_rsi_data_wrapper: Vec<(String, Vec<StochRsiData>)> = Vec::new();
|
||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||
) -> Result<HashMap<String, Vec<StochRsiData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut stoch_rsi_data_wrapper: HashMap<String, Vec<StochRsiData>> = HashMap::new();
|
||||
let mut stoch_rsi_data_wrapper_arc = Arc::new(Mutex::new(stoch_rsi_data_wrapper));
|
||||
let mut stoch_rsi_data_vec: Vec<StochRsiData> = Vec::new();
|
||||
|
||||
if rsi_length == 0 || stoch_rsi_length == 0 || smooth_k == 0 || smooth_d == 0 {
|
||||
panic!(
|
||||
"rsi_length or stoch_rsi_length or smooth_k or smooth_d can't be 0! rsi_length: {}, stoch_rsi_length: {}, k:{}, d:{}",
|
||||
rsi_length, stoch_rsi_length, smooth_k, smooth_d
|
||||
);
|
||||
}
|
||||
let rsi_data_vec = rsi(rsi_length, input_rt_data, filtered_symbols).await?;
|
||||
let rsi_data_map = rsi(rsi_length, input_rt_data, filtered_symbols).await?;
|
||||
let mut task_vec = Vec::new();
|
||||
for element in rsi_data_vec {
|
||||
for (symbol, rsi_vec) in rsi_data_map {
|
||||
let mut stoch_rsi_data = StochRsiData::new();
|
||||
let mut stoch_rsi_k_data = StochRsiKData::new();
|
||||
let stoch_rsi_data_wrapper_arc_c = Arc::clone(&stoch_rsi_data_wrapper_arc);
|
||||
|
||||
let element_c = element.clone();
|
||||
let symbol_c = symbol.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
let mut stoch_rsi_data_vec: Vec<StochRsiData> = Vec::new();
|
||||
let mut stoch_rsi_k_data_vec: Vec<StochRsiKData> = Vec::new();
|
||||
let mut stoch_rsi_vec: Vec<RsiData> = Vec::new();
|
||||
let mut stoch_rsi = RsiData::new();
|
||||
|
||||
if element_c.1.len() >= stoch_rsi_length
|
||||
&& element_c.1.len() >= smooth_k
|
||||
&& element_c.1.len() >= smooth_d
|
||||
if rsi_vec.len() >= stoch_rsi_length
|
||||
&& rsi_vec.len() >= smooth_k
|
||||
&& rsi_vec.len() >= smooth_d
|
||||
{
|
||||
let mut read_data_vec = element_c.1;
|
||||
let window_iter = read_data_vec.windows(stoch_rsi_length);
|
||||
let window_iter = rsi_vec.windows(stoch_rsi_length);
|
||||
|
||||
for buffer_window in window_iter {
|
||||
let max_value = buffer_window
|
||||
|
|
@ -131,7 +124,7 @@ pub async fn stoch_rsi(
|
|||
stoch_rsi_data_vec.push(stoch_rsi_data.clone());
|
||||
}
|
||||
let mut stoch_rsi_data_wrapper_lock = stoch_rsi_data_wrapper_arc_c.lock().await;
|
||||
stoch_rsi_data_wrapper_lock.push((element_c.0.clone(), stoch_rsi_data_vec.clone()));
|
||||
stoch_rsi_data_wrapper_lock.insert(symbol_c, stoch_rsi_data_vec.clone());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,21 @@
|
|||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use super::{HashMap, FilteredDataValue};
|
||||
use std::sync::Arc;
|
||||
use futures::future::try_join_all;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub enum SuperTrendArea { UP, DOWN }
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub enum SuperTrendSignal { BUY, SELL }
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SupertrendData {
|
||||
pub band_value: f64,
|
||||
pub signal: Option<String>, // BUY or SELL
|
||||
pub area: String, // UP or DOWN
|
||||
pub close_time: i64,
|
||||
pub signal: Option<SuperTrendSignal>, // BUY or SELL
|
||||
pub area: SuperTrendArea, // UP or DOWN
|
||||
pub close_time: i64
|
||||
}
|
||||
|
||||
impl SupertrendData {
|
||||
|
|
@ -13,8 +23,8 @@ impl SupertrendData {
|
|||
let a = SupertrendData {
|
||||
band_value: 0.0,
|
||||
signal: None,
|
||||
area: String::new(),
|
||||
close_time: 0,
|
||||
area: SuperTrendArea::DOWN,
|
||||
close_time: 0
|
||||
};
|
||||
|
||||
a
|
||||
|
|
@ -55,19 +65,27 @@ impl ATRData {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: should return type be Option?
|
||||
// Implementation from TradingView Script (SuperTrend by KivancOzbilgic, source price: closeprice)
|
||||
// return key: close_time
|
||||
pub async fn supertrend(
|
||||
symbol: &String,
|
||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
||||
atr_period: usize,
|
||||
multiplier: f64,
|
||||
is_original_method: bool,
|
||||
) -> Option<Vec<SupertrendData>> {
|
||||
let symbol_search_result = input_rt_data.iter().position(|x| x.0 == *symbol);
|
||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||
) -> Result<HashMap<String, Vec<SupertrendData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut supertrend_data_wrapper: HashMap<String, Vec<SupertrendData>> = HashMap::new();
|
||||
let mut supertrend_data_wrapper_arc = Arc::new(Mutex::new(supertrend_data_wrapper));
|
||||
|
||||
match symbol_search_result {
|
||||
Some(T) => {
|
||||
if input_rt_data[T].1.len() >= atr_period && atr_period >= 2 {
|
||||
let mut task_vec = Vec::new();
|
||||
for (symbol, filtered_data) in filtered_symbols {
|
||||
if let Some(rt_price_vec) = input_rt_data.get(symbol) {
|
||||
if atr_period < rt_price_vec.len()-1 {
|
||||
let symbol_c = symbol.clone();
|
||||
let supertrend_data_wrapper_arc_c = Arc::clone(&supertrend_data_wrapper_arc);
|
||||
let rt_price_vec_c = rt_price_vec.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
// making True Range
|
||||
let mut true_range_vec: Vec<TrueRangeData> = Vec::new();
|
||||
let mut tr_data = TrueRangeData::new();
|
||||
|
|
@ -75,11 +93,11 @@ pub async fn supertrend(
|
|||
let mut tr_val_hcp = 0.0; // Abs(High - Close_previous)
|
||||
let mut tr_val_lcp = 0.0; // Abs(Low - Close_previous)
|
||||
|
||||
let window_vec = input_rt_data[T].1.windows(2);
|
||||
let window_vec = rt_price_vec_c.windows(2);
|
||||
|
||||
tr_data.tr_value = input_rt_data[T].1.first().unwrap().high_price
|
||||
- input_rt_data[T].1.first().unwrap().low_price;
|
||||
tr_data.close_time = input_rt_data[T].1.first().unwrap().close_time;
|
||||
tr_data.tr_value = rt_price_vec_c.first().unwrap().high_price
|
||||
- rt_price_vec_c.first().unwrap().low_price;
|
||||
tr_data.close_time = rt_price_vec_c.first().unwrap().close_time;
|
||||
true_range_vec.push(tr_data.clone());
|
||||
|
||||
for buffer in window_vec {
|
||||
|
|
@ -155,10 +173,10 @@ pub async fn supertrend(
|
|||
close_time: 0,
|
||||
};
|
||||
|
||||
let closetime_search_result = input_rt_data[T].1.iter().position(|x| {
|
||||
let closetime_search_result = rt_price_vec_c.iter().position(|x| {
|
||||
x.close_time == average_true_range_vec.first().unwrap().close_time
|
||||
});
|
||||
let mut rt_data = &input_rt_data[T].1[closetime_search_result.unwrap()..];
|
||||
let mut rt_data = &rt_price_vec_c[closetime_search_result.unwrap()..];
|
||||
let zipped = rt_data.iter().zip(average_true_range_vec);
|
||||
|
||||
for element in zipped {
|
||||
|
|
@ -198,23 +216,23 @@ pub async fn supertrend(
|
|||
|
||||
// set supertrend
|
||||
if trend == -1 && element.0.close_price > prev_final_lowerband {
|
||||
supertrend_data.area = String::from("UP");
|
||||
supertrend_data.area = SuperTrendArea::UP;
|
||||
trend = 1;
|
||||
} else if trend == 1 && element.0.close_price < prev_final_upperband {
|
||||
supertrend_data.area = String::from("DOWN");
|
||||
supertrend_data.area = SuperTrendArea::DOWN;
|
||||
trend = -1;
|
||||
}
|
||||
|
||||
if supertrend_data.area.contains("UP") {
|
||||
if supertrend_data.area == SuperTrendArea::UP {
|
||||
supertrend_data.band_value = final_upperband;
|
||||
} else {
|
||||
supertrend_data.band_value = final_lowerband;
|
||||
}
|
||||
|
||||
if trend == 1 && prev_trend == -1 {
|
||||
supertrend_data.signal = Some(String::from("BUY"));
|
||||
supertrend_data.signal = Some(SuperTrendSignal::BUY);
|
||||
} else if trend == -1 && prev_trend == 1 {
|
||||
supertrend_data.signal = Some(String::from("SELL"));
|
||||
supertrend_data.signal = Some(SuperTrendSignal::SELL);
|
||||
} else {
|
||||
supertrend_data.signal = None;
|
||||
}
|
||||
|
|
@ -227,12 +245,13 @@ pub async fn supertrend(
|
|||
prev_final_lowerband = final_lowerband;
|
||||
prev_trend = trend;
|
||||
}
|
||||
|
||||
Some(supertrend_vec)
|
||||
} else {
|
||||
None
|
||||
let mut supertrend_data_wrapper_lock = supertrend_data_wrapper_arc_c.lock().await;
|
||||
supertrend_data_wrapper_lock.insert(symbol_c, supertrend_vec.clone());
|
||||
}));
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
let a = supertrend_data_wrapper_arc.lock().await.to_owned();
|
||||
Ok(a)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user