Formatting
This commit is contained in:
parent
e85690fd41
commit
23066cf0f3
|
|
@ -6,12 +6,12 @@ use crate::database_control::*;
|
||||||
use crate::decimal_funcs::*;
|
use crate::decimal_funcs::*;
|
||||||
use crate::RunningMode::*;
|
use crate::RunningMode::*;
|
||||||
use crate::RUNNING_MODE;
|
use crate::RUNNING_MODE;
|
||||||
|
use log;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use rust_decimal::{prelude::ToPrimitive, Decimal, RoundingStrategy};
|
use rust_decimal::{prelude::ToPrimitive, Decimal, RoundingStrategy};
|
||||||
use rust_decimal_macros::dec;
|
use rust_decimal_macros::dec;
|
||||||
use serde_json::{Result, Value};
|
use serde_json::{Result, Value};
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
use log;
|
|
||||||
|
|
||||||
#[derive(Debug, FromRow)]
|
#[derive(Debug, FromRow)]
|
||||||
pub struct AchievementEvaluationInfo {
|
pub struct AchievementEvaluationInfo {
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,9 @@ 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 {
|
||||||
if exchange_info_map.contains_key(&element.symbol) && trade_fee_map.contains_key(&element.symbol) {
|
if exchange_info_map.contains_key(&element.symbol)
|
||||||
|
&& trade_fee_map.contains_key(&element.symbol)
|
||||||
|
{
|
||||||
let exchange_info = exchange_info_map.get(&element.symbol).unwrap();
|
let exchange_info = exchange_info_map.get(&element.symbol).unwrap();
|
||||||
let lot_step_size = exchange_info.stepsize;
|
let lot_step_size = exchange_info.stepsize;
|
||||||
let tick_size = exchange_info.ticksize;
|
let tick_size = exchange_info.ticksize;
|
||||||
|
|
@ -375,10 +377,15 @@ 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 {
|
||||||
if exchange_info_map.contains_key(&element.symbol) && trade_fee_map.contains_key(&element.symbol){
|
if exchange_info_map.contains_key(&element.symbol)
|
||||||
|
&& trade_fee_map.contains_key(&element.symbol)
|
||||||
|
{
|
||||||
let lot_step_size = exchange_info_map.get(&element.symbol).unwrap().stepsize;
|
let lot_step_size = exchange_info_map.get(&element.symbol).unwrap().stepsize;
|
||||||
let tick_size = exchange_info_map.get(&element.symbol).unwrap().ticksize;
|
let tick_size = exchange_info_map.get(&element.symbol).unwrap().ticksize;
|
||||||
let base_commission_precision = exchange_info_map.get(&element.symbol).unwrap().base_commission_precision;
|
let base_commission_precision = exchange_info_map
|
||||||
|
.get(&element.symbol)
|
||||||
|
.unwrap()
|
||||||
|
.base_commission_precision;
|
||||||
let trade_fee = trade_fee_map.get(&element.symbol).unwrap().takercommission;
|
let trade_fee = trade_fee_map.get(&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]
|
||||||
|
|
@ -387,8 +394,10 @@ pub async fn buy_coin_for_test(
|
||||||
// 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(
|
||||||
.round_dp_with_strategy(lot_step_size.normalize().scale(), RoundingStrategy::ToZero);
|
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)
|
||||||
|
|
@ -865,7 +874,8 @@ pub async fn update_profit_percent() {
|
||||||
profit_percent = (decimal_sub(
|
profit_percent = (decimal_sub(
|
||||||
decimal_div(element.usdt_profit, element.invested_usdt),
|
decimal_div(element.usdt_profit, element.invested_usdt),
|
||||||
dec!(1),
|
dec!(1),
|
||||||
)).round_dp(2)
|
))
|
||||||
|
.round_dp(2)
|
||||||
.to_f64()
|
.to_f64()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
* 100.0;
|
* 100.0;
|
||||||
|
|
|
||||||
|
|
@ -24,14 +24,14 @@ use crate::value_estimation_team::indicators::supertrend::{supertrend, Supertren
|
||||||
use futures::future::try_join_all;
|
use futures::future::try_join_all;
|
||||||
use hex::ToHex;
|
use hex::ToHex;
|
||||||
use hmac_sha256::HMAC;
|
use hmac_sha256::HMAC;
|
||||||
|
use log;
|
||||||
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 serde_json::Value;
|
use serde_json::Value;
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
use tokio::time::*;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use log;
|
use tokio::time::*;
|
||||||
|
|
||||||
pub enum OrderSide {
|
pub enum OrderSide {
|
||||||
Buy,
|
Buy,
|
||||||
|
|
@ -598,15 +598,23 @@ 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();
|
||||||
if coin_price_map.contains_key(&element.symbol) && exchange_info_map.contains_key(&element.symbol) && trade_fee_map.contains_key(&element.symbol) {
|
if coin_price_map.contains_key(&element.symbol)
|
||||||
price = rust_decimal::prelude::FromPrimitive::from_f64(*coin_price_map.get(&element.symbol).unwrap()).unwrap();
|
&& exchange_info_map.contains_key(&element.symbol)
|
||||||
|
&& trade_fee_map.contains_key(&element.symbol)
|
||||||
|
{
|
||||||
|
price = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||||
|
*coin_price_map.get(&element.symbol).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
if !price.is_zero() {
|
if !price.is_zero() {
|
||||||
// to get quote_commission_precision
|
// to get quote_commission_precision
|
||||||
let trade_fee = trade_fee_map.get(&element.symbol).unwrap().takercommission;
|
let trade_fee = trade_fee_map.get(&element.symbol).unwrap().takercommission;
|
||||||
let lot_step_size = exchange_info_map.get(&element.symbol).unwrap().stepsize;
|
let lot_step_size = exchange_info_map.get(&element.symbol).unwrap().stepsize;
|
||||||
let quote_commission_precision = exchange_info_map.get(&element.symbol).unwrap().quote_commission_precision;
|
let quote_commission_precision = exchange_info_map
|
||||||
let base_qty_to_be_ordered =
|
.get(&element.symbol)
|
||||||
element.base_qty_fee_adjusted.round_dp_with_strategy(
|
.unwrap()
|
||||||
|
.quote_commission_precision;
|
||||||
|
let base_qty_to_be_ordered = element.base_qty_fee_adjusted.round_dp_with_strategy(
|
||||||
lot_step_size.normalize().scale(),
|
lot_step_size.normalize().scale(),
|
||||||
RoundingStrategy::ToZero,
|
RoundingStrategy::ToZero,
|
||||||
);
|
);
|
||||||
|
|
@ -705,9 +713,17 @@ pub async fn limit_order_sell(
|
||||||
let mut insert_value_container: Vec<String> = Vec::new();
|
let mut insert_value_container: Vec<String> = Vec::new();
|
||||||
unsafe {
|
unsafe {
|
||||||
if RUNNING_MODE == SIMUL && buy_ordered_coin.status == "SIMUL" {
|
if RUNNING_MODE == SIMUL && buy_ordered_coin.status == "SIMUL" {
|
||||||
if exchange_info_map.contains_key(&buy_ordered_coin.symbol) && trade_fee_map.contains_key(&buy_ordered_coin.symbol) {
|
if exchange_info_map.contains_key(&buy_ordered_coin.symbol)
|
||||||
let quote_asset_precision = exchange_info_map.get(&buy_ordered_coin.symbol).unwrap().quote_asset_precision;
|
&& trade_fee_map.contains_key(&buy_ordered_coin.symbol)
|
||||||
let trade_fee = trade_fee_map.get(&buy_ordered_coin.symbol).unwrap().takercommission;
|
{
|
||||||
|
let quote_asset_precision = exchange_info_map
|
||||||
|
.get(&buy_ordered_coin.symbol)
|
||||||
|
.unwrap()
|
||||||
|
.quote_asset_precision;
|
||||||
|
let trade_fee = trade_fee_map
|
||||||
|
.get(&buy_ordered_coin.symbol)
|
||||||
|
.unwrap()
|
||||||
|
.takercommission;
|
||||||
|
|
||||||
let get_usdt = decimal_mul(sell_base_quantity, sell_base_price)
|
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);
|
||||||
|
|
@ -735,7 +751,8 @@ pub async fn limit_order_sell(
|
||||||
dec!(1),
|
dec!(1),
|
||||||
),
|
),
|
||||||
dec!(100),
|
dec!(100),
|
||||||
).round_dp(2);
|
)
|
||||||
|
.round_dp(2);
|
||||||
insert_value_container.push(pure_profit_percent.to_string()); // pure_profit_percent
|
insert_value_container.push(pure_profit_percent.to_string()); // pure_profit_percent
|
||||||
insert_value_container.push(buy_ordered_coin.maximum_profit_percent.to_string()); // maximum_profit_percent
|
insert_value_container.push(buy_ordered_coin.maximum_profit_percent.to_string()); // maximum_profit_percent
|
||||||
insert_value_container.push(buy_ordered_coin.registerer.to_string()); // registerer
|
insert_value_container.push(buy_ordered_coin.registerer.to_string()); // registerer
|
||||||
|
|
@ -811,9 +828,17 @@ 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
|
||||||
|
|
||||||
if exchange_info_map.contains_key(&buy_ordered_coin.symbol) && trade_fee_map.contains_key(&buy_ordered_coin.symbol) {
|
if exchange_info_map.contains_key(&buy_ordered_coin.symbol)
|
||||||
let quote_asset_precision = exchange_info_map.get(&buy_ordered_coin.symbol).unwrap().quote_asset_precision;
|
&& trade_fee_map.contains_key(&buy_ordered_coin.symbol)
|
||||||
let trade_fee = trade_fee_map.get(&buy_ordered_coin.symbol).unwrap().takercommission;
|
{
|
||||||
|
let quote_asset_precision = exchange_info_map
|
||||||
|
.get(&buy_ordered_coin.symbol)
|
||||||
|
.unwrap()
|
||||||
|
.quote_asset_precision;
|
||||||
|
let trade_fee = trade_fee_map
|
||||||
|
.get(&buy_ordered_coin.symbol)
|
||||||
|
.unwrap()
|
||||||
|
.takercommission;
|
||||||
let get_usdt = rust_decimal::prelude::FromStr::from_str(
|
let get_usdt = rust_decimal::prelude::FromStr::from_str(
|
||||||
T.get("cummulativeQuoteQty").unwrap().as_str().unwrap(),
|
T.get("cummulativeQuoteQty").unwrap().as_str().unwrap(),
|
||||||
)
|
)
|
||||||
|
|
@ -859,11 +884,15 @@ pub async fn limit_order_sell(
|
||||||
if T.get("status").unwrap().as_str().unwrap() == "FILLED" {
|
if T.get("status").unwrap().as_str().unwrap() == "FILLED" {
|
||||||
let pure_profit_percent = decimal_mul(
|
let pure_profit_percent = decimal_mul(
|
||||||
decimal_sub(
|
decimal_sub(
|
||||||
decimal_div(get_usdt_fee_adjusted, buy_ordered_coin.used_usdt),
|
decimal_div(
|
||||||
|
get_usdt_fee_adjusted,
|
||||||
|
buy_ordered_coin.used_usdt,
|
||||||
|
),
|
||||||
dec!(1),
|
dec!(1),
|
||||||
),
|
),
|
||||||
dec!(100),
|
dec!(100),
|
||||||
).round_dp(2);
|
)
|
||||||
|
.round_dp(2);
|
||||||
insert_value_container
|
insert_value_container
|
||||||
.push(buy_ordered_coin.pure_profit_percent.to_string());
|
.push(buy_ordered_coin.pure_profit_percent.to_string());
|
||||||
// pure_profit_percent
|
// pure_profit_percent
|
||||||
|
|
@ -876,7 +905,8 @@ pub async fn limit_order_sell(
|
||||||
insert_value_container.push(buy_ordered_coin.is_long.to_string()); // is_long
|
insert_value_container.push(buy_ordered_coin.is_long.to_string()); // is_long
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
// delete record in buy_ordered_coin_list
|
// delete record in buy_ordered_coin_list
|
||||||
let delete_table_name = String::from("buy_ordered_coin_list");
|
let delete_table_name = String::from("buy_ordered_coin_list");
|
||||||
|
|
@ -962,7 +992,9 @@ pub async fn monitoring_filled_sell_order(
|
||||||
for element in filled_sell_orders {
|
for element in filled_sell_orders {
|
||||||
// build insert value
|
// build insert value
|
||||||
let pure_profit_usdt = decimal_sub(element.get_usdt_fee_adjusted, element.used_usdt);
|
let pure_profit_usdt = decimal_sub(element.get_usdt_fee_adjusted, element.used_usdt);
|
||||||
let pure_profit_percent = decimal_mul(decimal_div(pure_profit_usdt, element.used_usdt), dec!(100)).round_dp(2);
|
let pure_profit_percent =
|
||||||
|
decimal_mul(decimal_div(pure_profit_usdt, element.used_usdt), dec!(100))
|
||||||
|
.round_dp(2);
|
||||||
insert_value_build.clear();
|
insert_value_build.clear();
|
||||||
insert_value_build.push(element.symbol.clone()); // symbol
|
insert_value_build.push(element.symbol.clone()); // symbol
|
||||||
insert_value_build.push(server_epoch.to_string()); // soldtime
|
insert_value_build.push(server_epoch.to_string()); // soldtime
|
||||||
|
|
@ -1164,7 +1196,8 @@ pub async fn cancel_buy_order(
|
||||||
|
|
||||||
// calculate values to be updated
|
// calculate values to be updated
|
||||||
if trade_fee_map.contains_key(&order.symbol) {
|
if trade_fee_map.contains_key(&order.symbol) {
|
||||||
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
let trade_fee =
|
||||||
|
trade_fee_map.get(&order.symbol).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(),
|
||||||
)
|
)
|
||||||
|
|
@ -1344,9 +1377,15 @@ 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 {
|
||||||
if exchange_info_map.contains_key(&order.symbol) && trade_fee_map.contains_key(&order.symbol) {
|
if exchange_info_map.contains_key(&order.symbol)
|
||||||
let quote_asset_precision = exchange_info_map.get(&order.symbol).unwrap().quote_asset_precision;
|
&& trade_fee_map.contains_key(&order.symbol)
|
||||||
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
{
|
||||||
|
let quote_asset_precision = exchange_info_map
|
||||||
|
.get(&order.symbol)
|
||||||
|
.unwrap()
|
||||||
|
.quote_asset_precision;
|
||||||
|
let trade_fee =
|
||||||
|
trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||||
if base_qty_executed == base_qty_ordered {
|
if base_qty_executed == base_qty_ordered {
|
||||||
// FILLED case
|
// FILLED case
|
||||||
// update status FILLED
|
// update status FILLED
|
||||||
|
|
@ -1371,7 +1410,8 @@ pub async fn cancel_sell_order(
|
||||||
dec!(1),
|
dec!(1),
|
||||||
),
|
),
|
||||||
dec!(100),
|
dec!(100),
|
||||||
).round_dp(2);
|
)
|
||||||
|
.round_dp(2);
|
||||||
|
|
||||||
let table_name = String::from("sell_ordered_coin_list");
|
let table_name = String::from("sell_ordered_coin_list");
|
||||||
let mut value_build = String::from("\'");
|
let mut value_build = String::from("\'");
|
||||||
|
|
@ -1422,7 +1462,8 @@ pub async fn cancel_sell_order(
|
||||||
dec!(1),
|
dec!(1),
|
||||||
),
|
),
|
||||||
dec!(100),
|
dec!(100),
|
||||||
).round_dp(2);
|
)
|
||||||
|
.round_dp(2);
|
||||||
|
|
||||||
let table_name = String::from("sell_ordered_coin_list");
|
let table_name = String::from("sell_ordered_coin_list");
|
||||||
let mut value_build = String::from("\'");
|
let mut value_build = String::from("\'");
|
||||||
|
|
@ -1756,11 +1797,18 @@ pub async fn query_sell_order(
|
||||||
|
|
||||||
match v {
|
match v {
|
||||||
Ok(T) => {
|
Ok(T) => {
|
||||||
if T.get("status").is_some_and(|a| a.as_str().unwrap() == "FILLED")
|
if T.get("status")
|
||||||
|| T.get("status").is_some_and(|a| a.as_str().unwrap() == "PARTIALLY_FILLED")
|
.is_some_and(|a| a.as_str().unwrap() == "FILLED")
|
||||||
|
|| T.get("status")
|
||||||
|
.is_some_and(|a| a.as_str().unwrap() == "PARTIALLY_FILLED")
|
||||||
{
|
{
|
||||||
if exchange_info_map.contains_key(&order.symbol) && trade_fee_map.contains_key(&order.symbol) {
|
if exchange_info_map.contains_key(&order.symbol)
|
||||||
let quote_asset_precision = exchange_info_map.get(&order.symbol).unwrap().quote_asset_precision;
|
&& trade_fee_map.contains_key(&order.symbol)
|
||||||
|
{
|
||||||
|
let quote_asset_precision = exchange_info_map
|
||||||
|
.get(&order.symbol)
|
||||||
|
.unwrap()
|
||||||
|
.quote_asset_precision;
|
||||||
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
let trade_fee = trade_fee_map.get(&order.symbol).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(),
|
||||||
|
|
@ -1781,7 +1829,8 @@ pub async fn query_sell_order(
|
||||||
let pure_profit_percent = decimal_mul(
|
let pure_profit_percent = decimal_mul(
|
||||||
decimal_sub(decimal_div(get_usdt_fee_adjusted, order.used_usdt), dec!(1)),
|
decimal_sub(decimal_div(get_usdt_fee_adjusted, order.used_usdt), dec!(1)),
|
||||||
dec!(100),
|
dec!(100),
|
||||||
).round_dp(2);
|
)
|
||||||
|
.round_dp(2);
|
||||||
|
|
||||||
let table_name = String::from("sell_ordered_coin_list");
|
let table_name = String::from("sell_ordered_coin_list");
|
||||||
let mut value_build = String::from("\'");
|
let mut value_build = String::from("\'");
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ use serde::Deserialize;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use sqlx::{Error, FromRow};
|
use sqlx::{Error, FromRow};
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
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 {
|
||||||
|
|
@ -152,7 +152,8 @@ pub async fn collect_valid_usde_trade(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let step_size = value.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)) {
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ use serde::Deserialize;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use sqlx::{Error, FromRow};
|
use sqlx::{Error, FromRow};
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
|
use std::collections::HashMap;
|
||||||
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 {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,17 @@
|
||||||
use crate::database_control::*;
|
use crate::database_control::*;
|
||||||
use hex::ToHex;
|
use hex::ToHex;
|
||||||
use hmac_sha256::HMAC;
|
use hmac_sha256::HMAC;
|
||||||
|
use log;
|
||||||
use reqwest::{Client, ClientBuilder, Response};
|
use reqwest::{Client, ClientBuilder, Response};
|
||||||
use rust_decimal::{prelude::FromPrimitive, prelude::ToPrimitive, Decimal, RoundingStrategy};
|
use rust_decimal::{prelude::FromPrimitive, prelude::ToPrimitive, Decimal, RoundingStrategy};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use sqlx::{Error, FromRow};
|
use sqlx::{Error, FromRow};
|
||||||
use std::borrow::{Borrow, BorrowMut};
|
use std::borrow::{Borrow, BorrowMut};
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::HashMap;
|
|
||||||
use tokio::{join, sync::Mutex, time::*};
|
use tokio::{join, sync::Mutex, time::*};
|
||||||
use log;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct TradeFee {
|
pub struct TradeFee {
|
||||||
|
|
@ -374,8 +374,7 @@ pub async fn request_exchange_infomation(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.ends_with("USDT")
|
.ends_with("USDT")
|
||||||
{
|
{
|
||||||
symbol =
|
symbol = (element.get("symbol").unwrap().as_str().unwrap().to_string());
|
||||||
(element.get("symbol").unwrap().as_str().unwrap().to_string());
|
|
||||||
exchange_info.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;
|
||||||
exchange_info.base_commission_precision = (element
|
exchange_info.base_commission_precision = (element
|
||||||
|
|
@ -442,7 +441,7 @@ pub async fn request_delist_symbols(
|
||||||
secret_key: &str,
|
secret_key: &str,
|
||||||
local_epoch: u128,
|
local_epoch: u128,
|
||||||
difference_epoch: i64,
|
difference_epoch: i64,
|
||||||
client: &Client
|
client: &Client,
|
||||||
) -> 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/spot/delist-schedule?");
|
let mut base_url = String::from("https://api.binance.com/sapi/v1/spot/delist-schedule?");
|
||||||
|
|
||||||
|
|
@ -515,8 +514,7 @@ async fn de_deilst_symbol_json(
|
||||||
|
|
||||||
for element in object_map_iter {
|
for element in object_map_iter {
|
||||||
match element.0.as_str() {
|
match element.0.as_str() {
|
||||||
"delistTime" => {
|
"delistTime" => {}
|
||||||
},
|
|
||||||
"symbols" => {
|
"symbols" => {
|
||||||
if let Some(array) = element.1.as_array() {
|
if let Some(array) = element.1.as_array() {
|
||||||
for delist_symbol in array {
|
for delist_symbol in array {
|
||||||
|
|
@ -527,13 +525,12 @@ async fn de_deilst_symbol_json(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("Elements in body msg are changed. Please update both your delist table and vectors.");
|
log::error!("Elements in body msg are changed. Please update both your delist table and vectors.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if delist_hashset.len() != 0 {
|
if delist_hashset.len() != 0 {
|
||||||
|
|
|
||||||
|
|
@ -907,7 +907,8 @@ async fn initialize_database() {
|
||||||
let mut symbols = Symbols {
|
let mut symbols = Symbols {
|
||||||
symbol: String::new(),
|
symbol: String::new(),
|
||||||
};
|
};
|
||||||
let symbols_vec = select_record(&fetch_table_name, &column_name, &condition, &symbols)
|
let symbols_vec =
|
||||||
|
select_record(&fetch_table_name, &column_name, &condition, &symbols)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to fetch records!");
|
.expect("Failed to fetch records!");
|
||||||
let insert_table_name = String::from("wallet");
|
let insert_table_name = String::from("wallet");
|
||||||
|
|
|
||||||
81
src/main.rs
81
src/main.rs
|
|
@ -8,8 +8,11 @@ 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 clap::{arg, Command};
|
||||||
|
use log::Level;
|
||||||
use reqwest::{Client, ClientBuilder};
|
use reqwest::{Client, ClientBuilder};
|
||||||
use rust_decimal::Decimal;
|
use rust_decimal::Decimal;
|
||||||
|
use simple_logger::set_up_color_terminal;
|
||||||
use sqlx::{mysql::*, Connection, Executor, FromRow, Row};
|
use sqlx::{mysql::*, Connection, Executor, FromRow, Row};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::{
|
use std::{
|
||||||
|
|
@ -18,9 +21,6 @@ use std::{
|
||||||
};
|
};
|
||||||
use tokio::{fs::*, join, sync::mpsc, sync::watch, sync::Mutex, task::*, time::*};
|
use tokio::{fs::*, join, sync::mpsc, sync::watch, sync::Mutex, task::*, time::*};
|
||||||
use tradingbot::{RunningMode::*, *};
|
use tradingbot::{RunningMode::*, *};
|
||||||
use clap::{arg, Command};
|
|
||||||
use log::Level;
|
|
||||||
use simple_logger::set_up_color_terminal;
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
@ -330,14 +330,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(T) => {
|
Ok(T) => {
|
||||||
local_epoch_tx1.send(usertime.local_epoch)
|
local_epoch_tx1
|
||||||
|
.send(usertime.local_epoch)
|
||||||
.expect("local_epoch_tx1-local_epoch_rx1 channel has been closed.");
|
.expect("local_epoch_tx1-local_epoch_rx1 channel has been closed.");
|
||||||
epoch_difference_tx1.send(usertime.epoch_difference)
|
epoch_difference_tx1.send(usertime.epoch_difference).expect(
|
||||||
.expect("epoch_difference_tx1-epoch_difference_rx1 channel has been closed.");
|
"epoch_difference_tx1-epoch_difference_rx1 channel has been closed.",
|
||||||
local_epoch_tx2.send(usertime.local_epoch)
|
);
|
||||||
|
local_epoch_tx2
|
||||||
|
.send(usertime.local_epoch)
|
||||||
.expect("local_epoch_tx2-local_epoch_rx2 channel has been closed.");
|
.expect("local_epoch_tx2-local_epoch_rx2 channel has been closed.");
|
||||||
epoch_difference_tx2.send(usertime.epoch_difference)
|
epoch_difference_tx2.send(usertime.epoch_difference).expect(
|
||||||
.expect("epoch_difference_tx2-epoch_difference_rx2 channel has been closed.");
|
"epoch_difference_tx2-epoch_difference_rx2 channel has been closed.",
|
||||||
|
);
|
||||||
tx_task1.send(1).expect("The mpsc channel has been closed.");
|
tx_task1.send(1).expect("The mpsc channel has been closed.");
|
||||||
}
|
}
|
||||||
Err(E) => {}
|
Err(E) => {}
|
||||||
|
|
@ -429,7 +433,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
tx_tradefee_map.send_modify(|vec| *vec = tradefee_vec_temp);
|
tx_tradefee_map.send_modify(|vec| *vec = tradefee_vec_temp);
|
||||||
tx_task2.send(2).expect("The mpsc channel has been closed.");
|
tx_task2.send(2).expect("The mpsc channel has been closed.");
|
||||||
|
|
||||||
}
|
}
|
||||||
Err(E) => {
|
Err(E) => {
|
||||||
panic!("tx2-rx2 channel has been closed.")
|
panic!("tx2-rx2 channel has been closed.")
|
||||||
|
|
@ -472,7 +475,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tx_exchange_info_map.send_modify(|vec| *vec = exchange_info_map_temp);
|
tx_exchange_info_map.send_modify(|vec| *vec = exchange_info_map_temp);
|
||||||
tx_task3.send(3).expect("The mpsc channel has been closed.");
|
tx_task3.send(3).expect("The mpsc channel has been closed.");
|
||||||
|
|
||||||
|
|
@ -506,8 +508,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
tx_valid_usdt_trade_set
|
tx_valid_usdt_trade_set.send_modify(|vec| *vec = valid_usdt_trade_set_temp);
|
||||||
.send_modify(|vec| *vec = valid_usdt_trade_set_temp);
|
|
||||||
tx_task4.send(4).expect("The mpsc channel has been closed.");
|
tx_task4.send(4).expect("The mpsc channel has been closed.");
|
||||||
}
|
}
|
||||||
Err(E) => {
|
Err(E) => {
|
||||||
|
|
@ -576,8 +577,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let interval = String::from("1m");
|
let interval = String::from("1m");
|
||||||
let candle_1m_vec = rx_candle_1m_map.borrow().clone();
|
let candle_1m_vec = rx_candle_1m_map.borrow().clone();
|
||||||
let dummy_data: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
let dummy_data: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||||
let mut rt_price_1m_map_write_temp: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
let mut rt_price_1m_map_write_temp: HashMap<String, Vec<RealtimePriceData>> =
|
||||||
let mut rt_price_1m_map_write_temp_c: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
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,
|
||||||
|
|
@ -597,8 +600,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// 30m
|
// 30m
|
||||||
let interval = String::from("30m");
|
let interval = String::from("30m");
|
||||||
let candle_30m_map = rx_candle_30m_map.borrow().clone();
|
let candle_30m_map = rx_candle_30m_map.borrow().clone();
|
||||||
let mut rt_price_30m_map_write_temp: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
let mut rt_price_30m_map_write_temp: HashMap<String, Vec<RealtimePriceData>> =
|
||||||
let mut rt_price_30m_map_write_temp_c: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
HashMap::new();
|
||||||
|
let mut rt_price_30m_map_write_temp_c: HashMap<String, Vec<RealtimePriceData>> =
|
||||||
|
HashMap::new();
|
||||||
if !rt_price_1m_map_write_temp_c.is_empty() {
|
if !rt_price_1m_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(
|
||||||
|
|
@ -614,15 +619,19 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
if tx_rt_price_30m_map.is_closed() {
|
if tx_rt_price_30m_map.is_closed() {
|
||||||
log::error!("tx_rt_price_30m_vec has been closed!");
|
log::error!("tx_rt_price_30m_vec has been closed!");
|
||||||
} else {
|
} else {
|
||||||
tx_rt_price_30m_map
|
tx_rt_price_30m_map.send_modify(
|
||||||
.send_modify(|map: &mut HashMap<String, Vec<RealtimePriceData>>| *map = rt_price_30m_map_write_temp);
|
|map: &mut HashMap<String, Vec<RealtimePriceData>>| {
|
||||||
|
*map = rt_price_30m_map_write_temp
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1d
|
// 1d
|
||||||
let interval = String::from("1d");
|
let interval = String::from("1d");
|
||||||
let candle_1d_vec = rx_candle_1d_map.borrow().clone();
|
let candle_1d_vec = rx_candle_1d_map.borrow().clone();
|
||||||
let mut rt_price_1d_map_write_temp: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
let mut rt_price_1d_map_write_temp: HashMap<String, Vec<RealtimePriceData>> =
|
||||||
|
HashMap::new();
|
||||||
|
|
||||||
if !rt_price_30m_map_write_temp_c.is_empty() {
|
if !rt_price_30m_map_write_temp_c.is_empty() {
|
||||||
let result =
|
let result =
|
||||||
|
|
@ -1055,8 +1064,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let instant = Instant::now();
|
let instant = Instant::now();
|
||||||
let exchange_info_map = rx_exchange_info_map.borrow().clone();
|
let exchange_info_map = rx_exchange_info_map.borrow().clone();
|
||||||
let trade_fee_map = rx_tradefee_map.borrow().clone();
|
let trade_fee_map = rx_tradefee_map.borrow().clone();
|
||||||
let result =
|
let result = coex::exchange_team::buy_coin(&exchange_info_map, &trade_fee_map).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 {
|
||||||
|
|
@ -1091,11 +1099,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let trade_fee_map = rx2_tradefee_map.borrow().clone();
|
let trade_fee_map = rx2_tradefee_map.borrow().clone();
|
||||||
let result = coex::order_team::monitoring_open_buy_order(
|
let result =
|
||||||
&client,
|
coex::order_team::monitoring_open_buy_order(&client, &trade_fee_map).await;
|
||||||
&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 {
|
||||||
|
|
@ -1328,17 +1333,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let local_epoch = *local_epoch_rx2.borrow();
|
let local_epoch = *local_epoch_rx2.borrow();
|
||||||
let difference_epoch = *epoch_difference_rx2.borrow();
|
let difference_epoch = *epoch_difference_rx2.borrow();
|
||||||
|
|
||||||
|
|
||||||
let result = request_others::request_delist_symbols(
|
let result = request_others::request_delist_symbols(
|
||||||
API_KEY,
|
API_KEY,
|
||||||
SECRET_KEY,
|
SECRET_KEY,
|
||||||
local_epoch,
|
local_epoch,
|
||||||
difference_epoch,
|
difference_epoch,
|
||||||
&client
|
&client,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
tx_task27.send(27).expect("The mpsc channel has been closed.");
|
tx_task27
|
||||||
|
.send(27)
|
||||||
|
.expect("The mpsc channel has been closed.");
|
||||||
|
|
||||||
// sleep as much as the loop recurs per 300 seconds if all operation finished within 300 seconds.
|
// sleep as much as the loop recurs per 300 seconds if all operation finished within 300 seconds.
|
||||||
elapsed_time = instant.elapsed().as_secs();
|
elapsed_time = instant.elapsed().as_secs();
|
||||||
|
|
@ -1348,15 +1354,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
loop {
|
loop {}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn program_setting() {
|
fn program_setting() {
|
||||||
let matches = Command::new("Tradingbot")
|
let matches = Command::new("Tradingbot")
|
||||||
.arg(arg!(log_level: -l --log <level> "Select log level: trace, debug, info, warn, error").default_value("error"))
|
.arg(
|
||||||
|
arg!(log_level: -l --log <level> "Select log level: trace, debug, info, warn, error")
|
||||||
|
.default_value("error"),
|
||||||
|
)
|
||||||
.arg(arg!(mode: -m --mode <mode> "Select mode: real, simul, test").required(true))
|
.arg(arg!(mode: -m --mode <mode> "Select mode: real, simul, test").required(true))
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
|
|
@ -1374,7 +1382,6 @@ fn program_setting() {
|
||||||
log::error!("wrong log level argument.");
|
log::error!("wrong log level argument.");
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1385,15 +1392,15 @@ fn program_setting() {
|
||||||
"real" => {
|
"real" => {
|
||||||
RUNNING_MODE = RunningMode::REAL;
|
RUNNING_MODE = RunningMode::REAL;
|
||||||
println!("*** REAL MODE ***");
|
println!("*** REAL MODE ***");
|
||||||
},
|
}
|
||||||
"simul" => {
|
"simul" => {
|
||||||
RUNNING_MODE = RunningMode::SIMUL;
|
RUNNING_MODE = RunningMode::SIMUL;
|
||||||
println!("*** SIMULATION MODE ***");
|
println!("*** SIMULATION MODE ***");
|
||||||
},
|
}
|
||||||
"test" => {
|
"test" => {
|
||||||
RUNNING_MODE = RunningMode::TEST;
|
RUNNING_MODE = RunningMode::TEST;
|
||||||
println!("*** TEST MODE ***");
|
println!("*** TEST MODE ***");
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
log::error!("wrong mode argument.");
|
log::error!("wrong mode argument.");
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
use crate::database_control::*;
|
use crate::database_control::*;
|
||||||
use crate::time_checking_team::UserTime;
|
use crate::time_checking_team::UserTime;
|
||||||
|
use log;
|
||||||
use rand::*;
|
use rand::*;
|
||||||
use reqwest::{Client, ClientBuilder, Response};
|
use reqwest::{Client, ClientBuilder, Response};
|
||||||
use tokio::join;
|
use tokio::join;
|
||||||
use tokio::time::*;
|
use tokio::time::*;
|
||||||
use log;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ServerHealth {
|
pub struct ServerHealth {
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,15 @@ pub mod strategy_008;
|
||||||
// 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::exchange_team::get_server_epoch;
|
use crate::coex::exchange_team::get_server_epoch;
|
||||||
|
use crate::coex::order_team::{limit_order_sell, select_filled_buy_orders};
|
||||||
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, CandleType};
|
use crate::value_estimation_team::datapoints::price_data::{CandleType, RealtimePriceData};
|
||||||
|
use crate::value_estimation_team::indicators::adx::{adx, AdxData};
|
||||||
use crate::value_estimation_team::indicators::bollingerband::{bollingerband, BollingerBandData};
|
use crate::value_estimation_team::indicators::bollingerband::{bollingerband, BollingerBandData};
|
||||||
|
use crate::value_estimation_team::indicators::dema::{dema, DemaData};
|
||||||
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::{
|
||||||
heatmap_volume, HeatMapLevel, HeatmapVolumeData,
|
heatmap_volume, HeatMapLevel, HeatmapVolumeData,
|
||||||
|
|
@ -24,19 +26,19 @@ 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, SuperTrendArea, SuperTrendSignal};
|
use crate::value_estimation_team::indicators::supertrend::{
|
||||||
use crate::value_estimation_team::indicators::adx::{AdxData, adx};
|
supertrend, SuperTrendArea, SuperTrendSignal, SupertrendData,
|
||||||
use crate::value_estimation_team::indicators::dema::{DemaData, dema};
|
};
|
||||||
use crate::value_estimation_team::indicators::tema::{TemaData, tema};
|
use crate::value_estimation_team::indicators::tema::{tema, TemaData};
|
||||||
use futures::future::try_join_all;
|
use futures::future::try_join_all;
|
||||||
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, HashSet};
|
||||||
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 {
|
||||||
|
|
@ -92,9 +94,10 @@ impl FilteredDataValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn duplicate_filter(registerer: i32, original_filtered_data: &HashMap<String, FilteredDataValue>)
|
pub async fn duplicate_filter(
|
||||||
-> Result<HashMap<String, FilteredDataValue>, Box<dyn std::error::Error + Send + Sync>>
|
registerer: i32,
|
||||||
{
|
original_filtered_data: &HashMap<String, FilteredDataValue>,
|
||||||
|
) -> Result<HashMap<String, FilteredDataValue>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let inspect_table_name_1 = String::from("buy_ordered_coin_list");
|
let inspect_table_name_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");
|
||||||
|
|
@ -146,7 +149,10 @@ pub async fn duplicate_filter(registerer: i32, original_filtered_data: &HashMap<
|
||||||
Ok(filtered_data_c)
|
Ok(filtered_data_c)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn remove_keys(filtered_data: &mut HashMap<String, FilteredDataValue>, keys_to_remove: HashSet<String>) {
|
pub async fn remove_keys(
|
||||||
|
filtered_data: &mut HashMap<String, FilteredDataValue>,
|
||||||
|
keys_to_remove: HashSet<String>,
|
||||||
|
) {
|
||||||
let len_prev = filtered_data.len();
|
let len_prev = filtered_data.len();
|
||||||
// remove key-value in filtered_data
|
// remove key-value in filtered_data
|
||||||
for symbol in keys_to_remove {
|
for symbol in keys_to_remove {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
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,
|
adx, dec, decimal_add, decimal_div, decimal_sub, duplicate_filter, ema, ema_macd,
|
||||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
exists_record, get_server_epoch, insert_pre_suggested_coins, limit_order_sell, remove_keys,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, update_record3, AdxData,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
AllData, Arc, BollingerBandData, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
FilteredDataValue, HashMap, HashSet, MacdData, Mutex, RealtimePriceData, RoundingStrategy,
|
||||||
|
RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal, SupertrendData, ToPrimitive, TradeFee,
|
||||||
};
|
};
|
||||||
|
|
||||||
// BB lowerband + SuperTrend + StochRSI
|
// BB lowerband + SuperTrend + StochRSI
|
||||||
|
|
@ -36,7 +37,9 @@ pub async fn list_up_for_buy(
|
||||||
let mut average_amplitude = 0.0;
|
let mut average_amplitude = 0.0;
|
||||||
|
|
||||||
for window in windows {
|
for window in windows {
|
||||||
average_amplitude += (window.last().unwrap().high_price - window.last().unwrap().low_price) / window.first().unwrap().close_price;
|
average_amplitude += (window.last().unwrap().high_price
|
||||||
|
- window.last().unwrap().low_price)
|
||||||
|
/ window.first().unwrap().close_price;
|
||||||
}
|
}
|
||||||
average_amplitude /= 10.0;
|
average_amplitude /= 10.0;
|
||||||
|
|
||||||
|
|
@ -56,24 +59,39 @@ pub async fn list_up_for_buy(
|
||||||
// 2nd filtering: supertrend(ATR period 20, multiplier: 2, 30m close price)
|
// 2nd filtering: supertrend(ATR period 20, multiplier: 2, 30m close price)
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
let supertrend_30m_map = supertrend(20, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let supertrend_30m_map =
|
||||||
|
supertrend(20, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_30m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
supertrend_30m_map.get(symbol),
|
||||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
alldata.rt_price_30m_vec.get(symbol),
|
||||||
|
) {
|
||||||
|
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||||
|
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||||
|
{
|
||||||
// input closetime, current_price
|
// input closetime, current_price
|
||||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
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();
|
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||||
|
rt_price_vec.last().unwrap().close_price,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// input stoploss
|
// input stoploss
|
||||||
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(
|
||||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN &&
|
supertrend_vec.last().unwrap().band_value,
|
||||||
supertrend_vec.last().unwrap().band_value > values.current_price.to_f64().unwrap()
|
)
|
||||||
|
.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.stoploss = decimal_sub(
|
||||||
|
values.current_price,
|
||||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
decimal_sub(band_value, values.current_price),
|
||||||
supertrend_vec.last().unwrap().band_value < values.current_price.to_f64().unwrap()
|
);
|
||||||
|
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP
|
||||||
|
&& supertrend_vec.last().unwrap().band_value
|
||||||
|
< values.current_price.to_f64().unwrap()
|
||||||
{
|
{
|
||||||
values.stoploss = band_value;
|
values.stoploss = band_value;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -97,16 +115,34 @@ pub async fn list_up_for_buy(
|
||||||
let rt_price_30m = alldata.rt_price_30m_vec.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 rt_price_30m_len = rt_price_30m.len();
|
||||||
let search_result = ema.binary_search_by_key(
|
let search_result = ema.binary_search_by_key(
|
||||||
&alldata.rt_price_30m_vec.get(symbol).unwrap().last().unwrap().close_time,
|
&alldata
|
||||||
|
.rt_price_30m_vec
|
||||||
|
.get(symbol)
|
||||||
|
.unwrap()
|
||||||
|
.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[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) &&
|
if search_result.is_ok_and(|x| {
|
||||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-2].ema_value < rt_price_30m[rt_price_30m_len-3].close_price) &&
|
ema[search_result.unwrap()].ema_value
|
||||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-3].ema_value < rt_price_30m[rt_price_30m_len-4].close_price) &&
|
< rt_price_30m[rt_price_30m_len - 1].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) {
|
}) && 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 {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -122,8 +158,12 @@ pub async fn list_up_for_buy(
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if alldata.rt_price_30m_vec.contains_key(symbol) && stoch_rsis.contains_key(symbol) {
|
if alldata.rt_price_30m_vec.contains_key(symbol) && stoch_rsis.contains_key(symbol) {
|
||||||
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
||||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == values.closetime);
|
let search_result = stoch_rsi_vec
|
||||||
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) {
|
.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
|
||||||
|
}) {
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -137,12 +177,21 @@ pub async fn list_up_for_buy(
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
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?;
|
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
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 let (Some(macd_vec), Some(rt_price_vec)) =
|
||||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||||
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();
|
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;
|
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -161,10 +210,13 @@ pub async fn list_up_for_buy(
|
||||||
let adx_vec = adx(10, 10, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let adx_vec = adx(10, 10, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let Some(adx_vec) = adx_vec.get(symbol) {
|
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 let Some(last_idx) = adx_vec
|
||||||
if
|
.iter()
|
||||||
adx_vec[last_idx].adx < adx_vec[last_idx-1].adx &&
|
.position(|elem| elem.close_time == values.closetime)
|
||||||
adx_vec[last_idx-1].adx < adx_vec[last_idx-2].adx {
|
{
|
||||||
|
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 {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -202,20 +254,33 @@ pub async fn list_up_for_sell(
|
||||||
for element in &filled_buy_orders {
|
for element in &filled_buy_orders {
|
||||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||||
}
|
}
|
||||||
let supertrend_30m = supertrend(20, 2.0, true, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
let supertrend_30m =
|
||||||
let stoch_rsis = stoch_rsi(10, 10, 3, 3, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
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) {
|
||||||
if let (Some(exchange_info), Some(tradefee), Some(stoch_rsi), Some(supertrend_vec)) =
|
if let (
|
||||||
(exchange_info_map.get(&element.symbol), trade_fee_map.get(&element.symbol), stoch_rsis.get(&element.symbol), supertrend_30m.get(&element.symbol)) {
|
Some(exchange_info),
|
||||||
|
Some(tradefee),
|
||||||
|
Some(stoch_rsi),
|
||||||
|
Some(supertrend_vec),
|
||||||
|
) = (
|
||||||
|
exchange_info_map.get(&element.symbol),
|
||||||
|
trade_fee_map.get(&element.symbol),
|
||||||
|
stoch_rsis.get(&element.symbol),
|
||||||
|
supertrend_30m.get(&element.symbol),
|
||||||
|
) {
|
||||||
// update stoploss
|
// update stoploss
|
||||||
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 == SuperTrendArea::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![(String::from("stoploss"), band_value.to_string())];
|
||||||
(String::from("stoploss"), band_value.to_string()),
|
|
||||||
];
|
|
||||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||||
update_record3(&update_table_name, &update_value, &update_condition)
|
update_record3(&update_table_name, &update_value, &update_condition)
|
||||||
.await
|
.await
|
||||||
|
|
@ -224,8 +289,7 @@ pub async fn list_up_for_sell(
|
||||||
|
|
||||||
let lot_step_size = exchange_info.stepsize;
|
let lot_step_size = exchange_info.stepsize;
|
||||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
let quote_commission_precision = exchange_info.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,
|
||||||
);
|
);
|
||||||
|
|
@ -266,9 +330,9 @@ pub async fn list_up_for_sell(
|
||||||
&trade_fee_map,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
} else if stoch_rsi_k >= 90.0 &&
|
} else if stoch_rsi_k >= 90.0
|
||||||
(stoch_rsi_k < stoch_rsi_d &&
|
&& (stoch_rsi_k < stoch_rsi_d && stoch_rsi_k_prev > stoch_rsi_d_prev)
|
||||||
stoch_rsi_k_prev > stoch_rsi_d_prev) {
|
{
|
||||||
limit_order_sell(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
element.current_price,
|
element.current_price,
|
||||||
|
|
@ -305,7 +369,6 @@ pub async fn list_up_for_sell(
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
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,
|
adx, dec, decimal_add, decimal_div, decimal_sub, duplicate_filter, ema, ema_macd,
|
||||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
exists_record, get_server_epoch, insert_pre_suggested_coins, limit_order_sell, remove_keys,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, update_record3, AdxData,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
AllData, Arc, BollingerBandData, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
FilteredDataValue, HashMap, HashSet, MacdData, Mutex, RealtimePriceData, RoundingStrategy,
|
||||||
|
RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal, SupertrendData, ToPrimitive, TradeFee,
|
||||||
};
|
};
|
||||||
|
|
||||||
// BB 30m lowerband + BB 1m lowerband
|
// BB 30m lowerband + BB 1m lowerband
|
||||||
|
|
@ -34,7 +35,9 @@ pub async fn list_up_for_buy(
|
||||||
let mut average_amplitude = 0.0;
|
let mut average_amplitude = 0.0;
|
||||||
|
|
||||||
for window in windows {
|
for window in windows {
|
||||||
average_amplitude += (window.last().unwrap().high_price - window.last().unwrap().low_price) / window.first().unwrap().close_price;
|
average_amplitude += (window.last().unwrap().high_price
|
||||||
|
- window.last().unwrap().low_price)
|
||||||
|
/ window.first().unwrap().close_price;
|
||||||
}
|
}
|
||||||
average_amplitude /= 10.0;
|
average_amplitude /= 10.0;
|
||||||
|
|
||||||
|
|
@ -53,12 +56,22 @@ pub async fn list_up_for_buy(
|
||||||
|
|
||||||
// 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 keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let bollingerbands_30m_map = bollingerband(10, 2.5, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let bollingerbands_30m_map =
|
||||||
let bollingerbands_1m_map = bollingerband(30, 3.0, &alldata.rt_price_1m_vec, &filtered_data).await?;
|
bollingerband(10, 2.5, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
|
let bollingerbands_1m_map =
|
||||||
|
bollingerband(30, 3.0, &alldata.rt_price_1m_vec, &filtered_data).await?;
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
for (symbol, filtered_data) in &mut filtered_data {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
if let (Some(bb_30m_vec), Some(bb_1m_vec), Some(rt_30m_vec)) = (bollingerbands_30m_map.get(symbol), bollingerbands_1m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
if let (Some(bb_30m_vec), Some(bb_1m_vec), Some(rt_30m_vec)) = (
|
||||||
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 {
|
bollingerbands_30m_map.get(symbol),
|
||||||
|
bollingerbands_1m_map.get(symbol),
|
||||||
|
alldata.rt_price_30m_vec.get(symbol),
|
||||||
|
) {
|
||||||
|
if rt_30m_vec.len() >= 3
|
||||||
|
&& bb_30m_vec.len() >= 3
|
||||||
|
&& bb_1m_vec.len() >= 3
|
||||||
|
&& rt_30m_vec.last().unwrap().close_time > server_epoch
|
||||||
|
{
|
||||||
let bb_30m_search_result = bb_30m_vec.binary_search_by_key(
|
let bb_30m_search_result = bb_30m_vec.binary_search_by_key(
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
|BollingerBandData {
|
|BollingerBandData {
|
||||||
|
|
@ -69,11 +82,17 @@ pub async fn list_up_for_buy(
|
||||||
}| *close_time,
|
}| *close_time,
|
||||||
);
|
);
|
||||||
if bb_30m_search_result.is_ok() {
|
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 &&
|
if bb_30m_vec[bb_30m_search_result.unwrap()].lowerband
|
||||||
bb_1m_vec.last().unwrap().lowerband > rt_30m_vec[rt_30m_vec.len()-1].close_price
|
> 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
|
||||||
{
|
{
|
||||||
filtered_data.closetime = rt_30m_vec.last().unwrap().close_time;
|
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.current_price =
|
||||||
|
rust_decimal::prelude::FromPrimitive::from_f64(
|
||||||
|
rt_30m_vec.last().unwrap().close_price,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -91,11 +110,18 @@ pub async fn list_up_for_buy(
|
||||||
|
|
||||||
// 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 mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let supertrend_30m_map = supertrend( 7, 1.5, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let supertrend_30m_map =
|
||||||
|
supertrend(7, 1.5, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
for (symbol, filtered_data) in &mut filtered_data {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
if let (Some(rt_30m_vec), Some(supertrend_vec)) = (alldata.rt_price_30m_vec.get(symbol), supertrend_30m_map.get(symbol)) {
|
if let (Some(rt_30m_vec), Some(supertrend_vec)) = (
|
||||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
alldata.rt_price_30m_vec.get(symbol),
|
||||||
|
supertrend_30m_map.get(symbol),
|
||||||
|
) {
|
||||||
|
if rt_30m_vec.len() >= 3
|
||||||
|
&& supertrend_vec.len() >= 3
|
||||||
|
&& rt_30m_vec.last().unwrap().close_time > server_epoch
|
||||||
|
{
|
||||||
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
|SupertrendData {
|
|SupertrendData {
|
||||||
|
|
@ -106,11 +132,26 @@ 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 == SuperTrendArea::DOWN
|
if supertrend_vec[supertrend_search_result.unwrap()].area
|
||||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value > filtered_data.current_price.to_f64().unwrap()
|
== SuperTrendArea::DOWN
|
||||||
|
&& supertrend_vec[supertrend_search_result.unwrap()].band_value
|
||||||
|
> filtered_data.current_price.to_f64().unwrap()
|
||||||
{
|
{
|
||||||
filtered_data.target_price = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec[supertrend_search_result.unwrap()].band_value).unwrap();
|
filtered_data.target_price =
|
||||||
let stop_loss = decimal_sub(filtered_data.current_price, decimal_div(decimal_sub(filtered_data.target_price, filtered_data.current_price), dec!(2)));
|
rust_decimal::prelude::FromPrimitive::from_f64(
|
||||||
|
supertrend_vec[supertrend_search_result.unwrap()].band_value,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let stop_loss = decimal_sub(
|
||||||
|
filtered_data.current_price,
|
||||||
|
decimal_div(
|
||||||
|
decimal_sub(
|
||||||
|
filtered_data.target_price,
|
||||||
|
filtered_data.current_price,
|
||||||
|
),
|
||||||
|
dec!(2),
|
||||||
|
),
|
||||||
|
);
|
||||||
filtered_data.stoploss = stop_loss;
|
filtered_data.stoploss = stop_loss;
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -131,18 +172,31 @@ pub async fn list_up_for_buy(
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let ema_map = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let ema_map = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
for (symbol, filtered_data) in &mut filtered_data {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
if let (Some(ema_vec), Some(rt_30m_vec)) = (ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
if let (Some(ema_vec), Some(rt_30m_vec)) =
|
||||||
|
(ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol))
|
||||||
|
{
|
||||||
let search_result = ema_vec.binary_search_by_key(
|
let search_result = ema_vec.binary_search_by_key(
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
&rt_30m_vec.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[x].ema_value < rt_30m_vec[rt_30m_vec.len()-1].close_price) &&
|
);
|
||||||
search_result.is_ok_and(|x| ema_vec[x-1].ema_value < rt_30m_vec[rt_30m_vec.len()-2].close_price) &&
|
if search_result
|
||||||
search_result.is_ok_and(|x| ema_vec[x-2].ema_value < rt_30m_vec[rt_30m_vec.len()-3].close_price) &&
|
.is_ok_and(|x| ema_vec[x].ema_value < rt_30m_vec[rt_30m_vec.len() - 1].close_price)
|
||||||
search_result.is_ok_and(|x| ema_vec[x-3].ema_value < rt_30m_vec[rt_30m_vec.len()-4].close_price) &&
|
&& search_result.is_ok_and(|x| {
|
||||||
search_result.is_ok_and(|x| ema_vec[x-4].ema_value < rt_30m_vec[rt_30m_vec.len()-5].close_price) {
|
ema_vec[x - 1].ema_value < rt_30m_vec[rt_30m_vec.len() - 2].close_price
|
||||||
|
})
|
||||||
|
&& search_result.is_ok_and(|x| {
|
||||||
|
ema_vec[x - 2].ema_value < rt_30m_vec[rt_30m_vec.len() - 3].close_price
|
||||||
|
})
|
||||||
|
&& search_result.is_ok_and(|x| {
|
||||||
|
ema_vec[x - 3].ema_value < rt_30m_vec[rt_30m_vec.len() - 4].close_price
|
||||||
|
})
|
||||||
|
&& search_result.is_ok_and(|x| {
|
||||||
|
ema_vec[x - 4].ema_value < rt_30m_vec[rt_30m_vec.len() - 5].close_price
|
||||||
|
})
|
||||||
|
{
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -156,12 +210,21 @@ pub async fn list_up_for_buy(
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
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?;
|
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
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 let (Some(macd_vec), Some(rt_price_vec)) =
|
||||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||||
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();
|
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;
|
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -199,8 +262,7 @@ pub async fn list_up_for_sell(
|
||||||
if let Some(exchange_info) = exchange_info_map.get(&element.symbol) {
|
if let Some(exchange_info) = exchange_info_map.get(&element.symbol) {
|
||||||
let lot_step_size = exchange_info.stepsize;
|
let lot_step_size = exchange_info.stepsize;
|
||||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
let quote_commission_precision = exchange_info.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,
|
||||||
);
|
);
|
||||||
|
|
@ -208,8 +270,7 @@ 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.target_price {
|
||||||
{
|
|
||||||
limit_order_sell(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
element.current_price,
|
element.current_price,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
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,
|
adx, dec, decimal_add, decimal_div, decimal_sub, duplicate_filter, ema, ema_macd, ema_opclo,
|
||||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
exists_record, get_server_epoch, insert_pre_suggested_coins, limit_order_sell, remove_keys,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex, SmaData,
|
rsi, select_filled_buy_orders, sma, sma_opclo, stoch_rsi, supertrend, try_join_all,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
update_record3, AdxData, AllData, Arc, BollingerBandData, Client, ClientBuilder, Decimal,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
EmaData, ExchangeInfo, FilteredDataValue, HashMap, HashSet, MacdData, Mutex, RealtimePriceData,
|
||||||
|
RoundingStrategy, RsiData, SmaData, StochRsiData, SuperTrendArea, SuperTrendSignal,
|
||||||
|
SupertrendData, ToPrimitive, TradeFee,
|
||||||
};
|
};
|
||||||
|
|
||||||
// BUY: 30m SMA5 (opclo_price) < 30m EMA3 (opclo_price)
|
// BUY: 30m SMA5 (opclo_price) < 30m EMA3 (opclo_price)
|
||||||
|
|
@ -25,11 +27,18 @@ pub async fn list_up_for_buy(
|
||||||
|
|
||||||
// 3rd filtering: supertrend(ATR period 20, multiplier: 4.0, 30m close price), area should be UP
|
// 3rd filtering: supertrend(ATR period 20, multiplier: 4.0, 30m close price), area should be UP
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let supertrend_30m_map = supertrend(20, 4.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let supertrend_30m_map =
|
||||||
|
supertrend(20, 4.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
for (symbol, filtered_data) in &mut filtered_data {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
if let (Some(rt_30m_vec), Some(supertrend_vec)) = (alldata.rt_price_30m_vec.get(symbol), supertrend_30m_map.get(symbol)) {
|
if let (Some(rt_30m_vec), Some(supertrend_vec)) = (
|
||||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
alldata.rt_price_30m_vec.get(symbol),
|
||||||
|
supertrend_30m_map.get(symbol),
|
||||||
|
) {
|
||||||
|
if rt_30m_vec.len() >= 3
|
||||||
|
&& supertrend_vec.len() >= 3
|
||||||
|
&& rt_30m_vec.last().unwrap().close_time > server_epoch
|
||||||
|
{
|
||||||
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
|SupertrendData {
|
|SupertrendData {
|
||||||
|
|
@ -41,7 +50,8 @@ pub async fn list_up_for_buy(
|
||||||
);
|
);
|
||||||
if supertrend_search_result.is_ok() {
|
if supertrend_search_result.is_ok() {
|
||||||
if supertrend_vec[supertrend_search_result.unwrap()].area == SuperTrendArea::UP
|
if supertrend_vec[supertrend_search_result.unwrap()].area == SuperTrendArea::UP
|
||||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value < filtered_data.current_price.to_f64().unwrap()
|
&& supertrend_vec[supertrend_search_result.unwrap()].band_value
|
||||||
|
< filtered_data.current_price.to_f64().unwrap()
|
||||||
{
|
{
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -64,10 +74,17 @@ pub async fn list_up_for_buy(
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if alldata.rt_price_30m_vec.contains_key(symbol) && stoch_rsis.contains_key(symbol) {
|
if alldata.rt_price_30m_vec.contains_key(symbol) && stoch_rsis.contains_key(symbol) {
|
||||||
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
||||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == values.closetime);
|
let search_result = stoch_rsi_vec
|
||||||
if search_result.is_some_and(|a| stoch_rsi_vec[a-1].k < 10.0 && stoch_rsi_vec[a].k < 10.0
|
.iter()
|
||||||
&& stoch_rsi_vec[a-1].d < 10.0 && stoch_rsi_vec[a].d< 10.0 &&
|
.position(|x| x.close_time == values.closetime);
|
||||||
stoch_rsi_vec[a-1].k <= stoch_rsi_vec[a-1].d && stoch_rsi_vec[a].k > stoch_rsi_vec[a].d) {
|
if search_result.is_some_and(|a| {
|
||||||
|
stoch_rsi_vec[a - 1].k < 10.0
|
||||||
|
&& stoch_rsi_vec[a].k < 10.0
|
||||||
|
&& stoch_rsi_vec[a - 1].d < 10.0
|
||||||
|
&& stoch_rsi_vec[a].d < 10.0
|
||||||
|
&& stoch_rsi_vec[a - 1].k <= stoch_rsi_vec[a - 1].d
|
||||||
|
&& stoch_rsi_vec[a].k > stoch_rsi_vec[a].d
|
||||||
|
}) {
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -86,13 +103,25 @@ pub async fn list_up_for_buy(
|
||||||
let rt_price_30m = alldata.rt_price_30m_vec.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 rt_price_30m_len = rt_price_30m.len();
|
||||||
let search_result = ema.binary_search_by_key(
|
let search_result = ema.binary_search_by_key(
|
||||||
&alldata.rt_price_30m_vec.get(symbol).unwrap().last().unwrap().close_time,
|
&alldata
|
||||||
|
.rt_price_30m_vec
|
||||||
|
.get(symbol)
|
||||||
|
.unwrap()
|
||||||
|
.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[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) {
|
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 {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -106,12 +135,21 @@ pub async fn list_up_for_buy(
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
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?;
|
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
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 let (Some(macd_vec), Some(rt_price_vec)) =
|
||||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||||
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();
|
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;
|
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -148,14 +186,17 @@ pub async fn list_up_for_sell(
|
||||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||||
}
|
}
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
let stoch_rsis = stoch_rsi(30, 30, 3, 3, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
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 {
|
||||||
if element.used_usdt >= dec!(10.0) {
|
if element.used_usdt >= dec!(10.0) {
|
||||||
if let (Some(exchange_info), Some(stoch_rsi)) = (exchange_info_map.get(&element.symbol), stoch_rsis.get(&element.symbol)) {
|
if let (Some(exchange_info), Some(stoch_rsi)) = (
|
||||||
|
exchange_info_map.get(&element.symbol),
|
||||||
|
stoch_rsis.get(&element.symbol),
|
||||||
|
) {
|
||||||
let lot_step_size = exchange_info.stepsize;
|
let lot_step_size = exchange_info.stepsize;
|
||||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
let quote_commission_precision = exchange_info.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,
|
||||||
);
|
);
|
||||||
|
|
@ -167,8 +208,7 @@ 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.target_price {
|
||||||
{
|
|
||||||
limit_order_sell(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
element.current_price,
|
element.current_price,
|
||||||
|
|
@ -208,10 +248,12 @@ pub async fn list_up_for_sell(
|
||||||
&trade_fee_map,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
} else if stoch_rsi_k >= 20.0 && stoch_rsi_k >= 20.0 &&
|
} else if stoch_rsi_k >= 20.0
|
||||||
stoch_rsi_k_prev >= 20.0 && stoch_rsi_k_prev >= 20.0 &&
|
&& stoch_rsi_k >= 20.0
|
||||||
stoch_rsi_k < stoch_rsi_d &&
|
&& stoch_rsi_k_prev >= 20.0
|
||||||
stoch_rsi_k_prev >= stoch_rsi_d_prev
|
&& stoch_rsi_k_prev >= 20.0
|
||||||
|
&& stoch_rsi_k < stoch_rsi_d
|
||||||
|
&& stoch_rsi_k_prev >= stoch_rsi_d_prev
|
||||||
{
|
{
|
||||||
limit_order_sell(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
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,
|
adx, dec, decimal_add, decimal_div, decimal_sub, duplicate_filter, ema, ema_macd,
|
||||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
exists_record, get_server_epoch, insert_pre_suggested_coins, limit_order_sell, remove_keys,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, update_record3, AdxData,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
AllData, Arc, BollingerBandData, CandleType, Client, ClientBuilder, Decimal, EmaData,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, CandleType
|
ExchangeInfo, FilteredDataValue, HashMap, HashSet, MacdData, Mutex, RealtimePriceData,
|
||||||
|
RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal, SupertrendData,
|
||||||
|
ToPrimitive, TradeFee,
|
||||||
};
|
};
|
||||||
|
|
||||||
// BB lowerband + SuperTrend + StochRSI
|
// BB lowerband + SuperTrend + StochRSI
|
||||||
|
|
@ -35,7 +37,9 @@ pub async fn list_up_for_buy(
|
||||||
let mut average_amplitude = 0.0;
|
let mut average_amplitude = 0.0;
|
||||||
|
|
||||||
for window in windows {
|
for window in windows {
|
||||||
average_amplitude += (window.last().unwrap().high_price - window.last().unwrap().low_price) / window.first().unwrap().close_price;
|
average_amplitude += (window.last().unwrap().high_price
|
||||||
|
- window.last().unwrap().low_price)
|
||||||
|
/ window.first().unwrap().close_price;
|
||||||
}
|
}
|
||||||
average_amplitude /= 10.0;
|
average_amplitude /= 10.0;
|
||||||
|
|
||||||
|
|
@ -54,11 +58,18 @@ pub async fn list_up_for_buy(
|
||||||
|
|
||||||
// 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 keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let bollingerband_map = bollingerband(30, 3.0, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let bollingerband_map =
|
||||||
|
bollingerband(30, 3.0, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
for (symbol, filtered_data) in &mut filtered_data {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
if let (Some(bb_vec), Some(rt_30m_vec)) = (bollingerband_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
if let (Some(bb_vec), Some(rt_30m_vec)) = (
|
||||||
if rt_30m_vec.len() >= 3 && bb_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
bollingerband_map.get(symbol),
|
||||||
|
alldata.rt_price_30m_vec.get(symbol),
|
||||||
|
) {
|
||||||
|
if rt_30m_vec.len() >= 3
|
||||||
|
&& bb_vec.len() >= 3
|
||||||
|
&& rt_30m_vec.last().unwrap().close_time > server_epoch
|
||||||
|
{
|
||||||
let bb_search_result = bb_vec.binary_search_by_key(
|
let bb_search_result = bb_vec.binary_search_by_key(
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
|BollingerBandData {
|
|BollingerBandData {
|
||||||
|
|
@ -69,13 +80,20 @@ pub async fn list_up_for_buy(
|
||||||
}| *close_time,
|
}| *close_time,
|
||||||
);
|
);
|
||||||
if bb_search_result.is_ok() {
|
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 bb_vec[bb_search_result.unwrap() - 1].lowerband
|
||||||
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].low_price
|
||||||
rt_30m_vec[rt_30m_vec.len()-2].candle_type == CandleType::DOWN &&
|
&& rt_30m_vec[rt_30m_vec.len() - 2].opclo_price
|
||||||
rt_30m_vec[rt_30m_vec.len()-2].high_price < bb_vec[bb_search_result.unwrap()-1].sma
|
> rt_30m_vec.last().unwrap().close_price
|
||||||
|
&& rt_30m_vec[rt_30m_vec.len() - 2].candle_type == CandleType::DOWN
|
||||||
|
&& rt_30m_vec[rt_30m_vec.len() - 2].high_price
|
||||||
|
< bb_vec[bb_search_result.unwrap() - 1].sma
|
||||||
{
|
{
|
||||||
filtered_data.closetime = rt_30m_vec.last().unwrap().close_time;
|
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.current_price =
|
||||||
|
rust_decimal::prelude::FromPrimitive::from_f64(
|
||||||
|
rt_30m_vec.last().unwrap().close_price,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -94,10 +112,17 @@ pub async fn list_up_for_buy(
|
||||||
// 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 mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
let supertrend_30m_map = supertrend( 10, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let supertrend_30m_map =
|
||||||
|
supertrend(10, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
for (symbol, filtered_data) in &mut filtered_data {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
if let (Some(supertrend_vec), Some(rt_30m_vec)) = (supertrend_30m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
if let (Some(supertrend_vec), Some(rt_30m_vec)) = (
|
||||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
supertrend_30m_map.get(symbol),
|
||||||
|
alldata.rt_price_30m_vec.get(symbol),
|
||||||
|
) {
|
||||||
|
if rt_30m_vec.len() >= 3
|
||||||
|
&& supertrend_vec.len() >= 3
|
||||||
|
&& rt_30m_vec.last().unwrap().close_time > server_epoch
|
||||||
|
{
|
||||||
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
&rt_30m_vec.last().unwrap().close_time,
|
||||||
|SupertrendData {
|
|SupertrendData {
|
||||||
|
|
@ -107,10 +132,22 @@ pub async fn list_up_for_buy(
|
||||||
close_time,
|
close_time,
|
||||||
}| *close_time,
|
}| *close_time,
|
||||||
);
|
);
|
||||||
if supertrend_search_result.is_ok_and(|x|
|
if supertrend_search_result.is_ok_and(|x| {
|
||||||
supertrend_vec[x].area == SuperTrendArea::DOWN && supertrend_vec[x].band_value > filtered_data.current_price.to_f64().unwrap()) {
|
supertrend_vec[x].area == SuperTrendArea::DOWN
|
||||||
filtered_data.target_price = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec[supertrend_search_result.unwrap()].band_value).unwrap();
|
&& supertrend_vec[x].band_value
|
||||||
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.current_price.to_f64().unwrap()
|
||||||
|
}) {
|
||||||
|
filtered_data.target_price = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||||
|
supertrend_vec[supertrend_search_result.unwrap()].band_value,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let stop_loss = decimal_sub(
|
||||||
|
filtered_data.current_price,
|
||||||
|
decimal_div(
|
||||||
|
decimal_sub(filtered_data.target_price, filtered_data.current_price),
|
||||||
|
dec!(2),
|
||||||
|
),
|
||||||
|
);
|
||||||
filtered_data.stoploss = stop_loss;
|
filtered_data.stoploss = stop_loss;
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -128,18 +165,32 @@ pub async fn list_up_for_buy(
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let ema_map = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let ema_map = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
for (symbol, filtered_data) in &mut filtered_data {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
if let (Some(ema_vec), Some(rt_30m_vec)) = (ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
if let (Some(ema_vec), Some(rt_30m_vec)) =
|
||||||
|
(ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol))
|
||||||
|
{
|
||||||
let search_result = ema_vec.binary_search_by_key(
|
let search_result = ema_vec.binary_search_by_key(
|
||||||
&rt_30m_vec.last().unwrap().close_time,
|
&rt_30m_vec.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[search_result.unwrap()].ema_value < rt_30m_vec[rt_30m_vec.len()-1].close_price) &&
|
);
|
||||||
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-1].ema_value < rt_30m_vec[rt_30m_vec.len()-2].close_price) &&
|
if search_result.is_ok_and(|x| {
|
||||||
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-2].ema_value < rt_30m_vec[rt_30m_vec.len()-3].close_price) &&
|
ema_vec[search_result.unwrap()].ema_value
|
||||||
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-3].ema_value < rt_30m_vec[rt_30m_vec.len()-4].close_price) &&
|
< rt_30m_vec[rt_30m_vec.len() - 1].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) {
|
}) && search_result.is_ok_and(|x| {
|
||||||
|
ema_vec[search_result.unwrap() - 1].ema_value
|
||||||
|
< rt_30m_vec[rt_30m_vec.len() - 2].close_price
|
||||||
|
}) && search_result.is_ok_and(|x| {
|
||||||
|
ema_vec[search_result.unwrap() - 2].ema_value
|
||||||
|
< rt_30m_vec[rt_30m_vec.len() - 3].close_price
|
||||||
|
}) && search_result.is_ok_and(|x| {
|
||||||
|
ema_vec[search_result.unwrap() - 3].ema_value
|
||||||
|
< rt_30m_vec[rt_30m_vec.len() - 4].close_price
|
||||||
|
}) && search_result.is_ok_and(|x| {
|
||||||
|
ema_vec[search_result.unwrap() - 4].ema_value
|
||||||
|
< rt_30m_vec[rt_30m_vec.len() - 5].close_price
|
||||||
|
}) {
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -154,8 +205,11 @@ pub async fn list_up_for_buy(
|
||||||
let stoch_rsi_map = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let stoch_rsi_map = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
for (symbol, filtered_data) in &mut filtered_data {
|
for (symbol, filtered_data) in &mut filtered_data {
|
||||||
if let Some(stoch_rsi_vec) = stoch_rsi_map.get(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);
|
let search_result = stoch_rsi_vec
|
||||||
if search_result.is_some_and(|a| stoch_rsi_vec[a].k < 15.0 && stoch_rsi_vec[a].d < 15.0) {
|
.iter()
|
||||||
|
.position(|x| x.close_time == filtered_data.closetime);
|
||||||
|
if search_result.is_some_and(|a| stoch_rsi_vec[a].k < 15.0 && stoch_rsi_vec[a].d < 15.0)
|
||||||
|
{
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -169,12 +223,21 @@ pub async fn list_up_for_buy(
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
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?;
|
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
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 let (Some(macd_vec), Some(rt_price_vec)) =
|
||||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||||
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();
|
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;
|
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -213,8 +276,7 @@ pub async fn list_up_for_sell(
|
||||||
if let Some(exchange_info) = exchange_info_map.get(&element.symbol) {
|
if let Some(exchange_info) = exchange_info_map.get(&element.symbol) {
|
||||||
let lot_step_size = exchange_info.stepsize;
|
let lot_step_size = exchange_info.stepsize;
|
||||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
let quote_commission_precision = exchange_info.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,
|
||||||
);
|
);
|
||||||
|
|
@ -222,8 +284,7 @@ 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.target_price {
|
||||||
{
|
|
||||||
limit_order_sell(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
element.current_price,
|
element.current_price,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
use super::{
|
use super::{
|
||||||
dec, decimal_add, decimal_sub, decimal_div, decimal_mul, ema, exists_record, insert_pre_suggested_coins,
|
adx, dec, decimal_add, decimal_div, decimal_mul, decimal_sub, duplicate_filter, ema, ema_macd,
|
||||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
exists_record, get_current_price, get_server_epoch, insert_pre_suggested_coins,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
limit_order_sell, remove_keys, rsi, select_filled_buy_orders, stoch_rsi, supertrend,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
try_join_all, update_record3, AdxData, AllData, Arc, BollingerBandData, Client, ClientBuilder,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, get_current_price
|
Decimal, EmaData, ExchangeInfo, FilteredDataValue, HashMap, HashSet, MacdData, Mutex,
|
||||||
|
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal,
|
||||||
|
SupertrendData, ToPrimitive, TradeFee,
|
||||||
};
|
};
|
||||||
|
|
||||||
// BUY conditions
|
// BUY conditions
|
||||||
|
|
@ -27,11 +29,16 @@ pub async fn list_up_for_buy(
|
||||||
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
let supertrend_1d_map =
|
||||||
|
supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
supertrend_1d_map.get(symbol),
|
||||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
alldata.rt_price_1d_vec.get(symbol),
|
||||||
|
) {
|
||||||
|
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||||
|
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||||
|
{
|
||||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP {
|
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP {
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -49,12 +56,21 @@ pub async fn list_up_for_buy(
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let macd_1d_map = ema_macd(3, 5, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
let macd_1d_map = ema_macd(3, 5, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
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 let (Some(macd_vec), Some(rt_price_vec)) =
|
||||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||||
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 &&
|
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||||
macd_vec[macd_vec.len()-2].macd_value < macd_vec[macd_vec.len()-2].signal_value {
|
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).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
|
||||||
|
{
|
||||||
|
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;
|
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -71,24 +87,48 @@ pub async fn list_up_for_buy(
|
||||||
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
let supertrend_1d_map =
|
||||||
|
supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
supertrend_1d_map.get(symbol),
|
||||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
alldata.rt_price_1d_vec.get(symbol),
|
||||||
// input stoploss, target_price
|
) {
|
||||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN &&
|
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||||
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));
|
// input stoploss, target_price
|
||||||
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(2.0)), values.current_price);
|
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||||
|
supertrend_vec.last().unwrap().band_value,
|
||||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
)
|
||||||
supertrend_vec.last().unwrap().band_value < values.current_price.to_f64().unwrap()
|
.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,
|
||||||
|
);
|
||||||
|
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP
|
||||||
|
&& supertrend_vec.last().unwrap().band_value
|
||||||
|
< values.current_price.to_f64().unwrap()
|
||||||
{
|
{
|
||||||
values.stoploss = band_value;
|
values.stoploss = band_value;
|
||||||
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(2.0)), values.current_price);
|
values.target_price = decimal_add(
|
||||||
|
decimal_mul(
|
||||||
|
decimal_sub(values.current_price, values.stoploss),
|
||||||
|
dec!(2.0),
|
||||||
|
),
|
||||||
|
values.current_price,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -106,9 +146,11 @@ pub async fn list_up_for_buy(
|
||||||
let adx_vec = adx(3, 5, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
let adx_vec = adx(3, 5, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let Some(adx_vec) = adx_vec.get(symbol) {
|
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 let Some(last_idx) = adx_vec
|
||||||
if
|
.iter()
|
||||||
adx_vec[last_idx].adx > adx_vec[last_idx-1].adx {
|
.position(|elem| elem.close_time == values.closetime)
|
||||||
|
{
|
||||||
|
if adx_vec[last_idx].adx > adx_vec[last_idx - 1].adx {
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +175,12 @@ pub async fn list_up_for_buy(
|
||||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 4].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() - 5].opclo_price);
|
||||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 6].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());
|
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());
|
opclo_vec.remove(max_idx.unwrap());
|
||||||
|
|
||||||
let mut mean = 0.0;
|
let mut mean = 0.0;
|
||||||
|
|
@ -181,19 +228,25 @@ pub async fn list_up_for_sell(
|
||||||
for element in &filled_buy_orders {
|
for element in &filled_buy_orders {
|
||||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
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?;
|
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) {
|
||||||
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) =
|
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) = (
|
||||||
(exchange_info_map.get(&element.symbol), trade_fee_map.get(&element.symbol), supertrend_1d.get(&element.symbol)) {
|
exchange_info_map.get(&element.symbol),
|
||||||
|
trade_fee_map.get(&element.symbol),
|
||||||
|
supertrend_1d.get(&element.symbol),
|
||||||
|
) {
|
||||||
// update stoploss
|
// update stoploss
|
||||||
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 == SuperTrendArea::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![(String::from("stoploss"), band_value.to_string())];
|
||||||
(String::from("stoploss"), band_value.to_string()),
|
|
||||||
];
|
|
||||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||||
update_record3(&update_table_name, &update_value, &update_condition)
|
update_record3(&update_table_name, &update_value, &update_condition)
|
||||||
.await
|
.await
|
||||||
|
|
@ -202,8 +255,7 @@ pub async fn list_up_for_sell(
|
||||||
|
|
||||||
let lot_step_size = exchange_info.stepsize;
|
let lot_step_size = exchange_info.stepsize;
|
||||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
let quote_commission_precision = exchange_info.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,
|
||||||
);
|
);
|
||||||
|
|
@ -231,7 +283,8 @@ pub async fn list_up_for_sell(
|
||||||
&trade_fee_map,
|
&trade_fee_map,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 7 { // 7 days timeout selling
|
} else if server_epoch - element.transact_time > (86_400_000) * 7 {
|
||||||
|
// 7 days timeout selling
|
||||||
limit_order_sell(
|
limit_order_sell(
|
||||||
&element,
|
&element,
|
||||||
element.current_price,
|
element.current_price,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
use super::{
|
use super::{
|
||||||
dec, decimal_add, decimal_sub, decimal_div, decimal_mul, ema, exists_record, insert_pre_suggested_coins,
|
adx, dec, decimal_add, decimal_div, decimal_mul, decimal_sub, dema, duplicate_filter, ema,
|
||||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
ema_macd, exists_record, get_current_price, get_server_epoch, insert_pre_suggested_coins,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
limit_order_sell, remove_keys, rsi, select_filled_buy_orders, stoch_rsi, supertrend, tema,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
try_join_all, update_record3, AdxData, AllData, Arc, BollingerBandData, Client, ClientBuilder,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, get_current_price, dema, DemaData, tema, TemaData
|
Decimal, DemaData, EmaData, ExchangeInfo, FilteredDataValue, HashMap, HashSet, MacdData, Mutex,
|
||||||
|
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal,
|
||||||
|
SupertrendData, TemaData, ToPrimitive, TradeFee,
|
||||||
};
|
};
|
||||||
|
|
||||||
// BUY conditions
|
// BUY conditions
|
||||||
|
|
@ -29,15 +31,28 @@ pub async fn list_up_for_buy(
|
||||||
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
for (symbol, values) in &mut filtered_data {
|
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 let (Some(macd_vec), Some(rt_price_vec)) =
|
||||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
{
|
||||||
if macd_vec.len() >= 30 &&
|
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||||
(macd_vec[macd_vec.len()-1].macd_value - macd_vec[macd_vec.len()-1].signal_value).is_sign_negative() &&
|
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||||
(macd_vec[macd_vec.len()-2].macd_value - macd_vec[macd_vec.len()-2].signal_value).is_sign_negative() &&
|
{
|
||||||
(macd_vec[macd_vec.len()-1].macd_value - macd_vec[macd_vec.len()-1].signal_value >
|
if macd_vec.len() >= 30
|
||||||
macd_vec[macd_vec.len()-2].macd_value - macd_vec[macd_vec.len()-2].signal_value) {
|
&& (macd_vec[macd_vec.len() - 1].macd_value
|
||||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
- macd_vec[macd_vec.len() - 1].signal_value)
|
||||||
|
.is_sign_negative()
|
||||||
|
&& (macd_vec[macd_vec.len() - 2].macd_value
|
||||||
|
- macd_vec[macd_vec.len() - 2].signal_value)
|
||||||
|
.is_sign_negative()
|
||||||
|
&& (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;
|
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -57,14 +72,20 @@ pub async fn list_up_for_buy(
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if stoch_rsis.contains_key(symbol) {
|
if stoch_rsis.contains_key(symbol) {
|
||||||
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
||||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == values.closetime);
|
let search_result = stoch_rsi_vec
|
||||||
if stoch_rsi_vec.len() > 10 && search_result.is_some_and(|a| stoch_rsi_vec[a-3].k < 20.0 &&
|
.iter()
|
||||||
stoch_rsi_vec[a-2].k < 15.0 &&
|
.position(|x| x.close_time == values.closetime);
|
||||||
stoch_rsi_vec[a-1].k < 10.0 &&
|
if stoch_rsi_vec.len() > 10
|
||||||
stoch_rsi_vec[a-1].k < stoch_rsi_vec[a].k &&
|
&& search_result.is_some_and(|a| {
|
||||||
stoch_rsi_vec[a].k < stoch_rsi_vec[a].d &&
|
stoch_rsi_vec[a - 3].k < 20.0
|
||||||
!stoch_rsi_vec[a].d.is_subnormal() &&
|
&& stoch_rsi_vec[a - 2].k < 15.0
|
||||||
stoch_rsi_vec[a].d > 0.00000001) {
|
&& stoch_rsi_vec[a - 1].k < 10.0
|
||||||
|
&& stoch_rsi_vec[a - 1].k < stoch_rsi_vec[a].k
|
||||||
|
&& stoch_rsi_vec[a].k < stoch_rsi_vec[a].d
|
||||||
|
&& !stoch_rsi_vec[a].d.is_subnormal()
|
||||||
|
&& stoch_rsi_vec[a].d > 0.00000001
|
||||||
|
})
|
||||||
|
{
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -77,11 +98,16 @@ pub async fn list_up_for_buy(
|
||||||
// 2nd filtering: supertrend(ATR period 30, multiplier: 2.0, 1d close price) UP area
|
// 2nd filtering: supertrend(ATR period 30, multiplier: 2.0, 1d close price) UP area
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
let supertrend_1d_map = supertrend(30, 2.0, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
let supertrend_1d_map =
|
||||||
|
supertrend(30, 2.0, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
supertrend_1d_map.get(symbol),
|
||||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
alldata.rt_price_1d_vec.get(symbol),
|
||||||
|
) {
|
||||||
|
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||||
|
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||||
|
{
|
||||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP {
|
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP {
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -98,24 +124,48 @@ pub async fn list_up_for_buy(
|
||||||
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
let supertrend_1d_map =
|
||||||
|
supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
supertrend_1d_map.get(symbol),
|
||||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
alldata.rt_price_1d_vec.get(symbol),
|
||||||
// input stoploss, target_price
|
) {
|
||||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN &&
|
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||||
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));
|
// input stoploss, target_price
|
||||||
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(2.0)), values.current_price);
|
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||||
|
supertrend_vec.last().unwrap().band_value,
|
||||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
)
|
||||||
supertrend_vec.last().unwrap().band_value < values.current_price.to_f64().unwrap()
|
.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,
|
||||||
|
);
|
||||||
|
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP
|
||||||
|
&& supertrend_vec.last().unwrap().band_value
|
||||||
|
< values.current_price.to_f64().unwrap()
|
||||||
{
|
{
|
||||||
values.stoploss = band_value;
|
values.stoploss = band_value;
|
||||||
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(2.0)), values.current_price);
|
values.target_price = decimal_add(
|
||||||
|
decimal_mul(
|
||||||
|
decimal_sub(values.current_price, values.stoploss),
|
||||||
|
dec!(2.0),
|
||||||
|
),
|
||||||
|
values.current_price,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +190,12 @@ pub async fn list_up_for_buy(
|
||||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 4].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() - 5].opclo_price);
|
||||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 6].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());
|
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());
|
opclo_vec.remove(max_idx.unwrap());
|
||||||
|
|
||||||
let mut mean = 0.0;
|
let mut mean = 0.0;
|
||||||
|
|
@ -188,49 +243,63 @@ pub async fn list_up_for_sell(
|
||||||
for element in &filled_buy_orders {
|
for element in &filled_buy_orders {
|
||||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
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?;
|
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 {
|
||||||
let mut is_sell = false;
|
let mut is_sell = false;
|
||||||
let opclo_sample_length: usize = 15; // 15 candle samsples
|
let opclo_sample_length: usize = 15; // 15 candle samsples
|
||||||
let mut target_profit_percent = 0.0;
|
let mut target_profit_percent = 0.0;
|
||||||
if let Some(price_1d_vec) = all_data
|
if let Some(price_1d_vec) = all_data.rt_price_1d_vec.get(&element.symbol) {
|
||||||
.rt_price_1d_vec
|
|
||||||
.get(&element.symbol)
|
|
||||||
{
|
|
||||||
let vec_len = price_1d_vec.len();
|
let vec_len = price_1d_vec.len();
|
||||||
if let Some(candles) = price_1d_vec.get(vec_len-opclo_sample_length-2..vec_len-1) {
|
if let Some(candles) =
|
||||||
|
price_1d_vec.get(vec_len - opclo_sample_length - 2..vec_len - 1)
|
||||||
|
{
|
||||||
let windows = candles.windows(2);
|
let windows = candles.windows(2);
|
||||||
let mut sum_amplitude_candles = 0.0;
|
let mut sum_amplitude_candles = 0.0;
|
||||||
let mut sum_ratio_amp_body = 0.0;
|
let mut sum_ratio_amp_body = 0.0;
|
||||||
let mut average_amplitude = 0.0;
|
let mut average_amplitude = 0.0;
|
||||||
|
|
||||||
for window in windows {
|
for window in windows {
|
||||||
sum_amplitude_candles += ((window.last().unwrap().high_price - window.last().unwrap().low_price) * 100.0) / window.first().unwrap().close_price;
|
sum_amplitude_candles += ((window.last().unwrap().high_price
|
||||||
|
- window.last().unwrap().low_price)
|
||||||
|
* 100.0)
|
||||||
|
/ window.first().unwrap().close_price;
|
||||||
}
|
}
|
||||||
let average_amplitude = sum_amplitude_candles / opclo_sample_length as f64; // percent unit
|
let average_amplitude = sum_amplitude_candles / opclo_sample_length as f64; // percent unit
|
||||||
let mut amplitude_variance = 0.0;
|
let mut amplitude_variance = 0.0;
|
||||||
|
|
||||||
let windows = candles.windows(2);
|
let windows = candles.windows(2);
|
||||||
for window in windows {
|
for window in windows {
|
||||||
amplitude_variance += ((((window.last().unwrap().high_price - window.last().unwrap().low_price) * 100.0) / window.first().unwrap().close_price) - average_amplitude).powi(2);
|
amplitude_variance += ((((window.last().unwrap().high_price
|
||||||
|
- window.last().unwrap().low_price)
|
||||||
|
* 100.0)
|
||||||
|
/ window.first().unwrap().close_price)
|
||||||
|
- average_amplitude)
|
||||||
|
.powi(2);
|
||||||
}
|
}
|
||||||
amplitude_variance = amplitude_variance / (opclo_sample_length - 1) as f64;
|
amplitude_variance = amplitude_variance / (opclo_sample_length - 1) as f64;
|
||||||
let standard_deviation_amplitude = amplitude_variance.sqrt();
|
let standard_deviation_amplitude = amplitude_variance.sqrt();
|
||||||
target_profit_percent = average_amplitude + (standard_deviation_amplitude * 0.5);
|
target_profit_percent =
|
||||||
|
average_amplitude + (standard_deviation_amplitude * 0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if element.used_usdt >= dec!(10.0) {
|
if element.used_usdt >= dec!(10.0) {
|
||||||
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) =
|
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) = (
|
||||||
(exchange_info_map.get(&element.symbol), trade_fee_map.get(&element.symbol), supertrend_1d.get(&element.symbol)) {
|
exchange_info_map.get(&element.symbol),
|
||||||
|
trade_fee_map.get(&element.symbol),
|
||||||
|
supertrend_1d.get(&element.symbol),
|
||||||
|
) {
|
||||||
// update stoploss
|
// update stoploss
|
||||||
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 == SuperTrendArea::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![(String::from("stoploss"), band_value.to_string())];
|
||||||
(String::from("stoploss"), band_value.to_string()),
|
|
||||||
];
|
|
||||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||||
update_record3(&update_table_name, &update_value, &update_condition)
|
update_record3(&update_table_name, &update_value, &update_condition)
|
||||||
.await
|
.await
|
||||||
|
|
@ -239,8 +308,7 @@ pub async fn list_up_for_sell(
|
||||||
|
|
||||||
let lot_step_size = exchange_info.stepsize;
|
let lot_step_size = exchange_info.stepsize;
|
||||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
let quote_commission_precision = exchange_info.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,
|
||||||
);
|
);
|
||||||
|
|
@ -252,15 +320,28 @@ pub async fn list_up_for_sell(
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if element.current_price >= element.target_price {
|
} else if element.current_price >= element.target_price {
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if (element.pure_profit_percent >= target_profit_percent * 2.5) && (target_profit_percent != 0.0 && target_profit_percent.is_sign_positive()) { // absolute sell profit percent
|
} else if (element.pure_profit_percent >= target_profit_percent * 2.5)
|
||||||
|
&& (target_profit_percent != 0.0
|
||||||
|
&& target_profit_percent.is_sign_positive())
|
||||||
|
{
|
||||||
|
// absolute sell profit percent
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 5 &&
|
} else if server_epoch - element.transact_time > (86_400_000) * 5
|
||||||
(target_profit_percent != 0.0 && target_profit_percent.is_sign_positive() && target_profit_percent * 2.0 <= element.pure_profit_percent){ // scaled selling with time up selling (5 days)
|
&& (target_profit_percent != 0.0
|
||||||
|
&& target_profit_percent.is_sign_positive()
|
||||||
|
&& target_profit_percent * 2.0 <= element.pure_profit_percent)
|
||||||
|
{
|
||||||
|
// scaled selling with time up selling (5 days)
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 6 &&
|
} else if server_epoch - element.transact_time > (86_400_000) * 6
|
||||||
(target_profit_percent != 0.0 && target_profit_percent.is_sign_positive() && target_profit_percent * 1.5 <= element.pure_profit_percent){ // scaled selling with time up selling (6 days)
|
&& (target_profit_percent != 0.0
|
||||||
|
&& target_profit_percent.is_sign_positive()
|
||||||
|
&& target_profit_percent * 1.5 <= element.pure_profit_percent)
|
||||||
|
{
|
||||||
|
// scaled selling with time up selling (6 days)
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 7 { // time up selling
|
} else if server_epoch - element.transact_time > (86_400_000) * 7 {
|
||||||
|
// time up selling
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
}
|
}
|
||||||
// TODO: sell_count가 1일 때 적용하기
|
// TODO: sell_count가 1일 때 적용하기
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
use super::{
|
use super::{
|
||||||
dec, decimal_add, decimal_sub, decimal_div, decimal_mul, ema, exists_record, insert_pre_suggested_coins,
|
adx, dec, decimal_add, decimal_div, decimal_mul, decimal_sub, duplicate_filter, ema, ema_macd,
|
||||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
exists_record, get_current_price, get_server_epoch, insert_pre_suggested_coins,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
limit_order_sell, remove_keys, rsi, select_filled_buy_orders, stoch_rsi, supertrend,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
try_join_all, update_record3, AdxData, AllData, Arc, BollingerBandData, Client, ClientBuilder,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, get_current_price
|
Decimal, EmaData, ExchangeInfo, FilteredDataValue, HashMap, HashSet, MacdData, Mutex,
|
||||||
|
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal,
|
||||||
|
SupertrendData, ToPrimitive, TradeFee,
|
||||||
};
|
};
|
||||||
|
|
||||||
// BUY conditions
|
// BUY conditions
|
||||||
|
|
@ -31,11 +33,15 @@ pub async fn list_up_for_buy(
|
||||||
let adx_vec = adx(10, 10, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
let adx_vec = adx(10, 10, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let Some(adx_vec) = adx_vec.get(symbol) {
|
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 let Some(last_idx) = adx_vec
|
||||||
if
|
.iter()
|
||||||
adx_vec[last_idx].adx > adx_vec[last_idx-1].adx &&
|
.position(|elem| elem.close_time == values.closetime)
|
||||||
adx_vec[last_idx-1].adx > adx_vec[last_idx-2].adx &&
|
{
|
||||||
adx_vec[last_idx].adx < 25.0 {
|
if adx_vec.len() > 10
|
||||||
|
&& adx_vec[last_idx].adx > adx_vec[last_idx - 1].adx
|
||||||
|
&& adx_vec[last_idx - 1].adx > adx_vec[last_idx - 2].adx
|
||||||
|
&& adx_vec[last_idx].adx < 25.0
|
||||||
|
{
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -47,17 +53,21 @@ pub async fn list_up_for_buy(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||||
|
println!("{}", filtered_data.keys().len());
|
||||||
// 2nd filtering: the 2 previous ADX(5, 5)s increase, ADX < 40
|
// 2nd filtering: the 2 previous ADX(5, 5)s increase, ADX < 40
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let adx_vec = adx(10, 10, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
let adx_vec = adx(10, 10, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let Some(adx_vec) = adx_vec.get(symbol) {
|
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 let Some(last_idx) = adx_vec
|
||||||
if
|
.iter()
|
||||||
adx_vec[last_idx].adx > adx_vec[last_idx-1].adx &&
|
.position(|elem| elem.close_time == values.closetime)
|
||||||
adx_vec[last_idx-1].adx > adx_vec[last_idx-2].adx &&
|
{
|
||||||
adx_vec[last_idx].adx < 40.0 {
|
if adx_vec.len() > 10
|
||||||
|
&& adx_vec[last_idx].adx > adx_vec[last_idx - 1].adx
|
||||||
|
&& adx_vec[last_idx - 1].adx > adx_vec[last_idx - 2].adx
|
||||||
|
&& adx_vec[last_idx].adx < 40.0
|
||||||
|
{
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +85,10 @@ pub async fn list_up_for_buy(
|
||||||
let rsi_map = rsi(5, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
let rsi_map = rsi(5, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let Some(rsi_vec) = rsi_map.get(symbol) {
|
if let Some(rsi_vec) = rsi_map.get(symbol) {
|
||||||
if let Some(last_idx) = rsi_vec.iter().position(|elem| elem.close_time == values.closetime) {
|
if let Some(last_idx) = rsi_vec
|
||||||
|
.iter()
|
||||||
|
.position(|elem| elem.close_time == values.closetime)
|
||||||
|
{
|
||||||
if rsi_vec[last_idx].rsi_value > 75.0 {
|
if rsi_vec[last_idx].rsi_value > 75.0 {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -91,20 +104,38 @@ pub async fn list_up_for_buy(
|
||||||
// 4th filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
// 4th filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
let supertrend_1d_map =
|
||||||
|
supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
supertrend_1d_map.get(symbol),
|
||||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
alldata.rt_price_1d_vec.get(symbol),
|
||||||
// input stoploss, target_price
|
) {
|
||||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||||
supertrend_vec.last().unwrap().band_value < values.current_price.to_f64().unwrap()
|
|
||||||
{
|
{
|
||||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
// input stoploss, target_price
|
||||||
|
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||||
|
supertrend_vec.last().unwrap().band_value,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP
|
||||||
|
&& supertrend_vec.last().unwrap().band_value
|
||||||
|
< values.current_price.to_f64().unwrap()
|
||||||
|
{
|
||||||
|
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;
|
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||||
values.stoploss = band_value;
|
values.stoploss = band_value;
|
||||||
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(3.0)), values.current_price);
|
values.target_price = decimal_add(
|
||||||
|
decimal_mul(
|
||||||
|
decimal_sub(values.current_price, values.stoploss),
|
||||||
|
dec!(3.0),
|
||||||
|
),
|
||||||
|
values.current_price,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +160,12 @@ pub async fn list_up_for_buy(
|
||||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 4].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() - 5].opclo_price);
|
||||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 6].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());
|
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());
|
opclo_vec.remove(max_idx.unwrap());
|
||||||
|
|
||||||
let mut mean = 0.0;
|
let mut mean = 0.0;
|
||||||
|
|
@ -180,22 +216,27 @@ pub async fn list_up_for_sell(
|
||||||
for element in &filled_buy_orders {
|
for element in &filled_buy_orders {
|
||||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
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?;
|
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 {
|
||||||
let mut is_sell = false;
|
let mut is_sell = false;
|
||||||
|
|
||||||
|
|
||||||
if element.used_usdt >= dec!(10.0) {
|
if element.used_usdt >= dec!(10.0) {
|
||||||
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) =
|
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) = (
|
||||||
(exchange_info_map.get(&element.symbol), trade_fee_map.get(&element.symbol), supertrend_1d.get(&element.symbol)) {
|
exchange_info_map.get(&element.symbol),
|
||||||
|
trade_fee_map.get(&element.symbol),
|
||||||
|
supertrend_1d.get(&element.symbol),
|
||||||
|
) {
|
||||||
// update stoploss
|
// update stoploss
|
||||||
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 == SuperTrendArea::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![(String::from("stoploss"), band_value.to_string())];
|
||||||
(String::from("stoploss"), band_value.to_string()),
|
|
||||||
];
|
|
||||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||||
update_record3(&update_table_name, &update_value, &update_condition)
|
update_record3(&update_table_name, &update_value, &update_condition)
|
||||||
.await
|
.await
|
||||||
|
|
@ -204,12 +245,16 @@ pub async fn list_up_for_sell(
|
||||||
|
|
||||||
let lot_step_size = exchange_info.stepsize;
|
let lot_step_size = exchange_info.stepsize;
|
||||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
let quote_commission_precision = exchange_info.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 target_profit_percent = decimal_div(decimal_sub(element.stoploss, element.buy_price), element.buy_price).to_f64().unwrap();
|
let target_profit_percent = decimal_div(
|
||||||
|
decimal_sub(element.target_price, element.buy_price),
|
||||||
|
element.buy_price,
|
||||||
|
)
|
||||||
|
.to_f64()
|
||||||
|
.unwrap();
|
||||||
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()
|
||||||
{
|
{
|
||||||
|
|
@ -217,28 +262,58 @@ pub async fn list_up_for_sell(
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if element.current_price >= element.target_price {
|
} else if element.current_price >= element.target_price {
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 8 &&
|
} else if server_epoch - element.transact_time > (86_400_000) * 8
|
||||||
(target_profit_percent != 0.0 && target_profit_percent.is_sign_positive() && target_profit_percent * (13.0/14.0) <= element.pure_profit_percent) {
|
&& (target_profit_percent != 0.0
|
||||||
|
&& target_profit_percent.is_sign_positive()
|
||||||
|
&& target_profit_percent * (13.0 / 14.0)
|
||||||
|
<= element.pure_profit_percent)
|
||||||
|
{
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 9 &&
|
} else if server_epoch - element.transact_time > (86_400_000) * 9
|
||||||
(target_profit_percent != 0.0 && target_profit_percent.is_sign_positive() && target_profit_percent * (12.0/14.0) <= element.pure_profit_percent) {
|
&& (target_profit_percent != 0.0
|
||||||
|
&& target_profit_percent.is_sign_positive()
|
||||||
|
&& target_profit_percent * (12.0 / 14.0)
|
||||||
|
<= element.pure_profit_percent)
|
||||||
|
{
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 10 &&
|
} else if server_epoch - element.transact_time > (86_400_000) * 10
|
||||||
(target_profit_percent != 0.0 && target_profit_percent.is_sign_positive() && target_profit_percent * (11.0/14.0) <= element.pure_profit_percent) {
|
&& (target_profit_percent != 0.0
|
||||||
|
&& target_profit_percent.is_sign_positive()
|
||||||
|
&& target_profit_percent * (11.0 / 14.0)
|
||||||
|
<= element.pure_profit_percent)
|
||||||
|
{
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 11 &&
|
} else if server_epoch - element.transact_time > (86_400_000) * 11
|
||||||
(target_profit_percent != 0.0 && target_profit_percent.is_sign_positive() && target_profit_percent * (10.0/14.0) <= element.pure_profit_percent) {
|
&& (target_profit_percent != 0.0
|
||||||
|
&& target_profit_percent.is_sign_positive()
|
||||||
|
&& target_profit_percent * (10.0 / 14.0)
|
||||||
|
<= element.pure_profit_percent)
|
||||||
|
{
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 12 &&
|
} else if server_epoch - element.transact_time > (86_400_000) * 12
|
||||||
(target_profit_percent != 0.0 && target_profit_percent.is_sign_positive() && target_profit_percent * (9.0/14.0) <= element.pure_profit_percent) {
|
&& (target_profit_percent != 0.0
|
||||||
|
&& target_profit_percent.is_sign_positive()
|
||||||
|
&& target_profit_percent * (9.0 / 14.0)
|
||||||
|
<= element.pure_profit_percent)
|
||||||
|
{
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 13 &&
|
} else if server_epoch - element.transact_time > (86_400_000) * 13
|
||||||
(target_profit_percent != 0.0 && target_profit_percent.is_sign_positive() && target_profit_percent * (8.0/14.0) <= element.pure_profit_percent) {
|
&& (target_profit_percent != 0.0
|
||||||
|
&& target_profit_percent.is_sign_positive()
|
||||||
|
&& target_profit_percent * (8.0 / 14.0)
|
||||||
|
<= element.pure_profit_percent)
|
||||||
|
{
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 14 &&
|
} else if server_epoch - element.transact_time > (86_400_000) * 14
|
||||||
(target_profit_percent != 0.0 && target_profit_percent.is_sign_positive() && target_profit_percent * (1.0/2.0) <= element.pure_profit_percent) { // scaled selling with time up selling (6 days){
|
&& (target_profit_percent != 0.0
|
||||||
|
&& target_profit_percent.is_sign_positive()
|
||||||
|
&& target_profit_percent * (1.0 / 2.0)
|
||||||
|
<= element.pure_profit_percent)
|
||||||
|
{
|
||||||
|
// scaled selling with time up selling (6 days){
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (86_400_000) * 15 { // time up selling
|
} else if server_epoch - element.transact_time > (86_400_000) * 15 {
|
||||||
|
// time up selling
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
}
|
}
|
||||||
// TODO: sell_count가 1일 때 적용하기
|
// TODO: sell_count가 1일 때 적용하기
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
use super::{
|
use super::{
|
||||||
dec, decimal_add, decimal_sub, decimal_div, decimal_mul, ema, exists_record, insert_pre_suggested_coins,
|
adx, dec, decimal_add, decimal_div, decimal_mul, decimal_sub, dema, duplicate_filter, ema,
|
||||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
ema_macd, exists_record, get_current_price, get_server_epoch, heatmap_volume,
|
||||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
insert_pre_suggested_coins, limit_order_sell, remove_keys, rsi, select_filled_buy_orders,
|
||||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
stoch_rsi, supertrend, tema, try_join_all, update_record3, AdxData, AllData, Arc,
|
||||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, get_current_price, dema, DemaData, tema, TemaData,
|
BollingerBandData, Client, ClientBuilder, Decimal, DemaData, EmaData, ExchangeInfo,
|
||||||
heatmap_volume, HeatMapLevel, HeatmapVolumeData
|
FilteredDataValue, HashMap, HashSet, HeatMapLevel, HeatmapVolumeData, MacdData, Mutex,
|
||||||
|
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal,
|
||||||
|
SupertrendData, TemaData, ToPrimitive, TradeFee,
|
||||||
};
|
};
|
||||||
|
|
||||||
// BUY conditions
|
// BUY conditions
|
||||||
|
|
@ -28,10 +30,12 @@ pub async fn list_up_for_buy(
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let (Some(tema5_vec), Some(tema10_vec)) = (tema_3.get(symbol), tema_10.get(symbol)) {
|
if let (Some(tema5_vec), Some(tema10_vec)) = (tema_3.get(symbol), tema_10.get(symbol)) {
|
||||||
if tema5_vec.len() > 2 && tema10_vec.len() > 2 &&
|
if tema5_vec.len() > 2
|
||||||
tema5_vec.last().unwrap().close_time == tema10_vec.last().unwrap().close_time &&
|
&& tema10_vec.len() > 2
|
||||||
tema5_vec.last().unwrap().close_time > server_epoch &&
|
&& tema5_vec.last().unwrap().close_time == tema10_vec.last().unwrap().close_time
|
||||||
tema10_vec.last().unwrap().close_time > server_epoch {
|
&& tema5_vec.last().unwrap().close_time > server_epoch
|
||||||
|
&& tema10_vec.last().unwrap().close_time > server_epoch
|
||||||
|
{
|
||||||
if tema5_vec.last().unwrap().tema_value > tema10_vec.last().unwrap().tema_value {
|
if tema5_vec.last().unwrap().tema_value > tema10_vec.last().unwrap().tema_value {
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
|
|
@ -53,17 +57,30 @@ pub async fn list_up_for_buy(
|
||||||
let tema_200 = tema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let tema_200 = tema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let (Some(tema30_vec), Some(tema5_vec), Some(tema_200_vec), Some(rt_price_vec)) =
|
if let (Some(tema30_vec), Some(tema5_vec), Some(tema_200_vec), Some(rt_price_vec)) = (
|
||||||
(tema_30.get(symbol), tema_5.get(symbol), tema_200.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
tema_30.get(symbol),
|
||||||
if (tema30_vec.len() > 10 && tema5_vec.len() > 10 && tema_200_vec.len() > 10 && rt_price_vec.len() > 10) &&
|
tema_5.get(symbol),
|
||||||
tema30_vec.last().unwrap().close_time == tema5_vec.last().unwrap().close_time &&
|
tema_200.get(symbol),
|
||||||
tema_200_vec.last().unwrap().close_time == tema5_vec.last().unwrap().close_time &&
|
alldata.rt_price_30m_vec.get(symbol),
|
||||||
tema5_vec.last().unwrap().close_time > server_epoch {
|
) {
|
||||||
if tema30_vec.last().unwrap().tema_value < tema5_vec.last().unwrap().tema_value &&
|
if (tema30_vec.len() > 10
|
||||||
tema30_vec[tema30_vec.len()-2].tema_value > tema5_vec[tema5_vec.len()-2].tema_value &&
|
&& tema5_vec.len() > 10
|
||||||
tema30_vec[tema30_vec.len()-3].tema_value > tema5_vec[tema5_vec.len()-3].tema_value &&
|
&& tema_200_vec.len() > 10
|
||||||
tema_200_vec.last().unwrap().tema_value < rt_price_vec.last().unwrap().opclo_price &&
|
&& rt_price_vec.len() > 10)
|
||||||
tema_200_vec[tema_200_vec.len()-2].tema_value < rt_price_vec[rt_price_vec.len()-2].opclo_price{
|
&& tema30_vec.last().unwrap().close_time == tema5_vec.last().unwrap().close_time
|
||||||
|
&& tema_200_vec.last().unwrap().close_time == tema5_vec.last().unwrap().close_time
|
||||||
|
&& tema5_vec.last().unwrap().close_time > server_epoch
|
||||||
|
{
|
||||||
|
if tema30_vec.last().unwrap().tema_value < tema5_vec.last().unwrap().tema_value
|
||||||
|
&& tema30_vec[tema30_vec.len() - 2].tema_value
|
||||||
|
> tema5_vec[tema5_vec.len() - 2].tema_value
|
||||||
|
&& tema30_vec[tema30_vec.len() - 3].tema_value
|
||||||
|
> tema5_vec[tema5_vec.len() - 3].tema_value
|
||||||
|
&& tema_200_vec.last().unwrap().tema_value
|
||||||
|
< rt_price_vec.last().unwrap().opclo_price
|
||||||
|
&& tema_200_vec[tema_200_vec.len() - 2].tema_value
|
||||||
|
< rt_price_vec[rt_price_vec.len() - 2].opclo_price
|
||||||
|
{
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -79,32 +96,51 @@ pub async fn list_up_for_buy(
|
||||||
// supertrend(ATR period 10, multiplier: 2.0, 30m close price)
|
// supertrend(ATR period 10, multiplier: 2.0, 30m close price)
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let server_epoch = get_server_epoch().await;
|
let server_epoch = get_server_epoch().await;
|
||||||
let supertrend_30m_map = supertrend(10, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
let supertrend_30m_map =
|
||||||
|
supertrend(10, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_30m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
supertrend_30m_map.get(symbol),
|
||||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
alldata.rt_price_30m_vec.get(symbol),
|
||||||
|
) {
|
||||||
|
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||||
|
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||||
|
{
|
||||||
// input stoploss, target_price
|
// input stoploss, target_price
|
||||||
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(
|
||||||
let open_price: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().open_price).unwrap();
|
supertrend_vec.last().unwrap().band_value,
|
||||||
let current_price: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
)
|
||||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
.unwrap();
|
||||||
band_value < current_price &&
|
let open_price: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||||
band_value < open_price
|
rt_price_vec.last().unwrap().open_price,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let current_price: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||||
|
rt_price_vec.last().unwrap().close_price,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP
|
||||||
|
&& band_value < current_price
|
||||||
|
&& band_value < open_price
|
||||||
{
|
{
|
||||||
values.current_price = current_price;
|
values.current_price = current_price;
|
||||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||||
values.stoploss = band_value;
|
values.stoploss = band_value;
|
||||||
values.target_price = decimal_add(decimal_mul(decimal_sub(current_price, values.stoploss), dec!(3.0)), current_price);
|
values.target_price = decimal_add(
|
||||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN &&
|
decimal_mul(decimal_sub(current_price, values.stoploss), dec!(3.0)),
|
||||||
band_value > current_price &&
|
current_price,
|
||||||
band_value > open_price
|
);
|
||||||
|
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN
|
||||||
|
&& band_value > current_price
|
||||||
|
&& band_value > open_price
|
||||||
{
|
{
|
||||||
values.current_price = current_price;
|
values.current_price = current_price;
|
||||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||||
values.stoploss = decimal_sub(open_price, decimal_sub(band_value, open_price));
|
values.stoploss = decimal_sub(open_price, decimal_sub(band_value, open_price));
|
||||||
values.target_price = decimal_add(decimal_mul(decimal_sub(open_price, values.stoploss), dec!(3.0)), current_price);
|
values.target_price = decimal_add(
|
||||||
|
decimal_mul(decimal_sub(open_price, values.stoploss), dec!(3.0)),
|
||||||
|
current_price,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -143,11 +179,17 @@ pub async fn list_up_for_buy(
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if stoch_rsis.contains_key(symbol) {
|
if stoch_rsis.contains_key(symbol) {
|
||||||
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
||||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == values.closetime);
|
let search_result = stoch_rsi_vec
|
||||||
if stoch_rsi_vec.len() > 10 && search_result.is_some_and(|a| stoch_rsi_vec[a].k > stoch_rsi_vec[a].d &&
|
.iter()
|
||||||
stoch_rsi_vec[a].k < 70.0 &&
|
.position(|x| x.close_time == values.closetime);
|
||||||
stoch_rsi_vec[a-1].k < 60.0 &&
|
if stoch_rsi_vec.len() > 10
|
||||||
stoch_rsi_vec[a-2].k < 50.0) {
|
&& search_result.is_some_and(|a| {
|
||||||
|
stoch_rsi_vec[a].k > stoch_rsi_vec[a].d
|
||||||
|
&& stoch_rsi_vec[a].k < 70.0
|
||||||
|
&& stoch_rsi_vec[a - 1].k < 60.0
|
||||||
|
&& stoch_rsi_vec[a - 2].k < 50.0
|
||||||
|
})
|
||||||
|
{
|
||||||
} else {
|
} else {
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -159,25 +201,52 @@ pub async fn list_up_for_buy(
|
||||||
|
|
||||||
// Heatmap volume: filtering close price with Extra High is over the previous candle from 30 previous candles
|
// Heatmap volume: filtering close price with Extra High is over the previous candle from 30 previous candles
|
||||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||||
let heatmap_volumes = heatmap_volume(30, 30, 4.0, 2.5, 1.0, -0.5, &filtered_data, &alldata.rt_price_30m_vec).await?;
|
let heatmap_volumes = heatmap_volume(
|
||||||
|
30,
|
||||||
|
30,
|
||||||
|
4.0,
|
||||||
|
2.5,
|
||||||
|
1.0,
|
||||||
|
-0.5,
|
||||||
|
&filtered_data,
|
||||||
|
&alldata.rt_price_30m_vec,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
for (symbol, values) in &mut filtered_data {
|
for (symbol, values) in &mut filtered_data {
|
||||||
if stoch_rsis.contains_key(symbol) {
|
if stoch_rsis.contains_key(symbol) {
|
||||||
let heatmap_volume_vec = heatmap_volumes.get(symbol).unwrap();
|
let heatmap_volume_vec = heatmap_volumes.get(symbol).unwrap();
|
||||||
if heatmap_volume_vec.len() > 50 {
|
if heatmap_volume_vec.len() > 50 {
|
||||||
let heatmap_volume_trunc = heatmap_volume_vec.get(heatmap_volume_vec.len()-31..heatmap_volume_vec.len()-1).unwrap();
|
let heatmap_volume_trunc = heatmap_volume_vec
|
||||||
|
.get(heatmap_volume_vec.len() - 31..heatmap_volume_vec.len() - 1)
|
||||||
|
.unwrap();
|
||||||
let windows = heatmap_volume_trunc.windows(2);
|
let windows = heatmap_volume_trunc.windows(2);
|
||||||
for slice in windows {
|
for slice in windows {
|
||||||
if slice[1].heatmap_level == HeatMapLevel::ExtraHigh {
|
if slice[1].heatmap_level == HeatMapLevel::ExtraHigh {
|
||||||
if let (prev_candle_idx, current_candle_idx) = (
|
if let (prev_candle_idx, current_candle_idx) = (
|
||||||
(&alldata.rt_price_30m_vec.get(symbol).unwrap().iter().position(|x| x.close_time == slice[0].close_time)).unwrap(),
|
(&alldata
|
||||||
(&alldata.rt_price_30m_vec.get(symbol).unwrap().iter().position(|x| x.close_time == slice[1].close_time)).unwrap()
|
.rt_price_30m_vec
|
||||||
|
.get(symbol)
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.position(|x| x.close_time == slice[0].close_time))
|
||||||
|
.unwrap(),
|
||||||
|
(&alldata
|
||||||
|
.rt_price_30m_vec
|
||||||
|
.get(symbol)
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.position(|x| x.close_time == slice[1].close_time))
|
||||||
|
.unwrap(),
|
||||||
) {
|
) {
|
||||||
let prev_candle = &alldata.rt_price_30m_vec.get(symbol).unwrap()[prev_candle_idx];
|
let prev_candle =
|
||||||
let current_candle = &alldata.rt_price_30m_vec.get(symbol).unwrap()[current_candle_idx];
|
&alldata.rt_price_30m_vec.get(symbol).unwrap()[prev_candle_idx];
|
||||||
if current_candle.close_price > prev_candle.close_price ||
|
let current_candle =
|
||||||
current_candle.close_price > prev_candle.open_price ||
|
&alldata.rt_price_30m_vec.get(symbol).unwrap()[current_candle_idx];
|
||||||
current_candle.close_price > prev_candle.high_price ||
|
if current_candle.close_price > prev_candle.close_price
|
||||||
current_candle.close_price > prev_candle.low_price {
|
|| current_candle.close_price > prev_candle.open_price
|
||||||
|
|| current_candle.close_price > prev_candle.high_price
|
||||||
|
|| current_candle.close_price > prev_candle.low_price
|
||||||
|
{
|
||||||
keys_to_remove.insert(symbol.clone());
|
keys_to_remove.insert(symbol.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -200,7 +269,12 @@ pub async fn list_up_for_buy(
|
||||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 4].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() - 5].opclo_price);
|
||||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 6].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());
|
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());
|
opclo_vec.remove(max_idx.unwrap());
|
||||||
|
|
||||||
let mut mean = 0.0;
|
let mut mean = 0.0;
|
||||||
|
|
@ -248,34 +322,47 @@ pub async fn list_up_for_sell(
|
||||||
for element in &filled_buy_orders {
|
for element in &filled_buy_orders {
|
||||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||||
}
|
}
|
||||||
let supertrend_30m = supertrend(10, 2.0, true, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
let supertrend_30m =
|
||||||
|
supertrend(10, 2.0, true, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
||||||
let tema_30 = tema(30, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
let tema_30 = tema(30, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
||||||
let tema_5 = tema(5, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
let tema_5 = tema(5, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
||||||
for element in filled_buy_orders {
|
for element in filled_buy_orders {
|
||||||
let mut is_sell = false;
|
let mut is_sell = false;
|
||||||
let mut is_overturned = false;
|
let mut is_overturned = false;
|
||||||
if element.used_usdt >= dec!(10.0) {
|
if element.used_usdt >= dec!(10.0) {
|
||||||
if let (Some(tema30_vec), Some(tema5_vec)) = (tema_30.get(&element.symbol), tema_5.get(&element.symbol)) {
|
if let (Some(tema30_vec), Some(tema5_vec)) =
|
||||||
if tema30_vec.len() > 2 && tema5_vec.len() > 2 &&
|
(tema_30.get(&element.symbol), tema_5.get(&element.symbol))
|
||||||
tema30_vec.last().unwrap().close_time == tema5_vec.last().unwrap().close_time &&
|
{
|
||||||
tema30_vec.last().unwrap().close_time > server_epoch &&
|
if tema30_vec.len() > 2
|
||||||
tema5_vec.last().unwrap().close_time > server_epoch &&
|
&& tema5_vec.len() > 2
|
||||||
tema30_vec.last().unwrap().tema_value > tema5_vec.last().unwrap().tema_value &&
|
&& tema30_vec.last().unwrap().close_time
|
||||||
tema30_vec[tema30_vec.len()-2].tema_value < tema5_vec[tema5_vec.len()-2].tema_value {
|
== tema5_vec.last().unwrap().close_time
|
||||||
|
&& tema30_vec.last().unwrap().close_time > server_epoch
|
||||||
|
&& tema5_vec.last().unwrap().close_time > server_epoch
|
||||||
|
&& tema30_vec.last().unwrap().tema_value
|
||||||
|
> tema5_vec.last().unwrap().tema_value
|
||||||
|
&& tema30_vec[tema30_vec.len() - 2].tema_value
|
||||||
|
< tema5_vec[tema5_vec.len() - 2].tema_value
|
||||||
|
{
|
||||||
is_overturned = true;
|
is_overturned = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) =
|
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) = (
|
||||||
(exchange_info_map.get(&element.symbol), trade_fee_map.get(&element.symbol), supertrend_30m.get(&element.symbol)) {
|
exchange_info_map.get(&element.symbol),
|
||||||
|
trade_fee_map.get(&element.symbol),
|
||||||
|
supertrend_30m.get(&element.symbol),
|
||||||
|
) {
|
||||||
// update stoploss
|
// update stoploss
|
||||||
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 == SuperTrendArea::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![(String::from("stoploss"), band_value.to_string())];
|
||||||
(String::from("stoploss"), band_value.to_string()),
|
|
||||||
];
|
|
||||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||||
update_record3(&update_table_name, &update_value, &update_condition)
|
update_record3(&update_table_name, &update_value, &update_condition)
|
||||||
.await
|
.await
|
||||||
|
|
@ -297,27 +384,40 @@ pub async fn list_up_for_sell(
|
||||||
lot_step_size.normalize().scale(),
|
lot_step_size.normalize().scale(),
|
||||||
RoundingStrategy::ToZero,
|
RoundingStrategy::ToZero,
|
||||||
);
|
);
|
||||||
let target_profit_percent = decimal_div(decimal_sub(element.target_price, element.buy_price), element.buy_price).to_f64().unwrap();
|
let target_profit_percent = decimal_div(
|
||||||
if !element.current_price.is_zero()
|
decimal_sub(element.target_price, element.buy_price),
|
||||||
{
|
element.buy_price,
|
||||||
|
)
|
||||||
|
.to_f64()
|
||||||
|
.unwrap();
|
||||||
|
if !element.current_price.is_zero() {
|
||||||
if element.current_price <= element.stoploss {
|
if element.current_price <= element.stoploss {
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if element.current_price >= element.target_price {
|
} else if element.current_price >= element.target_price {
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
} else if server_epoch - element.transact_time > (1_800_000) * 1 && is_overturned == true {
|
} else if server_epoch - element.transact_time > (1_800_000) * 1
|
||||||
|
&& is_overturned == true
|
||||||
|
{
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
let minimum_candles = 5;
|
let minimum_candles = 5;
|
||||||
let maximum_candles = 30;
|
let maximum_candles = 30;
|
||||||
for count_candles in minimum_candles..=maximum_candles {
|
for count_candles in minimum_candles..=maximum_candles {
|
||||||
if count_candles < maximum_candles &&
|
if count_candles < maximum_candles
|
||||||
server_epoch - element.transact_time > (1_800_000) * count_candles &&
|
&& server_epoch - element.transact_time
|
||||||
(target_profit_percent != 0.0 && target_profit_percent.is_sign_positive() &&
|
> (1_800_000) * count_candles
|
||||||
target_profit_percent * ((maximum_candles - count_candles) as f64 / (maximum_candles - minimum_candles + 1) as f64) <= element.pure_profit_percent) {
|
&& (target_profit_percent != 0.0
|
||||||
|
&& target_profit_percent.is_sign_positive()
|
||||||
|
&& target_profit_percent
|
||||||
|
* ((maximum_candles - count_candles) as f64
|
||||||
|
/ (maximum_candles - minimum_candles + 1) as f64)
|
||||||
|
<= element.pure_profit_percent)
|
||||||
|
{
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
break;
|
break;
|
||||||
} else if count_candles == maximum_candles { // time up selling
|
} else if count_candles == maximum_candles {
|
||||||
|
// time up selling
|
||||||
is_sell = true;
|
is_sell = true;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ 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,
|
||||||
FilteredDataValue, FromRow, RealtimePriceData, TradeFee, HashMap
|
FilteredDataValue, FromRow, HashMap, RealtimePriceData, TradeFee,
|
||||||
};
|
};
|
||||||
use crate::signal_association::signal_decision::*;
|
use crate::signal_association::signal_decision::*;
|
||||||
use tokio::time::{sleep, Duration, Instant};
|
use tokio::time::{sleep, Duration, Instant};
|
||||||
|
|
@ -53,9 +53,24 @@ pub async fn execute_list_up_for_sell(
|
||||||
// crate::strategy_team::strategy_003::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
// crate::strategy_team::strategy_003::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||||
// crate::strategy_team::strategy_004::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
// crate::strategy_team::strategy_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;
|
// crate::strategy_team::strategy_005::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||||
crate::strategy_team::strategy_006::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
crate::strategy_team::strategy_006::list_up_for_sell(
|
||||||
crate::strategy_team::strategy_007::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
&all_data,
|
||||||
crate::strategy_team::strategy_008::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
&exchange_info_map,
|
||||||
|
&trade_fee_map,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
crate::strategy_team::strategy_007::list_up_for_sell(
|
||||||
|
&all_data,
|
||||||
|
&exchange_info_map,
|
||||||
|
&trade_fee_map,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
crate::strategy_team::strategy_008::list_up_for_sell(
|
||||||
|
&all_data,
|
||||||
|
&exchange_info_map,
|
||||||
|
&trade_fee_map,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use super::{
|
use super::{
|
||||||
dec, decimal_add, decimal_sub, ema, exists_record, insert_pre_suggested_coins,
|
dec, decimal_add, decimal_sub, 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, MacdData, ema_macd
|
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, MacdData, ema_macd
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -14,13 +14,13 @@ pub async fn strategist_test(
|
||||||
// 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: lookup tables if the tradepair is already there
|
// 1st filtering: lookup tables if the tradepair is already there
|
||||||
let mut symbol_1 = FilteredData::new();
|
let mut symbol_1 = FilteredDataValue::new();
|
||||||
// let mut symbol_2 = FilteredData::new();
|
// let mut symbol_2 = FilteredData::new();
|
||||||
// let mut symbol_3 = FilteredData::new();
|
// let mut symbol_3 = FilteredData::new();
|
||||||
symbol_1.symbol = String::from("BTCUSDT");
|
symbol_1.symbol = String::from("BTCUSDT");
|
||||||
// symbol_2.symbol = String::from("XRPUSDT");
|
// symbol_2.symbol = String::from("XRPUSDT");
|
||||||
// symbol_3.symbol = String::from("ETHUSDT");
|
// symbol_3.symbol = String::from("ETHUSDT");
|
||||||
let mut test_symbols: Vec<FilteredData> = Vec::new();
|
let mut test_symbols: Vec<FilteredDataValue> = Vec::new();
|
||||||
test_symbols.push(symbol_1);
|
test_symbols.push(symbol_1);
|
||||||
// test_symbols.push(symbol_2);
|
// test_symbols.push(symbol_2);
|
||||||
// test_symbols.push(symbol_3);
|
// test_symbols.push(symbol_3);
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,15 @@ use csv::{DeserializeRecordsIter, StringRecord};
|
||||||
use rust_decimal::{prelude::ToPrimitive, Decimal};
|
use rust_decimal::{prelude::ToPrimitive, Decimal};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::FromRow;
|
use sqlx::FromRow;
|
||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
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)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum CandleType { UP, DOWN }
|
pub enum CandleType {
|
||||||
|
UP,
|
||||||
|
DOWN,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct RealtimePriceData {
|
pub struct RealtimePriceData {
|
||||||
|
|
@ -93,15 +96,11 @@ pub async fn update_realtime_price_data(
|
||||||
rt_price_vec.last_mut().unwrap().candle_type = CandleType::DOWN;
|
rt_price_vec.last_mut().unwrap().candle_type = CandleType::DOWN;
|
||||||
}
|
}
|
||||||
// update high_price
|
// update high_price
|
||||||
if rt_price_vec.last_mut().unwrap().high_price
|
if rt_price_vec.last_mut().unwrap().high_price < *current_price {
|
||||||
< *current_price
|
|
||||||
{
|
|
||||||
rt_price_vec.last_mut().unwrap().high_price = *current_price;
|
rt_price_vec.last_mut().unwrap().high_price = *current_price;
|
||||||
}
|
}
|
||||||
// update low_price
|
// update low_price
|
||||||
if rt_price_vec.last_mut().unwrap().low_price
|
if rt_price_vec.last_mut().unwrap().low_price > *current_price {
|
||||||
> *current_price
|
|
||||||
{
|
|
||||||
rt_price_vec.last_mut().unwrap().low_price = *current_price;
|
rt_price_vec.last_mut().unwrap().low_price = *current_price;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -134,25 +133,22 @@ pub async fn update_realtime_price_data(
|
||||||
}| *close_time,
|
}| *close_time,
|
||||||
);
|
);
|
||||||
if prev_closetime_result.is_ok() {
|
if prev_closetime_result.is_ok() {
|
||||||
let result =
|
let result = rt_vec.get(prev_closetime_result.unwrap() + 1..);
|
||||||
rt_vec.get(prev_closetime_result.unwrap() + 1..);
|
|
||||||
if result.is_some() {
|
if result.is_some() {
|
||||||
let update_highprice_result =
|
let update_highprice_result =
|
||||||
result.unwrap().iter().max_by(|x, y| {
|
result.unwrap().iter().max_by(|x, y| {
|
||||||
x.high_price.partial_cmp(&y.high_price).unwrap()
|
x.high_price.partial_cmp(&y.high_price).unwrap()
|
||||||
});
|
});
|
||||||
if update_highprice_result.is_some() {
|
if update_highprice_result.is_some() {
|
||||||
update_highprice =
|
update_highprice = update_highprice_result.unwrap().high_price;
|
||||||
update_highprice_result.unwrap().high_price;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let update_lowprice_result =
|
let update_lowprice_result = result
|
||||||
result.unwrap().iter().min_by(|x, y| {
|
.unwrap()
|
||||||
x.low_price.partial_cmp(&y.low_price).unwrap()
|
.iter()
|
||||||
});
|
.min_by(|x, y| x.low_price.partial_cmp(&y.low_price).unwrap());
|
||||||
if update_lowprice_result.is_some() {
|
if update_lowprice_result.is_some() {
|
||||||
update_lowprice =
|
update_lowprice = update_lowprice_result.unwrap().low_price;
|
||||||
update_lowprice_result.unwrap().low_price;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for element in result.unwrap() {
|
for element in result.unwrap() {
|
||||||
|
|
@ -189,10 +185,8 @@ pub async fn update_realtime_price_data(
|
||||||
&& !update_closeprice.is_nan()
|
&& !update_closeprice.is_nan()
|
||||||
&& update_closeprice.is_finite()
|
&& update_closeprice.is_finite()
|
||||||
{
|
{
|
||||||
rt_price_vec.last_mut().unwrap().close_price =
|
rt_price_vec.last_mut().unwrap().close_price = update_closeprice;
|
||||||
update_closeprice;
|
rt_price_vec.last_mut().unwrap().opclo_price = (update_closeprice
|
||||||
rt_price_vec.last_mut().unwrap().opclo_price =
|
|
||||||
(update_closeprice
|
|
||||||
+ rt_price_vec.last_mut().unwrap().open_price)
|
+ rt_price_vec.last_mut().unwrap().open_price)
|
||||||
/ 2.0;
|
/ 2.0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use super::{FilteredDataValue, RealtimePriceData, try_join_all, Arc, Mutex, HashMap};
|
use super::{try_join_all, Arc, FilteredDataValue, HashMap, Mutex, RealtimePriceData};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct AdxData {
|
pub struct AdxData {
|
||||||
pub adx: f64,
|
pub adx: f64,
|
||||||
pub close_time: i64
|
pub close_time: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BasicData {
|
struct BasicData {
|
||||||
|
|
@ -19,8 +19,12 @@ struct DiData {
|
||||||
close_time: i64,
|
close_time: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn adx(adx_len: usize, di_len: usize, input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
pub async fn adx(
|
||||||
filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String, Vec<AdxData>>, Box<dyn std::error::Error + Send + Sync>> {
|
adx_len: usize,
|
||||||
|
di_len: usize,
|
||||||
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
|
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||||
|
) -> Result<HashMap<String, Vec<AdxData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
if filtered_symbols.is_empty() {
|
if filtered_symbols.is_empty() {
|
||||||
Err(("Err"))?;
|
Err(("Err"))?;
|
||||||
}
|
}
|
||||||
|
|
@ -46,9 +50,13 @@ filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String
|
||||||
let basic_data = BasicData {
|
let basic_data = BasicData {
|
||||||
dm_plus: if up > down && up > 0.0 { up } else { 0.0 },
|
dm_plus: if up > down && up > 0.0 { up } else { 0.0 },
|
||||||
dm_minus: if down > up && down > 0.0 { down } 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,
|
true_range: f64::max(
|
||||||
current_rt_data.high_price - prev_rt_data.close_price),
|
f64::max(
|
||||||
current_rt_data.low_price - prev_rt_data.close_price),
|
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,
|
close_time: current_rt_data.close_time,
|
||||||
};
|
};
|
||||||
basic_data_vec.push(basic_data);
|
basic_data_vec.push(basic_data);
|
||||||
|
|
@ -72,21 +80,37 @@ filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String
|
||||||
dm_minus_calculated /= di_len as f64;
|
dm_minus_calculated /= di_len as f64;
|
||||||
tr_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 };
|
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);
|
smoothed_basic_data_vec.push(basic_data);
|
||||||
|
|
||||||
for element in partial_vec2 {
|
for element in partial_vec2 {
|
||||||
dm_plus_calculated = alpha * element.dm_plus + (1.0 - alpha) * dm_plus_calculated;
|
dm_plus_calculated =
|
||||||
dm_minus_calculated = alpha * element.dm_minus + (1.0 - alpha) * dm_minus_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;
|
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 };
|
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
|
// step 3: calculate DI
|
||||||
let mut di_data_vec: Vec<DiData> = Vec::new();
|
let mut di_data_vec: Vec<DiData> = Vec::new();
|
||||||
for basic_data in smoothed_basic_data_vec {
|
for basic_data in smoothed_basic_data_vec {
|
||||||
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 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,
|
||||||
|
};
|
||||||
di_data_vec.push(di_data);
|
di_data_vec.push(di_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,11 +120,17 @@ filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String
|
||||||
let sum = di_data.di_plus + di_data.di_minus;
|
let sum = di_data.di_plus + di_data.di_minus;
|
||||||
let difference = (di_data.di_plus - di_data.di_minus).abs();
|
let difference = (di_data.di_plus - di_data.di_minus).abs();
|
||||||
let divisor = if sum <= 0.00000001 { 1.0 } else { sum };
|
let divisor = if sum <= 0.00000001 { 1.0 } else { sum };
|
||||||
let adx_data = AdxData { adx: difference.abs()/divisor, close_time: di_data.close_time };
|
let adx_data = AdxData {
|
||||||
|
adx: difference.abs() / divisor,
|
||||||
|
close_time: di_data.close_time,
|
||||||
|
};
|
||||||
initial_adx_vec.push(adx_data);
|
initial_adx_vec.push(adx_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let (Some(partial_vec1), Some(partial_vec2)) = (initial_adx_vec.get(..adx_len), initial_adx_vec.get(adx_len..)) {
|
if let (Some(partial_vec1), Some(partial_vec2)) = (
|
||||||
|
initial_adx_vec.get(..adx_len),
|
||||||
|
initial_adx_vec.get(adx_len..),
|
||||||
|
) {
|
||||||
// partial_vec1 is for calculation of initial value
|
// partial_vec1 is for calculation of initial value
|
||||||
// partial_vec2 is for calculation of the rest
|
// partial_vec2 is for calculation of the rest
|
||||||
let mut smoothed_adx_vec: Vec<AdxData> = Vec::new();
|
let mut smoothed_adx_vec: Vec<AdxData> = Vec::new();
|
||||||
|
|
@ -110,13 +140,19 @@ filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String
|
||||||
}
|
}
|
||||||
adx_calculated /= adx_len as f64;
|
adx_calculated /= adx_len as f64;
|
||||||
|
|
||||||
let adx_data = AdxData { adx: adx_calculated, close_time: partial_vec1.last().unwrap().close_time };
|
let adx_data = AdxData {
|
||||||
|
adx: adx_calculated,
|
||||||
|
close_time: partial_vec1.last().unwrap().close_time,
|
||||||
|
};
|
||||||
smoothed_adx_vec.push(adx_data);
|
smoothed_adx_vec.push(adx_data);
|
||||||
|
|
||||||
let alpha: f64 = 1.0 / (adx_len as f64);
|
let alpha: f64 = 1.0 / (adx_len as f64);
|
||||||
for element in partial_vec2 {
|
for element in partial_vec2 {
|
||||||
adx_calculated = alpha * element.adx + (1.0 - alpha) * adx_calculated;
|
adx_calculated = alpha * element.adx + (1.0 - alpha) * adx_calculated;
|
||||||
let adx_data = AdxData { adx: 100.0 * adx_calculated, close_time: element.close_time };
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,5 +167,4 @@ filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String
|
||||||
|
|
||||||
let a = adx_vec_arc.lock().await.to_owned();
|
let a = adx_vec_arc.lock().await.to_owned();
|
||||||
Ok(a)
|
Ok(a)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
use super::HashMap;
|
||||||
use crate::database_control::*;
|
use crate::database_control::*;
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
|
||||||
use crate::value_estimation_team::indicators::sma::{SmaData, sma};
|
|
||||||
use crate::strategy_team::FilteredDataValue;
|
use crate::strategy_team::FilteredDataValue;
|
||||||
|
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||||
|
use crate::value_estimation_team::indicators::sma::{sma, SmaData};
|
||||||
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 {
|
||||||
|
|
@ -43,7 +43,8 @@ pub async fn bollingerband(
|
||||||
Err(("Err"))?;
|
Err(("Err"))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut sma_data_map: HashMap<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: HashMap<String, Vec<BollingerBandData>> = HashMap::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();
|
||||||
|
|
@ -76,13 +77,11 @@ pub async fn bollingerband(
|
||||||
match result {
|
match result {
|
||||||
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.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.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;
|
||||||
|
|
@ -94,16 +93,14 @@ pub async fn bollingerband(
|
||||||
standard_deviation +=
|
standard_deviation +=
|
||||||
(element.close_price - sd_mean).powi(2);
|
(element.close_price - sd_mean).powi(2);
|
||||||
}
|
}
|
||||||
standard_deviation = sd_factor
|
standard_deviation =
|
||||||
* ((standard_deviation / period as f64).sqrt());
|
sd_factor * ((standard_deviation / period as f64).sqrt());
|
||||||
|
|
||||||
match read_data_iter.next() {
|
match read_data_iter.next() {
|
||||||
Some(T) => {
|
Some(T) => {
|
||||||
bb_data.sma = T.sma_value;
|
bb_data.sma = T.sma_value;
|
||||||
bb_data.upperband =
|
bb_data.upperband = T.sma_value + standard_deviation;
|
||||||
T.sma_value + standard_deviation;
|
bb_data.lowerband = T.sma_value - standard_deviation;
|
||||||
bb_data.lowerband =
|
|
||||||
T.sma_value - standard_deviation;
|
|
||||||
bb_data.close_time = T.close_time;
|
bb_data.close_time = T.close_time;
|
||||||
bb_data_vec.push(bb_data.clone());
|
bb_data_vec.push(bb_data.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -115,8 +112,7 @@ pub async fn bollingerband(
|
||||||
Err(E) => {}
|
Err(E) => {}
|
||||||
}
|
}
|
||||||
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.insert(symbol_c, bb_data_vec.clone());
|
||||||
.insert(symbol_c, bb_data_vec.clone());
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
use super::ema::{ema, EmaData};
|
||||||
|
use super::FilteredDataValue;
|
||||||
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 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::collections::HashMap;
|
||||||
use std::{iter::zip, sync::Arc};
|
use std::{iter::zip, sync::Arc};
|
||||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||||
use super::FilteredDataValue;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use super::ema::{ema, EmaData};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DemaData {
|
pub struct DemaData {
|
||||||
|
|
@ -81,7 +81,6 @@ pub async fn dema(
|
||||||
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
try_join_all(task_vec).await?;
|
try_join_all(task_vec).await?;
|
||||||
let e2 = ema_data_wrapper_arc.lock().await.to_owned();
|
let e2 = ema_data_wrapper_arc.lock().await.to_owned();
|
||||||
|
|
@ -91,12 +90,14 @@ pub async fn dema(
|
||||||
let mut task_vec = Vec::new();
|
let mut task_vec = Vec::new();
|
||||||
for (symbol, e2_vec) in e2 {
|
for (symbol, e2_vec) in e2 {
|
||||||
if let Some(e1_vec) = e1.get(&symbol) {
|
if let Some(e1_vec) = e1.get(&symbol) {
|
||||||
let dema_data_wrapper_arc_c: Arc<Mutex<HashMap<String, Vec<DemaData>>>> = Arc::clone(&dema_data_wrapper_arc);
|
let dema_data_wrapper_arc_c: Arc<Mutex<HashMap<String, Vec<DemaData>>>> =
|
||||||
|
Arc::clone(&dema_data_wrapper_arc);
|
||||||
let symbol_c = symbol.clone();
|
let symbol_c = symbol.clone();
|
||||||
let e1_vec_c = e1_vec.clone();
|
let e1_vec_c = e1_vec.clone();
|
||||||
task_vec.push(tokio::spawn(async move {
|
task_vec.push(tokio::spawn(async move {
|
||||||
if e2_vec.last().unwrap().close_time == e1_vec_c.last().unwrap().close_time &&
|
if e2_vec.last().unwrap().close_time == e1_vec_c.last().unwrap().close_time
|
||||||
e2_vec.len() < e1_vec_c.len() {
|
&& e2_vec.len() < e1_vec_c.len()
|
||||||
|
{
|
||||||
let mut dema_data_vec: Vec<DemaData> = Vec::new();
|
let mut dema_data_vec: Vec<DemaData> = Vec::new();
|
||||||
let e1_vec_part = e1_vec_c.get(e1_vec_c.len() - e2_vec.len()..).unwrap();
|
let e1_vec_part = e1_vec_c.get(e1_vec_c.len() - e2_vec.len()..).unwrap();
|
||||||
let zipped = e1_vec_part.iter().zip(e2_vec.iter());
|
let zipped = e1_vec_part.iter().zip(e2_vec.iter());
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
use super::FilteredDataValue;
|
||||||
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 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::collections::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 super::FilteredDataValue;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct EmaData {
|
pub struct EmaData {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
|
||||||
use super::FilteredDataValue;
|
use super::FilteredDataValue;
|
||||||
|
use super::HashMap;
|
||||||
|
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||||
|
use futures::future::try_join_all;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use futures::future::try_join_all;
|
|
||||||
use super::HashMap;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub enum HeatMapLevel {
|
pub enum HeatMapLevel {
|
||||||
|
|
@ -172,7 +172,6 @@ pub async fn heatmap_volume(
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
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,9 +1,9 @@
|
||||||
use crate::value_estimation_team::indicators::ema::{EmaData, ema};
|
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
|
||||||
use super::{FilteredDataValue, HashMap};
|
use super::{FilteredDataValue, HashMap};
|
||||||
|
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||||
|
use crate::value_estimation_team::indicators::ema::{ema, EmaData};
|
||||||
|
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 futures::future::try_join_all;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MacdData {
|
pub struct MacdData {
|
||||||
|
|
@ -44,7 +44,7 @@ pub async fn ema_macd(
|
||||||
slow_len: usize,
|
slow_len: usize,
|
||||||
signal_smoothing: usize,
|
signal_smoothing: usize,
|
||||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||||
filtered_symbols: &HashMap<String, FilteredDataValue>
|
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||||
) -> Result<HashMap<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: HashMap<String, Vec<MacdData>> = HashMap::new();
|
let mut macd_oscil_vec: HashMap<String, Vec<MacdData>> = HashMap::new();
|
||||||
|
|
||||||
|
|
@ -56,13 +56,17 @@ pub async fn ema_macd(
|
||||||
for (symbol, filtered_data) 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();
|
||||||
if let (Some(fast_ema_vec), Some(slow_ema_vec)) = (fast_emas.get(symbol), slow_emas_c.get(symbol)) {
|
if let (Some(fast_ema_vec), Some(slow_ema_vec)) =
|
||||||
|
(fast_emas.get(symbol), slow_emas_c.get(symbol))
|
||||||
|
{
|
||||||
let symbol_c = symbol.clone();
|
let symbol_c = symbol.clone();
|
||||||
let fast_ema_vec_c = fast_ema_vec.clone();
|
let fast_ema_vec_c = fast_ema_vec.clone();
|
||||||
let slow_ema_vec_c = slow_ema_vec.clone();
|
let slow_ema_vec_c = slow_ema_vec.clone();
|
||||||
let macd_data_wrapper_arc_c = Arc::clone(&macd_data_wrapper_arc);
|
let macd_data_wrapper_arc_c = Arc::clone(&macd_data_wrapper_arc);
|
||||||
task_vec.push(tokio::spawn(async move {
|
task_vec.push(tokio::spawn(async move {
|
||||||
if fast_ema_vec_c.len() >= signal_smoothing && slow_ema_vec_c.len() >= signal_smoothing {
|
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(
|
let result = fast_ema_vec_c.binary_search_by_key(
|
||||||
&slow_ema_vec_c.first().unwrap().close_time,
|
&slow_ema_vec_c.first().unwrap().close_time,
|
||||||
|&EmaData {
|
|&EmaData {
|
||||||
|
|
@ -124,10 +128,7 @@ pub async fn ema_macd(
|
||||||
|
|
||||||
let result = macd_vec.binary_search_by_key(
|
let result = macd_vec.binary_search_by_key(
|
||||||
&macd_signal_vec.first().unwrap().close_time,
|
&macd_signal_vec.first().unwrap().close_time,
|
||||||
|&TempData {
|
|&TempData { value, close_time }| close_time,
|
||||||
value,
|
|
||||||
close_time,
|
|
||||||
}| close_time,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
|
|
@ -143,7 +144,8 @@ pub async fn ema_macd(
|
||||||
macd.close_time = element.0.close_time;
|
macd.close_time = element.0.close_time;
|
||||||
macd_vec.push(macd);
|
macd_vec.push(macd);
|
||||||
}
|
}
|
||||||
let mut macd_data_wrapper_lock = macd_data_wrapper_arc_c.lock().await;
|
let mut macd_data_wrapper_lock =
|
||||||
|
macd_data_wrapper_arc_c.lock().await;
|
||||||
macd_data_wrapper_lock.insert(symbol_c, macd_vec.clone());
|
macd_data_wrapper_lock.insert(symbol_c, macd_vec.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
pub mod adx;
|
pub mod adx;
|
||||||
pub mod bollingerband;
|
pub mod bollingerband;
|
||||||
|
pub mod dema;
|
||||||
pub mod ema;
|
pub mod ema;
|
||||||
pub mod heatmap_volume;
|
pub mod heatmap_volume;
|
||||||
pub mod macd;
|
pub mod macd;
|
||||||
|
|
@ -8,11 +9,10 @@ pub mod sma;
|
||||||
pub mod stoch_rsi;
|
pub mod stoch_rsi;
|
||||||
pub mod supertrend;
|
pub mod supertrend;
|
||||||
pub mod tema;
|
pub mod tema;
|
||||||
pub mod dema;
|
|
||||||
|
|
||||||
use crate::strategy_team::FilteredDataValue;
|
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::collections::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 std::collections::HashMap;
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
use super::HashMap;
|
||||||
use crate::database_control::*;
|
use crate::database_control::*;
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
|
||||||
use crate::strategy_team::FilteredDataValue;
|
use crate::strategy_team::FilteredDataValue;
|
||||||
|
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||||
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 {
|
||||||
|
|
@ -132,8 +132,8 @@ pub async fn rsi(
|
||||||
prev_avg_ups = current_avg_ups;
|
prev_avg_ups = current_avg_ups;
|
||||||
prev_avg_downs = current_avg_downs;
|
prev_avg_downs = current_avg_downs;
|
||||||
|
|
||||||
let rs = current_avg_ups.unwrap()
|
let rs =
|
||||||
/ (current_avg_downs.unwrap() + 0.00000001); // 0.00000001 is used to avoid division by 0
|
current_avg_ups.unwrap() / (current_avg_downs.unwrap() + 0.00000001); // 0.00000001 is used to avoid division by 0
|
||||||
|
|
||||||
let rsi = 100.0 - (100.0 / (1.0 + rs));
|
let rsi = 100.0 - (100.0 / (1.0 + rs));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
|
||||||
|
use super::HashMap;
|
||||||
use crate::database_control::*;
|
use crate::database_control::*;
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
|
||||||
use crate::strategy_team::FilteredDataValue;
|
use crate::strategy_team::FilteredDataValue;
|
||||||
|
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||||
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 {
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,16 @@
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
|
||||||
use crate::database_control::*;
|
use crate::database_control::*;
|
||||||
use crate::value_estimation_team::indicators::rsi::{RsiData, rsi};
|
|
||||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
|
||||||
use crate::strategy_team::FilteredDataValue;
|
use crate::strategy_team::FilteredDataValue;
|
||||||
|
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||||
|
use crate::value_estimation_team::indicators::rsi::{rsi, RsiData};
|
||||||
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::collections::{HashMap, HashSet};
|
||||||
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 {
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,27 @@
|
||||||
|
use super::{FilteredDataValue, HashMap};
|
||||||
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 futures::future::try_join_all;
|
||||||
|
use std::sync::Arc;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub enum SuperTrendArea { UP, DOWN }
|
pub enum SuperTrendArea {
|
||||||
|
UP,
|
||||||
|
DOWN,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Debug)]
|
#[derive(PartialEq, Clone, Debug)]
|
||||||
pub enum SuperTrendSignal { BUY, SELL }
|
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<SuperTrendSignal>, // BUY or SELL
|
pub signal: Option<SuperTrendSignal>, // BUY or SELL
|
||||||
pub area: SuperTrendArea, // UP or DOWN
|
pub area: SuperTrendArea, // UP or DOWN
|
||||||
pub close_time: i64
|
pub close_time: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SupertrendData {
|
impl SupertrendData {
|
||||||
|
|
@ -24,7 +30,7 @@ impl SupertrendData {
|
||||||
band_value: 0.0,
|
band_value: 0.0,
|
||||||
signal: None,
|
signal: None,
|
||||||
area: SuperTrendArea::DOWN,
|
area: SuperTrendArea::DOWN,
|
||||||
close_time: 0
|
close_time: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
a
|
a
|
||||||
|
|
@ -130,7 +136,8 @@ pub async fn supertrend(
|
||||||
|
|
||||||
let mut temp_prev_atr_value = first_value;
|
let mut temp_prev_atr_value = first_value;
|
||||||
for element in &true_range_vec[atr_period..] {
|
for element in &true_range_vec[atr_period..] {
|
||||||
atr_data.atr_value = ((temp_prev_atr_value * ((atr_period - 1) as f64))
|
atr_data.atr_value = ((temp_prev_atr_value
|
||||||
|
* ((atr_period - 1) as f64))
|
||||||
+ element.tr_value)
|
+ element.tr_value)
|
||||||
/ atr_period as f64;
|
/ atr_period as f64;
|
||||||
atr_data.close_time = element.close_time;
|
atr_data.close_time = element.close_time;
|
||||||
|
|
@ -245,7 +252,8 @@ pub async fn supertrend(
|
||||||
prev_final_lowerband = final_lowerband;
|
prev_final_lowerband = final_lowerband;
|
||||||
prev_trend = trend;
|
prev_trend = trend;
|
||||||
}
|
}
|
||||||
let mut supertrend_data_wrapper_lock = supertrend_data_wrapper_arc_c.lock().await;
|
let mut supertrend_data_wrapper_lock =
|
||||||
|
supertrend_data_wrapper_arc_c.lock().await;
|
||||||
supertrend_data_wrapper_lock.insert(symbol_c, supertrend_vec.clone());
|
supertrend_data_wrapper_lock.insert(symbol_c, supertrend_vec.clone());
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
use super::ema::{ema, EmaData};
|
||||||
|
use super::FilteredDataValue;
|
||||||
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 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::collections::HashMap;
|
||||||
use std::{iter::zip, sync::Arc};
|
use std::{iter::zip, sync::Arc};
|
||||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||||
use super::FilteredDataValue;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use super::ema::{ema, EmaData};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct TemaData {
|
pub struct TemaData {
|
||||||
|
|
@ -81,7 +81,6 @@ pub async fn tema(
|
||||||
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
try_join_all(task_vec).await?;
|
try_join_all(task_vec).await?;
|
||||||
let e2 = ema_data_wrapper_arc.lock().await.to_owned();
|
let e2 = ema_data_wrapper_arc.lock().await.to_owned();
|
||||||
|
|
@ -126,7 +125,6 @@ pub async fn tema(
|
||||||
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
try_join_all(task_vec).await?;
|
try_join_all(task_vec).await?;
|
||||||
let e3 = ema_data_wrapper_arc.lock().await.to_owned();
|
let e3 = ema_data_wrapper_arc.lock().await.to_owned();
|
||||||
|
|
@ -136,16 +134,18 @@ pub async fn tema(
|
||||||
let mut task_vec = Vec::new();
|
let mut task_vec = Vec::new();
|
||||||
for (symbol, e3_vec) in e3 {
|
for (symbol, e3_vec) in e3 {
|
||||||
if let (Some(e1_vec), Some(e2_vec)) = (e1.get(&symbol), e2.get(&symbol)) {
|
if let (Some(e1_vec), Some(e2_vec)) = (e1.get(&symbol), e2.get(&symbol)) {
|
||||||
let tema_data_wrapper_arc_c: Arc<Mutex<HashMap<String, Vec<TemaData>>>> = Arc::clone(&tema_data_wrapper_arc);
|
let tema_data_wrapper_arc_c: Arc<Mutex<HashMap<String, Vec<TemaData>>>> =
|
||||||
|
Arc::clone(&tema_data_wrapper_arc);
|
||||||
let symbol_c = symbol.clone();
|
let symbol_c = symbol.clone();
|
||||||
let e1_vec_c = e1_vec.clone();
|
let e1_vec_c = e1_vec.clone();
|
||||||
let e2_vec_c = e2_vec.clone();
|
let e2_vec_c = e2_vec.clone();
|
||||||
task_vec.push(tokio::spawn(async move {
|
task_vec.push(tokio::spawn(async move {
|
||||||
if e3_vec.last().unwrap().close_time == e1_vec_c.last().unwrap().close_time &&
|
if e3_vec.last().unwrap().close_time == e1_vec_c.last().unwrap().close_time
|
||||||
e3_vec.last().unwrap().close_time == e2_vec_c.last().unwrap().close_time &&
|
&& e3_vec.last().unwrap().close_time == e2_vec_c.last().unwrap().close_time
|
||||||
e3_vec.len() < e1_vec_c.len() &&
|
&& e3_vec.len() < e1_vec_c.len()
|
||||||
e3_vec.len() < e2_vec_c.len() &&
|
&& e3_vec.len() < e2_vec_c.len()
|
||||||
e2_vec_c.len() < e1_vec_c.len() {
|
&& e2_vec_c.len() < e1_vec_c.len()
|
||||||
|
{
|
||||||
let mut tema_data_vec: Vec<TemaData> = Vec::new();
|
let mut tema_data_vec: Vec<TemaData> = Vec::new();
|
||||||
let e1_vec_part = e1_vec_c.get(e1_vec_c.len() - e3_vec.len()..).unwrap();
|
let e1_vec_part = e1_vec_c.get(e1_vec_c.len() - e3_vec.len()..).unwrap();
|
||||||
let e2_vec_part = e2_vec_c.get(e2_vec_c.len() - e3_vec.len()..).unwrap();
|
let e2_vec_part = e2_vec_c.get(e2_vec_c.len() - e3_vec.len()..).unwrap();
|
||||||
|
|
@ -154,7 +154,9 @@ pub async fn tema(
|
||||||
for element in zipped_e1_e2_e3 {
|
for element in zipped_e1_e2_e3 {
|
||||||
let mut tema_data = TemaData::new();
|
let mut tema_data = TemaData::new();
|
||||||
tema_data.close_time = element.0 .0.close_time;
|
tema_data.close_time = element.0 .0.close_time;
|
||||||
tema_data.tema_value = (3.0 * (element.0.0.ema_value - element.0.1.ema_value)) + element.1.ema_value;
|
tema_data.tema_value = (3.0
|
||||||
|
* (element.0 .0.ema_value - element.0 .1.ema_value))
|
||||||
|
+ element.1.ema_value;
|
||||||
tema_data_vec.push(tema_data);
|
tema_data_vec.push(tema_data);
|
||||||
}
|
}
|
||||||
let mut dema_data_wrapper_lock = tema_data_wrapper_arc_c.lock().await;
|
let mut dema_data_wrapper_lock = tema_data_wrapper_arc_c.lock().await;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user