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::assets_managing_team::*;
|
||||||
use crate::coex::order_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::database_control::*;
|
||||||
use crate::decimal_funcs::{decimal, decimal_add, decimal_div, decimal_mul, decimal_sub};
|
use crate::decimal_funcs::{decimal, decimal_add, decimal_div, decimal_mul, decimal_sub};
|
||||||
use crate::signal_association::signal_decision::*;
|
use crate::signal_association::signal_decision::*;
|
||||||
use crate::strategy_team::AllData;
|
use crate::strategy_team::AllData;
|
||||||
|
use hmac_sha256::Hash;
|
||||||
use reqwest::{Client, ClientBuilder};
|
use reqwest::{Client, ClientBuilder};
|
||||||
use rust_decimal::{prelude::FromPrimitive, prelude::ToPrimitive, Decimal, RoundingStrategy};
|
use rust_decimal::{prelude::FromPrimitive, prelude::ToPrimitive, Decimal, RoundingStrategy};
|
||||||
use rust_decimal_macros::dec;
|
use rust_decimal_macros::dec;
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, FromRow)]
|
#[derive(Debug, FromRow)]
|
||||||
struct IsTradableInfo {
|
struct IsTradableInfo {
|
||||||
|
|
@ -219,13 +221,13 @@ impl DBlist for MarketCapIndex {
|
||||||
|
|
||||||
// buy coin
|
// buy coin
|
||||||
pub async fn buy_coin(
|
pub async fn buy_coin(
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut suggested_coin = get_suggested_coin_list().await;
|
let mut suggested_coin = get_suggested_coin_list().await;
|
||||||
|
|
||||||
if !suggested_coin.is_empty() && exchange_info_vec.len() != 0 && trade_fee_vec.len() != 0 {
|
if !suggested_coin.is_empty() && exchange_info_map.len() != 0 && trade_fee_map.len() != 0 {
|
||||||
let server_epoch = server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
let mut filtered_suggested_coin_vec: Vec<&SuggestedCoin> = Vec::new();
|
let mut filtered_suggested_coin_vec: Vec<&SuggestedCoin> = Vec::new();
|
||||||
let mut is_exist_delete_symbol: bool = false;
|
let mut is_exist_delete_symbol: bool = false;
|
||||||
let mut delete_condition = String::from("WHERE ");
|
let mut delete_condition = String::from("WHERE ");
|
||||||
|
|
@ -255,22 +257,12 @@ pub async fn buy_coin(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
for element in &filtered_suggested_coin_vec {
|
for element in &filtered_suggested_coin_vec {
|
||||||
if is_tradable == true {
|
if is_tradable == true {
|
||||||
let exchange_info_result = exchange_info_vec
|
if exchange_info_map.contains_key(&element.symbol) && trade_fee_map.contains_key(&element.symbol) {
|
||||||
.iter()
|
let exchange_info = exchange_info_map.get(&element.symbol).unwrap();
|
||||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
let lot_step_size = exchange_info.stepsize;
|
||||||
|
let tick_size = exchange_info.ticksize;
|
||||||
let trade_fee_result = trade_fee_vec
|
let base_commission_precision = exchange_info.base_commission_precision;
|
||||||
.iter()
|
let trade_fee = trade_fee_map.get(&element.symbol).unwrap().takercommission;
|
||||||
.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;
|
|
||||||
|
|
||||||
// buy the suggested coin and transfer it into [buy_ordered_coin_list]
|
// buy the suggested coin and transfer it into [buy_ordered_coin_list]
|
||||||
let mut base_qty_ordered = Decimal::new(0, 8);
|
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
|
// order the symbol based on base_qty_ordered and current_price
|
||||||
limit_order_buy(
|
limit_order_buy(
|
||||||
element,
|
element,
|
||||||
exchange_info_vec,
|
exchange_info_map,
|
||||||
trade_fee,
|
trade_fee,
|
||||||
TimeInForce::Gtc,
|
TimeInForce::Gtc,
|
||||||
element.suggested_price,
|
element.suggested_price,
|
||||||
|
|
@ -348,7 +340,6 @@ pub async fn buy_coin(
|
||||||
delete_record(&suggested_coin_list_table_name, &delete_condition)
|
delete_record(&suggested_coin_list_table_name, &delete_condition)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
println!("Delete suggested coin list");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -358,16 +349,15 @@ pub async fn buy_coin(
|
||||||
// buy coin for test
|
// buy coin for test
|
||||||
pub async fn buy_coin_for_test(
|
pub async fn buy_coin_for_test(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
coin_price_vec: &Vec<CoinPriceData>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut suggested_coin = get_suggested_coin_list().await;
|
let mut suggested_coin = get_suggested_coin_list().await;
|
||||||
let mut delete_condition = String::from("WHERE ");
|
let mut delete_condition = String::from("WHERE ");
|
||||||
|
|
||||||
let unit_trade_usdt = get_unit_trade_usdt().await;
|
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();
|
let mut filtered_suggested_coin_vec: Vec<&SuggestedCoin> = Vec::new();
|
||||||
|
|
||||||
for element in &suggested_coin {
|
for element in &suggested_coin {
|
||||||
|
|
@ -385,74 +375,60 @@ pub async fn buy_coin_for_test(
|
||||||
|
|
||||||
let insert_table_name = String::from("buy_ordered_coin_list");
|
let insert_table_name = String::from("buy_ordered_coin_list");
|
||||||
for element in &filtered_suggested_coin_vec {
|
for element in &filtered_suggested_coin_vec {
|
||||||
let lot_step_size = exchange_info_vec
|
if exchange_info_map.contains_key(&element.symbol) && trade_fee_map.contains_key(&element.symbol){
|
||||||
.iter()
|
let lot_step_size = exchange_info_map.get(&element.symbol).unwrap().stepsize;
|
||||||
.find(|exchange_info| exchange_info.symbol == element.symbol)
|
let tick_size = exchange_info_map.get(&element.symbol).unwrap().ticksize;
|
||||||
.unwrap()
|
let base_commission_precision = exchange_info_map.get(&element.symbol).unwrap().base_commission_precision;
|
||||||
.stepsize;
|
let trade_fee = trade_fee_map.get(&element.symbol).unwrap().takercommission;
|
||||||
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;
|
|
||||||
|
|
||||||
// buy the suggested coin and transfer it into [buy_ordered_coin_list]
|
// 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);
|
// let price_index = coin_price_vec.iter().position(|x| *x.symbol == element.symbol);
|
||||||
// let current_price: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(coin_price_vec[price_index.unwrap()].current_price).unwrap();
|
// let current_price: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(coin_price_vec[price_index.unwrap()].current_price).unwrap();
|
||||||
// let order_price = current_price;
|
// let order_price = current_price;
|
||||||
let order_price = element.suggested_price;
|
let order_price = element.suggested_price;
|
||||||
|
|
||||||
base_qty_ordered = decimal_div(unit_trade_usdt, order_price)
|
base_qty_ordered = decimal_div(unit_trade_usdt, order_price)
|
||||||
.round_dp_with_strategy(lot_step_size.normalize().scale(), RoundingStrategy::ToZero);
|
.round_dp_with_strategy(lot_step_size.normalize().scale(), RoundingStrategy::ToZero);
|
||||||
base_qty_fee_adjusted = decimal_mul(base_qty_ordered, decimal_sub(dec!(1), trade_fee))
|
base_qty_fee_adjusted = decimal_mul(base_qty_ordered, decimal_sub(dec!(1), trade_fee))
|
||||||
.round_dp_with_strategy(base_commission_precision, RoundingStrategy::ToZero);
|
.round_dp_with_strategy(base_commission_precision, RoundingStrategy::ToZero);
|
||||||
used_usdt = decimal_mul(base_qty_ordered, order_price)
|
used_usdt = decimal_mul(base_qty_ordered, order_price)
|
||||||
.round_dp_with_strategy(tick_size.normalize().scale(), RoundingStrategy::ToZero);
|
.round_dp_with_strategy(tick_size.normalize().scale(), RoundingStrategy::ToZero);
|
||||||
expected_pure_profit_percent = decimal_sub(
|
expected_pure_profit_percent = decimal_sub(
|
||||||
decimal_div(
|
decimal_div(
|
||||||
decimal_mul(base_qty_fee_adjusted, order_price).round_dp_with_strategy(
|
decimal_mul(base_qty_fee_adjusted, order_price).round_dp_with_strategy(
|
||||||
tick_size.normalize().scale(),
|
tick_size.normalize().scale(),
|
||||||
RoundingStrategy::ToZero,
|
RoundingStrategy::ToZero,
|
||||||
|
),
|
||||||
|
used_usdt,
|
||||||
),
|
),
|
||||||
used_usdt,
|
dec!(1),
|
||||||
),
|
)
|
||||||
dec!(1),
|
.to_f64()
|
||||||
)
|
.unwrap()
|
||||||
.to_f64()
|
* 100.0;
|
||||||
.unwrap()
|
|
||||||
* 100.0;
|
|
||||||
|
|
||||||
// order the symbol based on base_qty_ordered and current_price
|
// order the symbol based on base_qty_ordered and current_price
|
||||||
limit_order_buy(
|
limit_order_buy(
|
||||||
element,
|
element,
|
||||||
exchange_info_vec,
|
exchange_info_map,
|
||||||
trade_fee,
|
trade_fee,
|
||||||
TimeInForce::Gtc,
|
TimeInForce::Gtc,
|
||||||
order_price,
|
order_price,
|
||||||
base_qty_ordered,
|
base_qty_ordered,
|
||||||
used_usdt,
|
used_usdt,
|
||||||
&base_qty_fee_adjusted.to_string(),
|
&base_qty_fee_adjusted.to_string(),
|
||||||
&client,
|
&client,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
println!(" buy coin 완료");
|
println!(" buy coin 완료");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
// monitoring the price change of pre-suggested coins before suggesting them and move them when conditions are agree
|
// 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(
|
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>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let select_table_name = String::from("pre_suggested_coin_list");
|
let select_table_name = String::from("pre_suggested_coin_list");
|
||||||
let pre_suggested_coin_list = select_pre_suggested_coin_list().await;
|
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();
|
let mut update_condition: Vec<(String, String)> = Vec::new();
|
||||||
|
|
||||||
for element in pre_suggested_coin_list {
|
for element in pre_suggested_coin_list {
|
||||||
let price_index = coin_price_vec
|
if let Some(current_price) = coin_price_map.get(&element.symbol) {
|
||||||
.iter()
|
price = rust_decimal::prelude::FromPrimitive::from_f64(*current_price).unwrap();
|
||||||
.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();
|
|
||||||
profit_percent = ((price - element.suggested_price) / element.suggested_price)
|
profit_percent = ((price - element.suggested_price) / element.suggested_price)
|
||||||
.to_f64()
|
.to_f64()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -561,7 +531,7 @@ pub async fn monitoring_pre_suggested_coins(
|
||||||
insert_values.push(element.stoploss.to_string()); // stoploss
|
insert_values.push(element.stoploss.to_string()); // stoploss
|
||||||
insert_values.push(element.target_price.to_string()); // target_price
|
insert_values.push(element.target_price.to_string()); // target_price
|
||||||
insert_values.push(element.close_time.to_string()); // close_time
|
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.registerer.to_string()); // registerer
|
||||||
insert_values.push(element.is_long.to_string()); // is_long
|
insert_values.push(element.is_long.to_string()); // is_long
|
||||||
insert_values.push(0.to_string()); // already_buy
|
insert_values.push(0.to_string()); // already_buy
|
||||||
|
|
@ -626,7 +596,7 @@ pub async fn monitoring_scoreboard(
|
||||||
let scoreboard_list = select_scoreboard().await;
|
let scoreboard_list = select_scoreboard().await;
|
||||||
let mut count_short_coins = 0;
|
let mut count_short_coins = 0;
|
||||||
let mut count_long_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;
|
let mut timer_check = false;
|
||||||
|
|
||||||
for element in &filled_buy_orders {
|
for element in &filled_buy_orders {
|
||||||
|
|
@ -756,12 +726,9 @@ pub async fn monitoring_scoreboard(
|
||||||
let mut base_profit_percent = 0.0;
|
let mut base_profit_percent = 0.0;
|
||||||
let mut target_profit_percent = 0.0;
|
let mut target_profit_percent = 0.0;
|
||||||
|
|
||||||
let opclo_1m_option = all_data
|
let symbol = String::from("BTCUSDT");
|
||||||
.rt_price_1m_vec
|
if let Some(rt_price_1m_vec) = all_data.rt_price_1m_vec.get(&symbol) {
|
||||||
.iter()
|
let mut opclo_1m_vec = rt_price_1m_vec.clone();
|
||||||
.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 opclo_sample_length: usize = 5; // 10 candle samsples
|
let opclo_sample_length: usize = 5; // 10 candle samsples
|
||||||
opclo_1m_vec.pop();
|
opclo_1m_vec.pop();
|
||||||
opclo_1m_vec.reverse();
|
opclo_1m_vec.reverse();
|
||||||
|
|
@ -949,7 +916,7 @@ async fn get_suggested_coin_list() -> Vec<SuggestedCoin> {
|
||||||
select_result
|
select_result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn server_epoch() -> i64 {
|
pub async fn get_server_epoch() -> i64 {
|
||||||
let table_name = String::from("time");
|
let table_name = String::from("time");
|
||||||
let columns = String::from("*");
|
let columns = String::from("*");
|
||||||
let condition = None;
|
let condition = None;
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ use crate::URL_TEST;
|
||||||
// use crates
|
// use crates
|
||||||
use crate::coex::assets_managing_team::*;
|
use crate::coex::assets_managing_team::*;
|
||||||
use crate::coex::exchange_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::database_control::*;
|
||||||
use crate::decimal_funcs::*;
|
use crate::decimal_funcs::*;
|
||||||
use crate::signal_association::signal_decision::*;
|
use crate::signal_association::signal_decision::*;
|
||||||
|
|
@ -30,6 +30,7 @@ use rust_decimal_macros::dec;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
use tokio::time::*;
|
use tokio::time::*;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub enum OrderSide {
|
pub enum OrderSide {
|
||||||
Buy,
|
Buy,
|
||||||
|
|
@ -298,7 +299,7 @@ pub async fn limit_order_buy_test(
|
||||||
|
|
||||||
pub async fn limit_order_buy(
|
pub async fn limit_order_buy(
|
||||||
element: &SuggestedCoin,
|
element: &SuggestedCoin,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee: Decimal,
|
trade_fee: Decimal,
|
||||||
tif: TimeInForce,
|
tif: TimeInForce,
|
||||||
order_price: Decimal,
|
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_values: Vec<Vec<String>> = Vec::new();
|
||||||
let mut insert_value_container: 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 {
|
if RUNNING_MODE == SIMUL {
|
||||||
insert_value_container.push(element.symbol.clone()); // symbol
|
insert_value_container.push(element.symbol.clone()); // symbol
|
||||||
insert_value_container.push(0.to_string()); // order_id
|
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()); // pure_profit_percent
|
||||||
insert_value_container.push(0.0.to_string()); // minimum_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.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(element.registerer.to_string()); // registerer
|
||||||
insert_value_container.push(0.to_string()); // is_long
|
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(
|
pub async fn monitoring_open_buy_order(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let open_buy_orders = select_open_buy_orders().await;
|
let open_buy_orders = select_open_buy_orders().await;
|
||||||
|
|
||||||
if !open_buy_orders.is_empty() {
|
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
|
let orders_outdated = open_buy_orders
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&element| server_epoch - element.transact_time >= 600_000)
|
.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]
|
// cancel orders outdated over 3mins and delete the records in [buy_ordered_coin_list]
|
||||||
if !orders_outdated.is_empty() {
|
if !orders_outdated.is_empty() {
|
||||||
for element in orders_outdated {
|
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
|
sleep(Duration::from_millis(500)).await; // Use max 30 LIMIT/min
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !orders_to_be_queried.is_empty() {
|
if !orders_to_be_queried.is_empty() {
|
||||||
for element in orders_to_be_queried {
|
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
|
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(
|
pub async fn update_price_of_filled_buy_order(
|
||||||
coin_price_vec: &Vec<CoinPriceData>,
|
coin_price_map: &HashMap<String, f64>,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let filled_buy_orders = select_filled_buy_orders(0).await?;
|
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 {
|
for chunk in chunks {
|
||||||
let chunk_vec = chunk.to_vec();
|
let chunk_vec = chunk.to_vec();
|
||||||
let coin_price_vec_c = coin_price_vec.clone();
|
let coin_price_vec_c = coin_price_map.clone();
|
||||||
let exchange_info_vec_c = exchange_info_vec.clone();
|
let exchange_info_vec_c = exchange_info_map.clone();
|
||||||
let trade_fee_vec_c = trade_fee_vec.clone();
|
let trade_fee_vec_c = trade_fee_map.clone();
|
||||||
task_vec.push(tokio::spawn(async move {
|
task_vec.push(tokio::spawn(async move {
|
||||||
update_repeat_task(
|
update_repeat_task(
|
||||||
chunk_vec,
|
chunk_vec,
|
||||||
|
|
@ -567,16 +566,16 @@ pub async fn update_price_of_filled_buy_order(
|
||||||
|
|
||||||
async fn update_repeat_task(
|
async fn update_repeat_task(
|
||||||
buy_ordered_coin_vec: Vec<BuyOrderedCoinList>,
|
buy_ordered_coin_vec: Vec<BuyOrderedCoinList>,
|
||||||
coin_price_vec: &Vec<CoinPriceData>,
|
coin_price_map: &HashMap<String, f64>,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let update_table_name = String::from("buy_ordered_coin_list");
|
let update_table_name = String::from("buy_ordered_coin_list");
|
||||||
let mut update_values: Vec<(String, String)> = Vec::new();
|
let mut update_values: Vec<(String, String)> = Vec::new();
|
||||||
let mut update_condition: Vec<(String, String)> = Vec::new();
|
let mut update_condition: Vec<(String, String)> = Vec::new();
|
||||||
let mut price = Decimal::new(0, 8);
|
let mut price = Decimal::new(0, 8);
|
||||||
let mut profit_percent = 0.0;
|
let mut profit_percent = 0.0;
|
||||||
let server_epoch = server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
|
|
||||||
let update_colums = vec![
|
let update_colums = vec![
|
||||||
"current_price",
|
"current_price",
|
||||||
|
|
@ -594,96 +593,71 @@ async fn update_repeat_task(
|
||||||
for element in buy_ordered_coin_vec {
|
for element in buy_ordered_coin_vec {
|
||||||
// build update values
|
// build update values
|
||||||
update_record_build.clear();
|
update_record_build.clear();
|
||||||
let price_index_option = coin_price_vec
|
if coin_price_map.contains_key(&element.symbol) && exchange_info_map.contains_key(&element.symbol) && trade_fee_map.contains_key(&element.symbol) {
|
||||||
.iter()
|
price = rust_decimal::prelude::FromPrimitive::from_f64(*coin_price_map.get(&element.symbol).unwrap()).unwrap();
|
||||||
.position(|x| *x.symbol == element.symbol);
|
if !price.is_zero() {
|
||||||
let lot_step_size_result = exchange_info_vec
|
// to get quote_commission_precision
|
||||||
.iter()
|
let trade_fee = trade_fee_map.get(&element.symbol).unwrap().takercommission;
|
||||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
let lot_step_size = exchange_info_map.get(&element.symbol).unwrap().stepsize;
|
||||||
let quote_commission_precision_result = exchange_info_vec
|
let quote_commission_precision = exchange_info_map.get(&element.symbol).unwrap().quote_commission_precision;
|
||||||
.iter()
|
let base_qty_to_be_ordered =
|
||||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
element.base_qty_fee_adjusted.round_dp_with_strategy(
|
||||||
let trade_fee_result = trade_fee_vec
|
lot_step_size.normalize().scale(),
|
||||||
.iter()
|
RoundingStrategy::ToZero,
|
||||||
.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 !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 base_qty_to_be_ordered =
|
|
||||||
element.base_qty_fee_adjusted.round_dp_with_strategy(
|
|
||||||
lot_step_size.normalize().scale(),
|
|
||||||
RoundingStrategy::ToZero,
|
|
||||||
);
|
|
||||||
let expected_get_usdt = decimal_mul(
|
|
||||||
decimal_mul(base_qty_to_be_ordered, price).round_dp_with_strategy(
|
|
||||||
quote_commission_precision,
|
|
||||||
RoundingStrategy::ToZero,
|
|
||||||
),
|
|
||||||
decimal_sub(dec!(1), trade_fee),
|
|
||||||
);
|
);
|
||||||
|
let expected_get_usdt = decimal_mul(
|
||||||
|
decimal_mul(base_qty_to_be_ordered, price).round_dp_with_strategy(
|
||||||
|
quote_commission_precision,
|
||||||
|
RoundingStrategy::ToZero,
|
||||||
|
),
|
||||||
|
decimal_sub(dec!(1), trade_fee),
|
||||||
|
);
|
||||||
|
|
||||||
// TODO: sell_count >=1 이면 expected_get_usdt 는 한번만 tradefee만 적용하여 업데이트 할 것. 현재는 수수료를 2번 (매수,매도)를 계산함. 아래 변수에 든 값으로 업데이트 하면 됨
|
// TODO: sell_count >=1 이면 expected_get_usdt 는 한번만 tradefee만 적용하여 업데이트 할 것. 현재는 수수료를 2번 (매수,매도)를 계산함. 아래 변수에 든 값으로 업데이트 하면 됨
|
||||||
// let expected_get_usdt =
|
// let expected_get_usdt =
|
||||||
// decimal_mul(base_qty_to_be_ordered, price).round_dp_with_strategy(
|
// decimal_mul(base_qty_to_be_ordered, price).round_dp_with_strategy(
|
||||||
// quote_commission_precision,
|
// quote_commission_precision,
|
||||||
// RoundingStrategy::ToZero,
|
// RoundingStrategy::ToZero,
|
||||||
// );
|
// );
|
||||||
let pure_profit_percent = ((expected_get_usdt.to_f64().unwrap()
|
let pure_profit_percent = ((expected_get_usdt.to_f64().unwrap()
|
||||||
/ element.used_usdt.to_f64().unwrap())
|
/ element.used_usdt.to_f64().unwrap())
|
||||||
- 1.0)
|
- 1.0)
|
||||||
* 100.0;
|
* 100.0;
|
||||||
|
|
||||||
update_record_build.push(element.id.to_string()); // id
|
update_record_build.push(element.id.to_string()); // id
|
||||||
update_record_build.push(price.to_string()); // current_price
|
update_record_build.push(price.to_string()); // current_price
|
||||||
update_record_build.push(expected_get_usdt.to_string()); //expected_get_usdt
|
update_record_build.push(expected_get_usdt.to_string()); //expected_get_usdt
|
||||||
update_record_build
|
update_record_build
|
||||||
.push(decimal_sub(expected_get_usdt, element.used_usdt).to_string()); // expected_usdt_profit
|
.push(decimal_sub(expected_get_usdt, element.used_usdt).to_string()); // expected_usdt_profit
|
||||||
update_record_build.push(pure_profit_percent.to_string()); // pure_profit_percent
|
update_record_build.push(pure_profit_percent.to_string()); // pure_profit_percent
|
||||||
|
|
||||||
if element.minimum_profit_percent > pure_profit_percent {
|
if element.minimum_profit_percent > pure_profit_percent {
|
||||||
update_record_build.push(pure_profit_percent.to_string());
|
update_record_build.push(pure_profit_percent.to_string());
|
||||||
|
// minimum_profit_percent
|
||||||
|
} else if pure_profit_percent >= 0.0 {
|
||||||
|
update_record_build.push(0.0.to_string()); // minimum_profit_percent
|
||||||
|
} else {
|
||||||
|
update_record_build.push(element.minimum_profit_percent.to_string());
|
||||||
// minimum_profit_percent
|
// minimum_profit_percent
|
||||||
} else if pure_profit_percent >= 0.0 {
|
|
||||||
update_record_build.push(0.0.to_string()); // minimum_profit_percent
|
|
||||||
} else {
|
|
||||||
update_record_build.push(element.minimum_profit_percent.to_string());
|
|
||||||
// minimum_profit_percent
|
|
||||||
}
|
|
||||||
|
|
||||||
if element.maximum_profit_percent < pure_profit_percent {
|
|
||||||
update_record_build.push(pure_profit_percent.to_string());
|
|
||||||
// maximum_profit_percent
|
|
||||||
} else if pure_profit_percent <= 0.0 {
|
|
||||||
update_record_build.push(0.0.to_string()); // maximum_profit_percent
|
|
||||||
} else {
|
|
||||||
update_record_build.push(element.maximum_profit_percent.to_string());
|
|
||||||
// maximum_profit_percent
|
|
||||||
}
|
|
||||||
|
|
||||||
if server_epoch - element.transact_time >= 86_400_000 {
|
|
||||||
// turn is_long from 0 to 1 for orders whose transact time is over than a day (86,400,000 millis = a day)
|
|
||||||
update_record_build.push(1.to_string());
|
|
||||||
} else {
|
|
||||||
update_record_build.push(0.to_string());
|
|
||||||
}
|
|
||||||
update_record.push(update_record_build.clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if element.maximum_profit_percent < pure_profit_percent {
|
||||||
|
update_record_build.push(pure_profit_percent.to_string());
|
||||||
|
// maximum_profit_percent
|
||||||
|
} else if pure_profit_percent <= 0.0 {
|
||||||
|
update_record_build.push(0.0.to_string()); // maximum_profit_percent
|
||||||
|
} else {
|
||||||
|
update_record_build.push(element.maximum_profit_percent.to_string());
|
||||||
|
// maximum_profit_percent
|
||||||
|
}
|
||||||
|
|
||||||
|
if server_epoch - element.transact_time >= 86_400_000 {
|
||||||
|
// turn is_long from 0 to 1 for orders whose transact time is over than a day (86,400,000 millis = a day)
|
||||||
|
update_record_build.push(1.to_string());
|
||||||
|
} else {
|
||||||
|
update_record_build.push(0.to_string());
|
||||||
|
}
|
||||||
|
update_record.push(update_record_build.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -698,8 +672,8 @@ pub async fn limit_order_sell(
|
||||||
sell_base_price: Decimal,
|
sell_base_price: Decimal,
|
||||||
sell_base_quantity: Decimal,
|
sell_base_quantity: Decimal,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let insert_table_name = String::from("sell_ordered_coin_list");
|
let insert_table_name = String::from("sell_ordered_coin_list");
|
||||||
let insert_columns = vec![
|
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_values: Vec<Vec<String>> = Vec::new();
|
||||||
let mut insert_value_container: 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" {
|
if RUNNING_MODE == SIMUL && buy_ordered_coin.status == "SIMUL" {
|
||||||
let quote_asset_precision_option = exchange_info_vec
|
if exchange_info_map.contains_key(&buy_ordered_coin.symbol) && trade_fee_map.contains_key(&buy_ordered_coin.symbol) {
|
||||||
.iter()
|
let quote_asset_precision = exchange_info_map.get(&buy_ordered_coin.symbol).unwrap().quote_asset_precision;
|
||||||
.position(|exchange_info| exchange_info.symbol == buy_ordered_coin.symbol);
|
let trade_fee = trade_fee_map.get(&buy_ordered_coin.symbol).unwrap().takercommission;
|
||||||
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;
|
|
||||||
|
|
||||||
let get_usdt = decimal_mul(sell_base_quantity, sell_base_price)
|
let get_usdt = decimal_mul(sell_base_quantity, sell_base_price)
|
||||||
.round_dp_with_strategy(quote_asset_precision, RoundingStrategy::ToZero);
|
.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
|
.push(T.get("status").unwrap().as_str().unwrap().to_string()); // status
|
||||||
insert_value_container.push(buy_ordered_coin.used_usdt.to_string()); // used_usdt
|
insert_value_container.push(buy_ordered_coin.used_usdt.to_string()); // used_usdt
|
||||||
|
|
||||||
let quote_asset_precision_option = exchange_info_vec
|
if exchange_info_map.contains_key(&buy_ordered_coin.symbol) && trade_fee_map.contains_key(&buy_ordered_coin.symbol) {
|
||||||
.iter()
|
let quote_asset_precision = exchange_info_map.get(&buy_ordered_coin.symbol).unwrap().quote_asset_precision;
|
||||||
.position(|exchange_info| exchange_info.symbol == buy_ordered_coin.symbol);
|
let trade_fee = trade_fee_map.get(&buy_ordered_coin.symbol).unwrap().takercommission;
|
||||||
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;
|
|
||||||
let get_usdt = rust_decimal::prelude::FromStr::from_str(
|
let get_usdt = rust_decimal::prelude::FromStr::from_str(
|
||||||
T.get("cummulativeQuoteQty").unwrap().as_str().unwrap(),
|
T.get("cummulativeQuoteQty").unwrap().as_str().unwrap(),
|
||||||
)
|
)
|
||||||
|
|
@ -932,13 +891,13 @@ pub async fn limit_order_sell(
|
||||||
|
|
||||||
pub async fn monitoring_open_sell_order(
|
pub async fn monitoring_open_sell_order(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let open_sell_orders = select_open_sell_orders().await;
|
let open_sell_orders = select_open_sell_orders().await;
|
||||||
|
|
||||||
if !open_sell_orders.is_empty() {
|
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
|
let orders_outdated = open_sell_orders
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&element| server_epoch - element.transact_time >= 5_000)
|
.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]
|
// 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() {
|
if !orders_outdated.is_empty() {
|
||||||
for element in orders_outdated {
|
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
|
sleep(Duration::from_millis(200)).await; // Use max 30 LIMIT/min
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !orders_to_be_queried.is_empty() {
|
if !orders_to_be_queried.is_empty() {
|
||||||
for element in orders_to_be_queried {
|
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
|
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 mut insert_value_build: Vec<String> = Vec::new();
|
||||||
|
|
||||||
let update_table_name = String::from("achievement_evaluation");
|
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);
|
let mut total_get_usdt = Decimal::new(0, 8);
|
||||||
|
|
||||||
for element in filled_sell_orders {
|
for element in filled_sell_orders {
|
||||||
|
|
@ -1119,8 +1078,7 @@ pub async fn market_order(
|
||||||
pub async fn cancel_buy_order(
|
pub async fn cancel_buy_order(
|
||||||
order: &BuyOrderedCoinList,
|
order: &BuyOrderedCoinList,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
// building URL and API-keys
|
// building URL and API-keys
|
||||||
let mut url = String::new();
|
let mut url = String::new();
|
||||||
|
|
@ -1195,18 +1153,8 @@ pub async fn cancel_buy_order(
|
||||||
status_value_build.push('\'');
|
status_value_build.push('\'');
|
||||||
|
|
||||||
// calculate values to be updated
|
// calculate values to be updated
|
||||||
let trade_fee_option = trade_fee_vec
|
if trade_fee_map.contains_key(&order.symbol) {
|
||||||
.iter()
|
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||||
.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_qty_ordered = rust_decimal::prelude::FromStr::from_str(
|
let base_qty_ordered = rust_decimal::prelude::FromStr::from_str(
|
||||||
T.get("executedQty").unwrap().as_str().unwrap(),
|
T.get("executedQty").unwrap().as_str().unwrap(),
|
||||||
)
|
)
|
||||||
|
|
@ -1214,10 +1162,6 @@ pub async fn cancel_buy_order(
|
||||||
|
|
||||||
let base_qty_fee_adjusted =
|
let base_qty_fee_adjusted =
|
||||||
decimal_mul(base_qty_ordered, decimal_sub(dec!(1), trade_fee));
|
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)
|
let buy_price = decimal_div(cummulative_quote_qty, base_qty_ordered)
|
||||||
.round_dp_with_strategy(8, RoundingStrategy::ToZero);
|
.round_dp_with_strategy(8, RoundingStrategy::ToZero);
|
||||||
|
|
||||||
|
|
@ -1261,11 +1205,11 @@ pub async fn cancel_buy_order(
|
||||||
} else if T.get("code").is_some() {
|
} else if T.get("code").is_some() {
|
||||||
// case that the order isn't canceled because the order completes while canceling
|
// case that the order isn't canceled because the order completes while canceling
|
||||||
// update record in ordered_coin_list
|
// 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) => {
|
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);
|
// println!("cancel order buy failed!: {}", body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1277,8 +1221,8 @@ pub async fn cancel_buy_order(
|
||||||
pub async fn cancel_sell_order(
|
pub async fn cancel_sell_order(
|
||||||
order: &SellOrderedCoinList,
|
order: &SellOrderedCoinList,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
// building URL and API-keys
|
// building URL and API-keys
|
||||||
let mut url = String::new();
|
let mut url = String::new();
|
||||||
|
|
@ -1364,7 +1308,7 @@ pub async fn cancel_sell_order(
|
||||||
// insert record in [buy_ordered_coin_list]
|
// insert record in [buy_ordered_coin_list]
|
||||||
let mut insert_values: Vec<Vec<String>> = Vec::new();
|
let mut insert_values: Vec<Vec<String>> = Vec::new();
|
||||||
let mut insert_value_container: 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.symbol.clone()); // symbol
|
||||||
insert_value_container.push(order.buy_order_id.to_string()); // order_id
|
insert_value_container.push(order.buy_order_id.to_string()); // order_id
|
||||||
insert_value_container.push(order.transact_time.to_string()); // transact_time
|
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_values.push(insert_value_container.clone());
|
||||||
insert_records(&insert_table_name, &insert_columns, &insert_values).await;
|
insert_records(&insert_table_name, &insert_columns, &insert_values).await;
|
||||||
} else {
|
} else {
|
||||||
let quote_asset_precision_option = exchange_info_vec
|
if exchange_info_map.contains_key(&order.symbol) && trade_fee_map.contains_key(&order.symbol) {
|
||||||
.iter()
|
let quote_asset_precision = exchange_info_map.get(&order.symbol).unwrap().quote_asset_precision;
|
||||||
.position(|exchange_info| exchange_info.symbol == order.symbol);
|
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||||
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 base_qty_executed == base_qty_ordered {
|
if base_qty_executed == base_qty_ordered {
|
||||||
// FILLED case
|
// FILLED case
|
||||||
// update status FILLED
|
// update status FILLED
|
||||||
|
|
@ -1514,7 +1448,7 @@ pub async fn cancel_sell_order(
|
||||||
decimal_mul(rest_base_qty, decimal_sub(dec!(1), trade_fee));
|
decimal_mul(rest_base_qty, decimal_sub(dec!(1), trade_fee));
|
||||||
let mut insert_values: Vec<Vec<String>> = Vec::new();
|
let mut insert_values: Vec<Vec<String>> = Vec::new();
|
||||||
let mut insert_value_container: 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.symbol.clone()); // symbol
|
||||||
insert_value_container.push(order.buy_order_id.to_string()); // order_id
|
insert_value_container.push(order.buy_order_id.to_string()); // order_id
|
||||||
insert_value_container.push(server_epoch.to_string()); // transact_time
|
insert_value_container.push(server_epoch.to_string()); // transact_time
|
||||||
|
|
@ -1542,12 +1476,12 @@ pub async fn cancel_sell_order(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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() {
|
} else if T.get("code").is_some() {
|
||||||
// case that the order isn't canceled because the order completes while canceling
|
// case that the order isn't canceled because the order completes while canceling
|
||||||
// update record in ordered_coin_list
|
// 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) => {
|
Err(e) => {
|
||||||
|
|
@ -1626,8 +1560,7 @@ pub async fn all_orders(
|
||||||
pub async fn query_buy_order(
|
pub async fn query_buy_order(
|
||||||
order: &BuyOrderedCoinList,
|
order: &BuyOrderedCoinList,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
// building URL and API-keys
|
// building URL and API-keys
|
||||||
let mut url = String::new();
|
let mut url = String::new();
|
||||||
|
|
@ -1687,18 +1620,8 @@ pub async fn query_buy_order(
|
||||||
value_build.push('\'');
|
value_build.push('\'');
|
||||||
|
|
||||||
// calculate values to be updated
|
// calculate values to be updated
|
||||||
let trade_fee_option = trade_fee_vec
|
if trade_fee_map.contains_key(&order.symbol) {
|
||||||
.iter()
|
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||||
.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;
|
|
||||||
let base_qty_ordered = rust_decimal::prelude::FromStr::from_str(
|
let base_qty_ordered = rust_decimal::prelude::FromStr::from_str(
|
||||||
T.get("executedQty").unwrap().as_str().unwrap(),
|
T.get("executedQty").unwrap().as_str().unwrap(),
|
||||||
)
|
)
|
||||||
|
|
@ -1773,8 +1696,8 @@ pub async fn query_buy_order(
|
||||||
pub async fn query_sell_order(
|
pub async fn query_sell_order(
|
||||||
order: &SellOrderedCoinList,
|
order: &SellOrderedCoinList,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
// building URL and API-keys
|
// building URL and API-keys
|
||||||
let mut url = String::new();
|
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")
|
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")
|
|| T.get("status").is_some_and(|a| a.as_str().unwrap() == "PARTIALLY_FILLED")
|
||||||
{
|
{
|
||||||
let quote_asset_precision_option = exchange_info_vec
|
if exchange_info_map.contains_key(&order.symbol) && trade_fee_map.contains_key(&order.symbol) {
|
||||||
.iter()
|
let quote_asset_precision = exchange_info_map.get(&order.symbol).unwrap().quote_asset_precision;
|
||||||
.position(|exchange_info| exchange_info.symbol == order.symbol);
|
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||||
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;
|
|
||||||
let get_usdt = rust_decimal::prelude::FromStr::from_str(
|
let get_usdt = rust_decimal::prelude::FromStr::from_str(
|
||||||
T.get("cummulativeQuoteQty").unwrap().as_str().unwrap(),
|
T.get("cummulativeQuoteQty").unwrap().as_str().unwrap(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use sqlx::{Error, FromRow};
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{join, sync::Mutex, time::*};
|
use tokio::{join, sync::Mutex, time::*};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
#[derive(Debug, FromRow)]
|
#[derive(Debug, FromRow)]
|
||||||
struct AllCoinProfitChangeAvgList {
|
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
|
// filter valid USDT trades from all24hstatistics table in database
|
||||||
pub async fn collect_valid_usde_trade(
|
pub async fn collect_valid_usde_trade(
|
||||||
valid_usdt_trade_vec: &mut Vec<String>,
|
valid_usdt_trade_vec: &mut HashSet<String>,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_vec: &HashMap<String, ExchangeInfo>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
#[derive(Debug, FromRow)]
|
#[derive(Debug, FromRow)]
|
||||||
struct UsdtTrades {
|
struct UsdtTrades {
|
||||||
|
|
@ -138,27 +139,23 @@ pub async fn collect_valid_usde_trade(
|
||||||
select_record(&fetch_table_name, &column_name, &condition, &usdt_trades).await?;
|
select_record(&fetch_table_name, &column_name, &condition, &usdt_trades).await?;
|
||||||
|
|
||||||
// filtering usdt trades
|
// filtering usdt trades
|
||||||
let mut filtered_usdt_trades: Vec<String> = Vec::new();
|
let mut filtered_usdt_trades: HashSet<String> = HashSet::new();
|
||||||
let mut excluded_usdt_trades: Vec<String> = Vec::new();
|
let mut excluded_usdt_trades: HashSet<String> = HashSet::new();
|
||||||
for usdt_trade in usdt_trades {
|
for usdt_trade in usdt_trades {
|
||||||
// build update values
|
// build update values
|
||||||
let step_size_result = exchange_info_vec
|
if let Some(value) = exchange_info_vec.get(&usdt_trade.symbol) {
|
||||||
.iter()
|
|
||||||
.position(|exchange_info| exchange_info.symbol == usdt_trade.symbol);
|
|
||||||
|
|
||||||
if step_size_result.is_some() {
|
|
||||||
let avg_price: Decimal =
|
let avg_price: Decimal =
|
||||||
rust_decimal::prelude::FromPrimitive::from_f64(usdt_trade.weightedavgprice)
|
rust_decimal::prelude::FromPrimitive::from_f64(usdt_trade.weightedavgprice)
|
||||||
.unwrap();
|
.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 step_price = decimal_mul(step_size, avg_price);
|
||||||
let unit_trade_usdt = crate::coex::assets_managing_team::get_unit_trade_usdt().await;
|
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
|
// 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)) {
|
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 {
|
} 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?;
|
delete_all_rows(&table_name).await?;
|
||||||
insert_records(&table_name, &columns, &value_wrapper).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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use sqlx::{Error, FromRow};
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{join, sync::Mutex, time::*};
|
use tokio::{join, sync::Mutex, time::*};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CandleData {
|
pub struct CandleData {
|
||||||
|
|
@ -25,6 +26,26 @@ pub struct CandleData {
|
||||||
pub ignore_this: f64,
|
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
|
// fetch the list of valid usdt trades
|
||||||
#[derive(Debug, FromRow, Clone)]
|
#[derive(Debug, FromRow, Clone)]
|
||||||
struct Symbols {
|
struct Symbols {
|
||||||
|
|
@ -37,7 +58,7 @@ async fn request_candlestick_data(
|
||||||
symbol: String,
|
symbol: String,
|
||||||
interval: &String,
|
interval: &String,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
candle_set: &mut Vec<(String, Vec<CandleData>)>,
|
candle_set: &mut HashMap<String, Vec<CandleData>>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut query = String::from("https://api.binance.com/api/v3/klines?");
|
let mut query = String::from("https://api.binance.com/api/v3/klines?");
|
||||||
query.push_str("&symbol=");
|
query.push_str("&symbol=");
|
||||||
|
|
@ -67,7 +88,7 @@ async fn de_candle_json(
|
||||||
symbol: String,
|
symbol: String,
|
||||||
interval: &String,
|
interval: &String,
|
||||||
body: &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>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let v: Value = serde_json::from_str(body.as_str())?;
|
let v: Value = serde_json::from_str(body.as_str())?;
|
||||||
let mut into_vec = v.as_array();
|
let mut into_vec = v.as_array();
|
||||||
|
|
@ -75,21 +96,8 @@ async fn de_candle_json(
|
||||||
return Err("Err")?;
|
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_vec: Vec<CandleData> = Vec::new();
|
||||||
|
let mut candle_data = CandleData::new();
|
||||||
for element in into_vec.unwrap() {
|
for element in into_vec.unwrap() {
|
||||||
let inner_into_vec = element.as_array().unwrap();
|
let inner_into_vec = element.as_array().unwrap();
|
||||||
candle_data.open_time = element[0].as_i64().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_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);
|
// let search_result = candle_set.iter().position(|x| x.0 == symbol);
|
||||||
// match search_result {
|
// match search_result {
|
||||||
// Some(T) => {
|
// Some(T) => {
|
||||||
|
|
@ -127,7 +135,7 @@ async fn de_candle_json2(
|
||||||
symbol: String,
|
symbol: String,
|
||||||
interval: &String,
|
interval: &String,
|
||||||
body: &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>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let v: Value = serde_json::from_str(body.as_str())?;
|
let v: Value = serde_json::from_str(body.as_str())?;
|
||||||
let mut into_vec = v.as_array();
|
let mut into_vec = v.as_array();
|
||||||
|
|
@ -135,21 +143,8 @@ async fn de_candle_json2(
|
||||||
return Err("Err")?;
|
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_vec: Vec<CandleData> = Vec::new();
|
||||||
|
let mut candle_data = CandleData::new();
|
||||||
for element in into_vec.unwrap() {
|
for element in into_vec.unwrap() {
|
||||||
let inner_into_vec = element.as_array().unwrap();
|
let inner_into_vec = element.as_array().unwrap();
|
||||||
candle_data.open_time = element[0].as_i64().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());
|
candle_vec.push(candle_data.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let search_result = candle_set.iter().position(|x| x.0 == symbol);
|
if let Some(value) = candle_map.get_mut(&symbol) {
|
||||||
match search_result {
|
*value = candle_vec;
|
||||||
Some(T) => {
|
} else {
|
||||||
candle_set[T].1 = candle_vec;
|
candle_map.insert(symbol, candle_vec);
|
||||||
}
|
|
||||||
None => {
|
|
||||||
candle_set.push((symbol, candle_vec));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -262,7 +253,7 @@ pub async fn request_candlestick_initial(
|
||||||
symbol: String,
|
symbol: String,
|
||||||
interval: &String,
|
interval: &String,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> 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()
|
let client = ClientBuilder::new()
|
||||||
.timeout(tokio::time::Duration::from_millis(20000))
|
.timeout(tokio::time::Duration::from_millis(20000))
|
||||||
.build()
|
.build()
|
||||||
|
|
@ -449,7 +440,7 @@ pub async fn create_candle_table(
|
||||||
// for fetching 1m and 30m candle
|
// for fetching 1m and 30m candle
|
||||||
pub async fn fetch_candle_parallel(
|
pub async fn fetch_candle_parallel(
|
||||||
interval: &String,
|
interval: &String,
|
||||||
candle_vec: &mut Vec<(String, Vec<CandleData>)>,
|
candle_map: &mut HashMap<String, Vec<CandleData>>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
let fetch_table_name = String::from("valid_usdt_trades");
|
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 chunks = select_result.chunks(20);
|
||||||
let nbr_chunks = chunks.len();
|
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 {
|
for _ in 0..nbr_chunks {
|
||||||
let mut candle_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::new();
|
let mut candle_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||||
let mut candle_vec_arc = Arc::new(Mutex::new(candle_vec_temp));
|
let mut candle_vec_arc = Arc::new(Mutex::new(candle_map_temp));
|
||||||
candle_vec_arc_wrapper.push(candle_vec_arc);
|
candle_vec_arc_wrapper.push(candle_vec_arc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -490,15 +481,15 @@ pub async fn fetch_candle_parallel(
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(T) => {
|
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 {
|
for element in candle_vec_arc_wrapper {
|
||||||
let a = element.lock().await.clone();
|
let a = element.lock().await.clone();
|
||||||
for element in a {
|
for (symbol, candle_data) in a {
|
||||||
candle_buffer.push(element);
|
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());
|
// println!(" candle {} 완료 elapsed:{:.2}s", interval.as_str(), instant.elapsed().as_secs_f32());
|
||||||
}
|
}
|
||||||
Err(E) => {
|
Err(E) => {
|
||||||
|
|
@ -512,7 +503,7 @@ pub async fn fetch_candle_parallel(
|
||||||
async fn repeat_task(
|
async fn repeat_task(
|
||||||
interval: String,
|
interval: String,
|
||||||
symbol_vec: Vec<Symbols>,
|
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>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let client = ClientBuilder::new()
|
let client = ClientBuilder::new()
|
||||||
.timeout(tokio::time::Duration::from_millis(5000))
|
.timeout(tokio::time::Duration::from_millis(5000))
|
||||||
|
|
@ -531,7 +522,7 @@ async fn repeat_task(
|
||||||
// for fetching 1d, 1w, and 1mon candle
|
// for fetching 1d, 1w, and 1mon candle
|
||||||
pub async fn fetch_candle_delay(
|
pub async fn fetch_candle_delay(
|
||||||
interval: &String,
|
interval: &String,
|
||||||
candle_vec: &mut Vec<(String, Vec<CandleData>)>,
|
candle_vec: &mut HashMap<String, Vec<CandleData>>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let instant_func = Instant::now();
|
let instant_func = Instant::now();
|
||||||
let server_epoch = server_epoch().await;
|
let server_epoch = server_epoch().await;
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ use serde_json::Value;
|
||||||
use sqlx::{Error, FromRow};
|
use sqlx::{Error, FromRow};
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::collections::HashMap;
|
||||||
use tokio::{join, sync::Mutex, time::*};
|
use tokio::{join, sync::Mutex, time::*};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TradeFee {
|
pub struct TradeFee {
|
||||||
pub symbol: String,
|
|
||||||
pub makercommission: Decimal,
|
pub makercommission: Decimal,
|
||||||
pub takercommission: Decimal,
|
pub takercommission: Decimal,
|
||||||
}
|
}
|
||||||
|
|
@ -20,7 +20,6 @@ pub struct TradeFee {
|
||||||
impl TradeFee {
|
impl TradeFee {
|
||||||
fn new() -> TradeFee {
|
fn new() -> TradeFee {
|
||||||
let a = TradeFee {
|
let a = TradeFee {
|
||||||
symbol: String::new(),
|
|
||||||
makercommission: Decimal::new(0, 8),
|
makercommission: Decimal::new(0, 8),
|
||||||
takercommission: Decimal::new(0, 8),
|
takercommission: Decimal::new(0, 8),
|
||||||
};
|
};
|
||||||
|
|
@ -30,7 +29,6 @@ impl TradeFee {
|
||||||
|
|
||||||
#[derive(Debug, FromRow, Clone)]
|
#[derive(Debug, FromRow, Clone)]
|
||||||
pub struct ExchangeInfo {
|
pub struct ExchangeInfo {
|
||||||
pub symbol: String,
|
|
||||||
pub stepsize: Decimal,
|
pub stepsize: Decimal,
|
||||||
pub ticksize: Decimal,
|
pub ticksize: Decimal,
|
||||||
pub base_asset_precision: u32,
|
pub base_asset_precision: u32,
|
||||||
|
|
@ -42,7 +40,6 @@ pub struct ExchangeInfo {
|
||||||
impl ExchangeInfo {
|
impl ExchangeInfo {
|
||||||
fn new() -> ExchangeInfo {
|
fn new() -> ExchangeInfo {
|
||||||
let a = ExchangeInfo {
|
let a = ExchangeInfo {
|
||||||
symbol: String::new(),
|
|
||||||
stepsize: Decimal::new(0, 8),
|
stepsize: Decimal::new(0, 8),
|
||||||
ticksize: Decimal::new(0, 8),
|
ticksize: Decimal::new(0, 8),
|
||||||
base_asset_precision: 0,
|
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 (/api, Weight(IP) 2)
|
||||||
// request_all_coin_price -> de_all_coin_price_json -> store_coin_price_db
|
// 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: &Arc<Mutex<Vec<(String, f64)>>>) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
pub async fn request_all_coin_price(
|
pub async fn request_all_coin_price(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
price_vec: &mut Vec<CoinPriceData>,
|
price_vec: &mut HashMap<String, f64>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let url = "https://api.binance.com/api/v3/ticker/price";
|
let url = "https://api.binance.com/api/v3/ticker/price";
|
||||||
let mut response = client.get(url).send().await?;
|
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(
|
async fn de_all_coin_price_json(
|
||||||
body: &String,
|
body: &String,
|
||||||
price_vec: &mut Vec<CoinPriceData>,
|
price_vec: &mut HashMap<String, f64>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let v: Value = serde_json::from_str(body.as_str())?;
|
let v: Value = serde_json::from_str(body.as_str())?;
|
||||||
let into_vec = v.as_array();
|
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 object_map = &serde_json::map::Map::new();
|
||||||
|
|
||||||
let mut de_price_vec: Vec<CoinPriceData> = Vec::new();
|
let mut symbol = String::new();
|
||||||
let mut data_temp = CoinPriceData::new();
|
let mut price = 0.0;
|
||||||
|
|
||||||
for element in into_vec.unwrap() {
|
for element in into_vec.unwrap() {
|
||||||
object_map = element.as_object().unwrap();
|
object_map = element.as_object().unwrap();
|
||||||
let mut object_map_iter = object_map.iter();
|
let mut object_map_iter = object_map.iter();
|
||||||
|
|
||||||
for element in object_map_iter {
|
for element in object_map_iter {
|
||||||
match element.0.as_str() {
|
match element.0.as_str() {
|
||||||
"symbol" => data_temp.symbol = element.1.as_str().unwrap().to_string(),
|
"symbol" => symbol = element.1.as_str().unwrap().to_string(),
|
||||||
"price" => {
|
"price" => price = element.1.as_str().unwrap().parse::<f64>().unwrap(),
|
||||||
data_temp.current_price = element.1.as_str().unwrap().parse::<f64>().unwrap()
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
println!("Elements in body msg are changed. Please update both your coinprices table and vectors.");
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -129,7 +107,7 @@ pub async fn request_trade_fee(
|
||||||
local_epoch: u128,
|
local_epoch: u128,
|
||||||
difference_epoch: i64,
|
difference_epoch: i64,
|
||||||
client: &Client,
|
client: &Client,
|
||||||
tradefee_vec: &mut Vec<TradeFee>,
|
tradefee_vec: &mut HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut base_url = String::from("https://api.binance.com/sapi/v1/asset/tradeFee?");
|
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(
|
async fn de_trade_fee_json(
|
||||||
body: &String,
|
body: &String,
|
||||||
tradefee_vec: &mut Vec<TradeFee>,
|
tradefee_map: &mut HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let v: Value = serde_json::from_str(body.as_str())?;
|
let v: Value = serde_json::from_str(body.as_str())?;
|
||||||
|
|
||||||
|
|
@ -197,9 +175,9 @@ async fn de_trade_fee_json(
|
||||||
return Err("Err")?;
|
return Err("Err")?;
|
||||||
}
|
}
|
||||||
let mut object_map = &serde_json::map::Map::new();
|
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();
|
let mut tradefee_data = TradeFee::new();
|
||||||
|
|
||||||
for element in into_vec.unwrap() {
|
for element in into_vec.unwrap() {
|
||||||
object_map = element.as_object().unwrap();
|
object_map = element.as_object().unwrap();
|
||||||
|
|
||||||
|
|
@ -207,7 +185,7 @@ async fn de_trade_fee_json(
|
||||||
|
|
||||||
for element in object_map_iter {
|
for element in object_map_iter {
|
||||||
match element.0.as_str() {
|
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" => {
|
"makerCommission" => {
|
||||||
tradefee_data.makercommission =
|
tradefee_data.makercommission =
|
||||||
rust_decimal::prelude::FromStr::from_str(element.1.as_str().unwrap())
|
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_map = tradefee_map_build;
|
||||||
*tradefee_vec = de_tradefee_vec;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -354,7 +331,7 @@ async fn store_24h_change_db(
|
||||||
// request exchange information. (/api, Weight(IP) 10)
|
// request exchange information. (/api, Weight(IP) 10)
|
||||||
pub async fn request_exchange_infomation(
|
pub async fn request_exchange_infomation(
|
||||||
client: &Client,
|
client: &Client,
|
||||||
exchange_info_data: &mut Vec<ExchangeInfo>,
|
exchange_info_map: &mut HashMap<String, ExchangeInfo>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
// building URL and API-keys
|
// building URL and API-keys
|
||||||
let mut url = String::new();
|
let mut url = String::new();
|
||||||
|
|
@ -380,8 +357,9 @@ pub async fn request_exchange_infomation(
|
||||||
return Err("Err")?;
|
return Err("Err")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut data_temp = ExchangeInfo::new();
|
let mut symbol = String::new();
|
||||||
let mut data_temp_vec: Vec<ExchangeInfo> = Vec::new();
|
let mut exchange_info = ExchangeInfo::new();
|
||||||
|
let mut data_map_temp: HashMap<String, ExchangeInfo> = HashMap::new();
|
||||||
|
|
||||||
for element in into_vec.unwrap() {
|
for element in into_vec.unwrap() {
|
||||||
if element.0.contains("symbols") {
|
if element.0.contains("symbols") {
|
||||||
|
|
@ -394,23 +372,23 @@ pub async fn request_exchange_infomation(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ends_with("USDT")
|
.ends_with("USDT")
|
||||||
{
|
{
|
||||||
data_temp.symbol =
|
symbol =
|
||||||
(element.get("symbol").unwrap().as_str().unwrap().to_string());
|
(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;
|
(element.get("baseAssetPrecision").unwrap().as_u64().unwrap()) as u32;
|
||||||
data_temp.base_commission_precision = (element
|
exchange_info.base_commission_precision = (element
|
||||||
.get("baseCommissionPrecision")
|
.get("baseCommissionPrecision")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_u64()
|
.as_u64()
|
||||||
.unwrap())
|
.unwrap())
|
||||||
as u32;
|
as u32;
|
||||||
data_temp.quote_asset_precision = (element
|
exchange_info.quote_asset_precision = (element
|
||||||
.get("quoteAssetPrecision")
|
.get("quoteAssetPrecision")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_u64()
|
.as_u64()
|
||||||
.unwrap())
|
.unwrap())
|
||||||
as u32;
|
as u32;
|
||||||
data_temp.quote_commission_precision = (element
|
exchange_info.quote_commission_precision = (element
|
||||||
.get("quoteCommissionPrecision")
|
.get("quoteCommissionPrecision")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_u64()
|
.as_u64()
|
||||||
|
|
@ -426,7 +404,7 @@ pub async fn request_exchange_infomation(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.starts_with("LOT_SIZE")
|
.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(),
|
element.get("stepSize").unwrap().as_str().unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -439,20 +417,20 @@ pub async fn request_exchange_infomation(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.starts_with("PRICE_FILTER")
|
.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(),
|
element.get("tickSize").unwrap().as_str().unwrap(),
|
||||||
)
|
)
|
||||||
.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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ pub enum RunningMode {
|
||||||
TEST,
|
TEST,
|
||||||
REAL,
|
REAL,
|
||||||
}
|
}
|
||||||
pub const RUNNING_MODE: RunningMode = RunningMode::REAL;
|
pub const RUNNING_MODE: RunningMode = RunningMode::SIMUL;
|
||||||
|
|
||||||
pub mod coex;
|
pub mod coex;
|
||||||
pub mod coin_health_check_team;
|
pub mod coin_health_check_team;
|
||||||
|
|
|
||||||
424
src/main.rs
424
src/main.rs
|
|
@ -3,13 +3,15 @@
|
||||||
|
|
||||||
use crate::coin_health_check_team::*;
|
use crate::coin_health_check_team::*;
|
||||||
use crate::request_candles::CandleData;
|
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::server_health_check_team::ServerHealth;
|
||||||
use crate::strategy_team::AllData;
|
use crate::strategy_team::AllData;
|
||||||
use crate::time_checking_team::UserTime;
|
use crate::time_checking_team::UserTime;
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||||
use reqwest::{Client, ClientBuilder};
|
use reqwest::{Client, ClientBuilder};
|
||||||
|
use rust_decimal::Decimal;
|
||||||
use sqlx::{mysql::*, Connection, Executor, FromRow, Row};
|
use sqlx::{mysql::*, Connection, Executor, FromRow, Row};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::{
|
use std::{
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
|
|
@ -80,88 +82,88 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let (tx2, mut rx2) = watch::channel(0); // epoch_difference
|
let (tx2, mut rx2) = watch::channel(0); // epoch_difference
|
||||||
|
|
||||||
// trade fee data
|
// trade fee data
|
||||||
let mut tradefee_vec: Vec<TradeFee> = Vec::new(); // (symbol, makerCommission, takerCommission)
|
let mut tradefee_map: HashMap<String, TradeFee> = HashMap::new(); // <symbol, TradeFee>
|
||||||
let (tx_tradefee_vec, mut rx_tradefee_vec) = watch::channel(tradefee_vec);
|
let (tx_tradefee_map, mut rx_tradefee_map) = watch::channel(tradefee_map);
|
||||||
let mut rx2_tradefee_vec = rx_tradefee_vec.clone();
|
let mut rx2_tradefee_map = rx_tradefee_map.clone();
|
||||||
let mut rx3_tradefee_vec = rx_tradefee_vec.clone();
|
let mut rx3_tradefee_map = rx_tradefee_map.clone();
|
||||||
let mut rx4_tradefee_vec = rx_tradefee_vec.clone();
|
let mut rx4_tradefee_map = rx_tradefee_map.clone();
|
||||||
let mut rx5_tradefee_vec = rx_tradefee_vec.clone();
|
let mut rx5_tradefee_map = rx_tradefee_map.clone();
|
||||||
let mut tradefee_vec_capacity = rx_tradefee_vec.clone();
|
let mut tradefee_map_capacity = rx_tradefee_map.clone();
|
||||||
|
|
||||||
// valid usdt trade data
|
// valid usdt trade data
|
||||||
let mut valid_usdt_trade_vec: Vec<String> = Vec::new(); // symbol
|
let mut valid_usdt_trade_set: HashSet<String> = HashSet::new(); // symbol
|
||||||
let (tx_valid_usdt_trade_vec, mut rx_valid_usdt_trade_vec) =
|
let (tx_valid_usdt_trade_set, mut rx_valid_usdt_trade_set) =
|
||||||
watch::channel(valid_usdt_trade_vec);
|
watch::channel(valid_usdt_trade_set);
|
||||||
let mut rx2_valid_usdt_trade_vec = rx_valid_usdt_trade_vec.clone();
|
let mut rx2_valid_usdt_trade_set = rx_valid_usdt_trade_set.clone();
|
||||||
let mut rx3_valid_usdt_trade_vec = rx_valid_usdt_trade_vec.clone();
|
let mut rx3_valid_usdt_trade_set = rx_valid_usdt_trade_set.clone();
|
||||||
let mut rx4_valid_usdt_trade_vec = rx_valid_usdt_trade_vec.clone();
|
let mut rx4_valid_usdt_trade_set = rx_valid_usdt_trade_set.clone();
|
||||||
let mut valid_usdt_trade_vec_capacity = rx_valid_usdt_trade_vec.clone();
|
let mut valid_usdt_trade_set_capacity = rx_valid_usdt_trade_set.clone();
|
||||||
|
|
||||||
// price per second data and channels
|
// price per second data and channels
|
||||||
let mut price_vec: Vec<CoinPriceData> = Vec::new(); // (symbol, price)
|
let mut price_map: HashMap<String, f64> = HashMap::new(); // <symbol, price>
|
||||||
let (tx_price_vec, mut rx_price_vec) = watch::channel(price_vec);
|
let (tx_price_map, mut rx_price_map) = watch::channel(price_map);
|
||||||
let mut rx3_price_vec = rx_price_vec.clone();
|
let mut rx3_price_map = rx_price_map.clone();
|
||||||
let mut rx5_price_vec = rx_price_vec.clone();
|
let mut rx5_price_map = rx_price_map.clone();
|
||||||
let mut price_vec_capacity = rx_price_vec.clone();
|
let mut price_map_capacity = rx_price_map.clone();
|
||||||
|
|
||||||
// candle data from endpoint and channels
|
// candle data from endpoint and channels
|
||||||
let mut candle_1m_vec: Vec<(String, Vec<CandleData>)> = Vec::new(); // (symbol, Vec<CandleData)>
|
let mut candle_1m_map: HashMap<String, Vec<CandleData>> = HashMap::new(); // <symbol, Vec<CandleData>>
|
||||||
let (tx_candle_1m_vec, mut rx_candle_1m_vec) = watch::channel(candle_1m_vec);
|
let (tx_candle_1m_map, mut rx_candle_1m_map) = watch::channel(candle_1m_map);
|
||||||
let mut candle_1m_vec_capacity = rx_candle_1m_vec.clone();
|
let mut candle_1m_map_capacity = rx_candle_1m_map.clone();
|
||||||
|
|
||||||
let mut candle_30m_vec: Vec<(String, Vec<CandleData>)> = Vec::new();
|
let mut candle_30m_map: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||||
let (tx_candle_30m_vec, mut rx_candle_30m_vec) = watch::channel(candle_30m_vec);
|
let (tx_candle_30m_map, mut rx_candle_30m_map) = watch::channel(candle_30m_map);
|
||||||
let mut candle_30m_vec_capacity = rx_candle_30m_vec.clone();
|
let mut candle_30m_map_capacity = rx_candle_30m_map.clone();
|
||||||
|
|
||||||
let mut candle_1d_vec: Vec<(String, Vec<CandleData>)> = Vec::new();
|
let mut candle_1d_map: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||||
let (tx_candle_1d_vec, mut rx_candle_1d_vec) = watch::channel(candle_1d_vec);
|
let (tx_candle_1d_map, mut rx_candle_1d_map) = watch::channel(candle_1d_map);
|
||||||
let mut candle_1d_vec_capacity = rx_candle_1d_vec.clone();
|
let mut candle_1d_map_capacity = rx_candle_1d_map.clone();
|
||||||
|
|
||||||
let mut candle_1w_vec: Vec<(String, Vec<CandleData>)> = Vec::new();
|
let mut candle_1w_map: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||||
let (tx_candle_1w_vec, mut rx_candle_1w_vec) = watch::channel(candle_1w_vec);
|
let (tx_candle_1w_map, mut rx_candle_1w_map) = watch::channel(candle_1w_map);
|
||||||
let mut candle_1w_vec_capacity = rx_candle_1w_vec.clone();
|
let mut candle_1w_map_capacity = rx_candle_1w_map.clone();
|
||||||
|
|
||||||
let mut candle_1mon_vec: Vec<(String, Vec<CandleData>)> = Vec::new();
|
let mut candle_1mon_map: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||||
let (tx_candle_1mon_vec, mut rx_candle_1mon_vec) = watch::channel(candle_1mon_vec);
|
let (tx_candle_1mon_map, mut rx_candle_1mon_map) = watch::channel(candle_1mon_map);
|
||||||
let mut candle_1mon_vec_capacity = rx_candle_1mon_vec.clone();
|
let mut candle_1mon_map_capacity = rx_candle_1mon_map.clone();
|
||||||
|
|
||||||
// real-time reflected price data and channels
|
// real-time reflected price data and channels
|
||||||
let mut rt_price_1m_vec: Vec<(String, Vec<RealtimePriceData>)> = Vec::new(); // (symbol, Vec<RealtimePriceData)>
|
let mut rt_price_1m_map: HashMap<String, Vec<RealtimePriceData>> = HashMap::new(); // <symbol, Vec<RealtimePriceData>>
|
||||||
let (tx_rt_price_1m_vec, mut rx_rt_price_1m_vec) = watch::channel(rt_price_1m_vec);
|
let (tx_rt_price_1m_map, mut rx_rt_price_1m_map) = watch::channel(rt_price_1m_map);
|
||||||
let mut rx2_rt_price_1m_vec = rx_rt_price_1m_vec.clone();
|
let mut rx2_rt_price_1m_map = rx_rt_price_1m_map.clone();
|
||||||
let mut rx3_rt_price_1m_vec = rx_rt_price_1m_vec.clone();
|
let mut rx3_rt_price_1m_map = rx_rt_price_1m_map.clone();
|
||||||
let mut rx4_rt_price_1m_vec = rx_rt_price_1m_vec.clone();
|
let mut rx4_rt_price_1m_map = rx_rt_price_1m_map.clone();
|
||||||
let mut rx5_rt_price_1m_vec = rx_rt_price_1m_vec.clone();
|
let mut rx5_rt_price_1m_map = rx_rt_price_1m_map.clone();
|
||||||
let mut rt_price_1m_vec_capacity = rx_rt_price_1m_vec.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 mut rt_price_30m_map: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||||
let (tx_rt_price_30m_vec, mut rx_rt_price_30m_vec) = watch::channel(rt_price_30m_vec);
|
let (tx_rt_price_30m_map, mut rx_rt_price_30m_map) = watch::channel(rt_price_30m_map);
|
||||||
let mut rx2_rt_price_30m_vec = rx_rt_price_30m_vec.clone();
|
let mut rx2_rt_price_30m_map = rx_rt_price_30m_map.clone();
|
||||||
let mut rx3_rt_price_30m_vec = rx_rt_price_30m_vec.clone();
|
let mut rx3_rt_price_30m_map = rx_rt_price_30m_map.clone();
|
||||||
let mut rx4_rt_price_30m_vec = rx_rt_price_30m_vec.clone();
|
let mut rx4_rt_price_30m_map = rx_rt_price_30m_map.clone();
|
||||||
let mut rx5_rt_price_30m_vec = rx_rt_price_30m_vec.clone();
|
let mut rx5_rt_price_30m_map = rx_rt_price_30m_map.clone();
|
||||||
let mut rt_price_30m_vec_capacity = rx_rt_price_30m_vec.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 mut rt_price_1d_map: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||||
let (tx_rt_price_1d_vec, mut rx_rt_price_1d_vec) = watch::channel(rt_price_1d_vec);
|
let (tx_rt_price_1d_map, mut rx_rt_price_1d_map) = watch::channel(rt_price_1d_map);
|
||||||
let mut rx2_rt_price_1d_vec = rx_rt_price_1d_vec.clone();
|
let mut rx2_rt_price_1d_map = rx_rt_price_1d_map.clone();
|
||||||
let mut rx3_rt_price_1d_vec = rx_rt_price_1d_vec.clone();
|
let mut rx3_rt_price_1d_map = rx_rt_price_1d_map.clone();
|
||||||
let mut rx4_rt_price_1d_vec = rx_rt_price_1d_vec.clone();
|
let mut rx4_rt_price_1d_map = rx_rt_price_1d_map.clone();
|
||||||
let mut rt_price_1d_vec_capacity = rx_rt_price_1d_vec.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 mut rt_price_1w_map: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||||
let (tx_rt_price_1w_vec, mut rx_rt_price_1w_vec) = watch::channel(rt_price_1w_vec);
|
let (tx_rt_price_1w_map, mut rx_rt_price_1w_map) = watch::channel(rt_price_1w_map);
|
||||||
let mut rx2_rt_price_1w_vec = rx_rt_price_1w_vec.clone();
|
let mut rx2_rt_price_1w_map = rx_rt_price_1w_map.clone();
|
||||||
let mut rx3_rt_price_1w_vec = rx_rt_price_1w_vec.clone();
|
let mut rx3_rt_price_1w_map = rx_rt_price_1w_map.clone();
|
||||||
let mut rx4_rt_price_1w_vec = rx_rt_price_1w_vec.clone();
|
let mut rx4_rt_price_1w_map = rx_rt_price_1w_map.clone();
|
||||||
let mut rt_price_1w_vec_capacity = rx_rt_price_1w_vec.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 mut rt_price_1mon_map: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||||
let (tx_rt_price_1mon_vec, mut rx_rt_price_1mon_vec) = watch::channel(rt_price_1mon_vec);
|
let (tx_rt_price_1mon_map, mut rx_rt_price_1mon_map) = watch::channel(rt_price_1mon_map);
|
||||||
let mut rx2_rt_price_1mon_vec = rx_rt_price_1mon_vec.clone();
|
let mut rx2_rt_price_1mon_map = rx_rt_price_1mon_map.clone();
|
||||||
let mut rx3_rt_price_1mon_vec = rx_rt_price_1mon_vec.clone();
|
let mut rx3_rt_price_1mon_map = rx_rt_price_1mon_map.clone();
|
||||||
let mut rx4_rt_price_1mon_vec = rx_rt_price_1mon_vec.clone();
|
let mut rx4_rt_price_1mon_map = rx_rt_price_1mon_map.clone();
|
||||||
let mut rt_price_1mon_vec_capacity = rx_rt_price_1mon_vec.clone();
|
let mut rt_price_1mon_map_capacity = rx_rt_price_1mon_map.clone();
|
||||||
|
|
||||||
// TEMA data
|
// TEMA data
|
||||||
// let mut tema3_1m_data: Vec<(String, Vec<(f64, i64)>)> = Vec::new(); // Vec<(symbol, Vec<(price, closetime)>)>
|
// 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);
|
// let (tx_tema30_1mon_data, mut rx_tema30_1mon_data) = watch::channel(tema30_1mon_data);
|
||||||
|
|
||||||
// Exchange Information data
|
// Exchange Information data
|
||||||
let mut exchange_info_data: Vec<ExchangeInfo> = Vec::new();
|
let mut exchange_info_map: HashMap<String, ExchangeInfo> = HashMap::new();
|
||||||
let (tx_exchange_info_data, mut rx_exchange_info_data) = watch::channel(exchange_info_data);
|
let (tx_exchange_info_map, mut rx_exchange_info_map) = watch::channel(exchange_info_map);
|
||||||
let mut rx2_exchange_info_data = rx_exchange_info_data.clone();
|
let mut rx2_exchange_info_map = rx_exchange_info_map.clone();
|
||||||
let mut rx3_exchange_info_data = rx_exchange_info_data.clone();
|
let mut rx3_exchange_info_map = rx_exchange_info_map.clone();
|
||||||
let mut rx4_exchange_info_data = rx_exchange_info_data.clone();
|
let mut rx4_exchange_info_map = rx_exchange_info_map.clone();
|
||||||
let mut rx5_exchange_info_data = rx_exchange_info_data.clone();
|
let mut rx5_exchange_info_map = rx_exchange_info_map.clone();
|
||||||
let mut rx6_exchange_info_data = rx_exchange_info_data.clone();
|
let mut rx6_exchange_info_map = rx_exchange_info_map.clone();
|
||||||
let mut exchange_info_data_capacity = rx_exchange_info_data.clone();
|
let mut exchange_info_map_capacity = rx_exchange_info_map.clone();
|
||||||
|
|
||||||
{
|
{
|
||||||
if RUNNING_MODE == RunningMode::REAL {
|
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_1w = String::from("1w");
|
||||||
let interval_1mon = String::from("1mon");
|
let interval_1mon = String::from("1mon");
|
||||||
|
|
||||||
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 mut candle_1d_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::new();
|
let mut candle_1d_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||||
let mut candle_1w_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::new();
|
let mut candle_1w_map_temp: HashMap<String, Vec<CandleData>> = HashMap::new();
|
||||||
let mut candle_1mon_vec_temp: Vec<(String, Vec<CandleData>)> = Vec::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_30m, &mut candle_30m_map_temp).await;
|
||||||
request_candles::fetch_candle_parallel(&interval_1d, &mut candle_1d_vec_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_vec_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_vec_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_30m_map.send_modify(|map| *map = candle_30m_map_temp);
|
||||||
tx_candle_1d_vec.send_modify(|vec| *vec = candle_1d_vec_temp);
|
tx_candle_1d_map.send_modify(|map| *map = candle_1d_map_temp);
|
||||||
tx_candle_1w_vec.send_modify(|vec| *vec = candle_1w_vec_temp);
|
tx_candle_1w_map.send_modify(|map| *map = candle_1w_map_temp);
|
||||||
tx_candle_1mon_vec.send_modify(|vec| *vec = candle_1mon_vec_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.
|
// sleep as much as the loop recurs per 60 seconds, expecting child threads will have finished within 60 seconds.
|
||||||
println!("Ok..");
|
println!("Ok..");
|
||||||
|
|
@ -515,10 +517,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
match tx1_changed {
|
match tx1_changed {
|
||||||
Ok(T) => match tx2_changed {
|
Ok(T) => match tx2_changed {
|
||||||
Ok(T) => {
|
Ok(T) => {
|
||||||
let mut tradefee_vec_temp: Vec<TradeFee> = Vec::new();
|
let mut tradefee_vec_temp: HashMap<String, TradeFee> = HashMap::new();
|
||||||
let mut result;
|
|
||||||
loop {
|
loop {
|
||||||
result = request_others::request_trade_fee(
|
let result = request_others::request_trade_fee(
|
||||||
API_KEY,
|
API_KEY,
|
||||||
SECRET_KEY,
|
SECRET_KEY,
|
||||||
local_epoch,
|
local_epoch,
|
||||||
|
|
@ -535,13 +536,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match result {
|
tx_tradefee_map.send_modify(|vec| *vec = tradefee_vec_temp);
|
||||||
Ok(T) => {
|
tx_task2.send(2).expect("The mpsc channel has been closed.");
|
||||||
tx_tradefee_vec.send_modify(|vec| *vec = tradefee_vec_temp);
|
|
||||||
tx_task2.send(2).expect("The mpsc channel has been closed.");
|
|
||||||
}
|
|
||||||
Err(E) => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(E) => {
|
Err(E) => {
|
||||||
panic!("tx2-rx2 channel has been closed.")
|
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))
|
.timeout(tokio::time::Duration::from_millis(3000))
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.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;
|
let mut result;
|
||||||
loop {
|
loop {
|
||||||
result = coin_health_check_team::request_others::request_exchange_infomation(
|
result = coin_health_check_team::request_others::request_exchange_infomation(
|
||||||
&client,
|
&client,
|
||||||
&mut exchange_info_data_temp,
|
&mut exchange_info_map_temp,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// retry
|
// retry
|
||||||
if exchange_info_data_temp.len() == 0 {
|
if exchange_info_map_temp.len() == 0 {
|
||||||
sleep(Duration::from_secs(3)).await;
|
sleep(Duration::from_secs(3)).await;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(T) => {
|
tx_exchange_info_map.send_modify(|vec| *vec = exchange_info_map_temp);
|
||||||
tx_exchange_info_data.send_modify(|vec| *vec = exchange_info_data_temp);
|
tx_task3.send(3).expect("The mpsc channel has been closed.");
|
||||||
tx_task3.send(3).expect("The mpsc channel has been closed.");
|
|
||||||
}
|
|
||||||
Err(E) => {}
|
|
||||||
}
|
|
||||||
sleep(Duration::from_secs(300)).await; // sleep for 5 mins
|
sleep(Duration::from_secs(300)).await; // sleep for 5 mins
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -613,22 +607,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let result = request_others::request_24hr_ticker_price_change_statistics(&client).await;
|
let result = request_others::request_24hr_ticker_price_change_statistics(&client).await;
|
||||||
match result {
|
match result {
|
||||||
Ok(T) => {
|
Ok(T) => {
|
||||||
let exchange_info_vec = rx5_exchange_info_data.borrow().clone();
|
let exchange_info_map = rx5_exchange_info_map.borrow().clone();
|
||||||
let mut valid_usdt_trade_vec_temp: Vec<String> = Vec::new();
|
let mut valid_usdt_trade_set_temp: HashSet<String> = HashSet::new();
|
||||||
let result = monitors::collect_valid_usde_trade(
|
monitors::collect_valid_usde_trade(
|
||||||
&mut valid_usdt_trade_vec_temp,
|
&mut valid_usdt_trade_set_temp,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
match result {
|
tx_valid_usdt_trade_set
|
||||||
Ok(T) => {
|
.send_modify(|vec| *vec = valid_usdt_trade_set_temp);
|
||||||
tx_valid_usdt_trade_vec
|
tx_task4.send(4).expect("The mpsc channel has been closed.");
|
||||||
.send_modify(|vec| *vec = valid_usdt_trade_vec_temp);
|
|
||||||
tx_task4.send(4).expect("The mpsc channel has been closed.");
|
|
||||||
}
|
|
||||||
Err(E) => {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(E) => {
|
Err(E) => {
|
||||||
println!(">>> Failed to monitor usdt_24h_change_profit_index.");
|
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
|
// Task#5: price per second
|
||||||
tokio::task::spawn(async move {
|
tokio::task::spawn(async move {
|
||||||
sleep(Duration::from_secs(20)).await;
|
sleep(Duration::from_secs(20)).await;
|
||||||
let mut server_epoch = 0;
|
|
||||||
let mut elapsed_time = 0;
|
let mut elapsed_time = 0;
|
||||||
loop {
|
loop {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
|
|
@ -684,101 +672,85 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.timeout(tokio::time::Duration::from_millis(1000))
|
.timeout(tokio::time::Duration::from_millis(1000))
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut price_vec_temp: Vec<CoinPriceData> = Vec::new();
|
let mut price_vec_temp: HashMap<String, f64> = HashMap::new();
|
||||||
let result = request_others::request_all_coin_price(&client, &mut price_vec_temp).await;
|
let mut price_vec_temp_c: HashMap<String, f64> = HashMap::new();
|
||||||
let mut price_vec_temp_c: Vec<CoinPriceData> = Vec::new();
|
request_others::request_all_coin_price(&client, &mut price_vec_temp).await;
|
||||||
match result {
|
price_vec_temp_c = price_vec_temp.clone();
|
||||||
Ok(T) => {
|
tx_price_map.send_modify(|vec| *vec = price_vec_temp);
|
||||||
price_vec_temp_c = price_vec_temp.clone();
|
tx_task5.send(5).expect("The mpsc channel has been closed.");
|
||||||
tx_price_vec.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
|
// 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
|
// 1m
|
||||||
let interval = String::from("1m");
|
let interval = String::from("1m");
|
||||||
let candle_1m_vec = rx_candle_1m_vec.borrow().clone();
|
let candle_1m_vec = rx_candle_1m_map.borrow().clone();
|
||||||
let rt_price_1m_vec_read_temp: Vec<(String, Vec<RealtimePriceData>)> = Vec::new();
|
let dummy_data: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||||
let mut rt_price_1m_vec_write_temp: Vec<(String, Vec<RealtimePriceData>)> = Vec::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(
|
let result = value_estimation_team::datapoints::price_data::update_realtime_price_data(
|
||||||
&interval,
|
&interval,
|
||||||
&candle_1m_vec,
|
&candle_1m_vec,
|
||||||
&rt_price_1m_vec_read_temp,
|
&dummy_data,
|
||||||
&mut rt_price_1m_vec_write_temp,
|
&mut rt_price_1m_map_write_temp,
|
||||||
&price_vec_temp_c,
|
&price_vec_temp_c,
|
||||||
&valid_usdt_trade_vec,
|
&valid_usdt_trade_set,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
rt_price_1m_map_write_temp_c = rt_price_1m_map_write_temp.clone();
|
||||||
match result {
|
if tx_rt_price_1m_map.is_closed() {
|
||||||
Ok(T) => {
|
eprintln!("tx_rt_price_1m_vec has been closed!");
|
||||||
if tx_rt_price_1m_vec.is_closed() {
|
} else {
|
||||||
eprintln!("tx_rt_price_1m_vec has been closed!");
|
tx_rt_price_1m_map.send_modify(|vec| *vec = rt_price_1m_map_write_temp);
|
||||||
} else {
|
|
||||||
tx_rt_price_1m_vec.send_modify(|vec| *vec = rt_price_1m_vec_write_temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(E) => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 30m
|
// 30m
|
||||||
let interval = String::from("30m");
|
let interval = String::from("30m");
|
||||||
let candle_30m_vec = rx_candle_30m_vec.borrow().clone();
|
let candle_30m_map = rx_candle_30m_map.borrow().clone();
|
||||||
let rt_price_1m_vec = rx_rt_price_1m_vec.borrow().clone();
|
let mut rt_price_30m_map_write_temp: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||||
let mut rt_price_30m_vec_write_temp: Vec<(String, Vec<RealtimePriceData>)> = Vec::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() {
|
||||||
if !rt_price_1m_vec.is_empty() {
|
|
||||||
let result =
|
let result =
|
||||||
value_estimation_team::datapoints::price_data::update_realtime_price_data(
|
value_estimation_team::datapoints::price_data::update_realtime_price_data(
|
||||||
&interval,
|
&interval,
|
||||||
&candle_30m_vec,
|
&candle_30m_map,
|
||||||
&rt_price_1m_vec,
|
&rt_price_1m_map_write_temp_c,
|
||||||
&mut rt_price_30m_vec_write_temp,
|
&mut rt_price_30m_map_write_temp,
|
||||||
&price_vec_temp_c,
|
&price_vec_temp_c,
|
||||||
&valid_usdt_trade_vec,
|
&valid_usdt_trade_set,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
rt_price_30m_map_write_temp_c = rt_price_30m_map_write_temp.clone();
|
||||||
match result {
|
if tx_rt_price_30m_map.is_closed() {
|
||||||
Ok(T) => {
|
eprintln!("tx_rt_price_30m_vec has been closed!");
|
||||||
if tx_rt_price_30m_vec.is_closed() {
|
} else {
|
||||||
eprintln!("tx_rt_price_30m_vec has been closed!");
|
tx_rt_price_30m_map
|
||||||
} else {
|
.send_modify(|map: &mut HashMap<String, Vec<RealtimePriceData>>| *map = rt_price_30m_map_write_temp);
|
||||||
tx_rt_price_30m_vec
|
|
||||||
.send_modify(|vec| *vec = rt_price_30m_vec_write_temp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(E) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1d
|
// 1d
|
||||||
let interval = String::from("1d");
|
let interval = String::from("1d");
|
||||||
let candle_1d_vec = rx_candle_1d_vec.borrow().clone();
|
let candle_1d_vec = rx_candle_1d_map.borrow().clone();
|
||||||
let rt_price_30m_vec = rx_rt_price_30m_vec.borrow().clone();
|
let mut rt_price_1d_map_write_temp: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||||
let mut rt_price_1d_vec_write_temp: Vec<(String, Vec<RealtimePriceData>)> = Vec::new();
|
|
||||||
|
|
||||||
if !rt_price_30m_vec.is_empty() {
|
if !rt_price_30m_map_write_temp_c.is_empty() {
|
||||||
let result =
|
let result =
|
||||||
value_estimation_team::datapoints::price_data::update_realtime_price_data(
|
value_estimation_team::datapoints::price_data::update_realtime_price_data(
|
||||||
&interval,
|
&interval,
|
||||||
&candle_1d_vec,
|
&candle_1d_vec,
|
||||||
&rt_price_30m_vec,
|
&rt_price_30m_map_write_temp_c,
|
||||||
&mut rt_price_1d_vec_write_temp,
|
&mut rt_price_1d_map_write_temp,
|
||||||
&price_vec_temp_c,
|
&price_vec_temp_c,
|
||||||
&valid_usdt_trade_vec,
|
&valid_usdt_trade_set,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(T) => {
|
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!");
|
eprintln!("tx_rt_price_1d_vec has been closed!");
|
||||||
} else {
|
} 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) => {}
|
Err(E) => {}
|
||||||
|
|
@ -831,13 +803,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let interval = String::from("1m");
|
let interval = String::from("1m");
|
||||||
loop {
|
loop {
|
||||||
let instant = Instant::now();
|
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 =
|
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 {
|
match result {
|
||||||
Ok(T) => {
|
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.");
|
tx_task6.send(6).expect("The mpsc channel has been closed.");
|
||||||
}
|
}
|
||||||
Err(E) => {}
|
Err(E) => {}
|
||||||
|
|
@ -858,14 +830,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let interval = String::from("30m");
|
let interval = String::from("30m");
|
||||||
loop {
|
loop {
|
||||||
let instant = Instant::now();
|
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 =
|
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;
|
// request_candles::fetch_candle_parallel(&interval, &mut candle_30m_vec_temp).await;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(T) => {
|
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.");
|
tx_task7.send(7).expect("The mpsc channel has been closed.");
|
||||||
}
|
}
|
||||||
Err(E) => {}
|
Err(E) => {}
|
||||||
|
|
@ -886,13 +858,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
sleep(Duration::from_secs(600)).await;
|
sleep(Duration::from_secs(600)).await;
|
||||||
loop {
|
loop {
|
||||||
let instant = Instant::now();
|
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 =
|
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 {
|
match result {
|
||||||
Ok(T) => {
|
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.");
|
tx_task8.send(8).expect("The mpsc channel has been closed.");
|
||||||
}
|
}
|
||||||
Err(E) => {}
|
Err(E) => {}
|
||||||
|
|
@ -1039,14 +1011,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
loop {
|
loop {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
let mut all_data = AllData::new();
|
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
|
// realtime price data
|
||||||
all_data.rt_price_1m_vec = rx3_rt_price_1m_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_vec.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_vec.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_vec.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_vec.borrow().clone();
|
all_data.rt_price_1mon_vec = rx3_rt_price_1mon_map.borrow().clone();
|
||||||
|
|
||||||
let result =
|
let result =
|
||||||
strategy_team::strategy_manager::execute_list_up_for_buy(&all_data).await;
|
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();
|
let mut all_data = AllData::new();
|
||||||
loop {
|
loop {
|
||||||
let instant = Instant::now();
|
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
|
// realtime price data
|
||||||
all_data.rt_price_1m_vec = rx3_rt_price_1m_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_vec.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_vec.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_vec.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_vec.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;
|
// 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 {
|
loop {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
let mut all_data = AllData::new();
|
let mut all_data = AllData::new();
|
||||||
let mut exchange_info_vec: Vec<ExchangeInfo> = Vec::new();
|
let mut exchange_info_map: HashMap<String, ExchangeInfo> = HashMap::new();
|
||||||
let mut trade_fee_vec: Vec<TradeFee> = Vec::new();
|
let mut trade_fee_map: HashMap<String, TradeFee> = HashMap::new();
|
||||||
|
|
||||||
all_data.valid_symbol_vec = rx4_valid_usdt_trade_vec.borrow().clone();
|
all_data.valid_symbol_vec = rx4_valid_usdt_trade_set.borrow().clone();
|
||||||
exchange_info_vec = rx6_exchange_info_data.borrow().clone();
|
exchange_info_map = rx6_exchange_info_map.borrow().clone();
|
||||||
trade_fee_vec = rx5_tradefee_vec.borrow().clone();
|
trade_fee_map = rx5_tradefee_map.borrow().clone();
|
||||||
// realtime price data
|
// realtime price data
|
||||||
all_data.rt_price_1m_vec = rx5_rt_price_1m_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_vec.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_vec.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_vec.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_vec.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(
|
let result = strategy_team::strategy_manager::execute_list_up_for_sell(
|
||||||
&all_data,
|
&all_data,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|
@ -1158,7 +1130,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut elapsed_time = 0;
|
let mut elapsed_time = 0;
|
||||||
loop {
|
loop {
|
||||||
let instant = Instant::now();
|
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;
|
let result = coex::exchange_team::monitoring_pre_suggested_coins(&coin_price_vec).await;
|
||||||
|
|
||||||
// send Task#0 a message to notify running on
|
// 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;
|
let mut elapsed_time = 0;
|
||||||
loop {
|
loop {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
let exchange_info_vec = rx_exchange_info_data.borrow().clone();
|
let exchange_info_map = rx_exchange_info_map.borrow().clone();
|
||||||
let trade_fee_vec = rx_tradefee_vec.borrow().clone();
|
let trade_fee_map = rx_tradefee_map.borrow().clone();
|
||||||
let result =
|
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
|
// send Task#0 a message to notify running on
|
||||||
match result {
|
match result {
|
||||||
|
|
@ -1217,8 +1189,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut elapsed_time = 0;
|
let mut elapsed_time = 0;
|
||||||
|
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
let exchange_info_vec = rx_exchange_info_data.borrow().clone();
|
let exchange_info_vec = rx_exchange_info_map.borrow().clone();
|
||||||
let trade_fee_vec = rx_tradefee_vec.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_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;
|
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))
|
.timeout(tokio::time::Duration::from_millis(3000))
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let exchange_info_vec = rx3_exchange_info_data.borrow().clone();
|
let trade_fee_map = rx2_tradefee_map.borrow().clone();
|
||||||
let trade_fee_vec = rx2_tradefee_vec.borrow().clone();
|
|
||||||
let result = coex::order_team::monitoring_open_buy_order(
|
let result = coex::order_team::monitoring_open_buy_order(
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&trade_fee_map,
|
||||||
&trade_fee_vec,
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|
@ -1293,9 +1263,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut elapsed_time = 0;
|
let mut elapsed_time = 0;
|
||||||
loop {
|
loop {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
let coin_price_vec = rx5_price_vec.borrow().clone();
|
let coin_price_vec = rx5_price_map.borrow().clone();
|
||||||
let exchange_info_vec = rx2_exchange_info_data.borrow().clone();
|
let exchange_info_vec = rx2_exchange_info_map.borrow().clone();
|
||||||
let trade_fee_vec = rx3_tradefee_vec.borrow().clone();
|
let trade_fee_vec = rx3_tradefee_map.borrow().clone();
|
||||||
|
|
||||||
let result = coex::order_team::update_price_of_filled_buy_order(
|
let result = coex::order_team::update_price_of_filled_buy_order(
|
||||||
&coin_price_vec,
|
&coin_price_vec,
|
||||||
|
|
@ -1338,8 +1308,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.timeout(tokio::time::Duration::from_millis(3000))
|
.timeout(tokio::time::Duration::from_millis(3000))
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let exchange_info_vec = rx4_exchange_info_data.borrow().clone();
|
let exchange_info_vec = rx4_exchange_info_map.borrow().clone();
|
||||||
let trade_fee_vec = rx4_tradefee_vec.borrow().clone();
|
let trade_fee_vec = rx4_tradefee_map.borrow().clone();
|
||||||
let result = coex::order_team::monitoring_open_sell_order(
|
let result = coex::order_team::monitoring_open_sell_order(
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_vec,
|
||||||
|
|
@ -1403,7 +1373,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let mut all_data = AllData::new();
|
let mut all_data = AllData::new();
|
||||||
|
|
||||||
// realtime price data
|
// 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;
|
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_003;
|
||||||
pub mod strategy_004;
|
pub mod strategy_004;
|
||||||
pub mod strategy_005;
|
pub mod strategy_005;
|
||||||
pub mod strategy_006;
|
// pub mod strategy_006;
|
||||||
pub mod strategy_test;
|
// pub mod strategy_test;
|
||||||
pub mod strategy_manager;
|
pub mod strategy_manager;
|
||||||
|
|
||||||
use crate::coex::order_team::{limit_order_sell, select_filled_buy_orders};
|
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::coin_health_check_team::request_others::{ExchangeInfo, TradeFee};
|
||||||
use crate::database_control::*;
|
use crate::database_control::*;
|
||||||
use crate::decimal_funcs::*;
|
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::bollingerband::{bollingerband, BollingerBandData};
|
||||||
use crate::value_estimation_team::indicators::ema::{ema, ema_opclo, EmaData};
|
use crate::value_estimation_team::indicators::ema::{ema, ema_opclo, EmaData};
|
||||||
use crate::value_estimation_team::indicators::heatmap_volume::{
|
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::rsi::{rsi, RsiData};
|
||||||
use crate::value_estimation_team::indicators::sma::{sma, sma_opclo, SmaData};
|
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::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 crate::value_estimation_team::indicators::adx::{AdxData, adx};
|
||||||
use futures::future::try_join_all;
|
use futures::future::try_join_all;
|
||||||
use reqwest::{Client, ClientBuilder};
|
use reqwest::{Client, ClientBuilder};
|
||||||
|
|
@ -32,25 +32,26 @@ use sqlx::FromRow;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use strategy_manager::insert_pre_suggested_coins;
|
use strategy_manager::insert_pre_suggested_coins;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct AllData {
|
pub struct AllData {
|
||||||
pub valid_symbol_vec: Vec<String>,
|
pub valid_symbol_vec: HashSet<String>,
|
||||||
pub rt_price_1m_vec: Vec<(String, Vec<RealtimePriceData>)>,
|
pub rt_price_1m_vec: HashMap<String, Vec<RealtimePriceData>>,
|
||||||
pub rt_price_30m_vec: Vec<(String, Vec<RealtimePriceData>)>,
|
pub rt_price_30m_vec: HashMap<String, Vec<RealtimePriceData>>,
|
||||||
pub rt_price_1d_vec: Vec<(String, Vec<RealtimePriceData>)>,
|
pub rt_price_1d_vec: HashMap<String, Vec<RealtimePriceData>>,
|
||||||
pub rt_price_1w_vec: Vec<(String, Vec<RealtimePriceData>)>,
|
pub rt_price_1w_vec: HashMap<String, Vec<RealtimePriceData>>,
|
||||||
pub rt_price_1mon_vec: Vec<(String, Vec<RealtimePriceData>)>,
|
pub rt_price_1mon_vec: HashMap<String, Vec<RealtimePriceData>>,
|
||||||
}
|
}
|
||||||
impl AllData {
|
impl AllData {
|
||||||
pub fn new() -> AllData {
|
pub fn new() -> AllData {
|
||||||
let a = AllData {
|
let a = AllData {
|
||||||
valid_symbol_vec: Vec::new(),
|
valid_symbol_vec: HashSet::new(),
|
||||||
rt_price_1m_vec: Vec::new(),
|
rt_price_1m_vec: HashMap::new(),
|
||||||
rt_price_30m_vec: Vec::new(),
|
rt_price_30m_vec: HashMap::new(),
|
||||||
rt_price_1d_vec: Vec::new(),
|
rt_price_1d_vec: HashMap::new(),
|
||||||
rt_price_1w_vec: Vec::new(),
|
rt_price_1w_vec: HashMap::new(),
|
||||||
rt_price_1mon_vec: Vec::new(),
|
rt_price_1mon_vec: HashMap::new(),
|
||||||
};
|
};
|
||||||
a
|
a
|
||||||
}
|
}
|
||||||
|
|
@ -68,18 +69,16 @@ pub struct TimeData {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct FilteredData {
|
pub struct FilteredDataValue {
|
||||||
pub symbol: String,
|
|
||||||
pub closetime: i64,
|
pub closetime: i64,
|
||||||
pub stoploss: Decimal,
|
pub stoploss: Decimal,
|
||||||
pub target_price: Decimal,
|
pub target_price: Decimal,
|
||||||
pub current_price: Decimal,
|
pub current_price: Decimal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilteredData {
|
impl FilteredDataValue {
|
||||||
fn new() -> FilteredData {
|
fn new() -> FilteredDataValue {
|
||||||
let a = FilteredData {
|
let a = FilteredDataValue {
|
||||||
symbol: String::new(),
|
|
||||||
closetime: 0,
|
closetime: 0,
|
||||||
stoploss: Decimal::new(0, 8),
|
stoploss: Decimal::new(0, 8),
|
||||||
target_price: 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>)
|
pub async fn duplicate_filter(registerer: i32, original_filtered_data: &HashMap<String, FilteredDataValue>)
|
||||||
-> Result<Vec<FilteredData>, Box<dyn std::error::Error + Send + Sync>>
|
-> 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_1 = String::from("buy_ordered_coin_list");
|
||||||
let inspect_table_name_2 = String::from("sell_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_3 = String::from("pre_suggested_coin_list");
|
||||||
let inspect_table_name_4 = String::from("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: HashMap<String, FilteredDataValue> = HashMap::new();
|
||||||
let mut filtered_data_arc: Arc<Mutex<Vec<FilteredData>>> =
|
let mut filtered_data_arc: Arc<Mutex<HashMap<String, FilteredDataValue>>> =
|
||||||
Arc::new(Mutex::new(filtered_data));
|
Arc::new(Mutex::new(filtered_data));
|
||||||
let mut task_vec = Vec::new();
|
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=\'");
|
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("\' AND registerer=");
|
||||||
exists_condition_build.push_str(registerer.to_string().as_str());
|
exists_condition_build.push_str(registerer.to_string().as_str());
|
||||||
// exists_condition_build.push_str("\' AND close_time=");
|
// 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_2_c = inspect_table_name_2.clone();
|
||||||
let inspect_table_name_3_c = inspect_table_name_3.clone();
|
let inspect_table_name_3_c = inspect_table_name_3.clone();
|
||||||
let inspect_table_name_4_c = inspect_table_name_4.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);
|
let filtered_data_arc_c = Arc::clone(&filtered_data_arc);
|
||||||
task_vec.push(tokio::spawn(async move {
|
task_vec.push(tokio::spawn(async move {
|
||||||
let inspect_result_1 =
|
let inspect_result_1 =
|
||||||
|
|
@ -133,7 +133,7 @@ pub async fn duplicate_filter(registerer: i32, original_filtered_data: &Vec<Filt
|
||||||
&& inspect_result_4 == false
|
&& inspect_result_4 == false
|
||||||
{
|
{
|
||||||
let mut filtered_data_lock = filtered_data_arc_c.lock().await;
|
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();
|
let filtered_data_c = filtered_data_arc.lock().await.clone();
|
||||||
Ok(filtered_data_c)
|
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::{
|
use super::{
|
||||||
dec, decimal_add, decimal_sub, decimal_div, ema, exists_record, insert_pre_suggested_coins,
|
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,
|
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredData, Mutex,
|
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, server_epoch, MacdData, ema_macd,
|
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter
|
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
||||||
};
|
};
|
||||||
|
|
||||||
// BB lowerband + SuperTrend + StochRSI
|
// 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());
|
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
|
||||||
|
|
||||||
// 1st filtering: filtering valid trade pair
|
// 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 {
|
for symbol in &alldata.valid_symbol_vec {
|
||||||
let mut filtered_data = FilteredData::new();
|
filtered_data.insert(symbol.clone(), FilteredDataValue::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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
|
// 4th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
|
||||||
let mut filtered_data_4th: Vec<FilteredData> = Vec::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
for element in filtered_data_3rd {
|
for (symbol, values) in &mut filtered_data {
|
||||||
let position_idx = alldata.rt_price_30m_vec.iter().position(|elem| elem.0 == element.symbol);
|
if alldata.rt_price_30m_vec.contains_key(symbol) {
|
||||||
if position_idx.is_some() {
|
let rt_price_30m = alldata.rt_price_30m_vec.get(symbol).unwrap();
|
||||||
let vec_len = alldata.rt_price_30m_vec[position_idx.unwrap()].1.len();
|
let vec_len = rt_price_30m.len();
|
||||||
if vec_len >= 11 {
|
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 windows = candles.windows(2);
|
||||||
let mut average_amplitude = 0.0;
|
let mut average_amplitude = 0.0;
|
||||||
|
|
||||||
|
|
@ -137,41 +41,143 @@ pub async fn list_up_for_buy(
|
||||||
average_amplitude /= 10.0;
|
average_amplitude /= 10.0;
|
||||||
|
|
||||||
if 0.005 <= average_amplitude && average_amplitude <= 0.01 {
|
if 0.005 <= average_amplitude && average_amplitude <= 0.01 {
|
||||||
let mut filtered_data = FilteredData::new();
|
} else {
|
||||||
filtered_data.symbol = element.symbol.clone();
|
keys_to_remove.insert(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);
|
|
||||||
}
|
}
|
||||||
|
} 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: 10, StochRSI_len: 10, K: 3, D: 3) previous K < 5 && current K > previous K
|
// 2nd filtering: supertrend(ATR period 20, multiplier: 2, 30m close price)
|
||||||
let mut filtered_data_5th: Vec<FilteredData> = Vec::new();
|
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_4th).await?;
|
let server_epoch = get_server_epoch().await;
|
||||||
for element in filtered_data_4th {
|
let supertrend_30m_map = supertrend(20, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
let position_idx = stoch_rsis.iter().position(|elem| elem.0 == element.symbol);
|
for (symbol, values) in &mut filtered_data {
|
||||||
if position_idx.is_some() {
|
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_30m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||||
let stoch_rsi_vec = stoch_rsis[position_idx.unwrap()].1.clone();
|
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == element.closetime);
|
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();
|
||||||
|
|
||||||
|
// 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) {
|
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();
|
} else {
|
||||||
filtered_data.symbol = element.symbol.clone();
|
keys_to_remove.insert(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);
|
|
||||||
}
|
}
|
||||||
|
} 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: 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;
|
||||||
|
|
||||||
|
// 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;
|
insert_pre_suggested_coins(1, false, &final_filtered_data, &alldata).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -179,8 +185,8 @@ pub async fn list_up_for_buy(
|
||||||
|
|
||||||
pub async fn list_up_for_sell(
|
pub async fn list_up_for_sell(
|
||||||
all_data: &AllData,
|
all_data: &AllData,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let filled_buy_orders = select_filled_buy_orders(1).await?;
|
let filled_buy_orders = select_filled_buy_orders(1).await?;
|
||||||
|
|
||||||
|
|
@ -190,47 +196,21 @@ pub async fn list_up_for_sell(
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
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 {
|
for element in &filled_buy_orders {
|
||||||
let filltered_data = FilteredData{
|
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||||
symbol: element.symbol.clone(),
|
|
||||||
closetime: 0,
|
|
||||||
stoploss: dec!(0),
|
|
||||||
target_price: dec!(0),
|
|
||||||
current_price: dec!(0),
|
|
||||||
};
|
|
||||||
filtered_symbol_vec.push(filltered_data);
|
|
||||||
}
|
}
|
||||||
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 {
|
for element in filled_buy_orders {
|
||||||
if element.used_usdt >= dec!(10.0) {
|
if element.used_usdt >= dec!(10.0) {
|
||||||
let lot_step_size_option = exchange_info_vec
|
if let (Some(exchange_info), Some(tradefee), Some(stoch_rsi), Some(supertrend_vec)) =
|
||||||
.iter()
|
(exchange_info_map.get(&element.symbol), trade_fee_map.get(&element.symbol), stoch_rsis.get(&element.symbol), supertrend_30m.get(&element.symbol)) {
|
||||||
.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()
|
|
||||||
{
|
|
||||||
// update stoploss
|
// 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();
|
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 {
|
&& band_value > element.stoploss {
|
||||||
let update_table_name = String::from("buy_ordered_coin_list");
|
let update_table_name = String::from("buy_ordered_coin_list");
|
||||||
let update_value = vec![
|
let update_value = vec![
|
||||||
|
|
@ -242,19 +222,17 @@ pub async fn list_up_for_sell(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let lot_step_size = exchange_info_vec[lot_step_size_option.unwrap()].stepsize;
|
let lot_step_size = exchange_info.stepsize;
|
||||||
let quote_commission_precision = exchange_info_vec
|
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||||
[quote_commission_precision_option.unwrap()]
|
|
||||||
.quote_commission_precision;
|
|
||||||
let base_qty_to_be_ordered =
|
let base_qty_to_be_ordered =
|
||||||
element.base_qty_ordered.round_dp_with_strategy(
|
element.base_qty_ordered.round_dp_with_strategy(
|
||||||
lot_step_size.normalize().scale(),
|
lot_step_size.normalize().scale(),
|
||||||
RoundingStrategy::ToZero,
|
RoundingStrategy::ToZero,
|
||||||
);
|
);
|
||||||
let stoch_rsi_k = stoch_rsis[search_result.unwrap()].1.last().unwrap().k;
|
let stoch_rsi_k = stoch_rsi.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_k_prev = stoch_rsi[stoch_rsi.len()-2].k;
|
||||||
let stoch_rsi_d = stoch_rsis[search_result.unwrap()].1.last().unwrap().d;
|
let stoch_rsi_d = stoch_rsi.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_d_prev = stoch_rsi[stoch_rsi.len()-2].d;
|
||||||
if (element.is_long == 0 || element.is_long == 1)
|
if (element.is_long == 0 || element.is_long == 1)
|
||||||
&& !element.current_price.is_zero()
|
&& !element.current_price.is_zero()
|
||||||
{
|
{
|
||||||
|
|
@ -264,49 +242,40 @@ pub async fn list_up_for_sell(
|
||||||
element.current_price,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.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(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
element.current_price,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
} else if element.pure_profit_percent > 5.0 {
|
} else if element.pure_profit_percent > 3.0 {
|
||||||
limit_order_sell(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
element.current_price,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.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(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
element.current_price,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
|
||||||
.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,
|
|
||||||
)
|
)
|
||||||
.await;
|
.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::{
|
use super::{
|
||||||
dec, decimal_add, decimal_sub, decimal_div, ema, exists_record, insert_pre_suggested_coins,
|
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,
|
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredData, Mutex,
|
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, server_epoch, MacdData, ema_macd,
|
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter
|
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
||||||
};
|
};
|
||||||
|
|
||||||
// BB 30m lowerband + BB 1m lowerband
|
// BB 30m lowerband + BB 1m lowerband
|
||||||
|
|
@ -18,82 +18,83 @@ pub async fn list_up_for_buy(
|
||||||
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
|
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
|
||||||
|
|
||||||
// 1st filtering: filtering valid trade pair
|
// 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 {
|
for symbol in &alldata.valid_symbol_vec {
|
||||||
let mut filtered_data = FilteredData::new();
|
filtered_data.insert(symbol.clone(), FilteredDataValue::new());
|
||||||
filtered_data.symbol = symbol.clone();
|
|
||||||
filtered_data_1st.push(filtered_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// 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 keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let mut filtered_data_2nd_arc: Arc<Mutex<Vec<FilteredData>>> =
|
let bollingerbands_30m_map = bollingerband(10, 2.5, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
Arc::new(Mutex::new(filtered_data_2nd));
|
let bollingerbands_1m_map = bollingerband(30, 3.0, &alldata.rt_price_1m_vec, &filtered_data).await?;
|
||||||
let mut task_vec = Vec::new();
|
let server_epoch = get_server_epoch().await;
|
||||||
let bollingerbands_30m = bollingerband(10, 2.5, &alldata.rt_price_30m_vec, &filtered_data_1st).await?;
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
let bollingerbands_1m = bollingerband(30, 3.0, &alldata.rt_price_1m_vec, &filtered_data_1st).await?;
|
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)) {
|
||||||
for element in filtered_data_1st {
|
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 mut rt_30m_vec: Vec<RealtimePriceData> = Vec::new();
|
let bb_30m_search_result = bb_30m_vec.binary_search_by_key(
|
||||||
let mut bb_30m_vec: Vec<BollingerBandData> = Vec::new();
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
let mut bb_1m_vec: Vec<BollingerBandData> = Vec::new();
|
|BollingerBandData {
|
||||||
let rt_price_30m_vec_c: Vec<(String, Vec<RealtimePriceData>)> = alldata.rt_price_30m_vec.clone();
|
sma,
|
||||||
let bollingerbands_30m_c = bollingerbands_30m.clone();
|
upperband,
|
||||||
let bollingerbands_1m_c = bollingerbands_1m.clone();
|
lowerband,
|
||||||
let filtered_data_2nd_arc_c = Arc::clone(&filtered_data_2nd_arc);
|
close_time,
|
||||||
task_vec.push(tokio::spawn(async move {
|
}| *close_time,
|
||||||
let rt_30m_option = rt_price_30m_vec_c
|
);
|
||||||
.iter()
|
if bb_30m_search_result.is_ok() {
|
||||||
.position(|x| *x.0 == element.symbol);
|
if bb_30m_vec[bb_30m_search_result.unwrap()].lowerband > rt_30m_vec[rt_30m_vec.len()-1].close_price &&
|
||||||
let bb_option_30m = bollingerbands_30m_c.iter().position(|x| x.0 == element.symbol);
|
bb_1m_vec.last().unwrap().lowerband > rt_30m_vec[rt_30m_vec.len()-1].close_price
|
||||||
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() {
|
filtered_data.closetime = rt_30m_vec.last().unwrap().close_time;
|
||||||
rt_30m_vec = rt_price_30m_vec_c[rt_30m_option.unwrap()].1.clone();
|
filtered_data.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_30m_vec.last().unwrap().close_price).unwrap();
|
||||||
bb_30m_vec = bollingerbands_30m_c[bb_option_30m.unwrap()].1.clone();
|
} else {
|
||||||
bb_1m_vec = bollingerbands_1m_c[bb_option_1m.unwrap()].1.clone();
|
keys_to_remove.insert(symbol.clone());
|
||||||
let server_epoch = server_epoch().await;
|
|
||||||
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,
|
|
||||||
|BollingerBandData {
|
|
||||||
sma,
|
|
||||||
upperband,
|
|
||||||
lowerband,
|
|
||||||
close_time,
|
|
||||||
}| *close_time,
|
|
||||||
);
|
|
||||||
if bb_30m_search_result.is_ok() {
|
|
||||||
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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
|
// 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 keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let mut filtered_data_3rd: Vec<FilteredData> = Vec::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 element in filtered_data_2nd {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
let rt_30m_option = alldata.rt_price_30m_vec
|
if let (Some(rt_30m_vec), Some(supertrend_vec)) = (alldata.rt_price_30m_vec.get(symbol), supertrend_30m_map.get(symbol)) {
|
||||||
.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;
|
|
||||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
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(
|
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
|
|
@ -105,88 +106,76 @@ pub async fn list_up_for_buy(
|
||||||
}| *close_time,
|
}| *close_time,
|
||||||
);
|
);
|
||||||
if supertrend_search_result.is_ok() {
|
if supertrend_search_result.is_ok() {
|
||||||
if supertrend_vec[supertrend_search_result.unwrap()].area.contains("DOWN")
|
if supertrend_vec[supertrend_search_result.unwrap()].area == SuperTrendArea::DOWN
|
||||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value > element.current_price.to_f64().unwrap()
|
&& 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();
|
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)));
|
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.stoploss = stop_loss;
|
||||||
|
} else {
|
||||||
filtered_data_3rd.push(filtered_data);
|
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
|
// 4th filtering: the latest 5 30m candle close prices > EMA 200
|
||||||
let mut filtered_data_4th: Vec<FilteredData> = Vec::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let ema_vec = ema(200, &alldata.rt_price_30m_vec, &filtered_data_3rd).await?;
|
let ema_map = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
for element in filtered_data_3rd {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
let mut opclo_30m_vec = alldata.rt_price_30m_vec.clone();
|
if let (Some(ema_vec), Some(rt_30m_vec)) = (ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||||
let ema_search_result = ema_vec.iter().position(|x| x.0 == element.symbol);
|
let search_result = ema_vec.binary_search_by_key(
|
||||||
let candle_search_result = alldata.rt_price_30m_vec.iter().position(|x| x.0 == element.symbol);
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
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 {
|
|EmaData {
|
||||||
ema_value,
|
ema_value,
|
||||||
close_time,
|
close_time,
|
||||||
}| *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) &&
|
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[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[x-1].ema_value < rt_30m_vec[rt_30m_vec.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[x-2].ema_value < rt_30m_vec[rt_30m_vec.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[x-3].ema_value < rt_30m_vec[rt_30m_vec.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) {
|
search_result.is_ok_and(|x| ema_vec[x-4].ema_value < rt_30m_vec[rt_30m_vec.len()-5].close_price) {
|
||||||
|
} else {
|
||||||
let mut filtered_data = FilteredData::new();
|
keys_to_remove.insert(symbol.clone());
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||||
|
|
||||||
// 5th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
|
// filtering: 1d MACD (3, 7, 30) current MACD-signal > prev MACD-signal
|
||||||
let mut filtered_data_5th: Vec<FilteredData> = Vec::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
for element in filtered_data_4th {
|
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
let position_idx = alldata.rt_price_30m_vec.iter().position(|elem| elem.0 == element.symbol);
|
for (symbol, values) in &mut filtered_data {
|
||||||
if position_idx.is_some() {
|
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||||
let vec_len = alldata.rt_price_30m_vec[position_idx.unwrap()].1.len();
|
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||||
if vec_len >= 11 {
|
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||||
let candles = alldata.rt_price_30m_vec[position_idx.unwrap()].1.get(vec_len-12..vec_len-1).unwrap();
|
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 windows = candles.windows(2);
|
{
|
||||||
let mut average_amplitude = 0.0;
|
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;
|
||||||
for window in windows {
|
} else {
|
||||||
average_amplitude += (window.last().unwrap().high_price - window.last().unwrap().low_price) / window.first().unwrap().close_price;
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
} 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(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;
|
insert_pre_suggested_coins(2, false, &final_filtered_data, &alldata).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -194,8 +183,8 @@ pub async fn list_up_for_buy(
|
||||||
|
|
||||||
pub async fn list_up_for_sell(
|
pub async fn list_up_for_sell(
|
||||||
all_data: &AllData,
|
all_data: &AllData,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let filled_buy_orders = select_filled_buy_orders(2).await?;
|
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))
|
.timeout(tokio::time::Duration::from_millis(5000))
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
let server_epoch = get_server_epoch().await;
|
||||||
let server_epoch = server_epoch().await;
|
|
||||||
for element in filled_buy_orders {
|
for element in filled_buy_orders {
|
||||||
if element.used_usdt >= dec!(10.0) {
|
if element.used_usdt >= dec!(10.0) {
|
||||||
let lot_step_size_option = exchange_info_vec
|
if let Some(exchange_info) = exchange_info_map.get(&element.symbol) {
|
||||||
.iter()
|
let lot_step_size = exchange_info.stepsize;
|
||||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||||
let quote_commission_precision_option = exchange_info_vec
|
|
||||||
.iter()
|
|
||||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
|
||||||
|
|
||||||
if lot_step_size_option.is_some()
|
|
||||||
&& quote_commission_precision_option.is_some()
|
|
||||||
{
|
|
||||||
let lot_step_size = exchange_info_vec[lot_step_size_option.unwrap()].stepsize;
|
|
||||||
let quote_commission_precision = exchange_info_vec
|
|
||||||
[quote_commission_precision_option.unwrap()]
|
|
||||||
.quote_commission_precision;
|
|
||||||
let base_qty_to_be_ordered =
|
let base_qty_to_be_ordered =
|
||||||
element.base_qty_ordered.round_dp_with_strategy(
|
element.base_qty_ordered.round_dp_with_strategy(
|
||||||
lot_step_size.normalize().scale(),
|
lot_step_size.normalize().scale(),
|
||||||
|
|
@ -238,8 +215,8 @@ pub async fn list_up_for_sell(
|
||||||
element.current_price,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
} else if element.current_price <= element.stoploss {
|
} else if element.current_price <= element.stoploss {
|
||||||
|
|
@ -248,8 +225,8 @@ pub async fn list_up_for_sell(
|
||||||
element.current_price,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
} else if server_epoch - element.transact_time > (1_800_000) * 20 {
|
} 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,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,188 +3,129 @@ use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
||||||
use super::{
|
use super::{
|
||||||
dec, decimal_add, decimal_sub, decimal_div, ema, ema_opclo, sma, sma_opclo, exists_record, insert_pre_suggested_coins,
|
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,
|
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredData, Mutex, SmaData,
|
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex, SmaData,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, server_epoch, MacdData, ema_macd,
|
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter
|
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
||||||
};
|
};
|
||||||
|
|
||||||
// BUY: 30m SMA5 (opclo_price) < 30m EMA3 (opclo_price)
|
// BUY: 30m SMA5 (opclo_price) < 30m EMA3 (opclo_price)
|
||||||
// SELL: 30m SMA5 (opclo_price) > 30m EMA3 (opclo_price)
|
// SELL: 30m SMA5 (opclo_price) > 30m EMA3 (opclo_price)
|
||||||
pub async fn list_up_for_buy(
|
pub async fn list_up_for_buy(
|
||||||
alldata: AllData,
|
alldata: &AllData,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
// print rt_price for debugging
|
// print rt_price for debugging
|
||||||
// let a = alldata.rt_price_30m_vec.iter().position(|a| a.0 == "BTCUSDT");
|
// 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());
|
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
|
||||||
|
|
||||||
// 1st filtering: filtering valid trade pair
|
// 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 {
|
for symbol in &alldata.valid_symbol_vec {
|
||||||
let mut filtered_data = FilteredData::new();
|
filtered_data.insert(symbol.clone(), FilteredDataValue::new());
|
||||||
filtered_data.symbol = symbol.clone();
|
|
||||||
filtered_data_1st.push(filtered_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd filtering: SMA5 (opclo_price) < EMA3 (opclo_price) && 5 previous MA > current MA
|
// 3rd filtering: supertrend(ATR period 20, multiplier: 4.0, 30m close price), area should be UP
|
||||||
let mut filtered_data_2nd: Vec<FilteredData> = Vec::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let mut filtered_data_2nd_arc: Arc<Mutex<Vec<FilteredData>>> =
|
let supertrend_30m_map = supertrend(20, 4.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
Arc::new(Mutex::new(filtered_data_2nd));
|
let server_epoch = get_server_epoch().await;
|
||||||
let mut task_vec = Vec::new();
|
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)) {
|
||||||
let sma_close = sma(5, &alldata.rt_price_30m_vec, &filtered_data_1st).await?;
|
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||||
let ema_close = ema(3, &alldata.rt_price_30m_vec, &filtered_data_1st).await?;
|
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||||
for element in filtered_data_1st {
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
let mut rt_30m_vec: Vec<RealtimePriceData> = Vec::new();
|
|SupertrendData {
|
||||||
let mut sma_vec: Vec<SmaData> = Vec::new();
|
band_value,
|
||||||
let mut ema_vec: Vec<EmaData> = Vec::new();
|
signal,
|
||||||
let rt_price_30m_vec_c: Vec<(String, Vec<RealtimePriceData>)> = alldata.rt_price_30m_vec.clone();
|
area,
|
||||||
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(
|
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
|
||||||
|SmaData {
|
|
||||||
sma_value,
|
|
||||||
close_time,
|
close_time,
|
||||||
}| *close_time,
|
}| *close_time,
|
||||||
);
|
);
|
||||||
let ema_search_result = ema_vec.binary_search_by_key(
|
if supertrend_search_result.is_ok() {
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
if supertrend_vec[supertrend_search_result.unwrap()].area == SuperTrendArea::UP
|
||||||
|EmaData {
|
&& supertrend_vec[supertrend_search_result.unwrap()].band_value < filtered_data.current_price.to_f64().unwrap()
|
||||||
ema_value,
|
{
|
||||||
close_time,
|
} else {
|
||||||
}| *close_time,
|
keys_to_remove.insert(symbol.clone());
|
||||||
);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} 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: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
|
// 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 filtered_data_2nd_c = filtered_data_2nd_arc.lock().await.clone();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let mut filtered_data_3rd: Vec<FilteredData> = Vec::new();
|
let stoch_rsis = stoch_rsi(30, 30, 3, 3, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
let mut filtered_data_3rd_arc: Arc<Mutex<Vec<FilteredData>>> =
|
for (symbol, values) in &mut filtered_data {
|
||||||
Arc::new(Mutex::new(filtered_data_3rd));
|
if alldata.rt_price_30m_vec.contains_key(symbol) && stoch_rsis.contains_key(symbol) {
|
||||||
let mut task_vec = Vec::new();
|
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
||||||
for element in filtered_data_2nd_c {
|
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == values.closetime);
|
||||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
if search_result.is_some_and(|a| stoch_rsi_vec[a-1].k < 10.0 && stoch_rsi_vec[a].k < 10.0
|
||||||
let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone();
|
&& stoch_rsi_vec[a-1].d < 10.0 && stoch_rsi_vec[a].d< 10.0 &&
|
||||||
let filtered_data_3rd_arc_c = Arc::clone(&filtered_data_3rd_arc);
|
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;
|
||||||
|
|
||||||
task_vec.push(tokio::spawn(async move {
|
// 3rd filtering: the latest 5 30m candle close prices > EMA 200
|
||||||
let position_idx = rt_price_30m_vec_c.iter().position(|elem| elem.0 == element.symbol);
|
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) {
|
||||||
|
} else {
|
||||||
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||||
|
|
||||||
if position_idx.is_some() {
|
// filtering: 1d MACD (3, 7, 30) current MACD-signal > prev MACD-signal
|
||||||
let vec_len = rt_price_30m_vec_c[position_idx.unwrap()].1.len();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
if vec_len >= 11 {
|
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
let candles = rt_price_30m_vec_c[position_idx.unwrap()].1.get(vec_len-12..vec_len-1).unwrap();
|
for (symbol, values) in &mut filtered_data {
|
||||||
let windows = candles.windows(2);
|
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||||
let mut average_amplitude = 0.0;
|
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||||
|
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||||
for window in windows {
|
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
|
||||||
average_amplitude += (window.last().unwrap().high_price - window.last().unwrap().low_price) / window.first().unwrap().close_price;
|
{
|
||||||
}
|
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||||
average_amplitude /= 10.0;
|
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||||
|
} else {
|
||||||
if 0.005 <= average_amplitude && average_amplitude <= 0.01 {
|
keys_to_remove.insert(symbol.clone());
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} 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;
|
||||||
|
|
||||||
// 4th filtering: BollingerBand (len:20, multiplier 2) 5 previous_30m_price (close or low price) < lower_band
|
let final_filtered_data = duplicate_filter(3, &filtered_data).await?;
|
||||||
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
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
try_join_all(task_vec).await?;
|
|
||||||
|
|
||||||
let final_filtered_data = duplicate_filter(3, &filtered_data_4th_arc.lock().await.clone()).await?;
|
|
||||||
insert_pre_suggested_coins(3, false, &final_filtered_data, &alldata).await;
|
insert_pre_suggested_coins(3, false, &final_filtered_data, &alldata).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -192,8 +133,8 @@ pub async fn list_up_for_buy(
|
||||||
|
|
||||||
pub async fn list_up_for_sell(
|
pub async fn list_up_for_sell(
|
||||||
all_data: &AllData,
|
all_data: &AllData,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let filled_buy_orders = select_filled_buy_orders(3).await?;
|
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))
|
.timeout(tokio::time::Duration::from_millis(5000))
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
let mut filtered_symbols: HashMap<String, FilteredDataValue> = HashMap::new();
|
||||||
let server_epoch = server_epoch().await;
|
|
||||||
|
|
||||||
let mut filtered_symbol_vec: Vec<FilteredData> = Vec::new();
|
|
||||||
for element in &filled_buy_orders {
|
for element in &filled_buy_orders {
|
||||||
let filltered_data = FilteredData{
|
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||||
symbol: element.symbol.clone(),
|
|
||||||
closetime: 0,
|
|
||||||
stoploss: dec!(0),
|
|
||||||
target_price: dec!(0),
|
|
||||||
current_price: dec!(0),
|
|
||||||
};
|
|
||||||
filtered_symbol_vec.push(filltered_data);
|
|
||||||
}
|
}
|
||||||
let sma_close = sma(5, &all_data.rt_price_30m_vec, &filtered_symbol_vec).await?;
|
let server_epoch = get_server_epoch().await;
|
||||||
let ema_close = ema(3, &all_data.rt_price_30m_vec, &filtered_symbol_vec).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 {
|
for element in filled_buy_orders {
|
||||||
let sma_result = sma_close.iter().position(|x| x.0 == element.symbol);
|
if element.used_usdt >= dec!(10.0) {
|
||||||
let ema_result = ema_close.iter().position(|x| x.0 == element.symbol);
|
if let (Some(exchange_info), Some(stoch_rsi)) = (exchange_info_map.get(&element.symbol), stoch_rsis.get(&element.symbol)) {
|
||||||
if sma_result.is_some() && ema_result.is_some() && element.used_usdt >= dec!(10.0) {
|
let lot_step_size = exchange_info.stepsize;
|
||||||
let lot_step_size_option = exchange_info_vec
|
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||||
.iter()
|
|
||||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
|
||||||
let quote_commission_precision_option = exchange_info_vec
|
|
||||||
.iter()
|
|
||||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
|
||||||
|
|
||||||
if lot_step_size_option.is_some()
|
|
||||||
&& quote_commission_precision_option.is_some()
|
|
||||||
{
|
|
||||||
let lot_step_size = exchange_info_vec[lot_step_size_option.unwrap()].stepsize;
|
|
||||||
let quote_commission_precision = exchange_info_vec
|
|
||||||
[quote_commission_precision_option.unwrap()]
|
|
||||||
.quote_commission_precision;
|
|
||||||
let base_qty_to_be_ordered =
|
let base_qty_to_be_ordered =
|
||||||
element.base_qty_ordered.round_dp_with_strategy(
|
element.base_qty_ordered.round_dp_with_strategy(
|
||||||
lot_step_size.normalize().scale(),
|
lot_step_size.normalize().scale(),
|
||||||
RoundingStrategy::ToZero,
|
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)
|
if (element.is_long == 0 || element.is_long == 1)
|
||||||
&& !element.current_price.is_zero()
|
&& !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 &&
|
if element.current_price >= element.target_price
|
||||||
sma_close[sma_result.unwrap()].1[sma_close.len()-2].sma_value < ema_close[ema_result.unwrap()].1[ema_close.len()-2].ema_value
|
|
||||||
{
|
{
|
||||||
limit_order_sell(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
element.current_price,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&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;
|
.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::{
|
use super::{
|
||||||
dec, decimal_add, decimal_sub, decimal_div, ema, exists_record, insert_pre_suggested_coins,
|
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,
|
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredData, Mutex,
|
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, server_epoch, MacdData, ema_macd,
|
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter
|
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, CandleType
|
||||||
};
|
};
|
||||||
|
|
||||||
// BB lowerband + SuperTrend + StochRSI
|
// BB lowerband + SuperTrend + StochRSI
|
||||||
|
|
@ -19,81 +19,84 @@ pub async fn list_up_for_buy(
|
||||||
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
|
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
|
||||||
|
|
||||||
// 1st filtering: filtering valid trade pair
|
// 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 {
|
for symbol in &alldata.valid_symbol_vec {
|
||||||
let mut filtered_data = FilteredData::new();
|
filtered_data.insert(symbol.clone(), FilteredDataValue::new());
|
||||||
filtered_data.symbol = symbol.clone();
|
|
||||||
filtered_data_1st.push(filtered_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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:30, multiplier 3) previous_30m_price (close or low price) < lower_band
|
// 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 keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let mut filtered_data_2nd_arc: Arc<Mutex<Vec<FilteredData>>> =
|
let bollingerband_map = bollingerband(30, 3.0, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
Arc::new(Mutex::new(filtered_data_2nd));
|
let server_epoch = get_server_epoch().await;
|
||||||
let mut task_vec = Vec::new();
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
let bollingerbands = bollingerband(30, 3.0, &alldata.rt_price_30m_vec, &filtered_data_1st).await?;
|
if let (Some(bb_vec), Some(rt_30m_vec)) = (bollingerband_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||||
for element in filtered_data_1st {
|
if rt_30m_vec.len() >= 3 && bb_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||||
let mut rt_30m_vec: Vec<RealtimePriceData> = Vec::new();
|
let bb_search_result = bb_vec.binary_search_by_key(
|
||||||
let mut bb_vec: Vec<BollingerBandData> = Vec::new();
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
let rt_price_30m_vec_c: Vec<(String, Vec<RealtimePriceData>)> = alldata.rt_price_30m_vec.clone();
|
|BollingerBandData {
|
||||||
let bollingerbands_c = bollingerbands.clone();
|
sma,
|
||||||
let filtered_data_2nd_arc_c = Arc::clone(&filtered_data_2nd_arc);
|
upperband,
|
||||||
task_vec.push(tokio::spawn(async move {
|
lowerband,
|
||||||
let rt_30m_option = rt_price_30m_vec_c
|
close_time,
|
||||||
.iter()
|
}| *close_time,
|
||||||
.position(|x| *x.0 == element.symbol);
|
);
|
||||||
let bb_option_30m = bollingerbands_c.iter().position(|x| x.0 == element.symbol);
|
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 &&
|
||||||
if rt_30m_option.is_some() && bb_option_30m.is_some() {
|
rt_30m_vec[rt_30m_vec.len()-2].opclo_price > rt_30m_vec.last().unwrap().close_price &&
|
||||||
rt_30m_vec = rt_price_30m_vec_c[rt_30m_option.unwrap()].1.clone();
|
rt_30m_vec[rt_30m_vec.len()-2].candle_type == CandleType::DOWN &&
|
||||||
bb_vec = bollingerbands_c[bb_option_30m.unwrap()].1.clone();
|
rt_30m_vec[rt_30m_vec.len()-2].high_price < bb_vec[bb_search_result.unwrap()-1].sma
|
||||||
let server_epoch = server_epoch().await;
|
{
|
||||||
if rt_30m_vec.len() >= 3 && bb_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
filtered_data.closetime = rt_30m_vec.last().unwrap().close_time;
|
||||||
let bb_search_result = bb_vec.binary_search_by_key(
|
filtered_data.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_30m_vec.last().unwrap().close_price).unwrap();
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
} else {
|
||||||
|BollingerBandData {
|
keys_to_remove.insert(symbol.clone());
|
||||||
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 &&
|
|
||||||
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].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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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
|
// 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 keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let mut filtered_data_3rd: Vec<FilteredData> = Vec::new();
|
let server_epoch = get_server_epoch().await;
|
||||||
for element in filtered_data_2nd {
|
let supertrend_30m_map = supertrend( 10, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
let mut rt_30m_vec: Vec<RealtimePriceData> = Vec::new();
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
if let (Some(supertrend_vec), Some(rt_30m_vec)) = (supertrend_30m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||||
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;
|
|
||||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
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(
|
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
|
|
@ -105,106 +108,87 @@ pub async fn list_up_for_buy(
|
||||||
}| *close_time,
|
}| *close_time,
|
||||||
);
|
);
|
||||||
if supertrend_search_result.is_ok_and(|x|
|
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()) {
|
supertrend_vec[x].area == SuperTrendArea::DOWN && supertrend_vec[x].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();
|
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)));
|
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.stoploss = stop_loss;
|
||||||
|
} else {
|
||||||
filtered_data_3rd.push(filtered_data);
|
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
|
// 4th filtering: the latest 5 30m candle close prices > EMA 200
|
||||||
let mut filtered_data_4th: Vec<FilteredData> = Vec::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let ema_vec = ema(200, &alldata.rt_price_30m_vec, &filtered_data_3rd).await?;
|
let ema_map = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
for element in filtered_data_3rd {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
let ema_search_result = ema_vec.iter().position(|x| x.0 == element.symbol);
|
if let (Some(ema_vec), Some(rt_30m_vec)) = (ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||||
let candle_search_result = alldata.rt_price_30m_vec.iter().position(|x| x.0 == element.symbol);
|
let search_result = ema_vec.binary_search_by_key(
|
||||||
if ema_search_result.is_some() && candle_search_result.is_some() {
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
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 {
|
|EmaData {
|
||||||
ema_value,
|
ema_value,
|
||||||
close_time,
|
close_time,
|
||||||
}| *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) &&
|
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[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[search_result.unwrap()-1].ema_value < rt_30m_vec[rt_30m_vec.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[search_result.unwrap()-2].ema_value < rt_30m_vec[rt_30m_vec.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[search_result.unwrap()-3].ema_value < rt_30m_vec[rt_30m_vec.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) {
|
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-4].ema_value < rt_30m_vec[rt_30m_vec.len()-5].close_price) {
|
||||||
let mut filtered_data = FilteredData::new();
|
} else {
|
||||||
filtered_data.symbol = element.symbol.clone();
|
keys_to_remove.insert(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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} 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
|
// 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 mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let stoch_rsis = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data_5th).await?;
|
let stoch_rsi_map = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
for element in filtered_data_5th {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
let position_idx = stoch_rsis.iter().position(|elem| elem.0 == element.symbol);
|
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 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);
|
|
||||||
if search_result.is_some_and(|a| stoch_rsi_vec[a].k < 15.0 && stoch_rsi_vec[a].d < 15.0) {
|
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();
|
} else {
|
||||||
filtered_data.symbol = element.symbol.clone();
|
keys_to_remove.insert(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_6th.push(filtered_data);
|
|
||||||
}
|
}
|
||||||
|
} 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?;
|
// 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).await?;
|
||||||
insert_pre_suggested_coins(4, false, &final_filtered_data, &alldata).await;
|
insert_pre_suggested_coins(4, false, &final_filtered_data, &alldata).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -212,8 +196,8 @@ pub async fn list_up_for_buy(
|
||||||
|
|
||||||
pub async fn list_up_for_sell(
|
pub async fn list_up_for_sell(
|
||||||
all_data: &AllData,
|
all_data: &AllData,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let filled_buy_orders = select_filled_buy_orders(4).await?;
|
let filled_buy_orders = select_filled_buy_orders(4).await?;
|
||||||
|
|
||||||
|
|
@ -223,23 +207,12 @@ pub async fn list_up_for_sell(
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
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 {
|
for element in filled_buy_orders {
|
||||||
if element.used_usdt >= dec!(10.0) {
|
if element.used_usdt >= dec!(10.0) {
|
||||||
let lot_step_size_option = exchange_info_vec
|
if let Some(exchange_info) = exchange_info_map.get(&element.symbol) {
|
||||||
.iter()
|
let lot_step_size = exchange_info.stepsize;
|
||||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||||
let quote_commission_precision_option = exchange_info_vec
|
|
||||||
.iter()
|
|
||||||
.position(|exchange_info| exchange_info.symbol == element.symbol);
|
|
||||||
|
|
||||||
if lot_step_size_option.is_some()
|
|
||||||
&& quote_commission_precision_option.is_some()
|
|
||||||
{
|
|
||||||
let lot_step_size = exchange_info_vec[lot_step_size_option.unwrap()].stepsize;
|
|
||||||
let quote_commission_precision = exchange_info_vec
|
|
||||||
[quote_commission_precision_option.unwrap()]
|
|
||||||
.quote_commission_precision;
|
|
||||||
let base_qty_to_be_ordered =
|
let base_qty_to_be_ordered =
|
||||||
element.base_qty_ordered.round_dp_with_strategy(
|
element.base_qty_ordered.round_dp_with_strategy(
|
||||||
lot_step_size.normalize().scale(),
|
lot_step_size.normalize().scale(),
|
||||||
|
|
@ -256,8 +229,8 @@ pub async fn list_up_for_sell(
|
||||||
element.current_price,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
} else if element.current_price <= element.stoploss {
|
} else if element.current_price <= element.stoploss {
|
||||||
|
|
@ -266,8 +239,8 @@ pub async fn list_up_for_sell(
|
||||||
element.current_price,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
} else if server_epoch - element.transact_time > (1_800_000) * 20 {
|
} 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,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,217 +1,163 @@
|
||||||
use super::{
|
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,
|
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredData, Mutex,
|
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, server_epoch, MacdData, ema_macd,
|
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||||
duplicate_filter
|
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, get_current_price
|
||||||
};
|
};
|
||||||
|
|
||||||
// Triple SuperTrend strategy
|
// BUY conditions
|
||||||
// SuperTrend length: 20, multiplier: 1.5, BUY signal
|
// (1) 1d MACD (3, 7, 30) cross
|
||||||
// ADX(10, 10) < 25.0
|
// (2) supertrend (30, 3): UP area
|
||||||
// the latest 5 candle close prices > EMA 200
|
// stoploss: (update) supertrend(10, 1.5) lowerband
|
||||||
|
// target price: (fixed) stoploss inverse x 3 times profit
|
||||||
pub async fn list_up_for_buy(
|
pub async fn list_up_for_buy(
|
||||||
alldata: AllData,
|
alldata: &AllData,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
// print rt_price for debugging
|
// print rt_price for debugging
|
||||||
// let a = alldata.rt_price_30m_vec.iter().position(|a| a.0 == "BTCUSDT");
|
// 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());
|
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
|
||||||
|
|
||||||
// 1st filtering: filtering valid trade pair
|
// 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 {
|
for symbol in &alldata.valid_symbol_vec {
|
||||||
let mut filtered_data = FilteredData::new();
|
filtered_data.insert(symbol.clone(), FilteredDataValue::new());
|
||||||
filtered_data.symbol = symbol.clone();
|
|
||||||
filtered_data_1st.push(filtered_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2nd filtering: supertrend(ATR period 20, multiplier: 1.5, 30m close price), signal should be BUY
|
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||||
let mut filtered_data_2nd: Vec<FilteredData> = Vec::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let mut filtered_data_2nd_arc: Arc<Mutex<Vec<FilteredData>>> =
|
let server_epoch = get_server_epoch().await;
|
||||||
Arc::new(Mutex::new(filtered_data_2nd));
|
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
let mut task_vec = Vec::new();
|
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)) {
|
||||||
for element in filtered_data_1st {
|
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||||
let mut rt_30m_vec: Vec<RealtimePriceData> = Vec::new();
|
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP{
|
||||||
let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone();
|
} else {
|
||||||
let filtered_data_2nd_arc_c = Arc::clone(&filtered_data_2nd_arc);
|
keys_to_remove.insert(symbol.clone());
|
||||||
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;
|
|
||||||
|
|
||||||
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
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
filtered_data_2nd_lock.push(filtered_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
}));
|
} else {
|
||||||
}
|
keys_to_remove.insert(symbol.clone());
|
||||||
try_join_all(task_vec).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;
|
|
||||||
|
|
||||||
filtered_3rd_symbols_lock.push(filtered_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try_join_all(task_vec).await?;
|
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||||
|
|
||||||
// 4th filtering: the latest 5 30m candle close prices > EMA 200
|
// 2nd filtering: 1d MACD (3, 5, 30) cross
|
||||||
let filtered_data_3rd = filtered_data_3rd_arc.lock().await.clone();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let mut filtered_data_4th: Vec<FilteredData> = Vec::new();
|
let macd_1d_map = ema_macd(3, 5, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
let mut filtered_data_4th_arc: Arc<Mutex<Vec<FilteredData>>> =
|
for (symbol, values) in &mut filtered_data {
|
||||||
Arc::new(Mutex::new(filtered_data_4th));
|
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||||
let mut task_vec = Vec::new();
|
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||||
let ema_vec = ema(200, &alldata.rt_price_30m_vec, &filtered_data_3rd).await?;
|
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||||
for element in filtered_data_3rd {
|
if macd_vec[macd_vec.len()-1].macd_value > macd_vec[macd_vec.len()-1].signal_value &&
|
||||||
let mut opclo_30m_vec = alldata.rt_price_30m_vec.clone();
|
macd_vec[macd_vec.len()-2].macd_value < macd_vec[macd_vec.len()-2].signal_value {
|
||||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||||
let ema_vec_c = ema_vec.clone();
|
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||||
let filtered_data_4th_arc_c = Arc::clone(&filtered_data_4th_arc);
|
} else {
|
||||||
task_vec.push(tokio::spawn(async move {
|
keys_to_remove.insert(symbol.clone());
|
||||||
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;
|
|
||||||
|
|
||||||
filtered_4th_symbols_lock.push(filtered_data);
|
|
||||||
}
|
}
|
||||||
|
} 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%
|
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||||
let filtered_data_4th_c = filtered_data_4th_arc.lock().await.clone();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let mut filtered_data_5th: Vec<FilteredData> = Vec::new();
|
let server_epoch = get_server_epoch().await;
|
||||||
let mut filtered_data_5th_arc: Arc<Mutex<Vec<FilteredData>>> =
|
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
Arc::new(Mutex::new(filtered_data_5th));
|
for (symbol, values) in &mut filtered_data {
|
||||||
let mut task_vec = Vec::new();
|
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||||
for element in filtered_data_4th_c {
|
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||||
let rt_price_30m_vec_c = alldata.rt_price_30m_vec.clone();
|
// input stoploss, target_price
|
||||||
let filtered_data_5th_arc_c = Arc::clone(&filtered_data_5th_arc);
|
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));
|
||||||
|
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(2.0)), values.current_price);
|
||||||
|
|
||||||
task_vec.push(tokio::spawn(async move {
|
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
||||||
let position_idx = rt_price_30m_vec_c.iter().position(|elem| elem.0 == element.symbol);
|
supertrend_vec.last().unwrap().band_value < values.current_price.to_f64().unwrap()
|
||||||
|
{
|
||||||
if position_idx.is_some() {
|
values.stoploss = band_value;
|
||||||
let vec_len = rt_price_30m_vec_c[position_idx.unwrap()].1.len();
|
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(2.0)), values.current_price);
|
||||||
if vec_len >= 11 {
|
} else {
|
||||||
let candles = rt_price_30m_vec_c[position_idx.unwrap()].1.get(vec_len-12..vec_len-1).unwrap();
|
keys_to_remove.insert(symbol.clone());
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} 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(5, &filtered_data_5th_arc.lock().await.clone()).await?;
|
// 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;
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||||
|
|
||||||
|
let final_filtered_data = duplicate_filter(5, &filtered_data).await?;
|
||||||
insert_pre_suggested_coins(5, false, &final_filtered_data, &alldata).await;
|
insert_pre_suggested_coins(5, false, &final_filtered_data, &alldata).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -219,8 +165,8 @@ pub async fn list_up_for_buy(
|
||||||
|
|
||||||
pub async fn list_up_for_sell(
|
pub async fn list_up_for_sell(
|
||||||
all_data: &AllData,
|
all_data: &AllData,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let filled_buy_orders = select_filled_buy_orders(5).await?;
|
let filled_buy_orders = select_filled_buy_orders(5).await?;
|
||||||
|
|
||||||
|
|
@ -230,32 +176,19 @@ pub async fn list_up_for_sell(
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
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 {
|
for element in filled_buy_orders {
|
||||||
if element.used_usdt >= dec!(10.0) {
|
if element.used_usdt >= dec!(10.0) {
|
||||||
let lot_step_size_option = exchange_info_vec
|
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) =
|
||||||
.iter()
|
(exchange_info_map.get(&element.symbol), trade_fee_map.get(&element.symbol), supertrend_1d.get(&element.symbol)) {
|
||||||
.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()
|
|
||||||
{
|
|
||||||
// update stoploss
|
// 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();
|
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 {
|
&& band_value > element.stoploss {
|
||||||
let update_table_name = String::from("buy_ordered_coin_list");
|
let update_table_name = String::from("buy_ordered_coin_list");
|
||||||
let update_value = vec![
|
let update_value = vec![
|
||||||
|
|
@ -267,10 +200,8 @@ pub async fn list_up_for_sell(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let lot_step_size = exchange_info_vec[lot_step_size_option.unwrap()].stepsize;
|
let lot_step_size = exchange_info.stepsize;
|
||||||
let quote_commission_precision = exchange_info_vec
|
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||||
[quote_commission_precision_option.unwrap()]
|
|
||||||
.quote_commission_precision;
|
|
||||||
let base_qty_to_be_ordered =
|
let base_qty_to_be_ordered =
|
||||||
element.base_qty_ordered.round_dp_with_strategy(
|
element.base_qty_ordered.round_dp_with_strategy(
|
||||||
lot_step_size.normalize().scale(),
|
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)
|
if (element.is_long == 0 || element.is_long == 1)
|
||||||
&& !element.current_price.is_zero()
|
&& !element.current_price.is_zero()
|
||||||
{
|
{
|
||||||
if element.current_price >= element.target_price
|
if element.current_price <= element.stoploss {
|
||||||
&& element.pure_profit_percent >= 0.1
|
|
||||||
{
|
|
||||||
limit_order_sell(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
element.current_price,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
} else if element.current_price <= element.stoploss {
|
} else if element.current_price >= element.target_price {
|
||||||
limit_order_sell(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
element.current_price,
|
element.current_price,
|
||||||
base_qty_to_be_ordered,
|
base_qty_to_be_ordered,
|
||||||
&client,
|
&client,
|
||||||
&exchange_info_vec,
|
&exchange_info_map,
|
||||||
&trade_fee_vec,
|
&trade_fee_map,
|
||||||
)
|
|
||||||
.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,
|
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
use crate::coex::exchange_team::*;
|
use crate::coex::exchange_team::*;
|
||||||
use crate::coex::order_team::*;
|
use crate::coex::order_team::*;
|
||||||
use crate::coin_health_check_team::request_others::CoinPriceData;
|
|
||||||
use csv::{DeserializeRecordsIter, StringRecord};
|
use csv::{DeserializeRecordsIter, StringRecord};
|
||||||
use rust_decimal::prelude::ToPrimitive;
|
use rust_decimal::prelude::ToPrimitive;
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::Decimal;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use super::strategy_test;
|
// use super::strategy_test;
|
||||||
use super::{
|
use super::{
|
||||||
exists_record, insert_one_record, try_join_all, try_select_record, AllData, ExchangeInfo,
|
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 crate::signal_association::signal_decision::*;
|
||||||
use tokio::time::{sleep, Duration, Instant};
|
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>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
crate::strategy_team::strategy_001::list_up_for_buy(all_data).await;
|
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_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_004::list_up_for_buy(all_data).await;
|
||||||
|
crate::strategy_team::strategy_005::list_up_for_buy(all_data).await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute_list_up_for_sell(
|
pub async fn execute_list_up_for_sell(
|
||||||
all_data: &AllData,
|
all_data: &AllData,
|
||||||
exchange_info_vec: &Vec<ExchangeInfo>,
|
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||||
trade_fee_vec: &Vec<TradeFee>,
|
trade_fee_map: &HashMap<String, TradeFee>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> 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_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_vec, &trade_fee_vec).await;
|
crate::strategy_team::strategy_002::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_vec, &trade_fee_vec).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(())
|
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(
|
pub async fn insert_pre_suggested_coins(
|
||||||
registerer: i32,
|
registerer: i32,
|
||||||
is_long: bool,
|
is_long: bool,
|
||||||
filtered_coins: &Vec<FilteredData>,
|
filtered_coins: &HashMap<String, FilteredDataValue>,
|
||||||
alldata: &AllData,
|
alldata: &AllData,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
// Check the existance of record that is registered by this strategist
|
// Check the existance of record that is registered by this strategist
|
||||||
|
|
@ -150,12 +134,12 @@ pub async fn insert_pre_suggested_coins(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
// 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
|
let mut is_dupe = false; // initialize
|
||||||
|
|
||||||
for list_element in &suggested_coin_list {
|
for list_element in &suggested_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -163,8 +147,8 @@ pub async fn insert_pre_suggested_coins(
|
||||||
}
|
}
|
||||||
|
|
||||||
for list_element in &ordered_coin_list {
|
for list_element in &ordered_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -172,8 +156,8 @@ pub async fn insert_pre_suggested_coins(
|
||||||
}
|
}
|
||||||
|
|
||||||
for list_element in &pre_suggested_coin_list {
|
for list_element in &pre_suggested_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -182,13 +166,13 @@ pub async fn insert_pre_suggested_coins(
|
||||||
|
|
||||||
if is_dupe == false {
|
if is_dupe == false {
|
||||||
let mut insert_values = vec![
|
let mut insert_values = vec![
|
||||||
filtered_coin.symbol.clone(), // symbol
|
symbol.clone(), // symbol
|
||||||
filtered_coin.closetime.to_string(), // close_time
|
filtered_data.closetime.to_string(), // close_time
|
||||||
filtered_coin.current_price.to_string(), // suggested_price
|
filtered_data.current_price.to_string(), // suggested_price
|
||||||
filtered_coin.current_price.to_string(), // current_price
|
filtered_data.current_price.to_string(), // current_price
|
||||||
filtered_coin.stoploss.to_string(), // stoploss
|
filtered_data.stoploss.to_string(), // stoploss
|
||||||
filtered_coin.target_price.to_string(), // target_price
|
filtered_data.target_price.to_string(), // target_price
|
||||||
server_epoch().await.to_string(), // registered_server_epoch
|
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||||
0.0.to_string(), // profit_percent
|
0.0.to_string(), // profit_percent
|
||||||
0.0.to_string(), // minimum_profit_percent
|
0.0.to_string(), // minimum_profit_percent
|
||||||
0.0.to_string(), // maximum_profit_percent
|
0.0.to_string(), // maximum_profit_percent
|
||||||
|
|
@ -245,12 +229,12 @@ pub async fn insert_pre_suggested_coins(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
// 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
|
let mut is_dupe = false; // initialize
|
||||||
|
|
||||||
for list_element in &suggested_coin_list {
|
for list_element in &suggested_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -258,8 +242,8 @@ pub async fn insert_pre_suggested_coins(
|
||||||
}
|
}
|
||||||
|
|
||||||
for list_element in &ordered_coin_list {
|
for list_element in &ordered_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -268,13 +252,13 @@ pub async fn insert_pre_suggested_coins(
|
||||||
|
|
||||||
if is_dupe == false {
|
if is_dupe == false {
|
||||||
let mut insert_values = vec![
|
let mut insert_values = vec![
|
||||||
filtered_coin.symbol.clone(), // symbol
|
symbol.clone(), // symbol
|
||||||
filtered_coin.closetime.to_string(), // close_time
|
filtered_data.closetime.to_string(), // close_time
|
||||||
filtered_coin.current_price.to_string(), // suggested_price
|
filtered_data.current_price.to_string(), // suggested_price
|
||||||
filtered_coin.current_price.to_string(), // current_price
|
filtered_data.current_price.to_string(), // current_price
|
||||||
filtered_coin.stoploss.to_string(), // stoploss
|
filtered_data.stoploss.to_string(), // stoploss
|
||||||
filtered_coin.target_price.to_string(), // target_price
|
filtered_data.target_price.to_string(), // target_price
|
||||||
server_epoch().await.to_string(), // registered_server_epoch
|
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||||
0.0.to_string(), // profit_percent
|
0.0.to_string(), // profit_percent
|
||||||
0.0.to_string(), // minimum_profit_percent
|
0.0.to_string(), // minimum_profit_percent
|
||||||
0.0.to_string(), // maximum_profit_percent
|
0.0.to_string(), // maximum_profit_percent
|
||||||
|
|
@ -321,12 +305,12 @@ pub async fn insert_pre_suggested_coins(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
// 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
|
let mut is_dupe = false; // initialize
|
||||||
|
|
||||||
for list_element in &suggested_coin_list {
|
for list_element in &suggested_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -334,8 +318,8 @@ pub async fn insert_pre_suggested_coins(
|
||||||
}
|
}
|
||||||
|
|
||||||
for list_element in &pre_suggested_coin_list {
|
for list_element in &pre_suggested_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -344,13 +328,13 @@ pub async fn insert_pre_suggested_coins(
|
||||||
|
|
||||||
if is_dupe == false {
|
if is_dupe == false {
|
||||||
let mut insert_values = vec![
|
let mut insert_values = vec![
|
||||||
filtered_coin.symbol.clone(), // symbol
|
symbol.clone(), // symbol
|
||||||
filtered_coin.closetime.to_string(), // close_time
|
filtered_data.closetime.to_string(), // close_time
|
||||||
filtered_coin.current_price.to_string(), // suggested_price
|
filtered_data.current_price.to_string(), // suggested_price
|
||||||
filtered_coin.current_price.to_string(), // current_price
|
filtered_data.current_price.to_string(), // current_price
|
||||||
filtered_coin.stoploss.to_string(), // stoploss
|
filtered_data.stoploss.to_string(), // stoploss
|
||||||
filtered_coin.target_price.to_string(), // target_price
|
filtered_data.target_price.to_string(), // target_price
|
||||||
server_epoch().await.to_string(), // registered_server_epoch
|
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||||
0.0.to_string(), // profit_percent
|
0.0.to_string(), // profit_percent
|
||||||
0.0.to_string(), // minimum_profit_percent
|
0.0.to_string(), // minimum_profit_percent
|
||||||
0.0.to_string(), // maximum_profit_percent
|
0.0.to_string(), // maximum_profit_percent
|
||||||
|
|
@ -390,12 +374,12 @@ pub async fn insert_pre_suggested_coins(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
// 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
|
let mut is_dupe = false; // initialize
|
||||||
|
|
||||||
for list_element in &suggested_coin_list {
|
for list_element in &suggested_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -404,13 +388,13 @@ pub async fn insert_pre_suggested_coins(
|
||||||
|
|
||||||
if is_dupe == false {
|
if is_dupe == false {
|
||||||
let mut insert_values = vec![
|
let mut insert_values = vec![
|
||||||
filtered_coin.symbol.clone(), // symbol
|
symbol.clone(), // symbol
|
||||||
filtered_coin.closetime.to_string(), // close_time
|
filtered_data.closetime.to_string(), // close_time
|
||||||
filtered_coin.current_price.to_string(), // suggested_price
|
filtered_data.current_price.to_string(), // suggested_price
|
||||||
filtered_coin.current_price.to_string(), // current_price
|
filtered_data.current_price.to_string(), // current_price
|
||||||
filtered_coin.stoploss.to_string(), // stoploss
|
filtered_data.stoploss.to_string(), // stoploss
|
||||||
filtered_coin.target_price.to_string(), // target_price
|
filtered_data.target_price.to_string(), // target_price
|
||||||
server_epoch().await.to_string(), // registered_server_epoch
|
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||||
0.0.to_string(), // profit_percent
|
0.0.to_string(), // profit_percent
|
||||||
0.0.to_string(), // minimum_profit_percent
|
0.0.to_string(), // minimum_profit_percent
|
||||||
0.0.to_string(), // maximum_profit_percent
|
0.0.to_string(), // maximum_profit_percent
|
||||||
|
|
@ -467,12 +451,12 @@ pub async fn insert_pre_suggested_coins(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// insert record without duplicate(registerer, close_time, symbol) into [pre_suggested_coin_list]
|
// 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
|
let mut is_dupe = false; // initialize
|
||||||
|
|
||||||
for list_element in &ordered_coin_list {
|
for list_element in &ordered_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -480,8 +464,8 @@ pub async fn insert_pre_suggested_coins(
|
||||||
}
|
}
|
||||||
|
|
||||||
for list_element in &pre_suggested_coin_list {
|
for list_element in &pre_suggested_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -490,13 +474,13 @@ pub async fn insert_pre_suggested_coins(
|
||||||
|
|
||||||
if is_dupe == false {
|
if is_dupe == false {
|
||||||
let mut insert_values = vec![
|
let mut insert_values = vec![
|
||||||
filtered_coin.symbol.clone(), // symbol
|
symbol.clone(), // symbol
|
||||||
filtered_coin.closetime.to_string(), // close_time
|
filtered_data.closetime.to_string(), // close_time
|
||||||
filtered_coin.current_price.to_string(), // suggested_price
|
filtered_data.current_price.to_string(), // suggested_price
|
||||||
filtered_coin.current_price.to_string(), // current_price
|
filtered_data.current_price.to_string(), // current_price
|
||||||
filtered_coin.stoploss.to_string(), // stoploss
|
filtered_data.stoploss.to_string(), // stoploss
|
||||||
filtered_coin.target_price.to_string(), // target_price
|
filtered_data.target_price.to_string(), // target_price
|
||||||
server_epoch().await.to_string(), // registered_server_epoch
|
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||||
0.0.to_string(), // profit_percent
|
0.0.to_string(), // profit_percent
|
||||||
0.0.to_string(), // minimum_profit_percent
|
0.0.to_string(), // minimum_profit_percent
|
||||||
0.0.to_string(), // maximum_profit_percent
|
0.0.to_string(), // maximum_profit_percent
|
||||||
|
|
@ -546,12 +530,12 @@ pub async fn insert_pre_suggested_coins(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
// 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
|
let mut is_dupe = false; // initialize
|
||||||
|
|
||||||
for list_element in &ordered_coin_list {
|
for list_element in &ordered_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -560,13 +544,13 @@ pub async fn insert_pre_suggested_coins(
|
||||||
|
|
||||||
if is_dupe == false {
|
if is_dupe == false {
|
||||||
let mut insert_values = vec![
|
let mut insert_values = vec![
|
||||||
filtered_coin.symbol.clone(), // symbol
|
symbol.clone(), // symbol
|
||||||
filtered_coin.closetime.to_string(), // close_time
|
filtered_data.closetime.to_string(), // close_time
|
||||||
filtered_coin.current_price.to_string(), // suggested_price
|
filtered_data.current_price.to_string(), // suggested_price
|
||||||
filtered_coin.current_price.to_string(), // current_price
|
filtered_data.current_price.to_string(), // current_price
|
||||||
filtered_coin.stoploss.to_string(), // stoploss
|
filtered_data.stoploss.to_string(), // stoploss
|
||||||
filtered_coin.target_price.to_string(), // target_price
|
filtered_data.target_price.to_string(), // target_price
|
||||||
server_epoch().await.to_string(), // registered_server_epoch
|
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||||
0.0.to_string(), // profit_percent
|
0.0.to_string(), // profit_percent
|
||||||
0.0.to_string(), // minimum_profit_percent
|
0.0.to_string(), // minimum_profit_percent
|
||||||
0.0.to_string(), // maximum_profit_percent
|
0.0.to_string(), // maximum_profit_percent
|
||||||
|
|
@ -606,12 +590,12 @@ pub async fn insert_pre_suggested_coins(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// insert record without duplicate(registerer, closetime, symbol) into [pre_suggested_coin_list]
|
// 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
|
let mut is_dupe = false; // initialize
|
||||||
|
|
||||||
for list_element in &pre_suggested_coin_list {
|
for list_element in &pre_suggested_coin_list {
|
||||||
if (filtered_coin.symbol == list_element.symbol)
|
if (*symbol == list_element.symbol)
|
||||||
&& (filtered_coin.closetime == list_element.close_time)
|
&& (filtered_data.closetime == list_element.close_time)
|
||||||
{
|
{
|
||||||
is_dupe = true;
|
is_dupe = true;
|
||||||
break;
|
break;
|
||||||
|
|
@ -620,13 +604,13 @@ pub async fn insert_pre_suggested_coins(
|
||||||
|
|
||||||
if is_dupe == false {
|
if is_dupe == false {
|
||||||
let mut insert_values = vec![
|
let mut insert_values = vec![
|
||||||
filtered_coin.symbol.clone(), // symbol
|
symbol.clone(), // symbol
|
||||||
filtered_coin.closetime.to_string(), // close_time
|
filtered_data.closetime.to_string(), // close_time
|
||||||
filtered_coin.current_price.to_string(), // suggested_price
|
filtered_data.current_price.to_string(), // suggested_price
|
||||||
filtered_coin.current_price.to_string(), // current_price
|
filtered_data.current_price.to_string(), // current_price
|
||||||
filtered_coin.stoploss.to_string(), // stoploss
|
filtered_data.stoploss.to_string(), // stoploss
|
||||||
filtered_coin.target_price.to_string(), // target_price
|
filtered_data.target_price.to_string(), // target_price
|
||||||
server_epoch().await.to_string(), // registered_server_epoch
|
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||||
0.0.to_string(), // profit_percent
|
0.0.to_string(), // profit_percent
|
||||||
0.0.to_string(), // minimum_profit_percent
|
0.0.to_string(), // minimum_profit_percent
|
||||||
0.0.to_string(), // maximum_profit_percent
|
0.0.to_string(), // maximum_profit_percent
|
||||||
|
|
@ -643,15 +627,15 @@ pub async fn insert_pre_suggested_coins(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for filtered_coin in filtered_coins {
|
for (symbol, filtered_data) in filtered_coins {
|
||||||
let mut insert_values = vec![
|
let mut insert_values = vec![
|
||||||
filtered_coin.symbol.clone(), // symbol
|
symbol.clone(), // symbol
|
||||||
filtered_coin.closetime.to_string(), // close_time
|
filtered_data.closetime.to_string(), // close_time
|
||||||
filtered_coin.current_price.to_string(), // suggested_price
|
filtered_data.current_price.to_string(), // suggested_price
|
||||||
filtered_coin.current_price.to_string(), // current_price
|
filtered_data.current_price.to_string(), // current_price
|
||||||
filtered_coin.stoploss.to_string(), // stoploss
|
filtered_data.stoploss.to_string(), // stoploss
|
||||||
filtered_coin.target_price.to_string(), // target_price
|
filtered_data.target_price.to_string(), // target_price
|
||||||
server_epoch().await.to_string(), // registered_server_epoch
|
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||||
0.0.to_string(), // profit_percent
|
0.0.to_string(), // profit_percent
|
||||||
0.0.to_string(), // minimum_profit_percent
|
0.0.to_string(), // minimum_profit_percent
|
||||||
0.0.to_string(), // maximum_profit_percent
|
0.0.to_string(), // maximum_profit_percent
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
|
||||||
use crate::coin_health_check_team::request_candles::CandleData;
|
use crate::coin_health_check_team::request_candles::CandleData;
|
||||||
use crate::coin_health_check_team::request_others::CoinPriceData;
|
|
||||||
use crate::database_control::*;
|
use crate::database_control::*;
|
||||||
use csv::{DeserializeRecordsIter, StringRecord};
|
use csv::{DeserializeRecordsIter, StringRecord};
|
||||||
use rust_decimal::{prelude::ToPrimitive, Decimal};
|
use rust_decimal::{prelude::ToPrimitive, Decimal};
|
||||||
|
|
@ -10,6 +9,10 @@ use serde::Deserialize;
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{fs::*, sync::Mutex, time::*};
|
use tokio::{fs::*, sync::Mutex, time::*};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub enum CandleType { UP, DOWN }
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct RealtimePriceData {
|
pub struct RealtimePriceData {
|
||||||
|
|
@ -20,7 +23,7 @@ pub struct RealtimePriceData {
|
||||||
pub low_price: f64,
|
pub low_price: f64,
|
||||||
pub close_time: i64,
|
pub close_time: i64,
|
||||||
pub quote_asset_volume: f64,
|
pub quote_asset_volume: f64,
|
||||||
pub candle_type: String,
|
pub candle_type: CandleType,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RealtimePriceData {
|
impl RealtimePriceData {
|
||||||
|
|
@ -33,7 +36,7 @@ impl RealtimePriceData {
|
||||||
low_price: 0.0,
|
low_price: 0.0,
|
||||||
close_time: 0,
|
close_time: 0,
|
||||||
quote_asset_volume: 0.0,
|
quote_asset_volume: 0.0,
|
||||||
candle_type: String::new(),
|
candle_type: CandleType::DOWN,
|
||||||
};
|
};
|
||||||
data
|
data
|
||||||
}
|
}
|
||||||
|
|
@ -41,194 +44,170 @@ impl RealtimePriceData {
|
||||||
|
|
||||||
pub async fn update_realtime_price_data(
|
pub async fn update_realtime_price_data(
|
||||||
interval: &String,
|
interval: &String,
|
||||||
read_candle_for_opclo: &Vec<(String, Vec<CandleData>)>,
|
read_candle: &HashMap<String, Vec<CandleData>>,
|
||||||
read_candle_for_rt: &Vec<(String, Vec<RealtimePriceData>)>,
|
read_candle_for_rt: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
write_rt_data: &mut Vec<(String, Vec<RealtimePriceData>)>,
|
write_rt_data: &mut HashMap<String, Vec<RealtimePriceData>>,
|
||||||
read_price: &Vec<CoinPriceData>,
|
read_price: &HashMap<String, f64>,
|
||||||
read_symbol: &Vec<String>,
|
read_symbol: &HashSet<String>,
|
||||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
|
|
||||||
let mut rt_price_vec: Vec<RealtimePriceData> = Vec::new();
|
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 {
|
for element in read_symbol {
|
||||||
let candle_search_result = read_candle_for_opclo.iter().position(|x| x.0 == *element);
|
if let Some(candle_data) = read_candle.get(element) {
|
||||||
|
for element in candle_data {
|
||||||
match candle_search_result {
|
let mut realtime_price_data_builder = RealtimePriceData::new();
|
||||||
Some(T) => {
|
realtime_price_data_builder.opclo_price =
|
||||||
for element in &read_candle_for_opclo[T].1 {
|
(element.open_price + element.close_price) / 2.0;
|
||||||
let mut realtime_price_data_builder = RealtimePriceData::new();
|
realtime_price_data_builder.open_price = element.open_price;
|
||||||
realtime_price_data_builder.opclo_price =
|
realtime_price_data_builder.close_price = element.close_price;
|
||||||
(element.open_price + element.close_price) / 2.0;
|
realtime_price_data_builder.high_price = element.high_price;
|
||||||
realtime_price_data_builder.open_price = element.open_price;
|
realtime_price_data_builder.low_price = element.low_price;
|
||||||
realtime_price_data_builder.close_price = element.close_price;
|
realtime_price_data_builder.close_time = element.close_time;
|
||||||
realtime_price_data_builder.high_price = element.high_price;
|
realtime_price_data_builder.quote_asset_volume = element.quote_asset_volume;
|
||||||
realtime_price_data_builder.low_price = element.low_price;
|
if element.open_price < element.close_price {
|
||||||
realtime_price_data_builder.close_time = element.close_time;
|
realtime_price_data_builder.candle_type = CandleType::UP;
|
||||||
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");
|
|
||||||
} else {
|
|
||||||
realtime_price_data_builder.candle_type = String::from("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() {
|
|
||||||
// update close_price
|
|
||||||
rt_price_vec.last_mut().unwrap().close_price =
|
|
||||||
read_price[price_search_result.unwrap()].current_price;
|
|
||||||
// update opclo_price
|
|
||||||
rt_price_vec.last_mut().unwrap().opclo_price =
|
|
||||||
(rt_price_vec.last_mut().unwrap().open_price
|
|
||||||
+ rt_price_vec.last_mut().unwrap().close_price)
|
|
||||||
/ 2.0;
|
|
||||||
// update candle_type
|
|
||||||
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");
|
|
||||||
} else {
|
|
||||||
rt_price_vec.last_mut().unwrap().candle_type = String::from("DOWN");
|
|
||||||
}
|
|
||||||
// update high_price
|
|
||||||
if rt_price_vec.last_mut().unwrap().high_price
|
|
||||||
< read_price[price_search_result.unwrap()].current_price
|
|
||||||
{
|
|
||||||
rt_price_vec.last_mut().unwrap().high_price =
|
|
||||||
read_price[price_search_result.unwrap()].current_price;
|
|
||||||
}
|
|
||||||
// update low_price
|
|
||||||
if rt_price_vec.last_mut().unwrap().low_price
|
|
||||||
> read_price[price_search_result.unwrap()].current_price
|
|
||||||
{
|
|
||||||
rt_price_vec.last_mut().unwrap().low_price =
|
|
||||||
read_price[price_search_result.unwrap()].current_price;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// for 30m, uses 1m candle
|
realtime_price_data_builder.candle_type = CandleType::DOWN;
|
||||||
// for 1d, uses 30m candle
|
}
|
||||||
// for 1w, uses 1d candle
|
rt_price_vec.push(realtime_price_data_builder);
|
||||||
// for 1mon, uses 1w candle
|
}
|
||||||
|
// reflect realtime data to the last element in rt_price_vec
|
||||||
|
if interval.contains("1m") {
|
||||||
|
if let Some(current_price) = read_price.get(element) {
|
||||||
|
// update close_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
|
||||||
|
+ rt_price_vec.last_mut().unwrap().close_price)
|
||||||
|
/ 2.0;
|
||||||
|
// update candle_type
|
||||||
|
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 = CandleType::UP;
|
||||||
|
} else {
|
||||||
|
rt_price_vec.last_mut().unwrap().candle_type = CandleType::DOWN;
|
||||||
|
}
|
||||||
|
// update high_price
|
||||||
|
if rt_price_vec.last_mut().unwrap().high_price
|
||||||
|
< *current_price
|
||||||
|
{
|
||||||
|
rt_price_vec.last_mut().unwrap().high_price = *current_price;
|
||||||
|
}
|
||||||
|
// update low_price
|
||||||
|
if rt_price_vec.last_mut().unwrap().low_price
|
||||||
|
> *current_price
|
||||||
|
{
|
||||||
|
rt_price_vec.last_mut().unwrap().low_price = *current_price;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// for 30m, uses 1m candle
|
||||||
|
// for 1d, uses 30m candle
|
||||||
|
// for 1w, uses 1d candle
|
||||||
|
// for 1mon, uses 1w candle
|
||||||
|
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;
|
||||||
|
let mut update_lowprice = 0.0;
|
||||||
|
let mut update_quote_asset_volume = 0.0;
|
||||||
|
|
||||||
// search symbol
|
// search close time
|
||||||
let candle_search_result =
|
let prev_closetime_result = rt_vec.binary_search_by_key(
|
||||||
read_candle_for_rt.iter().position(|x| x.0 == *element);
|
&previous_close_time,
|
||||||
match candle_search_result {
|
|RealtimePriceData {
|
||||||
Some(T) => {
|
opclo_price,
|
||||||
if read_candle_for_rt[T].1.len() >= 2 {
|
open_price,
|
||||||
let mut candle_vec_clone = read_candle_for_rt[T].1.clone();
|
close_price,
|
||||||
let mut rt_price_vec_clone = rt_price_vec.clone();
|
high_price,
|
||||||
rt_price_vec_clone.reverse();
|
low_price,
|
||||||
rt_price_vec_clone.truncate(2);
|
close_time,
|
||||||
rt_price_vec_clone.reverse();
|
quote_asset_volume,
|
||||||
|
candle_type,
|
||||||
// update realtime information for the latest candle
|
}| *close_time,
|
||||||
let mut update_closeprice = 0.0;
|
);
|
||||||
let mut update_highprice = 0.0;
|
if prev_closetime_result.is_ok() {
|
||||||
let mut update_lowprice = 0.0;
|
let result =
|
||||||
let mut update_quote_asset_volume = 0.0;
|
rt_vec.get(prev_closetime_result.unwrap() + 1..);
|
||||||
|
if result.is_some() {
|
||||||
// search close time
|
let update_highprice_result =
|
||||||
let prev_closetime_result = candle_vec_clone.binary_search_by_key(
|
result.unwrap().iter().max_by(|x, y| {
|
||||||
&rt_price_vec_clone.first().unwrap().close_time,
|
x.high_price.partial_cmp(&y.high_price).unwrap()
|
||||||
|RealtimePriceData {
|
});
|
||||||
opclo_price,
|
if update_highprice_result.is_some() {
|
||||||
open_price,
|
update_highprice =
|
||||||
close_price,
|
update_highprice_result.unwrap().high_price;
|
||||||
high_price,
|
|
||||||
low_price,
|
|
||||||
close_time,
|
|
||||||
quote_asset_volume,
|
|
||||||
candle_type,
|
|
||||||
}| *close_time,
|
|
||||||
);
|
|
||||||
if prev_closetime_result.is_ok() {
|
|
||||||
let result =
|
|
||||||
candle_vec_clone.get(prev_closetime_result.unwrap() + 1..);
|
|
||||||
if result.is_some() {
|
|
||||||
let update_highprice_result =
|
|
||||||
result.unwrap().iter().max_by(|x, y| {
|
|
||||||
x.high_price.partial_cmp(&y.high_price).unwrap()
|
|
||||||
});
|
|
||||||
if update_highprice_result.is_some() {
|
|
||||||
update_highprice =
|
|
||||||
update_highprice_result.unwrap().high_price;
|
|
||||||
}
|
|
||||||
|
|
||||||
let update_lowprice_result =
|
|
||||||
result.unwrap().iter().min_by(|x, y| {
|
|
||||||
x.low_price.partial_cmp(&y.low_price).unwrap()
|
|
||||||
});
|
|
||||||
if update_lowprice_result.is_some() {
|
|
||||||
update_lowprice =
|
|
||||||
update_lowprice_result.unwrap().low_price;
|
|
||||||
}
|
|
||||||
|
|
||||||
for element in result.unwrap() {
|
|
||||||
update_quote_asset_volume += element.quote_asset_volume;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let price_search_result =
|
let update_lowprice_result =
|
||||||
read_price.iter().position(|x| x.symbol == *element);
|
result.unwrap().iter().min_by(|x, y| {
|
||||||
if price_search_result.is_some() {
|
x.low_price.partial_cmp(&y.low_price).unwrap()
|
||||||
update_closeprice =
|
});
|
||||||
read_price[price_search_result.unwrap()].current_price;
|
if update_lowprice_result.is_some() {
|
||||||
|
update_lowprice =
|
||||||
|
update_lowprice_result.unwrap().low_price;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the latest candle with values
|
for element in result.unwrap() {
|
||||||
if update_highprice != 0.0
|
update_quote_asset_volume += element.quote_asset_volume;
|
||||||
&& !update_highprice.is_nan()
|
|
||||||
&& update_highprice.is_finite()
|
|
||||||
{
|
|
||||||
rt_price_vec.last_mut().unwrap().high_price = update_highprice;
|
|
||||||
}
|
|
||||||
if update_lowprice != 0.0
|
|
||||||
&& !update_lowprice.is_nan()
|
|
||||||
&& update_lowprice.is_finite()
|
|
||||||
{
|
|
||||||
rt_price_vec.last_mut().unwrap().low_price = update_lowprice;
|
|
||||||
}
|
|
||||||
if update_quote_asset_volume != 0.0
|
|
||||||
&& !update_quote_asset_volume.is_nan()
|
|
||||||
&& update_quote_asset_volume.is_finite()
|
|
||||||
{
|
|
||||||
rt_price_vec.last_mut().unwrap().quote_asset_volume =
|
|
||||||
update_quote_asset_volume;
|
|
||||||
}
|
|
||||||
if update_closeprice != 0.0
|
|
||||||
&& !update_closeprice.is_nan()
|
|
||||||
&& update_closeprice.is_finite()
|
|
||||||
{
|
|
||||||
rt_price_vec.last_mut().unwrap().close_price =
|
|
||||||
update_closeprice;
|
|
||||||
rt_price_vec.last_mut().unwrap().opclo_price =
|
|
||||||
(update_closeprice
|
|
||||||
+ rt_price_vec.last_mut().unwrap().open_price)
|
|
||||||
/ 2.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
|
||||||
|
if let Some(current_price) = read_price.get(element) {
|
||||||
|
update_closeprice = *current_price;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the latest candle with values
|
||||||
|
if update_highprice != 0.0
|
||||||
|
&& !update_highprice.is_nan()
|
||||||
|
&& update_highprice.is_finite()
|
||||||
|
{
|
||||||
|
rt_price_vec.last_mut().unwrap().high_price = update_highprice;
|
||||||
|
}
|
||||||
|
if update_lowprice != 0.0
|
||||||
|
&& !update_lowprice.is_nan()
|
||||||
|
&& update_lowprice.is_finite()
|
||||||
|
{
|
||||||
|
rt_price_vec.last_mut().unwrap().low_price = update_lowprice;
|
||||||
|
}
|
||||||
|
if update_quote_asset_volume != 0.0
|
||||||
|
&& !update_quote_asset_volume.is_nan()
|
||||||
|
&& update_quote_asset_volume.is_finite()
|
||||||
|
{
|
||||||
|
rt_price_vec.last_mut().unwrap().quote_asset_volume =
|
||||||
|
update_quote_asset_volume;
|
||||||
|
}
|
||||||
|
if update_closeprice != 0.0
|
||||||
|
&& !update_closeprice.is_nan()
|
||||||
|
&& update_closeprice.is_finite()
|
||||||
|
{
|
||||||
|
rt_price_vec.last_mut().unwrap().close_price =
|
||||||
|
update_closeprice;
|
||||||
|
rt_price_vec.last_mut().unwrap().opclo_price =
|
||||||
|
(update_closeprice
|
||||||
|
+ rt_price_vec.last_mut().unwrap().open_price)
|
||||||
|
/ 2.0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rt_data_vec.push((element.clone(), rt_price_vec.clone()));
|
|
||||||
rt_price_vec.clear();
|
|
||||||
}
|
}
|
||||||
None => {}
|
|
||||||
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*write_rt_data = rt_data_vec;
|
|
||||||
|
|
||||||
// println!(" datapoints/price_{} 완료 elapsed:{:.2}s", interval, instant.elapsed().as_secs_f32());
|
|
||||||
Ok(())
|
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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AdxData {
|
pub struct AdxData {
|
||||||
|
|
@ -19,109 +19,109 @@ struct DiData {
|
||||||
close_time: i64,
|
close_time: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn adx(adx_len: usize, di_len: usize, input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
pub async fn adx(adx_len: usize, di_len: usize, input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
filtered_symbols: &Vec<FilteredData>,) -> Result<Vec<(String, Vec<AdxData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String, Vec<AdxData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
if filtered_symbols.is_empty() {
|
if filtered_symbols.is_empty() {
|
||||||
Err(("Err"))?;
|
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 adx_vec_arc = Arc::new(Mutex::new(adx_vec));
|
||||||
let mut task_vec = Vec::new();
|
let mut task_vec = Vec::new();
|
||||||
for element in filtered_symbols {
|
for (filtered_symbol, filtered_data) in filtered_symbols {
|
||||||
let mut rt_data_vec = input_rt_data.clone();
|
let mut rt_data_map = input_rt_data.clone();
|
||||||
let adx_vec_arc_c = Arc::clone(&adx_vec_arc);
|
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 {
|
task_vec.push(tokio::spawn(async move {
|
||||||
let idx_result = rt_data_vec.iter().position(|a| a.0 == symbol);
|
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_price_data.windows(2);
|
||||||
|
let mut basic_data_vec: Vec<BasicData> = Vec::new();
|
||||||
|
for window in windows {
|
||||||
|
let prev_rt_data = window.first().unwrap();
|
||||||
|
let current_rt_data = window.last().unwrap();
|
||||||
|
let mut up = current_rt_data.high_price - prev_rt_data.high_price;
|
||||||
|
let mut down = prev_rt_data.low_price - current_rt_data.low_price;
|
||||||
|
let basic_data = BasicData {
|
||||||
|
dm_plus: if up > down && up > 0.0 { up } else { 0.0 },
|
||||||
|
dm_minus: if down > up && down > 0.0 { down } else { 0.0 },
|
||||||
|
true_range: f64::max(f64::max(current_rt_data.high_price - current_rt_data.low_price,
|
||||||
|
current_rt_data.high_price - prev_rt_data.close_price),
|
||||||
|
current_rt_data.low_price - prev_rt_data.close_price),
|
||||||
|
close_time: current_rt_data.close_time,
|
||||||
|
};
|
||||||
|
basic_data_vec.push(basic_data);
|
||||||
|
}
|
||||||
|
// step 2: smoothing +DM, -DM, TR
|
||||||
|
let alpha: f64 = 1.0/(di_len as f64);
|
||||||
|
let mut smoothed_basic_data_vec: Vec<BasicData> = Vec::new();
|
||||||
|
|
||||||
if idx_result.is_some() {
|
let partial_vec1 = basic_data_vec.get(..di_len).unwrap(); // for calculation of initial value
|
||||||
// step 1: calculate +DM, -DM, TR
|
let partial_vec2 = basic_data_vec.get(di_len..).unwrap(); // for calculation of the rest
|
||||||
let windows = rt_data_vec[idx_result.unwrap()].1.windows(2);
|
|
||||||
let mut basic_data_vec: Vec<BasicData> = Vec::new();
|
|
||||||
for window in windows {
|
|
||||||
let prev_rt_data = window.first().unwrap();
|
|
||||||
let current_rt_data = window.last().unwrap();
|
|
||||||
let mut up = current_rt_data.high_price - prev_rt_data.high_price;
|
|
||||||
let mut down = prev_rt_data.low_price - current_rt_data.low_price;
|
|
||||||
let basic_data = BasicData {
|
|
||||||
dm_plus: if up > down && up > 0.0 { up } else { 0.0 },
|
|
||||||
dm_minus: if down > up && down > 0.0 { down } else { 0.0 },
|
|
||||||
true_range: f64::max(f64::max(current_rt_data.high_price - current_rt_data.low_price,
|
|
||||||
current_rt_data.high_price - prev_rt_data.close_price),
|
|
||||||
current_rt_data.low_price - prev_rt_data.close_price),
|
|
||||||
close_time: current_rt_data.close_time,
|
|
||||||
};
|
|
||||||
basic_data_vec.push(basic_data);
|
|
||||||
}
|
|
||||||
// step 2: smoothing +DM, -DM, TR
|
|
||||||
let alpha: f64 = 1.0/(di_len as f64);
|
|
||||||
let mut smoothed_basic_data_vec: Vec<BasicData> = Vec::new();
|
|
||||||
|
|
||||||
let partial_vec1 = basic_data_vec.get(..di_len).unwrap(); // for calculation of initial value
|
let mut dm_plus_calculated = 0.0;
|
||||||
let partial_vec2 = basic_data_vec.get(di_len..).unwrap(); // for calculation of the rest
|
let mut dm_minus_calculated = 0.0;
|
||||||
|
let mut tr_calculated = 0.0;
|
||||||
|
for element in partial_vec1 {
|
||||||
|
dm_plus_calculated += element.dm_plus;
|
||||||
|
dm_minus_calculated += element.dm_minus;
|
||||||
|
tr_calculated += element.true_range;
|
||||||
|
}
|
||||||
|
dm_plus_calculated /= di_len as f64;
|
||||||
|
dm_minus_calculated /= di_len as f64;
|
||||||
|
tr_calculated /= di_len as f64;
|
||||||
|
|
||||||
let mut dm_plus_calculated = 0.0;
|
let basic_data = BasicData { dm_plus: dm_plus_calculated, dm_minus: dm_minus_calculated, true_range: tr_calculated, close_time: partial_vec1.last().unwrap().close_time };
|
||||||
let mut dm_minus_calculated = 0.0;
|
|
||||||
let mut tr_calculated = 0.0;
|
|
||||||
for element in partial_vec1 {
|
|
||||||
dm_plus_calculated += element.dm_plus;
|
|
||||||
dm_minus_calculated += element.dm_minus;
|
|
||||||
tr_calculated += element.true_range;
|
|
||||||
}
|
|
||||||
dm_plus_calculated /= di_len as f64;
|
|
||||||
dm_minus_calculated /= di_len as f64;
|
|
||||||
tr_calculated /= di_len as f64;
|
|
||||||
|
|
||||||
let basic_data = BasicData { dm_plus: dm_plus_calculated, dm_minus: dm_minus_calculated, true_range: tr_calculated, close_time: partial_vec1.last().unwrap().close_time };
|
|
||||||
smoothed_basic_data_vec.push(basic_data);
|
|
||||||
|
|
||||||
for element in partial_vec2 {
|
|
||||||
dm_plus_calculated = alpha * element.dm_plus + (1.0 - alpha) * dm_plus_calculated;
|
|
||||||
dm_minus_calculated = alpha * element.dm_minus + (1.0 - alpha) * dm_minus_calculated;
|
|
||||||
tr_calculated = alpha * element.true_range + (1.0 - alpha) * tr_calculated;
|
|
||||||
let basic_data = BasicData { dm_plus: dm_plus_calculated, dm_minus: dm_minus_calculated, true_range: tr_calculated, close_time: element.close_time };
|
|
||||||
smoothed_basic_data_vec.push(basic_data);
|
smoothed_basic_data_vec.push(basic_data);
|
||||||
}
|
|
||||||
|
|
||||||
// step 3: calculate DI
|
for element in partial_vec2 {
|
||||||
let mut di_data_vec: Vec<DiData> = Vec::new();
|
dm_plus_calculated = alpha * element.dm_plus + (1.0 - alpha) * dm_plus_calculated;
|
||||||
for basic_data in smoothed_basic_data_vec {
|
dm_minus_calculated = alpha * element.dm_minus + (1.0 - alpha) * dm_minus_calculated;
|
||||||
let di_data = DiData { di_plus: (100.0 * basic_data.dm_plus) / basic_data.true_range, di_minus: (100.0 * basic_data.dm_minus) / basic_data.true_range, close_time: basic_data.close_time};
|
tr_calculated = alpha * element.true_range + (1.0 - alpha) * tr_calculated;
|
||||||
di_data_vec.push(di_data);
|
let basic_data = BasicData { dm_plus: dm_plus_calculated, dm_minus: dm_minus_calculated, true_range: tr_calculated, close_time: element.close_time };
|
||||||
}
|
smoothed_basic_data_vec.push(basic_data);
|
||||||
|
}
|
||||||
|
|
||||||
// step 4: calculate ADX
|
// step 3: calculate DI
|
||||||
let mut initial_adx_vec: Vec<AdxData> = Vec::new();
|
let mut di_data_vec: Vec<DiData> = Vec::new();
|
||||||
for di_data in di_data_vec {
|
for basic_data in smoothed_basic_data_vec {
|
||||||
let sum = di_data.di_plus + di_data.di_minus;
|
let di_data = DiData { di_plus: (100.0 * basic_data.dm_plus) / basic_data.true_range, di_minus: (100.0 * basic_data.dm_minus) / basic_data.true_range, close_time: basic_data.close_time};
|
||||||
let difference = (di_data.di_plus - di_data.di_minus).abs();
|
di_data_vec.push(di_data);
|
||||||
let divisor = if sum <= 0.00000001 { 1.0 } else { sum };
|
}
|
||||||
let adx_data = AdxData { adx: difference.abs()/divisor, close_time: di_data.close_time };
|
|
||||||
initial_adx_vec.push(adx_data);
|
|
||||||
}
|
|
||||||
let partial_vec1 = initial_adx_vec.get(..adx_len).unwrap(); // for calculation of initial value
|
|
||||||
let partial_vec2 = initial_adx_vec.get(adx_len..).unwrap(); // for calculation of the rest
|
|
||||||
|
|
||||||
let mut smoothed_adx_vec: Vec<AdxData> = Vec::new();
|
// step 4: calculate ADX
|
||||||
let mut adx_calculated = 0.0;
|
let mut initial_adx_vec: Vec<AdxData> = Vec::new();
|
||||||
for element in partial_vec1 {
|
for di_data in di_data_vec {
|
||||||
adx_calculated += element.adx;
|
let sum = di_data.di_plus + di_data.di_minus;
|
||||||
}
|
let difference = (di_data.di_plus - di_data.di_minus).abs();
|
||||||
adx_calculated /= adx_len as f64;
|
let divisor = if sum <= 0.00000001 { 1.0 } else { sum };
|
||||||
|
let adx_data = AdxData { adx: difference.abs()/divisor, close_time: di_data.close_time };
|
||||||
|
initial_adx_vec.push(adx_data);
|
||||||
|
}
|
||||||
|
let partial_vec1 = initial_adx_vec.get(..adx_len).unwrap(); // for calculation of initial value
|
||||||
|
let partial_vec2 = initial_adx_vec.get(adx_len..).unwrap(); // for calculation of the rest
|
||||||
|
|
||||||
let adx_data = AdxData { adx: adx_calculated, close_time: partial_vec1.last().unwrap().close_time };
|
let mut smoothed_adx_vec: Vec<AdxData> = Vec::new();
|
||||||
smoothed_adx_vec.push(adx_data);
|
let mut adx_calculated = 0.0;
|
||||||
|
for element in partial_vec1 {
|
||||||
|
adx_calculated += element.adx;
|
||||||
|
}
|
||||||
|
adx_calculated /= adx_len as f64;
|
||||||
|
|
||||||
let alpha: f64 = 1.0 /(adx_len as f64);
|
let adx_data = AdxData { adx: adx_calculated, close_time: partial_vec1.last().unwrap().close_time };
|
||||||
for element in partial_vec2 {
|
|
||||||
adx_calculated = alpha * element.adx + (1.0 - alpha) * adx_calculated;
|
|
||||||
let adx_data = AdxData { adx: 100.0 * adx_calculated, close_time: element.close_time };
|
|
||||||
smoothed_adx_vec.push(adx_data);
|
smoothed_adx_vec.push(adx_data);
|
||||||
}
|
|
||||||
|
|
||||||
let mut adx_vec_arc_lock = adx_vec_arc_c.lock().await;
|
let alpha: f64 = 1.0 /(adx_len as f64);
|
||||||
adx_vec_arc_lock.push((symbol.clone(), smoothed_adx_vec.clone()));
|
for element in partial_vec2 {
|
||||||
|
adx_calculated = alpha * element.adx + (1.0 - alpha) * adx_calculated;
|
||||||
|
let adx_data = AdxData { adx: 100.0 * adx_calculated, close_time: element.close_time };
|
||||||
|
smoothed_adx_vec.push(adx_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut adx_vec_arc_lock = adx_vec_arc_c.lock().await;
|
||||||
|
adx_vec_arc_lock.insert(symbol.clone(), smoothed_adx_vec.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,13 @@
|
||||||
use crate::database_control::*;
|
use crate::database_control::*;
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||||
use crate::value_estimation_team::indicators::sma::{SmaData, sma};
|
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 futures::future::try_join_all;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||||
|
use super::{HashMap};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct BollingerBandData {
|
pub struct BollingerBandData {
|
||||||
|
|
@ -35,35 +36,31 @@ impl BollingerBandData {
|
||||||
pub async fn bollingerband(
|
pub async fn bollingerband(
|
||||||
period: usize,
|
period: usize,
|
||||||
sd_factor: f64,
|
sd_factor: f64,
|
||||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
filtered_symbols: &Vec<FilteredData>,
|
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||||
) -> Result<Vec<(String, Vec<BollingerBandData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<HashMap<String, Vec<BollingerBandData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
if filtered_symbols.is_empty() {
|
if filtered_symbols.is_empty() {
|
||||||
Err(("Err"))?;
|
Err(("Err"))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut sma_data_vec: Vec<(String, Vec<SmaData>)> = sma(period, input_rt_data, filtered_symbols).await?;
|
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: Vec<(String, Vec<BollingerBandData>)> = Vec::new();
|
|
||||||
let mut bb_data_wrapper_arc = Arc::new(Mutex::new(bb_data_wrapper));
|
let mut bb_data_wrapper_arc = Arc::new(Mutex::new(bb_data_wrapper));
|
||||||
let mut task_vec = Vec::new();
|
let mut task_vec = Vec::new();
|
||||||
for filtered_symbol in filtered_symbols {
|
for (symbol, filtered_data) in filtered_symbols {
|
||||||
let filtered_symbol_c = filtered_symbol.clone();
|
if input_rt_data.contains_key(symbol) && sma_data_map.contains_key(symbol) {
|
||||||
let rt_data_vec_c: Vec<(String, Vec<RealtimePriceData>)> = input_rt_data.clone();
|
let symbol_c = symbol.clone();
|
||||||
let sma_data_vec_c = sma_data_vec.clone();
|
let rt_data_vec_c = input_rt_data.get(symbol).unwrap().clone();
|
||||||
let bb_data_wrapper_arc_c = Arc::clone(&bb_data_wrapper_arc);
|
let sma_data_vec_c = sma_data_map.get(symbol).unwrap().clone();
|
||||||
task_vec.push(tokio::spawn(async move {
|
let bb_data_wrapper_arc_c = Arc::clone(&bb_data_wrapper_arc);
|
||||||
let search_result1 = rt_data_vec_c.clone().iter().position(|x| x.0 == *filtered_symbol_c.symbol);
|
task_vec.push(tokio::spawn(async move {
|
||||||
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 = BollingerBandData::new();
|
||||||
let mut bb_data_vec: Vec<BollingerBandData> = Vec::new();
|
let mut bb_data_vec: Vec<BollingerBandData> = Vec::new();
|
||||||
|
|
||||||
// if the data has shorter than buffer
|
// if the data has shorter than buffer
|
||||||
if sma_data_vec_c[search_result2.unwrap()].1.len() > period {
|
if sma_data_vec_c.len() > period {
|
||||||
let result = rt_data_vec_c[search_result1.unwrap()].1.binary_search_by_key(
|
let result = rt_data_vec_c.binary_search_by_key(
|
||||||
&sma_data_vec_c[search_result2.unwrap()].1.first().unwrap().close_time,
|
&sma_data_vec_c.first().unwrap().close_time,
|
||||||
|RealtimePriceData {
|
|RealtimePriceData {
|
||||||
opclo_price,
|
opclo_price,
|
||||||
open_price,
|
open_price,
|
||||||
|
|
@ -80,12 +77,12 @@ pub async fn bollingerband(
|
||||||
Ok(T) => {
|
Ok(T) => {
|
||||||
if T <= period - 1 {
|
if T <= period - 1 {
|
||||||
let mut read_data_iter =
|
let mut read_data_iter =
|
||||||
sma_data_vec_c[search_result2.unwrap()].1.iter();
|
sma_data_vec_c.iter();
|
||||||
for _ in T..period - 1 {
|
for _ in T..period - 1 {
|
||||||
read_data_iter.next();
|
read_data_iter.next();
|
||||||
}
|
}
|
||||||
let window_iter =
|
let window_iter =
|
||||||
rt_data_vec_c[search_result1.unwrap()].1.windows(period);
|
rt_data_vec_c.windows(period);
|
||||||
for buffer in window_iter {
|
for buffer in window_iter {
|
||||||
let mut sd_mean = 0.0;
|
let mut sd_mean = 0.0;
|
||||||
let mut standard_deviation = 0.0;
|
let mut standard_deviation = 0.0;
|
||||||
|
|
@ -119,10 +116,10 @@ pub async fn bollingerband(
|
||||||
}
|
}
|
||||||
let mut bb_data_wrapper_lock = bb_data_wrapper_arc_c.lock().await;
|
let mut bb_data_wrapper_lock = bb_data_wrapper_arc_c.lock().await;
|
||||||
bb_data_wrapper_lock
|
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?;
|
try_join_all(task_vec).await?;
|
||||||
let a = bb_data_wrapper_arc.lock().await.to_owned();
|
let a = bb_data_wrapper_arc.lock().await.to_owned();
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ use serde::Deserialize;
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||||
use super::FilteredData;
|
use super::FilteredDataValue;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EmaData {
|
pub struct EmaData {
|
||||||
|
|
@ -27,9 +28,9 @@ impl EmaData {
|
||||||
// Binance EMA (closeprice)
|
// Binance EMA (closeprice)
|
||||||
pub async fn ema(
|
pub async fn ema(
|
||||||
moving_number: usize,
|
moving_number: usize,
|
||||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
filtered_symbols: &Vec<FilteredData>,
|
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||||
) -> Result<Vec<(String, Vec<EmaData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<HashMap<String, Vec<EmaData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
if filtered_symbols.is_empty() {
|
if filtered_symbols.is_empty() {
|
||||||
Err("Err")?;
|
Err("Err")?;
|
||||||
}
|
}
|
||||||
|
|
@ -38,55 +39,50 @@ pub async fn ema(
|
||||||
let mut ema_t: f64 = 0.0;
|
let mut ema_t: f64 = 0.0;
|
||||||
let mut ema_prev: 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 ema_data_wrapper_arc = Arc::new(Mutex::new(ema_data_wrapper));
|
||||||
let mut task_vec = Vec::new();
|
let mut task_vec = Vec::new();
|
||||||
for filtered_elem in filtered_symbols {
|
for (symbol, filtered_data) in filtered_symbols {
|
||||||
let symbol_search_result = input_rt_data.iter().position(|x| x.0 == *filtered_elem.symbol);
|
if let Some(rt_data_vec) = input_rt_data.get(symbol) {
|
||||||
|
let ema_data_wrapper_arc_c = Arc::clone(&ema_data_wrapper_arc);
|
||||||
|
let mut ema_data = EmaData::new();
|
||||||
|
let mut ema_data_vec: Vec<EmaData> = Vec::new();
|
||||||
|
let symbol_c = symbol.clone();
|
||||||
|
let rt_data_vec_c = rt_data_vec.clone();
|
||||||
|
task_vec.push(tokio::spawn(async move {
|
||||||
|
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 = rt_data_vec_c.get(..moving_number).unwrap();
|
||||||
|
let partial_vec2 = rt_data_vec_c.get(moving_number..).unwrap();
|
||||||
|
|
||||||
match symbol_search_result {
|
let mut sma_for_initial_value = 0.0;
|
||||||
Some(T) => {
|
for element in partial_vec1 {
|
||||||
let ema_data_wrapper_arc_c = Arc::clone(&ema_data_wrapper_arc);
|
sma_for_initial_value += element.close_price;
|
||||||
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();
|
|
||||||
task_vec.push(tokio::spawn(async move {
|
|
||||||
if input_rt_data_c[T].1.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 mut sma_for_initial_value = 0.0;
|
|
||||||
for element in partial_vec1 {
|
|
||||||
sma_for_initial_value += element.close_price;
|
|
||||||
}
|
|
||||||
sma_for_initial_value /= moving_number as f64;
|
|
||||||
|
|
||||||
ema_data.ema_value = sma_for_initial_value;
|
|
||||||
ema_data.close_time = partial_vec1.last().unwrap().close_time;
|
|
||||||
ema_data_vec.push(ema_data.clone());
|
|
||||||
|
|
||||||
ema_prev = sma_for_initial_value;
|
|
||||||
|
|
||||||
for element in partial_vec2 {
|
|
||||||
ema_t = (1.0 - alpha) * ema_prev + alpha * element.close_price;
|
|
||||||
|
|
||||||
ema_data.ema_value = ema_t;
|
|
||||||
ema_data.close_time = element.close_time;
|
|
||||||
ema_data_vec.push(ema_data.clone());
|
|
||||||
|
|
||||||
ema_prev = ema_t;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let mut ema_data_wrapper_lock = ema_data_wrapper_arc_c.lock().await;
|
sma_for_initial_value /= moving_number as f64;
|
||||||
ema_data_wrapper_lock.push((filtered_elem_c.symbol.clone(), ema_data_vec.clone()));
|
|
||||||
}));
|
ema_data.ema_value = sma_for_initial_value;
|
||||||
}
|
ema_data.close_time = partial_vec1.last().unwrap().close_time;
|
||||||
None => {}
|
ema_data_vec.push(ema_data.clone());
|
||||||
|
|
||||||
|
ema_prev = sma_for_initial_value;
|
||||||
|
|
||||||
|
for element in partial_vec2 {
|
||||||
|
ema_t = (1.0 - alpha) * ema_prev + alpha * element.close_price;
|
||||||
|
|
||||||
|
ema_data.ema_value = ema_t;
|
||||||
|
ema_data.close_time = element.close_time;
|
||||||
|
ema_data_vec.push(ema_data.clone());
|
||||||
|
|
||||||
|
ema_prev = ema_t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut ema_data_wrapper_lock = ema_data_wrapper_arc_c.lock().await;
|
||||||
|
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try_join_all(task_vec).await?;
|
try_join_all(task_vec).await?;
|
||||||
|
|
@ -97,9 +93,9 @@ pub async fn ema(
|
||||||
// Binance EMA ((open+close)/2)
|
// Binance EMA ((open+close)/2)
|
||||||
pub async fn ema_opclo(
|
pub async fn ema_opclo(
|
||||||
moving_number: usize,
|
moving_number: usize,
|
||||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
filtered_symbols: &Vec<FilteredData>,
|
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||||
) -> Result<Vec<(String, Vec<EmaData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<HashMap<String, Vec<EmaData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
if filtered_symbols.is_empty() {
|
if filtered_symbols.is_empty() {
|
||||||
Err("Err")?;
|
Err("Err")?;
|
||||||
}
|
}
|
||||||
|
|
@ -108,55 +104,50 @@ pub async fn ema_opclo(
|
||||||
let mut ema_t: f64 = 0.0;
|
let mut ema_t: f64 = 0.0;
|
||||||
let mut ema_prev: 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 ema_data_wrapper_arc = Arc::new(Mutex::new(ema_data_wrapper));
|
||||||
let mut task_vec = Vec::new();
|
let mut task_vec = Vec::new();
|
||||||
for filtered_elem in filtered_symbols {
|
for (symbol, filtered_data) in filtered_symbols {
|
||||||
let symbol_search_result = input_rt_data.iter().position(|x| x.0 == *filtered_elem.symbol);
|
if let Some(rt_data_vec) = input_rt_data.get(symbol) {
|
||||||
|
let ema_data_wrapper_arc_c = Arc::clone(&ema_data_wrapper_arc);
|
||||||
|
let mut ema_data = EmaData::new();
|
||||||
|
let mut ema_data_vec: Vec<EmaData> = Vec::new();
|
||||||
|
let symbol_c = symbol.clone();
|
||||||
|
let rt_data_vec_c = rt_data_vec.clone();
|
||||||
|
task_vec.push(tokio::spawn(async move {
|
||||||
|
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 = rt_data_vec_c.get(..moving_number).unwrap();
|
||||||
|
let partial_vec2 = rt_data_vec_c.get(moving_number..).unwrap();
|
||||||
|
|
||||||
match symbol_search_result {
|
let mut sma_for_initial_value = 0.0;
|
||||||
Some(T) => {
|
for element in partial_vec1 {
|
||||||
let ema_data_wrapper_arc_c = Arc::clone(&ema_data_wrapper_arc);
|
sma_for_initial_value += element.opclo_price;
|
||||||
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();
|
|
||||||
task_vec.push(tokio::spawn(async move {
|
|
||||||
if input_rt_data_c[T].1.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 mut sma_for_initial_value = 0.0;
|
|
||||||
for element in partial_vec1 {
|
|
||||||
sma_for_initial_value += element.opclo_price;
|
|
||||||
}
|
|
||||||
sma_for_initial_value /= moving_number as f64;
|
|
||||||
|
|
||||||
ema_data.ema_value = sma_for_initial_value;
|
|
||||||
ema_data.close_time = partial_vec1.last().unwrap().close_time;
|
|
||||||
ema_data_vec.push(ema_data.clone());
|
|
||||||
|
|
||||||
ema_prev = sma_for_initial_value;
|
|
||||||
|
|
||||||
for element in partial_vec2 {
|
|
||||||
ema_t = (1.0 - alpha) * ema_prev + alpha * element.opclo_price;
|
|
||||||
|
|
||||||
ema_data.ema_value = ema_t;
|
|
||||||
ema_data.close_time = element.close_time;
|
|
||||||
ema_data_vec.push(ema_data.clone());
|
|
||||||
|
|
||||||
ema_prev = ema_t;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let mut ema_data_wrapper_lock = ema_data_wrapper_arc_c.lock().await;
|
sma_for_initial_value /= moving_number as f64;
|
||||||
ema_data_wrapper_lock.push((filtered_elem_c.symbol.clone(), ema_data_vec.clone()));
|
|
||||||
}));
|
ema_data.ema_value = sma_for_initial_value;
|
||||||
}
|
ema_data.close_time = partial_vec1.last().unwrap().close_time;
|
||||||
None => {}
|
ema_data_vec.push(ema_data.clone());
|
||||||
|
|
||||||
|
ema_prev = sma_for_initial_value;
|
||||||
|
|
||||||
|
for element in partial_vec2 {
|
||||||
|
ema_t = (1.0 - alpha) * ema_prev + alpha * element.close_price;
|
||||||
|
|
||||||
|
ema_data.ema_value = ema_t;
|
||||||
|
ema_data.close_time = element.close_time;
|
||||||
|
ema_data_vec.push(ema_data.clone());
|
||||||
|
|
||||||
|
ema_prev = ema_t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut ema_data_wrapper_lock = ema_data_wrapper_arc_c.lock().await;
|
||||||
|
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try_join_all(task_vec).await?;
|
try_join_all(task_vec).await?;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||||
use super::FilteredData;
|
use super::FilteredDataValue;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
use tokio::sync::Mutex;
|
||||||
use futures::future::try_join_all;
|
use futures::future::try_join_all;
|
||||||
|
use super::HashMap;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum HeatMapLevel {
|
pub enum HeatMapLevel {
|
||||||
|
|
@ -28,148 +29,150 @@ pub async fn heatmap_volume(
|
||||||
high_thold: f64,
|
high_thold: f64,
|
||||||
medium_thold: f64,
|
medium_thold: f64,
|
||||||
normal_thold: f64,
|
normal_thold: f64,
|
||||||
filtered_symbols: &Vec<FilteredData>,
|
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
) -> Result<Vec<(String, Vec<HeatmapVolumeData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<HashMap<String, Vec<HeatmapVolumeData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut heatmap_data_wrapper: Vec<(String, Vec<HeatmapVolumeData>)> = Vec::new();
|
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 heatmap_data_wrapper_arc = Arc::new(Mutex::new(heatmap_data_wrapper));
|
||||||
|
|
||||||
let mut task_vec = Vec::new();
|
let mut task_vec = Vec::new();
|
||||||
for element in filtered_symbols {
|
for (symbol, filtered_data) in filtered_symbols {
|
||||||
let heatmap_data_wrapper_arc_c = Arc::clone(&heatmap_data_wrapper_arc);
|
if let Some(rt_price_vec) = input_rt_data.get(symbol) {
|
||||||
let element_c = element.clone();
|
let heatmap_data_wrapper_arc_c = Arc::clone(&heatmap_data_wrapper_arc);
|
||||||
let input_rt_data_c = input_rt_data.clone();
|
let symbol_c = symbol.clone();
|
||||||
task_vec.push(tokio::spawn(async move {
|
let rt_price_vec_c = rt_price_vec.clone();
|
||||||
let search_result = input_rt_data_c.iter().position(|x| x.0 == element_c.symbol);
|
task_vec.push(tokio::spawn(async move {
|
||||||
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
|
// calc mean
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct MeanData {
|
struct MeanData {
|
||||||
mean_value: f64,
|
mean_value: f64,
|
||||||
close_time: i64,
|
close_time: i64,
|
||||||
}
|
|
||||||
|
|
||||||
let mut mean_vec: Vec<MeanData> = Vec::new();
|
|
||||||
let mut mean_data = MeanData {
|
|
||||||
mean_value: 0.0,
|
|
||||||
close_time: 0,
|
|
||||||
};
|
|
||||||
let window = input_rt_data_c[search_result.unwrap()].1.windows(ma_len);
|
|
||||||
for buffer in window {
|
|
||||||
// calculate SMA of volume
|
|
||||||
mean_data.mean_value = 0.0;
|
|
||||||
mean_data.close_time = 0;
|
|
||||||
for element in buffer {
|
|
||||||
mean_data.mean_value += element.quote_asset_volume;
|
|
||||||
}
|
|
||||||
mean_data.mean_value /= ma_len as f64;
|
|
||||||
mean_data.close_time = buffer.last().unwrap().close_time;
|
|
||||||
|
|
||||||
mean_vec.push(mean_data.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// calc pstdev
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
struct PstdevData {
|
|
||||||
pstdev_value: f64, // population standard deviation value
|
|
||||||
close_time: i64,
|
|
||||||
}
|
|
||||||
let mut pstdev_vec: Vec<PstdevData> = Vec::new();
|
|
||||||
let mut pstdev_data = PstdevData {
|
|
||||||
pstdev_value: 0.0,
|
|
||||||
close_time: 0,
|
|
||||||
};
|
|
||||||
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);
|
|
||||||
for buffer in window {
|
|
||||||
pstdev_data.pstdev_value = 0.0;
|
|
||||||
pstdev_data.close_time = 0;
|
|
||||||
mean = 0.0;
|
|
||||||
summation = 0.0;
|
|
||||||
sample_minus_mean = 0.0;
|
|
||||||
for element in buffer {
|
|
||||||
mean += element.quote_asset_volume;
|
|
||||||
}
|
|
||||||
mean /= std_len as f64;
|
|
||||||
|
|
||||||
for element in buffer {
|
|
||||||
sample_minus_mean = element.quote_asset_volume - mean;
|
|
||||||
summation += sample_minus_mean.powi(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pstdev_data.pstdev_value = (summation / std_len as f64).sqrt();
|
let mut mean_vec: Vec<MeanData> = Vec::new();
|
||||||
pstdev_data.close_time = buffer.last().unwrap().close_time;
|
let mut mean_data = MeanData {
|
||||||
|
mean_value: 0.0,
|
||||||
pstdev_vec.push(pstdev_data.clone());
|
close_time: 0,
|
||||||
}
|
};
|
||||||
|
let window = rt_price_vec_c.windows(ma_len);
|
||||||
// calc stdbar and heatmap volume
|
for buffer in window {
|
||||||
let mut heatmap_vol_vec: Vec<HeatmapVolumeData> = Vec::new();
|
// calculate SMA of volume
|
||||||
let mut heatmap_vol_data = HeatmapVolumeData {
|
mean_data.mean_value = 0.0;
|
||||||
heatmap_value: 0.0,
|
mean_data.close_time = 0;
|
||||||
heatmap_level: HeatMapLevel::Normal,
|
for element in buffer {
|
||||||
close_time: 0,
|
mean_data.mean_value += element.quote_asset_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();
|
|
||||||
|
|
||||||
let zipped = mean_vec.iter().zip(pstdev_vec.iter());
|
|
||||||
for element in zipped {
|
|
||||||
heatmap_vol_data.heatmap_value =
|
|
||||||
(rt_data_trunc_vec.next().unwrap().quote_asset_volume
|
|
||||||
- element.0.mean_value)
|
|
||||||
/ element.1.pstdev_value;
|
|
||||||
heatmap_vol_data.close_time = element.0.close_time;
|
|
||||||
if heatmap_vol_data.heatmap_value >= extra_high_thold {
|
|
||||||
heatmap_vol_data.heatmap_level = HeatMapLevel::ExtraHigh;
|
|
||||||
} else if heatmap_vol_data.heatmap_value > high_thold {
|
|
||||||
heatmap_vol_data.heatmap_level = HeatMapLevel::High;
|
|
||||||
} else if heatmap_vol_data.heatmap_value > medium_thold {
|
|
||||||
heatmap_vol_data.heatmap_level = HeatMapLevel::Medium;
|
|
||||||
} else if heatmap_vol_data.heatmap_value > normal_thold {
|
|
||||||
heatmap_vol_data.heatmap_level = HeatMapLevel::Normal;
|
|
||||||
} else {
|
|
||||||
heatmap_vol_data.heatmap_level = HeatMapLevel::Low;
|
|
||||||
}
|
}
|
||||||
heatmap_vol_vec.push(heatmap_vol_data.clone());
|
mean_data.mean_value /= ma_len as f64;
|
||||||
|
mean_data.close_time = buffer.last().unwrap().close_time;
|
||||||
|
|
||||||
|
mean_vec.push(mean_data.clone());
|
||||||
}
|
}
|
||||||
} else if ma_len > std_len {
|
|
||||||
let mut rt_data_trunc_vec =
|
// calc pstdev
|
||||||
input_rt_data_c[search_result.unwrap()].1.get(std_len - 1..).unwrap().iter();
|
#[derive(Debug, Clone)]
|
||||||
let mut mean_trunc_vec =
|
struct PstdevData {
|
||||||
mean_vec.get(mean_vec.len() - std_len..).unwrap().iter();
|
pstdev_value: f64, // population standard deviation value
|
||||||
let zipped = mean_trunc_vec.zip(pstdev_vec.iter());
|
close_time: i64,
|
||||||
for element in zipped {
|
|
||||||
heatmap_vol_data.heatmap_value =
|
|
||||||
(rt_data_trunc_vec.next().unwrap().quote_asset_volume
|
|
||||||
- element.0.mean_value)
|
|
||||||
/ element.1.pstdev_value;
|
|
||||||
heatmap_vol_data.close_time = element.0.close_time;
|
|
||||||
heatmap_vol_vec.push(heatmap_vol_data.clone());
|
|
||||||
}
|
}
|
||||||
} else {
|
let mut pstdev_vec: Vec<PstdevData> = Vec::new();
|
||||||
let mut rt_data_trunc_vec =
|
let mut pstdev_data = PstdevData {
|
||||||
input_rt_data_c[search_result.unwrap()].1.get(ma_len - 1..).unwrap().iter();
|
pstdev_value: 0.0,
|
||||||
let mut pstdev_trunc_vec =
|
close_time: 0,
|
||||||
pstdev_vec.get(pstdev_vec.len() - ma_len..).unwrap().iter();
|
};
|
||||||
let zipped = mean_vec.iter().zip(pstdev_trunc_vec);
|
let mut mean = 0.0;
|
||||||
for element in zipped {
|
let mut summation = 0.0;
|
||||||
heatmap_vol_data.heatmap_value =
|
let mut sample_minus_mean = 0.0;
|
||||||
(rt_data_trunc_vec.next().unwrap().quote_asset_volume
|
let window = rt_price_vec_c.windows(std_len);
|
||||||
- element.0.mean_value)
|
for buffer in window {
|
||||||
/ element.1.pstdev_value;
|
pstdev_data.pstdev_value = 0.0;
|
||||||
heatmap_vol_data.close_time = element.0.close_time;
|
pstdev_data.close_time = 0;
|
||||||
heatmap_vol_vec.push(heatmap_vol_data.clone());
|
mean = 0.0;
|
||||||
} // level 구현
|
summation = 0.0;
|
||||||
|
sample_minus_mean = 0.0;
|
||||||
|
for element in buffer {
|
||||||
|
mean += element.quote_asset_volume;
|
||||||
|
}
|
||||||
|
mean /= std_len as f64;
|
||||||
|
|
||||||
|
for element in buffer {
|
||||||
|
sample_minus_mean = element.quote_asset_volume - mean;
|
||||||
|
summation += sample_minus_mean.powi(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
pstdev_data.pstdev_value = (summation / std_len as f64).sqrt();
|
||||||
|
pstdev_data.close_time = buffer.last().unwrap().close_time;
|
||||||
|
|
||||||
|
pstdev_vec.push(pstdev_data.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
// calc stdbar and heatmap volume
|
||||||
|
let mut heatmap_vol_vec: Vec<HeatmapVolumeData> = Vec::new();
|
||||||
|
let mut heatmap_vol_data = HeatmapVolumeData {
|
||||||
|
heatmap_value: 0.0,
|
||||||
|
heatmap_level: HeatMapLevel::Normal,
|
||||||
|
close_time: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
if ma_len == std_len {
|
||||||
|
let mut rt_data_trunc_vec =
|
||||||
|
rt_price_vec_c.get(ma_len - 1..).unwrap().iter();
|
||||||
|
|
||||||
|
let zipped = mean_vec.iter().zip(pstdev_vec.iter());
|
||||||
|
for element in zipped {
|
||||||
|
heatmap_vol_data.heatmap_value =
|
||||||
|
(rt_data_trunc_vec.next().unwrap().quote_asset_volume
|
||||||
|
- element.0.mean_value)
|
||||||
|
/ element.1.pstdev_value;
|
||||||
|
heatmap_vol_data.close_time = element.0.close_time;
|
||||||
|
if heatmap_vol_data.heatmap_value >= extra_high_thold {
|
||||||
|
heatmap_vol_data.heatmap_level = HeatMapLevel::ExtraHigh;
|
||||||
|
} else if heatmap_vol_data.heatmap_value > high_thold {
|
||||||
|
heatmap_vol_data.heatmap_level = HeatMapLevel::High;
|
||||||
|
} else if heatmap_vol_data.heatmap_value > medium_thold {
|
||||||
|
heatmap_vol_data.heatmap_level = HeatMapLevel::Medium;
|
||||||
|
} else if heatmap_vol_data.heatmap_value > normal_thold {
|
||||||
|
heatmap_vol_data.heatmap_level = HeatMapLevel::Normal;
|
||||||
|
} else {
|
||||||
|
heatmap_vol_data.heatmap_level = HeatMapLevel::Low;
|
||||||
|
}
|
||||||
|
heatmap_vol_vec.push(heatmap_vol_data.clone());
|
||||||
|
}
|
||||||
|
} else if ma_len > std_len {
|
||||||
|
let mut rt_data_trunc_vec =
|
||||||
|
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());
|
||||||
|
for element in zipped {
|
||||||
|
heatmap_vol_data.heatmap_value =
|
||||||
|
(rt_data_trunc_vec.next().unwrap().quote_asset_volume
|
||||||
|
- element.0.mean_value)
|
||||||
|
/ element.1.pstdev_value;
|
||||||
|
heatmap_vol_data.close_time = element.0.close_time;
|
||||||
|
heatmap_vol_vec.push(heatmap_vol_data.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let mut rt_data_trunc_vec =
|
||||||
|
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);
|
||||||
|
for element in zipped {
|
||||||
|
heatmap_vol_data.heatmap_value =
|
||||||
|
(rt_data_trunc_vec.next().unwrap().quote_asset_volume
|
||||||
|
- element.0.mean_value)
|
||||||
|
/ element.1.pstdev_value;
|
||||||
|
heatmap_vol_data.close_time = element.0.close_time;
|
||||||
|
heatmap_vol_vec.push(heatmap_vol_data.clone());
|
||||||
|
} // level 구현
|
||||||
|
}
|
||||||
|
let mut heatmap_data_wrapper_lock = heatmap_data_wrapper_arc_c.lock().await;
|
||||||
|
heatmap_data_wrapper_lock.insert(symbol_c, heatmap_vol_vec.clone());
|
||||||
}
|
}
|
||||||
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()));
|
}
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
try_join_all(task_vec).await?;
|
try_join_all(task_vec).await?;
|
||||||
let a = heatmap_data_wrapper_arc.lock().await.to_owned();
|
let a = heatmap_data_wrapper_arc.lock().await.to_owned();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::value_estimation_team::indicators::ema::{EmaData, ema};
|
use crate::value_estimation_team::indicators::ema::{EmaData, ema};
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||||
use super::FilteredData;
|
use super::{FilteredDataValue, HashMap};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||||
use futures::future::try_join_all;
|
use futures::future::try_join_all;
|
||||||
|
|
@ -43,116 +43,114 @@ pub async fn ema_macd(
|
||||||
fast_len: usize,
|
fast_len: usize,
|
||||||
slow_len: usize,
|
slow_len: usize,
|
||||||
signal_smoothing: usize,
|
signal_smoothing: usize,
|
||||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
filtered_symbols: &Vec<FilteredData>
|
filtered_symbols: &HashMap<String, FilteredDataValue>
|
||||||
) -> Result<Vec<(String, Vec<MacdData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<HashMap<String, Vec<MacdData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut macd_oscil_vec: Vec<(String, Vec<MacdData>)> = Vec::new();
|
let mut macd_oscil_vec: HashMap<String, Vec<MacdData>> = HashMap::new();
|
||||||
|
|
||||||
let fast_emas = ema(fast_len, input_rt_data, filtered_symbols).await?;
|
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 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 macd_data_wrapper_arc = Arc::new(Mutex::new(macd_data_wrapper));
|
||||||
let mut task_vec = Vec::new();
|
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 fast_emas_c = fast_emas.clone();
|
||||||
let slow_emas_c = slow_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 macd_data_wrapper_arc_c = Arc::clone(&macd_data_wrapper_arc);
|
let symbol_c = symbol.clone();
|
||||||
task_vec.push(tokio::spawn(async move {
|
let fast_ema_vec_c = fast_ema_vec.clone();
|
||||||
let fast_search_result = fast_emas_c.iter().position(|x| x.0 == filtered_elem_c.symbol);
|
let slow_ema_vec_c = slow_ema_vec.clone();
|
||||||
let slow_search_result = slow_emas_c.iter().position(|x| x.0 == filtered_elem_c.symbol);
|
let macd_data_wrapper_arc_c = Arc::clone(&macd_data_wrapper_arc);
|
||||||
|
task_vec.push(tokio::spawn(async move {
|
||||||
|
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,
|
||||||
|
}| close_time,
|
||||||
|
);
|
||||||
|
if result.is_ok() {
|
||||||
|
// making MACD
|
||||||
|
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 {
|
||||||
|
macd.value = element.0.ema_value - element.1.ema_value;
|
||||||
|
macd.close_time = element.0.close_time;
|
||||||
|
macd_vec.push(macd.clone());
|
||||||
|
}
|
||||||
|
|
||||||
if fast_search_result.is_some_and(|a| fast_emas_c[a].1.len() >= signal_smoothing) &&
|
// making signal (smoothed MACD)
|
||||||
slow_search_result.is_some_and(|a| slow_emas_c[a].1.len() >= signal_smoothing) {
|
// TODO: this should be calculated in EMA (currently, SMA)
|
||||||
let fast_ema = fast_emas_c[fast_search_result.unwrap()].1.clone();
|
// let macd_vec_window = macd_vec.windows(signal_smoothing);
|
||||||
let slow_ema = slow_emas_c[fast_search_result.unwrap()].1.clone();
|
// let mut macd_signal_vec: Vec<TempData> = Vec::new();
|
||||||
let result = fast_ema.binary_search_by_key(
|
// for window in macd_vec_window {
|
||||||
&slow_ema.first().unwrap().close_time,
|
// let mut sum_value = 0.0;
|
||||||
|&EmaData {
|
// for element in window {
|
||||||
ema_value,
|
// sum_value += element.value;
|
||||||
close_time,
|
// }
|
||||||
}| close_time,
|
// macd.value = sum_value / signal_smoothing as f64;
|
||||||
);
|
// macd.close_time = window.last().unwrap().close_time;
|
||||||
if result.is_ok() {
|
// macd_signal_vec.push(macd.clone());
|
||||||
// making MACD
|
// }
|
||||||
let temp_vec = fast_ema.get(result.unwrap()..).unwrap();
|
let mut macd_signal = TempData::new();
|
||||||
let zipped = temp_vec.iter().zip(slow_ema);
|
let mut macd_signal_vec: Vec<TempData> = Vec::new();
|
||||||
let mut macd = TempData::new();
|
let partial_vec1 = macd_vec.get(..signal_smoothing).unwrap();
|
||||||
let mut macd_vec: Vec<TempData> = Vec::new();
|
let partial_vec2 = macd_vec.get(signal_smoothing..).unwrap();
|
||||||
for element in zipped {
|
|
||||||
macd.value = element.0.ema_value - element.1.ema_value;
|
|
||||||
macd.close_time = element.0.close_time;
|
|
||||||
macd_vec.push(macd.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
// making signal (smoothed MACD)
|
let mut sma_for_initial_value = 0.0;
|
||||||
// TODO: this should be calculated in EMA (currently, SMA)
|
for element in partial_vec1 {
|
||||||
// let macd_vec_window = macd_vec.windows(signal_smoothing);
|
sma_for_initial_value += element.value;
|
||||||
// let mut macd_signal_vec: Vec<TempData> = Vec::new();
|
}
|
||||||
// for window in macd_vec_window {
|
sma_for_initial_value /= signal_smoothing as f64;
|
||||||
// let mut sum_value = 0.0;
|
|
||||||
// for element in window {
|
|
||||||
// sum_value += element.value;
|
|
||||||
// }
|
|
||||||
// macd.value = sum_value / signal_smoothing as f64;
|
|
||||||
// macd.close_time = window.last().unwrap().close_time;
|
|
||||||
// macd_signal_vec.push(macd.clone());
|
|
||||||
// }
|
|
||||||
let mut macd_signal = TempData::new();
|
|
||||||
let mut macd_signal_vec: Vec<TempData> = Vec::new();
|
|
||||||
let partial_vec1 = macd_vec.get(..signal_smoothing).unwrap();
|
|
||||||
let partial_vec2 = macd_vec.get(signal_smoothing..).unwrap();
|
|
||||||
|
|
||||||
let mut sma_for_initial_value = 0.0;
|
macd_signal.value = sma_for_initial_value;
|
||||||
for element in partial_vec1 {
|
macd_signal.close_time = partial_vec1.last().unwrap().close_time;
|
||||||
sma_for_initial_value += element.value;
|
|
||||||
}
|
|
||||||
sma_for_initial_value /= signal_smoothing as f64;
|
|
||||||
|
|
||||||
macd_signal.value = sma_for_initial_value;
|
|
||||||
macd_signal.close_time = partial_vec1.last().unwrap().close_time;
|
|
||||||
macd_signal_vec.push(macd_signal.clone());
|
|
||||||
|
|
||||||
let alpha: f64 = 2.0 / (signal_smoothing as f64 + 1.0);
|
|
||||||
let mut ema_prev = sma_for_initial_value;
|
|
||||||
for element in partial_vec2 {
|
|
||||||
let ema_t = (1.0 - alpha) * ema_prev + alpha * element.value;
|
|
||||||
|
|
||||||
macd_signal.value = ema_t;
|
|
||||||
macd_signal.close_time = element.close_time;
|
|
||||||
macd_signal_vec.push(macd_signal.clone());
|
macd_signal_vec.push(macd_signal.clone());
|
||||||
|
|
||||||
ema_prev = ema_t;
|
let alpha: f64 = 2.0 / (signal_smoothing as f64 + 1.0);
|
||||||
}
|
let mut ema_prev = sma_for_initial_value;
|
||||||
|
for element in partial_vec2 {
|
||||||
|
let ema_t = (1.0 - alpha) * ema_prev + alpha * element.value;
|
||||||
|
|
||||||
let result = macd_vec.binary_search_by_key(
|
macd_signal.value = ema_t;
|
||||||
&macd_signal_vec.first().unwrap().close_time,
|
macd_signal.close_time = element.close_time;
|
||||||
|&TempData {
|
macd_signal_vec.push(macd_signal.clone());
|
||||||
value,
|
|
||||||
close_time,
|
|
||||||
}| close_time,
|
|
||||||
);
|
|
||||||
|
|
||||||
if result.is_ok() {
|
ema_prev = ema_t;
|
||||||
let result = macd_vec.get(result.unwrap()..);
|
}
|
||||||
if result.is_some() {
|
|
||||||
let zipped = result.unwrap().iter().zip(macd_signal_vec);
|
|
||||||
|
|
||||||
let mut macd_vec: Vec<MacdData> = Vec::new();
|
let result = macd_vec.binary_search_by_key(
|
||||||
for element in zipped {
|
&macd_signal_vec.first().unwrap().close_time,
|
||||||
let mut macd = MacdData::new();
|
|&TempData {
|
||||||
macd.macd_value = element.0.value;
|
value,
|
||||||
macd.signal_value = element.1.value;
|
close_time,
|
||||||
macd.close_time = element.0.close_time;
|
}| close_time,
|
||||||
macd_vec.push(macd);
|
);
|
||||||
|
|
||||||
|
if result.is_ok() {
|
||||||
|
let result = macd_vec.get(result.unwrap()..);
|
||||||
|
if result.is_some() {
|
||||||
|
let zipped = result.unwrap().iter().zip(macd_signal_vec);
|
||||||
|
|
||||||
|
let mut macd_vec: Vec<MacdData> = Vec::new();
|
||||||
|
for element in zipped {
|
||||||
|
let mut macd = MacdData::new();
|
||||||
|
macd.macd_value = element.0.value;
|
||||||
|
macd.signal_value = element.1.value;
|
||||||
|
macd.close_time = element.0.close_time;
|
||||||
|
macd_vec.push(macd);
|
||||||
|
}
|
||||||
|
let mut macd_data_wrapper_lock = macd_data_wrapper_arc_c.lock().await;
|
||||||
|
macd_data_wrapper_lock.insert(symbol_c, macd_vec.clone());
|
||||||
}
|
}
|
||||||
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()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}));
|
||||||
}));
|
}
|
||||||
}
|
}
|
||||||
try_join_all(task_vec).await?;
|
try_join_all(task_vec).await?;
|
||||||
let a = macd_data_wrapper_arc.lock().await.to_owned();
|
let a = macd_data_wrapper_arc.lock().await.to_owned();
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,9 @@ pub mod stoch_rsi;
|
||||||
pub mod supertrend;
|
pub mod supertrend;
|
||||||
pub mod tema;
|
pub mod tema;
|
||||||
|
|
||||||
use crate::strategy_team::FilteredData;
|
use crate::strategy_team::FilteredDataValue;
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||||
use futures::future::try_join_all;
|
use futures::future::try_join_all;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@
|
||||||
|
|
||||||
use crate::database_control::*;
|
use crate::database_control::*;
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
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 futures::future::try_join_all;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
use std::f64::NAN;
|
use std::f64::NAN;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||||
|
use super::HashMap;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RsiData {
|
pub struct RsiData {
|
||||||
|
|
@ -29,21 +30,20 @@ impl RsiData {
|
||||||
// Binance RSI (EMA, Closeprice, Wilder's weight, 150 candles)
|
// Binance RSI (EMA, Closeprice, Wilder's weight, 150 candles)
|
||||||
pub async fn rsi(
|
pub async fn rsi(
|
||||||
rsi_number: usize,
|
rsi_number: usize,
|
||||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
filtered_symbols: &Vec<FilteredData>,
|
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||||
) -> Result<Vec<(String, Vec<RsiData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<HashMap<String, Vec<RsiData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let instant = Instant::now();
|
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 rsi_data_wrapper_arc = Arc::new(Mutex::new(rsi_data_wrapper));
|
||||||
|
|
||||||
let mut task_vec = Vec::new();
|
let mut task_vec = Vec::new();
|
||||||
for element in filtered_symbols {
|
for (symbol, filtered_data) in filtered_symbols {
|
||||||
let element_c = element.clone();
|
if let Some(rt_price_vec) = input_rt_data.get(symbol) {
|
||||||
let rsi_data_wrapper_arc_c = Arc::clone(&rsi_data_wrapper_arc);
|
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);
|
let symbol_c = symbol.clone();
|
||||||
if search_result.is_some() {
|
let mut input_rt_data_c = rt_price_vec.clone();
|
||||||
let input_rt_data_c = input_rt_data.clone();
|
|
||||||
task_vec.push(tokio::spawn(async move {
|
task_vec.push(tokio::spawn(async move {
|
||||||
let mut rsi_data_vec: Vec<RsiData> = Vec::new();
|
let mut rsi_data_vec: Vec<RsiData> = Vec::new();
|
||||||
let mut rsi_data = RsiData::new();
|
let mut rsi_data = RsiData::new();
|
||||||
|
|
@ -56,18 +56,17 @@ pub async fn rsi(
|
||||||
let mut rsi: f64 = 0.0;
|
let mut rsi: f64 = 0.0;
|
||||||
let mut last_close_time = 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.rsi_value = 0.0;
|
||||||
rsi_data.close_time = 0;
|
rsi_data.close_time = 0;
|
||||||
rsi_data_vec.push(rsi_data.clone());
|
rsi_data_vec.push(rsi_data.clone());
|
||||||
} else {
|
} else {
|
||||||
read_data_vec = input_rt_data_c[search_result.unwrap()].1.clone();
|
if input_rt_data_c.len() >= (150 + rsi_number) as usize {
|
||||||
if read_data_vec.len() >= (150 + rsi_number) as usize {
|
input_rt_data_c.reverse();
|
||||||
read_data_vec.reverse();
|
input_rt_data_c.truncate((150 + rsi_number) as usize);
|
||||||
read_data_vec.truncate((150 + rsi_number) as usize);
|
input_rt_data_c.reverse();
|
||||||
read_data_vec.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_ups: Option<f64> = None;
|
||||||
let mut prev_avg_downs: 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());
|
rsi_data_vec.push(rsi_data.clone());
|
||||||
}
|
}
|
||||||
let mut rsi_data_wrapper_lock = rsi_data_wrapper_arc_c.lock().await;
|
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::database_control::*;
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
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 futures::future::try_join_all;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||||
|
use super::HashMap;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SmaData {
|
pub struct SmaData {
|
||||||
|
|
@ -28,29 +29,28 @@ impl SmaData {
|
||||||
// Binance MA (closeprice)
|
// Binance MA (closeprice)
|
||||||
pub async fn sma(
|
pub async fn sma(
|
||||||
moving_number: usize,
|
moving_number: usize,
|
||||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
filtered_symbols: &Vec<FilteredData>,
|
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||||
) -> Result<Vec<(String, Vec<SmaData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<HashMap<String, Vec<SmaData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
if filtered_symbols.is_empty() {
|
if filtered_symbols.is_empty() {
|
||||||
Err("Err")?;
|
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 sma_data_wrapper_arc = Arc::new(Mutex::new(sma_data_wrapper));
|
||||||
|
|
||||||
let mut task_vec = Vec::new();
|
let mut task_vec = Vec::new();
|
||||||
for filtered_symbol in filtered_symbols {
|
for (symbol, filtered_data) in filtered_symbols {
|
||||||
let filtered_symbol_c = filtered_symbol.clone();
|
if let Some(vec) = input_rt_data.get(symbol) {
|
||||||
let sma_data_wrapper_arc_c = Arc::clone(&sma_data_wrapper_arc);
|
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();
|
||||||
task_vec.push(tokio::spawn(async move {
|
let rt_price_data = vec.clone();
|
||||||
let search_result = input_rt_data_c.iter().position(|x| x.0 == *filtered_symbol_c.symbol);
|
task_vec.push(tokio::spawn(async move {
|
||||||
if search_result.is_some() {
|
|
||||||
let mut sma_data = SmaData::new();
|
let mut sma_data = SmaData::new();
|
||||||
let mut sma_data_vec: Vec<SmaData> = Vec::new();
|
let mut sma_data_vec: Vec<SmaData> = Vec::new();
|
||||||
|
|
||||||
if input_rt_data_c[search_result.unwrap()].1.len() >= moving_number {
|
if rt_price_data.len() >= moving_number {
|
||||||
let mut iter = input_rt_data_c[search_result.unwrap()].1.windows(moving_number);
|
let mut iter = rt_price_data.windows(moving_number);
|
||||||
for buffer in iter {
|
for buffer in iter {
|
||||||
let mut avg = 0.0;
|
let mut avg = 0.0;
|
||||||
for element in buffer {
|
for element in buffer {
|
||||||
|
|
@ -64,9 +64,9 @@ pub async fn sma(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut sma_data_wrapper_lock = sma_data_wrapper_arc_c.lock().await;
|
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?;
|
try_join_all(task_vec).await?;
|
||||||
let a = sma_data_wrapper_arc.lock().await.to_owned();
|
let a = sma_data_wrapper_arc.lock().await.to_owned();
|
||||||
|
|
@ -76,29 +76,28 @@ pub async fn sma(
|
||||||
// Binance MA ((open+close)/2)
|
// Binance MA ((open+close)/2)
|
||||||
pub async fn sma_opclo(
|
pub async fn sma_opclo(
|
||||||
moving_number: usize,
|
moving_number: usize,
|
||||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
filtered_symbols: &Vec<FilteredData>,
|
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||||
) -> Result<Vec<(String, Vec<SmaData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<HashMap<String, Vec<SmaData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
if filtered_symbols.is_empty() {
|
if filtered_symbols.is_empty() {
|
||||||
Err("Err")?;
|
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 sma_data_wrapper_arc = Arc::new(Mutex::new(sma_data_wrapper));
|
||||||
|
|
||||||
let mut task_vec = Vec::new();
|
let mut task_vec = Vec::new();
|
||||||
for filtered_symbol in filtered_symbols {
|
for (symbol, filtered_data) in filtered_symbols {
|
||||||
let filtered_symbol_c = filtered_symbol.clone();
|
if let Some(vec) = input_rt_data.get(symbol) {
|
||||||
let sma_data_wrapper_arc_c = Arc::clone(&sma_data_wrapper_arc);
|
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();
|
||||||
task_vec.push(tokio::spawn(async move {
|
let rt_price_data = vec.clone();
|
||||||
let search_result = input_rt_data_c.iter().position(|x| x.0 == *filtered_symbol_c.symbol);
|
task_vec.push(tokio::spawn(async move {
|
||||||
if search_result.is_some() {
|
|
||||||
let mut sma_data = SmaData::new();
|
let mut sma_data = SmaData::new();
|
||||||
let mut sma_data_vec: Vec<SmaData> = Vec::new();
|
let mut sma_data_vec: Vec<SmaData> = Vec::new();
|
||||||
|
|
||||||
if input_rt_data_c[search_result.unwrap()].1.len() >= moving_number {
|
if rt_price_data.len() >= moving_number {
|
||||||
let mut iter = input_rt_data_c[search_result.unwrap()].1.windows(moving_number);
|
let mut iter = rt_price_data.windows(moving_number);
|
||||||
for buffer in iter {
|
for buffer in iter {
|
||||||
let mut avg = 0.0;
|
let mut avg = 0.0;
|
||||||
for element in buffer {
|
for element in buffer {
|
||||||
|
|
@ -112,9 +111,9 @@ pub async fn sma_opclo(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut sma_data_wrapper_lock = sma_data_wrapper_arc_c.lock().await;
|
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?;
|
try_join_all(task_vec).await?;
|
||||||
let a = sma_data_wrapper_arc.lock().await.to_owned();
|
let a = sma_data_wrapper_arc.lock().await.to_owned();
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,14 @@
|
||||||
use crate::database_control::*;
|
use crate::database_control::*;
|
||||||
use crate::value_estimation_team::indicators::rsi::{RsiData, rsi};
|
use crate::value_estimation_team::indicators::rsi::{RsiData, rsi};
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
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 futures::{future::try_join_all, lock::Mutex};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
use std::f64::NAN;
|
use std::f64::NAN;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::{fs::*, io::AsyncWriteExt, time::*};
|
use tokio::{fs::*, io::AsyncWriteExt, time::*};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct StochRsiData {
|
pub struct StochRsiData {
|
||||||
|
|
@ -50,39 +51,31 @@ pub async fn stoch_rsi(
|
||||||
stoch_rsi_length: usize,
|
stoch_rsi_length: usize,
|
||||||
smooth_k: usize,
|
smooth_k: usize,
|
||||||
smooth_d: usize,
|
smooth_d: usize,
|
||||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
filtered_symbols: &Vec<FilteredData>
|
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||||
) -> Result<Vec<(String, Vec<StochRsiData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
) -> Result<HashMap<String, Vec<StochRsiData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let mut stoch_rsi_data_wrapper: Vec<(String, Vec<StochRsiData>)> = Vec::new();
|
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_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 {
|
let rsi_data_map = rsi(rsi_length, input_rt_data, filtered_symbols).await?;
|
||||||
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 mut task_vec = Vec::new();
|
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_data = StochRsiData::new();
|
||||||
let mut stoch_rsi_k_data = StochRsiKData::new();
|
let mut stoch_rsi_k_data = StochRsiKData::new();
|
||||||
let stoch_rsi_data_wrapper_arc_c = Arc::clone(&stoch_rsi_data_wrapper_arc);
|
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 {
|
task_vec.push(tokio::spawn(async move {
|
||||||
let mut stoch_rsi_data_vec: Vec<StochRsiData> = Vec::new();
|
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_k_data_vec: Vec<StochRsiKData> = Vec::new();
|
||||||
let mut stoch_rsi_vec: Vec<RsiData> = Vec::new();
|
let mut stoch_rsi_vec: Vec<RsiData> = Vec::new();
|
||||||
let mut stoch_rsi = RsiData::new();
|
let mut stoch_rsi = RsiData::new();
|
||||||
|
|
||||||
if element_c.1.len() >= stoch_rsi_length
|
if rsi_vec.len() >= stoch_rsi_length
|
||||||
&& element_c.1.len() >= smooth_k
|
&& rsi_vec.len() >= smooth_k
|
||||||
&& element_c.1.len() >= smooth_d
|
&& rsi_vec.len() >= smooth_d
|
||||||
{
|
{
|
||||||
let mut read_data_vec = element_c.1;
|
let window_iter = rsi_vec.windows(stoch_rsi_length);
|
||||||
let window_iter = read_data_vec.windows(stoch_rsi_length);
|
|
||||||
|
|
||||||
for buffer_window in window_iter {
|
for buffer_window in window_iter {
|
||||||
let max_value = buffer_window
|
let max_value = buffer_window
|
||||||
|
|
@ -131,7 +124,7 @@ pub async fn stoch_rsi(
|
||||||
stoch_rsi_data_vec.push(stoch_rsi_data.clone());
|
stoch_rsi_data_vec.push(stoch_rsi_data.clone());
|
||||||
}
|
}
|
||||||
let mut stoch_rsi_data_wrapper_lock = stoch_rsi_data_wrapper_arc_c.lock().await;
|
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 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)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SupertrendData {
|
pub struct SupertrendData {
|
||||||
pub band_value: f64,
|
pub band_value: f64,
|
||||||
pub signal: Option<String>, // BUY or SELL
|
pub signal: Option<SuperTrendSignal>, // BUY or SELL
|
||||||
pub area: String, // UP or DOWN
|
pub area: SuperTrendArea, // UP or DOWN
|
||||||
pub close_time: i64,
|
pub close_time: i64
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SupertrendData {
|
impl SupertrendData {
|
||||||
|
|
@ -13,8 +23,8 @@ impl SupertrendData {
|
||||||
let a = SupertrendData {
|
let a = SupertrendData {
|
||||||
band_value: 0.0,
|
band_value: 0.0,
|
||||||
signal: None,
|
signal: None,
|
||||||
area: String::new(),
|
area: SuperTrendArea::DOWN,
|
||||||
close_time: 0,
|
close_time: 0
|
||||||
};
|
};
|
||||||
|
|
||||||
a
|
a
|
||||||
|
|
@ -55,184 +65,193 @@ impl ATRData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: should return type be Option?
|
||||||
// Implementation from TradingView Script (SuperTrend by KivancOzbilgic, source price: closeprice)
|
// Implementation from TradingView Script (SuperTrend by KivancOzbilgic, source price: closeprice)
|
||||||
|
// return key: close_time
|
||||||
pub async fn supertrend(
|
pub async fn supertrend(
|
||||||
symbol: &String,
|
|
||||||
input_rt_data: &Vec<(String, Vec<RealtimePriceData>)>,
|
|
||||||
atr_period: usize,
|
atr_period: usize,
|
||||||
multiplier: f64,
|
multiplier: f64,
|
||||||
is_original_method: bool,
|
is_original_method: bool,
|
||||||
) -> Option<Vec<SupertrendData>> {
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
let symbol_search_result = input_rt_data.iter().position(|x| x.0 == *symbol);
|
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 {
|
let mut task_vec = Vec::new();
|
||||||
Some(T) => {
|
for (symbol, filtered_data) in filtered_symbols {
|
||||||
if input_rt_data[T].1.len() >= atr_period && atr_period >= 2 {
|
if let Some(rt_price_vec) = input_rt_data.get(symbol) {
|
||||||
// making True Range
|
if atr_period < rt_price_vec.len()-1 {
|
||||||
let mut true_range_vec: Vec<TrueRangeData> = Vec::new();
|
let symbol_c = symbol.clone();
|
||||||
let mut tr_data = TrueRangeData::new();
|
let supertrend_data_wrapper_arc_c = Arc::clone(&supertrend_data_wrapper_arc);
|
||||||
let mut tr_val_hl = 0.0; // High - Low
|
let rt_price_vec_c = rt_price_vec.clone();
|
||||||
let mut tr_val_hcp = 0.0; // Abs(High - Close_previous)
|
task_vec.push(tokio::spawn(async move {
|
||||||
let mut tr_val_lcp = 0.0; // Abs(Low - Close_previous)
|
// making True Range
|
||||||
|
let mut true_range_vec: Vec<TrueRangeData> = Vec::new();
|
||||||
|
let mut tr_data = TrueRangeData::new();
|
||||||
|
let mut tr_val_hl = 0.0; // High - Low
|
||||||
|
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;
|
|
||||||
true_range_vec.push(tr_data.clone());
|
|
||||||
|
|
||||||
for buffer in window_vec {
|
|
||||||
tr_val_hl = buffer[1].high_price - buffer[1].low_price;
|
|
||||||
tr_val_hcp = (buffer[1].high_price - buffer[0].close_price).abs();
|
|
||||||
tr_val_lcp = (buffer[1].low_price - buffer[0].close_price).abs();
|
|
||||||
|
|
||||||
tr_data.tr_value = tr_val_hl.max(tr_val_hcp.max(tr_val_lcp));
|
|
||||||
tr_data.close_time = buffer[1].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());
|
true_range_vec.push(tr_data.clone());
|
||||||
}
|
|
||||||
|
|
||||||
// making Average True Range
|
for buffer in window_vec {
|
||||||
let mut average_true_range_vec: Vec<ATRData> = Vec::new();
|
tr_val_hl = buffer[1].high_price - buffer[1].low_price;
|
||||||
let mut atr_data = ATRData::new();
|
tr_val_hcp = (buffer[1].high_price - buffer[0].close_price).abs();
|
||||||
|
tr_val_lcp = (buffer[1].low_price - buffer[0].close_price).abs();
|
||||||
|
|
||||||
if is_original_method == true {
|
tr_data.tr_value = tr_val_hl.max(tr_val_hcp.max(tr_val_lcp));
|
||||||
// original calculation of ATR
|
tr_data.close_time = buffer[1].close_time;
|
||||||
let mut first_value = 0.0;
|
|
||||||
let mut first_vec = &true_range_vec[0..atr_period];
|
|
||||||
|
|
||||||
for element in first_vec {
|
true_range_vec.push(tr_data.clone());
|
||||||
first_value += element.tr_value;
|
|
||||||
}
|
}
|
||||||
first_value /= (atr_period) as f64;
|
|
||||||
atr_data.atr_value = first_value;
|
|
||||||
atr_data.close_time = first_vec.last().unwrap().close_time;
|
|
||||||
average_true_range_vec.push(atr_data.clone());
|
|
||||||
|
|
||||||
let mut temp_prev_atr_value = first_value;
|
// making Average True Range
|
||||||
for element in &true_range_vec[atr_period..] {
|
let mut average_true_range_vec: Vec<ATRData> = Vec::new();
|
||||||
atr_data.atr_value = ((temp_prev_atr_value * ((atr_period - 1) as f64))
|
let mut atr_data = ATRData::new();
|
||||||
+ element.tr_value)
|
|
||||||
/ atr_period as f64;
|
|
||||||
atr_data.close_time = element.close_time;
|
|
||||||
|
|
||||||
|
if is_original_method == true {
|
||||||
|
// original calculation of ATR
|
||||||
|
let mut first_value = 0.0;
|
||||||
|
let mut first_vec = &true_range_vec[0..atr_period];
|
||||||
|
|
||||||
|
for element in first_vec {
|
||||||
|
first_value += element.tr_value;
|
||||||
|
}
|
||||||
|
first_value /= (atr_period) as f64;
|
||||||
|
atr_data.atr_value = first_value;
|
||||||
|
atr_data.close_time = first_vec.last().unwrap().close_time;
|
||||||
average_true_range_vec.push(atr_data.clone());
|
average_true_range_vec.push(atr_data.clone());
|
||||||
temp_prev_atr_value = atr_data.atr_value;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Calculation of ATR from SMA True Range with atr_period
|
|
||||||
let window = true_range_vec.windows(atr_period);
|
|
||||||
|
|
||||||
let mut sum = 0.0;
|
let mut temp_prev_atr_value = first_value;
|
||||||
for buffer in window {
|
for element in &true_range_vec[atr_period..] {
|
||||||
for element in buffer {
|
atr_data.atr_value = ((temp_prev_atr_value * ((atr_period - 1) as f64))
|
||||||
sum += element.tr_value;
|
+ element.tr_value)
|
||||||
|
/ atr_period as f64;
|
||||||
|
atr_data.close_time = element.close_time;
|
||||||
|
|
||||||
|
average_true_range_vec.push(atr_data.clone());
|
||||||
|
temp_prev_atr_value = atr_data.atr_value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Calculation of ATR from SMA True Range with atr_period
|
||||||
|
let window = true_range_vec.windows(atr_period);
|
||||||
|
|
||||||
|
let mut sum = 0.0;
|
||||||
|
for buffer in window {
|
||||||
|
for element in buffer {
|
||||||
|
sum += element.tr_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
atr_data.atr_value = sum / atr_period as f64;
|
||||||
|
atr_data.close_time = buffer.last().unwrap().close_time;
|
||||||
|
average_true_range_vec.push(atr_data.clone());
|
||||||
|
|
||||||
|
sum = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// making Supertrend
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct BandData {
|
||||||
|
basic_upperband: f64,
|
||||||
|
basic_lowerband: f64,
|
||||||
|
close_time: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
||||||
|
let mut supertrend_data = SupertrendData::new();
|
||||||
|
let mut band_vec: Vec<BandData> = Vec::new();
|
||||||
|
let mut band_data = BandData {
|
||||||
|
basic_upperband: 0.0,
|
||||||
|
basic_lowerband: 0.0,
|
||||||
|
close_time: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
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 = &rt_price_vec_c[closetime_search_result.unwrap()..];
|
||||||
|
let zipped = rt_data.iter().zip(average_true_range_vec);
|
||||||
|
|
||||||
|
for element in zipped {
|
||||||
|
band_data.basic_upperband = ((element.0.high_price + element.0.low_price)
|
||||||
|
/ 2.0)
|
||||||
|
- (multiplier * element.1.atr_value);
|
||||||
|
band_data.basic_lowerband = ((element.0.high_price + element.0.low_price)
|
||||||
|
/ 2.0)
|
||||||
|
+ (multiplier * element.1.atr_value);
|
||||||
|
band_data.close_time = element.1.close_time;
|
||||||
|
band_vec.push(band_data.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut zipped = rt_data.iter().zip(band_vec);
|
||||||
|
let first_element = zipped.next().unwrap();
|
||||||
|
let mut prev_close_price = first_element.0.close_price;
|
||||||
|
let mut final_upperband = 0.0;
|
||||||
|
let mut final_lowerband = 0.0;
|
||||||
|
let mut prev_final_upperband = first_element.1.basic_upperband;
|
||||||
|
let mut prev_final_lowerband = first_element.1.basic_lowerband;
|
||||||
|
let mut trend = 1; // 1 means up trend, -1 means down trend
|
||||||
|
let mut prev_trend = 1;
|
||||||
|
for element in zipped {
|
||||||
|
// set final upperband
|
||||||
|
if prev_close_price > prev_final_upperband {
|
||||||
|
final_upperband = prev_final_upperband.max(element.1.basic_upperband);
|
||||||
|
} else {
|
||||||
|
final_upperband = element.1.basic_upperband;
|
||||||
}
|
}
|
||||||
|
|
||||||
atr_data.atr_value = sum / atr_period as f64;
|
// set final lowerband
|
||||||
atr_data.close_time = buffer.last().unwrap().close_time;
|
if prev_close_price < prev_final_lowerband {
|
||||||
average_true_range_vec.push(atr_data.clone());
|
final_lowerband = prev_final_lowerband.min(element.1.basic_lowerband);
|
||||||
|
} else {
|
||||||
|
final_lowerband = element.1.basic_lowerband;
|
||||||
|
}
|
||||||
|
|
||||||
sum = 0.0;
|
// set supertrend
|
||||||
|
if trend == -1 && element.0.close_price > prev_final_lowerband {
|
||||||
|
supertrend_data.area = SuperTrendArea::UP;
|
||||||
|
trend = 1;
|
||||||
|
} else if trend == 1 && element.0.close_price < prev_final_upperband {
|
||||||
|
supertrend_data.area = SuperTrendArea::DOWN;
|
||||||
|
trend = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(SuperTrendSignal::BUY);
|
||||||
|
} else if trend == -1 && prev_trend == 1 {
|
||||||
|
supertrend_data.signal = Some(SuperTrendSignal::SELL);
|
||||||
|
} else {
|
||||||
|
supertrend_data.signal = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
supertrend_data.close_time = element.1.close_time;
|
||||||
|
supertrend_vec.push(supertrend_data.clone());
|
||||||
|
|
||||||
|
prev_close_price = element.0.close_price;
|
||||||
|
prev_final_upperband = final_upperband;
|
||||||
|
prev_final_lowerband = final_lowerband;
|
||||||
|
prev_trend = trend;
|
||||||
}
|
}
|
||||||
}
|
let mut supertrend_data_wrapper_lock = supertrend_data_wrapper_arc_c.lock().await;
|
||||||
|
supertrend_data_wrapper_lock.insert(symbol_c, supertrend_vec.clone());
|
||||||
// making Supertrend
|
}));
|
||||||
#[derive(Clone)]
|
|
||||||
struct BandData {
|
|
||||||
basic_upperband: f64,
|
|
||||||
basic_lowerband: f64,
|
|
||||||
close_time: i64,
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
|
||||||
let mut supertrend_data = SupertrendData::new();
|
|
||||||
let mut band_vec: Vec<BandData> = Vec::new();
|
|
||||||
let mut band_data = BandData {
|
|
||||||
basic_upperband: 0.0,
|
|
||||||
basic_lowerband: 0.0,
|
|
||||||
close_time: 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let closetime_search_result = input_rt_data[T].1.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 zipped = rt_data.iter().zip(average_true_range_vec);
|
|
||||||
|
|
||||||
for element in zipped {
|
|
||||||
band_data.basic_upperband = ((element.0.high_price + element.0.low_price)
|
|
||||||
/ 2.0)
|
|
||||||
- (multiplier * element.1.atr_value);
|
|
||||||
band_data.basic_lowerband = ((element.0.high_price + element.0.low_price)
|
|
||||||
/ 2.0)
|
|
||||||
+ (multiplier * element.1.atr_value);
|
|
||||||
band_data.close_time = element.1.close_time;
|
|
||||||
band_vec.push(band_data.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut zipped = rt_data.iter().zip(band_vec);
|
|
||||||
let first_element = zipped.next().unwrap();
|
|
||||||
let mut prev_close_price = first_element.0.close_price;
|
|
||||||
let mut final_upperband = 0.0;
|
|
||||||
let mut final_lowerband = 0.0;
|
|
||||||
let mut prev_final_upperband = first_element.1.basic_upperband;
|
|
||||||
let mut prev_final_lowerband = first_element.1.basic_lowerband;
|
|
||||||
let mut trend = 1; // 1 means up trend, -1 means down trend
|
|
||||||
let mut prev_trend = 1;
|
|
||||||
for element in zipped {
|
|
||||||
// set final upperband
|
|
||||||
if prev_close_price > prev_final_upperband {
|
|
||||||
final_upperband = prev_final_upperband.max(element.1.basic_upperband);
|
|
||||||
} else {
|
|
||||||
final_upperband = element.1.basic_upperband;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set final lowerband
|
|
||||||
if prev_close_price < prev_final_lowerband {
|
|
||||||
final_lowerband = prev_final_lowerband.min(element.1.basic_lowerband);
|
|
||||||
} else {
|
|
||||||
final_lowerband = element.1.basic_lowerband;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set supertrend
|
|
||||||
if trend == -1 && element.0.close_price > prev_final_lowerband {
|
|
||||||
supertrend_data.area = String::from("UP");
|
|
||||||
trend = 1;
|
|
||||||
} else if trend == 1 && element.0.close_price < prev_final_upperband {
|
|
||||||
supertrend_data.area = String::from("DOWN");
|
|
||||||
trend = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if supertrend_data.area.contains("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"));
|
|
||||||
} else if trend == -1 && prev_trend == 1 {
|
|
||||||
supertrend_data.signal = Some(String::from("SELL"));
|
|
||||||
} else {
|
|
||||||
supertrend_data.signal = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
supertrend_data.close_time = element.1.close_time;
|
|
||||||
supertrend_vec.push(supertrend_data.clone());
|
|
||||||
|
|
||||||
prev_close_price = element.0.close_price;
|
|
||||||
prev_final_upperband = final_upperband;
|
|
||||||
prev_final_lowerband = final_lowerband;
|
|
||||||
prev_trend = trend;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(supertrend_vec)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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