Formatting
This commit is contained in:
parent
e85690fd41
commit
23066cf0f3
|
|
@ -6,12 +6,12 @@ use crate::database_control::*;
|
|||
use crate::decimal_funcs::*;
|
||||
use crate::RunningMode::*;
|
||||
use crate::RUNNING_MODE;
|
||||
use log;
|
||||
use reqwest::Client;
|
||||
use rust_decimal::{prelude::ToPrimitive, Decimal, RoundingStrategy};
|
||||
use rust_decimal_macros::dec;
|
||||
use serde_json::{Result, Value};
|
||||
use sqlx::FromRow;
|
||||
use log;
|
||||
|
||||
#[derive(Debug, FromRow)]
|
||||
pub struct AchievementEvaluationInfo {
|
||||
|
|
@ -156,7 +156,7 @@ pub async fn add_extra_usdt(extra_usdt: Decimal) {
|
|||
|
||||
// add additional_usdt into [wallet_simul]
|
||||
let mut update_table_name = String::new();
|
||||
unsafe{
|
||||
unsafe {
|
||||
if RUNNING_MODE == SIMUL {
|
||||
let update_table_name = String::from("wallet");
|
||||
let mut value_build = String::from("free + ");
|
||||
|
|
@ -186,7 +186,7 @@ pub async fn update_current_total_usdt() {
|
|||
} else {
|
||||
profit = decimal_sub(decimal_div(free_usdt, initial_usdt), dec!(1));
|
||||
}
|
||||
|
||||
|
||||
update_values = vec![
|
||||
(String::from("current_total_usdt"), free_usdt.to_string()),
|
||||
(String::from("profit"), profit.to_string()),
|
||||
|
|
@ -198,19 +198,19 @@ pub async fn update_current_total_usdt() {
|
|||
];
|
||||
} else {
|
||||
let asset_info = select_asset_manage_announcement().await;
|
||||
|
||||
|
||||
let achievement_evaluation = select_achievement_evaluation().await;
|
||||
let balance = decimal_sub(
|
||||
achievement_evaluation.usdt_profit,
|
||||
achievement_evaluation.invested_usdt,
|
||||
);
|
||||
let current_total_usdt = decimal_add(asset_info.initial_usdt, balance);
|
||||
|
||||
|
||||
let profit = decimal_sub(
|
||||
decimal_div(current_total_usdt, asset_info.initial_usdt),
|
||||
dec!(1),
|
||||
);
|
||||
|
||||
|
||||
update_values = vec![
|
||||
(
|
||||
String::from("current_total_usdt"),
|
||||
|
|
@ -225,7 +225,7 @@ pub async fn update_current_total_usdt() {
|
|||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let update_table_name = String::from("asset_manage_announcement");
|
||||
let update_condition = vec![(String::from("id"), String::from("1"))];
|
||||
update_record3(&update_table_name, &update_values, &update_condition)
|
||||
|
|
@ -541,7 +541,7 @@ pub async fn select_asset_manage_announcement() -> AssetInfo {
|
|||
pub async fn fetch_free_usdt() -> Decimal {
|
||||
let wallet_info = WalletInfo::new();
|
||||
let select_table_name = {
|
||||
unsafe{
|
||||
unsafe {
|
||||
if RUNNING_MODE == SIMUL || RUNNING_MODE == REAL {
|
||||
String::from("wallet")
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -257,7 +257,9 @@ pub async fn buy_coin(
|
|||
.unwrap();
|
||||
for element in &filtered_suggested_coin_vec {
|
||||
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 lot_step_size = exchange_info.stepsize;
|
||||
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");
|
||||
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 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;
|
||||
|
||||
// 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 = element.suggested_price;
|
||||
|
||||
base_qty_ordered = decimal_div(unit_trade_usdt, order_price)
|
||||
.round_dp_with_strategy(lot_step_size.normalize().scale(), RoundingStrategy::ToZero);
|
||||
base_qty_ordered = decimal_div(unit_trade_usdt, order_price).round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
base_qty_fee_adjusted = decimal_mul(base_qty_ordered, decimal_sub(dec!(1), trade_fee))
|
||||
.round_dp_with_strategy(base_commission_precision, RoundingStrategy::ToZero);
|
||||
used_usdt = decimal_mul(base_qty_ordered, order_price)
|
||||
|
|
@ -865,7 +874,8 @@ pub async fn update_profit_percent() {
|
|||
profit_percent = (decimal_sub(
|
||||
decimal_div(element.usdt_profit, element.invested_usdt),
|
||||
dec!(1),
|
||||
)).round_dp(2)
|
||||
))
|
||||
.round_dp(2)
|
||||
.to_f64()
|
||||
.unwrap()
|
||||
* 100.0;
|
||||
|
|
|
|||
|
|
@ -24,14 +24,14 @@ use crate::value_estimation_team::indicators::supertrend::{supertrend, Supertren
|
|||
use futures::future::try_join_all;
|
||||
use hex::ToHex;
|
||||
use hmac_sha256::HMAC;
|
||||
use log;
|
||||
use reqwest::{Client, ClientBuilder};
|
||||
use rust_decimal::{prelude::FromPrimitive, prelude::ToPrimitive, Decimal, RoundingStrategy};
|
||||
use rust_decimal_macros::dec;
|
||||
use serde_json::Value;
|
||||
use sqlx::FromRow;
|
||||
use tokio::time::*;
|
||||
use std::collections::HashMap;
|
||||
use log;
|
||||
use tokio::time::*;
|
||||
|
||||
pub enum OrderSide {
|
||||
Buy,
|
||||
|
|
@ -199,7 +199,7 @@ pub async fn limit_order_buy_test(
|
|||
// building URL and API-keys
|
||||
let mut url = String::new();
|
||||
let mut api_key = String::new();
|
||||
unsafe{
|
||||
unsafe {
|
||||
if RUNNING_MODE == TEST {
|
||||
url.push_str(URL_TEST);
|
||||
api_key = API_KEY_TESTNET.to_string();
|
||||
|
|
@ -598,18 +598,26 @@ async fn update_repeat_task(
|
|||
for element in buy_ordered_coin_vec {
|
||||
// build update values
|
||||
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) {
|
||||
price = rust_decimal::prelude::FromPrimitive::from_f64(*coin_price_map.get(&element.symbol).unwrap()).unwrap();
|
||||
if coin_price_map.contains_key(&element.symbol)
|
||||
&& exchange_info_map.contains_key(&element.symbol)
|
||||
&& trade_fee_map.contains_key(&element.symbol)
|
||||
{
|
||||
price = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
*coin_price_map.get(&element.symbol).unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
if !price.is_zero() {
|
||||
// to get quote_commission_precision
|
||||
let trade_fee = trade_fee_map.get(&element.symbol).unwrap().takercommission;
|
||||
let lot_step_size = exchange_info_map.get(&element.symbol).unwrap().stepsize;
|
||||
let quote_commission_precision = exchange_info_map.get(&element.symbol).unwrap().quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_fee_adjusted.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let quote_commission_precision = exchange_info_map
|
||||
.get(&element.symbol)
|
||||
.unwrap()
|
||||
.quote_commission_precision;
|
||||
let base_qty_to_be_ordered = element.base_qty_fee_adjusted.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let expected_get_usdt = decimal_mul(
|
||||
decimal_mul(base_qty_to_be_ordered, price).round_dp_with_strategy(
|
||||
quote_commission_precision,
|
||||
|
|
@ -617,9 +625,9 @@ async fn update_repeat_task(
|
|||
),
|
||||
decimal_sub(dec!(1), trade_fee),
|
||||
);
|
||||
|
||||
|
||||
// TODO: sell_count >=1 이면 expected_get_usdt 는 한번만 tradefee만 적용하여 업데이트 할 것. 현재는 수수료를 2번 (매수,매도)를 계산함. 아래 변수에 든 값으로 업데이트 하면 됨
|
||||
// let expected_get_usdt =
|
||||
// let expected_get_usdt =
|
||||
// decimal_mul(base_qty_to_be_ordered, price).round_dp_with_strategy(
|
||||
// quote_commission_precision,
|
||||
// RoundingStrategy::ToZero,
|
||||
|
|
@ -628,7 +636,7 @@ async fn update_repeat_task(
|
|||
/ element.used_usdt.to_f64().unwrap())
|
||||
- 1.0)
|
||||
* 100.0;
|
||||
pure_profit_percent = (pure_profit_percent * 100.0).round() / 100.0; // Rounding
|
||||
pure_profit_percent = (pure_profit_percent * 100.0).round() / 100.0; // Rounding
|
||||
update_record_build.push(element.id.to_string()); // id
|
||||
update_record_build.push(price.to_string()); // current_price
|
||||
update_record_build.push(expected_get_usdt.to_string()); //expected_get_usdt
|
||||
|
|
@ -705,9 +713,17 @@ pub async fn limit_order_sell(
|
|||
let mut insert_value_container: Vec<String> = Vec::new();
|
||||
unsafe {
|
||||
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) {
|
||||
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;
|
||||
if exchange_info_map.contains_key(&buy_ordered_coin.symbol)
|
||||
&& trade_fee_map.contains_key(&buy_ordered_coin.symbol)
|
||||
{
|
||||
let quote_asset_precision = exchange_info_map
|
||||
.get(&buy_ordered_coin.symbol)
|
||||
.unwrap()
|
||||
.quote_asset_precision;
|
||||
let trade_fee = trade_fee_map
|
||||
.get(&buy_ordered_coin.symbol)
|
||||
.unwrap()
|
||||
.takercommission;
|
||||
|
||||
let get_usdt = decimal_mul(sell_base_quantity, sell_base_price)
|
||||
.round_dp_with_strategy(quote_asset_precision, RoundingStrategy::ToZero);
|
||||
|
|
@ -735,7 +751,8 @@ pub async fn limit_order_sell(
|
|||
dec!(1),
|
||||
),
|
||||
dec!(100),
|
||||
).round_dp(2);
|
||||
)
|
||||
.round_dp(2);
|
||||
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.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
|
||||
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) {
|
||||
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;
|
||||
if exchange_info_map.contains_key(&buy_ordered_coin.symbol)
|
||||
&& trade_fee_map.contains_key(&buy_ordered_coin.symbol)
|
||||
{
|
||||
let quote_asset_precision = exchange_info_map
|
||||
.get(&buy_ordered_coin.symbol)
|
||||
.unwrap()
|
||||
.quote_asset_precision;
|
||||
let trade_fee = trade_fee_map
|
||||
.get(&buy_ordered_coin.symbol)
|
||||
.unwrap()
|
||||
.takercommission;
|
||||
let get_usdt = rust_decimal::prelude::FromStr::from_str(
|
||||
T.get("cummulativeQuoteQty").unwrap().as_str().unwrap(),
|
||||
)
|
||||
|
|
@ -859,11 +884,15 @@ pub async fn limit_order_sell(
|
|||
if T.get("status").unwrap().as_str().unwrap() == "FILLED" {
|
||||
let pure_profit_percent = decimal_mul(
|
||||
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!(100),
|
||||
).round_dp(2);
|
||||
)
|
||||
.round_dp(2);
|
||||
insert_value_container
|
||||
.push(buy_ordered_coin.pure_profit_percent.to_string());
|
||||
// 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_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
|
||||
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 {
|
||||
// build insert value
|
||||
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.push(element.symbol.clone()); // symbol
|
||||
insert_value_build.push(server_epoch.to_string()); // soldtime
|
||||
|
|
@ -1164,7 +1196,8 @@ pub async fn cancel_buy_order(
|
|||
|
||||
// calculate values to be updated
|
||||
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(
|
||||
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_records(&insert_table_name, &insert_columns, &insert_values).await;
|
||||
} else {
|
||||
if exchange_info_map.contains_key(&order.symbol) && trade_fee_map.contains_key(&order.symbol) {
|
||||
let quote_asset_precision = exchange_info_map.get(&order.symbol).unwrap().quote_asset_precision;
|
||||
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||
if exchange_info_map.contains_key(&order.symbol)
|
||||
&& trade_fee_map.contains_key(&order.symbol)
|
||||
{
|
||||
let quote_asset_precision = exchange_info_map
|
||||
.get(&order.symbol)
|
||||
.unwrap()
|
||||
.quote_asset_precision;
|
||||
let trade_fee =
|
||||
trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||
if base_qty_executed == base_qty_ordered {
|
||||
// FILLED case
|
||||
// update status FILLED
|
||||
|
|
@ -1371,7 +1410,8 @@ pub async fn cancel_sell_order(
|
|||
dec!(1),
|
||||
),
|
||||
dec!(100),
|
||||
).round_dp(2);
|
||||
)
|
||||
.round_dp(2);
|
||||
|
||||
let table_name = String::from("sell_ordered_coin_list");
|
||||
let mut value_build = String::from("\'");
|
||||
|
|
@ -1422,7 +1462,8 @@ pub async fn cancel_sell_order(
|
|||
dec!(1),
|
||||
),
|
||||
dec!(100),
|
||||
).round_dp(2);
|
||||
)
|
||||
.round_dp(2);
|
||||
|
||||
let table_name = String::from("sell_ordered_coin_list");
|
||||
let mut value_build = String::from("\'");
|
||||
|
|
@ -1756,11 +1797,18 @@ pub async fn query_sell_order(
|
|||
|
||||
match v {
|
||||
Ok(T) => {
|
||||
if T.get("status").is_some_and(|a| a.as_str().unwrap() == "FILLED")
|
||||
|| T.get("status").is_some_and(|a| a.as_str().unwrap() == "PARTIALLY_FILLED")
|
||||
if T.get("status")
|
||||
.is_some_and(|a| a.as_str().unwrap() == "FILLED")
|
||||
|| T.get("status")
|
||||
.is_some_and(|a| a.as_str().unwrap() == "PARTIALLY_FILLED")
|
||||
{
|
||||
if exchange_info_map.contains_key(&order.symbol) && trade_fee_map.contains_key(&order.symbol) {
|
||||
let quote_asset_precision = exchange_info_map.get(&order.symbol).unwrap().quote_asset_precision;
|
||||
if exchange_info_map.contains_key(&order.symbol)
|
||||
&& trade_fee_map.contains_key(&order.symbol)
|
||||
{
|
||||
let quote_asset_precision = exchange_info_map
|
||||
.get(&order.symbol)
|
||||
.unwrap()
|
||||
.quote_asset_precision;
|
||||
let trade_fee = trade_fee_map.get(&order.symbol).unwrap().takercommission;
|
||||
let get_usdt = rust_decimal::prelude::FromStr::from_str(
|
||||
T.get("cummulativeQuoteQty").unwrap().as_str().unwrap(),
|
||||
|
|
@ -1781,7 +1829,8 @@ pub async fn query_sell_order(
|
|||
let pure_profit_percent = decimal_mul(
|
||||
decimal_sub(decimal_div(get_usdt_fee_adjusted, order.used_usdt), dec!(1)),
|
||||
dec!(100),
|
||||
).round_dp(2);
|
||||
)
|
||||
.round_dp(2);
|
||||
|
||||
let table_name = String::from("sell_ordered_coin_list");
|
||||
let mut value_build = String::from("\'");
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ use serde::Deserialize;
|
|||
use serde_json::Value;
|
||||
use sqlx::{Error, FromRow};
|
||||
use std::borrow::{Borrow, BorrowMut};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
use tokio::{join, sync::Mutex, time::*};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Debug, FromRow)]
|
||||
struct AllCoinProfitChangeAvgList {
|
||||
|
|
@ -115,13 +115,13 @@ pub async fn collect_valid_usde_trade(
|
|||
// get valid usdt trades
|
||||
let usdt_trades =
|
||||
select_record(&fetch_table_name, &column_name, &condition, &usdt_trades).await?;
|
||||
|
||||
|
||||
// get banned usdt trades
|
||||
#[derive(Debug, FromRow)]
|
||||
struct Symbols {
|
||||
symbol: String,
|
||||
}
|
||||
|
||||
|
||||
let table_name = String::from("banned_usdt_trades");
|
||||
let column_name = String::from("symbol");
|
||||
let condition = None;
|
||||
|
|
@ -152,7 +152,8 @@ pub async fn collect_valid_usde_trade(
|
|||
.unwrap();
|
||||
let step_size = value.stepsize;
|
||||
let step_price = decimal_mul(step_size, avg_price);
|
||||
let unit_trade_usdt = crate::coex::assets_managing_team::get_unit_trade_usdt().await;
|
||||
let unit_trade_usdt =
|
||||
crate::coex::assets_managing_team::get_unit_trade_usdt().await;
|
||||
|
||||
// exclude USDT trades whose step_price is over than 1% of unit_trade_usdt
|
||||
if step_price > decimal_mul(unit_trade_usdt, dec!(0.01)) {
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ use serde::Deserialize;
|
|||
use serde_json::Value;
|
||||
use sqlx::{Error, FromRow};
|
||||
use std::borrow::{Borrow, BorrowMut};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::{join, sync::Mutex, time::*};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CandleData {
|
||||
|
|
@ -166,7 +166,7 @@ async fn de_candle_json2(
|
|||
}
|
||||
|
||||
if let Some(value) = candle_map.get_mut(&symbol) {
|
||||
*value = candle_vec;
|
||||
*value = candle_vec;
|
||||
} else {
|
||||
candle_map.insert(symbol, candle_vec);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
use crate::database_control::*;
|
||||
use hex::ToHex;
|
||||
use hmac_sha256::HMAC;
|
||||
use log;
|
||||
use reqwest::{Client, ClientBuilder, Response};
|
||||
use rust_decimal::{prelude::FromPrimitive, prelude::ToPrimitive, Decimal, RoundingStrategy};
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
use sqlx::{Error, FromRow};
|
||||
use std::borrow::{Borrow, BorrowMut};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use tokio::{join, sync::Mutex, time::*};
|
||||
use log;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TradeFee {
|
||||
|
|
@ -184,7 +184,7 @@ async fn de_trade_fee_json(
|
|||
object_map = element.as_object().unwrap();
|
||||
|
||||
let mut object_map_iter = object_map.iter();
|
||||
|
||||
|
||||
for element in object_map_iter {
|
||||
match element.0.as_str() {
|
||||
"symbol" => symbol = element.1.as_str().unwrap().to_string(),
|
||||
|
|
@ -203,7 +203,7 @@ async fn de_trade_fee_json(
|
|||
}
|
||||
}
|
||||
}
|
||||
tradefee_map_build.insert(symbol.clone(), tradefee_data.clone());
|
||||
tradefee_map_build.insert(symbol.clone(), tradefee_data.clone());
|
||||
}
|
||||
*tradefee_map = tradefee_map_build;
|
||||
Ok(())
|
||||
|
|
@ -374,8 +374,7 @@ pub async fn request_exchange_infomation(
|
|||
.unwrap()
|
||||
.ends_with("USDT")
|
||||
{
|
||||
symbol =
|
||||
(element.get("symbol").unwrap().as_str().unwrap().to_string());
|
||||
symbol = (element.get("symbol").unwrap().as_str().unwrap().to_string());
|
||||
exchange_info.base_asset_precision =
|
||||
(element.get("baseAssetPrecision").unwrap().as_u64().unwrap()) as u32;
|
||||
exchange_info.base_commission_precision = (element
|
||||
|
|
@ -442,7 +441,7 @@ pub async fn request_delist_symbols(
|
|||
secret_key: &str,
|
||||
local_epoch: u128,
|
||||
difference_epoch: i64,
|
||||
client: &Client
|
||||
client: &Client,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut base_url = String::from("https://api.binance.com/sapi/v1/spot/delist-schedule?");
|
||||
|
||||
|
|
@ -512,28 +511,26 @@ async fn de_deilst_symbol_json(
|
|||
for element in into_vec.unwrap() {
|
||||
object_map = element.as_object().unwrap();
|
||||
let mut object_map_iter = object_map.iter();
|
||||
|
||||
|
||||
for element in object_map_iter {
|
||||
match element.0.as_str() {
|
||||
"delistTime" => {
|
||||
},
|
||||
"delistTime" => {}
|
||||
"symbols" => {
|
||||
if let Some(array) = element.1.as_array() {
|
||||
for delist_symbol in array {
|
||||
if let Some(symbol) = delist_symbol.as_str() {
|
||||
if symbol.ends_with("USDT") && !delist_hashset.contains(symbol) {
|
||||
delist_hashset.insert(symbol.to_string());
|
||||
delist_hashset.insert(symbol.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
log::error!("Elements in body msg are changed. Please update both your delist table and vectors.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if delist_hashset.len() != 0 {
|
||||
|
|
@ -541,7 +538,7 @@ async fn de_deilst_symbol_json(
|
|||
struct Symbols {
|
||||
symbol: String,
|
||||
}
|
||||
|
||||
|
||||
let table_name = String::from("banned_usdt_trades");
|
||||
let column_name = String::from("symbol");
|
||||
let condition = None;
|
||||
|
|
@ -550,8 +547,8 @@ async fn de_deilst_symbol_json(
|
|||
};
|
||||
|
||||
let mut select_result = try_select_record(&table_name, &column_name, &condition, &symbols)
|
||||
.await
|
||||
.unwrap();
|
||||
.await
|
||||
.unwrap();
|
||||
let mut banned_usdt_trades_set: HashSet<String> = HashSet::new();
|
||||
for element in select_result {
|
||||
banned_usdt_trades_set.insert(element.symbol.clone());
|
||||
|
|
@ -562,11 +559,11 @@ async fn de_deilst_symbol_json(
|
|||
if !banned_usdt_trades_set.contains(element) {
|
||||
let insert_values = vec![element.clone()];
|
||||
insert_one_record(&table_name, &insert_column, &insert_values)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,8 +292,8 @@ async fn initialize_database() {
|
|||
vec![String::from("ANCUSDT")],
|
||||
];
|
||||
insert_records(&table_name, &columns, &value_wrapper)
|
||||
.await
|
||||
.unwrap();
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
println!("Ok");
|
||||
}
|
||||
|
|
@ -907,9 +907,10 @@ async fn initialize_database() {
|
|||
let mut symbols = Symbols {
|
||||
symbol: String::new(),
|
||||
};
|
||||
let symbols_vec = select_record(&fetch_table_name, &column_name, &condition, &symbols)
|
||||
.await
|
||||
.expect("Failed to fetch records!");
|
||||
let symbols_vec =
|
||||
select_record(&fetch_table_name, &column_name, &condition, &symbols)
|
||||
.await
|
||||
.expect("Failed to fetch records!");
|
||||
let insert_table_name = String::from("wallet");
|
||||
let insert_columns = vec!["asset", "free", "locked"];
|
||||
let mut insert_values: Vec<Vec<String>> = Vec::new();
|
||||
|
|
|
|||
149
src/main.rs
149
src/main.rs
|
|
@ -8,8 +8,11 @@ use crate::server_health_check_team::ServerHealth;
|
|||
use crate::strategy_team::AllData;
|
||||
use crate::time_checking_team::UserTime;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use clap::{arg, Command};
|
||||
use log::Level;
|
||||
use reqwest::{Client, ClientBuilder};
|
||||
use rust_decimal::Decimal;
|
||||
use simple_logger::set_up_color_terminal;
|
||||
use sqlx::{mysql::*, Connection, Executor, FromRow, Row};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::{
|
||||
|
|
@ -18,9 +21,6 @@ use std::{
|
|||
};
|
||||
use tokio::{fs::*, join, sync::mpsc, sync::watch, sync::Mutex, task::*, time::*};
|
||||
use tradingbot::{RunningMode::*, *};
|
||||
use clap::{arg, Command};
|
||||
use log::Level;
|
||||
use simple_logger::set_up_color_terminal;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
|
|
@ -301,9 +301,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
loop {
|
||||
let instant = Instant::now();
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(Duration::from_millis(1000))
|
||||
.build()
|
||||
.unwrap();
|
||||
.timeout(Duration::from_millis(1000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let mut usertime = UserTime::new();
|
||||
let mut serverhealth = ServerHealth::new();
|
||||
let mut epoch_difference_vec: Vec<f64> = Vec::new();
|
||||
|
|
@ -330,14 +330,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
match result {
|
||||
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.");
|
||||
epoch_difference_tx1.send(usertime.epoch_difference)
|
||||
.expect("epoch_difference_tx1-epoch_difference_rx1 channel has been closed.");
|
||||
local_epoch_tx2.send(usertime.local_epoch)
|
||||
epoch_difference_tx1.send(usertime.epoch_difference).expect(
|
||||
"epoch_difference_tx1-epoch_difference_rx1 channel has been closed.",
|
||||
);
|
||||
local_epoch_tx2
|
||||
.send(usertime.local_epoch)
|
||||
.expect("local_epoch_tx2-local_epoch_rx2 channel has been closed.");
|
||||
epoch_difference_tx2.send(usertime.epoch_difference)
|
||||
.expect("epoch_difference_tx2-epoch_difference_rx2 channel has been closed.");
|
||||
epoch_difference_tx2.send(usertime.epoch_difference).expect(
|
||||
"epoch_difference_tx2-epoch_difference_rx2 channel has been closed.",
|
||||
);
|
||||
tx_task1.send(1).expect("The mpsc channel has been closed.");
|
||||
}
|
||||
Err(E) => {}
|
||||
|
|
@ -398,9 +402,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
loop {
|
||||
let instant = Instant::now();
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let tx1_changed = local_epoch_rx1.changed().await;
|
||||
let tx2_changed = epoch_difference_rx1.changed().await;
|
||||
let local_epoch = *local_epoch_rx1.borrow();
|
||||
|
|
@ -429,7 +433,6 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
tx_tradefee_map.send_modify(|vec| *vec = tradefee_vec_temp);
|
||||
tx_task2.send(2).expect("The mpsc channel has been closed.");
|
||||
|
||||
}
|
||||
Err(E) => {
|
||||
panic!("tx2-rx2 channel has been closed.")
|
||||
|
|
@ -452,9 +455,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
tokio::task::spawn(async move {
|
||||
loop {
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let mut exchange_info_map_temp: HashMap<String, ExchangeInfo> = HashMap::new();
|
||||
let mut result;
|
||||
loop {
|
||||
|
|
@ -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_task3.send(3).expect("The mpsc channel has been closed.");
|
||||
|
||||
|
|
@ -492,9 +494,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
loop {
|
||||
let instant = Instant::now();
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let result = request_others::request_24hr_ticker_price_change_statistics(&client).await;
|
||||
match result {
|
||||
Ok(T) => {
|
||||
|
|
@ -506,9 +508,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
)
|
||||
.await;
|
||||
|
||||
tx_valid_usdt_trade_set
|
||||
.send_modify(|vec| *vec = valid_usdt_trade_set_temp);
|
||||
tx_task4.send(4).expect("The mpsc channel has been closed.");
|
||||
tx_valid_usdt_trade_set.send_modify(|vec| *vec = valid_usdt_trade_set_temp);
|
||||
tx_task4.send(4).expect("The mpsc channel has been closed.");
|
||||
}
|
||||
Err(E) => {
|
||||
log::warn!(">>> Failed to monitor usdt_24h_change_profit_index.");
|
||||
|
|
@ -560,9 +561,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
loop {
|
||||
let instant = Instant::now();
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(tokio::time::Duration::from_millis(1000))
|
||||
.build()
|
||||
.unwrap();
|
||||
.timeout(tokio::time::Duration::from_millis(1000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let mut price_vec_temp: HashMap<String, f64> = HashMap::new();
|
||||
let mut price_vec_temp_c: HashMap<String, f64> = HashMap::new();
|
||||
request_others::request_all_coin_price(&client, &mut price_vec_temp).await;
|
||||
|
|
@ -576,8 +577,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let interval = String::from("1m");
|
||||
let candle_1m_vec = rx_candle_1m_map.borrow().clone();
|
||||
let dummy_data: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let mut rt_price_1m_map_write_temp: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let mut rt_price_1m_map_write_temp_c: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let mut rt_price_1m_map_write_temp: HashMap<String, Vec<RealtimePriceData>> =
|
||||
HashMap::new();
|
||||
let mut rt_price_1m_map_write_temp_c: HashMap<String, Vec<RealtimePriceData>> =
|
||||
HashMap::new();
|
||||
let result = value_estimation_team::datapoints::price_data::update_realtime_price_data(
|
||||
&interval,
|
||||
&candle_1m_vec,
|
||||
|
|
@ -597,8 +600,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
// 30m
|
||||
let interval = String::from("30m");
|
||||
let candle_30m_map = rx_candle_30m_map.borrow().clone();
|
||||
let mut rt_price_30m_map_write_temp: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let mut rt_price_30m_map_write_temp_c: HashMap<String, Vec<RealtimePriceData>> = HashMap::new();
|
||||
let mut rt_price_30m_map_write_temp: HashMap<String, Vec<RealtimePriceData>> =
|
||||
HashMap::new();
|
||||
let mut rt_price_30m_map_write_temp_c: HashMap<String, Vec<RealtimePriceData>> =
|
||||
HashMap::new();
|
||||
if !rt_price_1m_map_write_temp_c.is_empty() {
|
||||
let result =
|
||||
value_estimation_team::datapoints::price_data::update_realtime_price_data(
|
||||
|
|
@ -614,15 +619,19 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
if tx_rt_price_30m_map.is_closed() {
|
||||
log::error!("tx_rt_price_30m_vec has been closed!");
|
||||
} else {
|
||||
tx_rt_price_30m_map
|
||||
.send_modify(|map: &mut HashMap<String, Vec<RealtimePriceData>>| *map = rt_price_30m_map_write_temp);
|
||||
}
|
||||
tx_rt_price_30m_map.send_modify(
|
||||
|map: &mut HashMap<String, Vec<RealtimePriceData>>| {
|
||||
*map = rt_price_30m_map_write_temp
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 1d
|
||||
let interval = String::from("1d");
|
||||
let candle_1d_vec = rx_candle_1d_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() {
|
||||
let result =
|
||||
|
|
@ -1055,8 +1064,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let instant = Instant::now();
|
||||
let exchange_info_map = rx_exchange_info_map.borrow().clone();
|
||||
let trade_fee_map = rx_tradefee_map.borrow().clone();
|
||||
let result =
|
||||
coex::exchange_team::buy_coin(&exchange_info_map, &trade_fee_map).await;
|
||||
let result = coex::exchange_team::buy_coin(&exchange_info_map, &trade_fee_map).await;
|
||||
|
||||
// send Task#0 a message to notify running on
|
||||
match result {
|
||||
|
|
@ -1087,15 +1095,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
loop {
|
||||
let instant = Instant::now();
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let trade_fee_map = rx2_tradefee_map.borrow().clone();
|
||||
let result = coex::order_team::monitoring_open_buy_order(
|
||||
&client,
|
||||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
let result =
|
||||
coex::order_team::monitoring_open_buy_order(&client, &trade_fee_map).await;
|
||||
|
||||
// send Task#0 a message to notify running on
|
||||
match result {
|
||||
|
|
@ -1162,9 +1167,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
loop {
|
||||
let instant = Instant::now();
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let exchange_info_vec = rx4_exchange_info_map.borrow().clone();
|
||||
let trade_fee_vec = rx4_tradefee_map.borrow().clone();
|
||||
let result = coex::order_team::monitoring_open_sell_order(
|
||||
|
|
@ -1200,9 +1205,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
loop {
|
||||
let instant = Instant::now();
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let result = coex::order_team::monitoring_filled_sell_order(&client).await;
|
||||
|
||||
// send Task#0 a message to notify running on
|
||||
|
|
@ -1260,9 +1265,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
loop {
|
||||
let instant = Instant::now();
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let result =
|
||||
coex::assets_managing_team::monitoring_asset_usdt(&mut previous_result, &client)
|
||||
.await;
|
||||
|
|
@ -1320,25 +1325,26 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
loop {
|
||||
let instant = Instant::now();
|
||||
let client = ClientBuilder::new()
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
.timeout(tokio::time::Duration::from_millis(3000))
|
||||
.build()
|
||||
.unwrap();
|
||||
let tx1_changed = local_epoch_rx2.changed().await;
|
||||
let tx2_changed = epoch_difference_rx2.changed().await;
|
||||
let local_epoch = *local_epoch_rx2.borrow();
|
||||
let difference_epoch = *epoch_difference_rx2.borrow();
|
||||
|
||||
|
||||
|
||||
let result = request_others::request_delist_symbols(
|
||||
API_KEY,
|
||||
SECRET_KEY,
|
||||
local_epoch,
|
||||
difference_epoch,
|
||||
&client
|
||||
&client,
|
||||
)
|
||||
.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.
|
||||
elapsed_time = instant.elapsed().as_secs();
|
||||
|
|
@ -1348,18 +1354,20 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
}
|
||||
});
|
||||
|
||||
loop {
|
||||
}
|
||||
loop {}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn program_setting() {
|
||||
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))
|
||||
.get_matches();
|
||||
|
||||
|
||||
// set log level
|
||||
set_up_color_terminal();
|
||||
if let Some(level) = matches.get_one::<String>("log_level") {
|
||||
|
|
@ -1374,7 +1382,6 @@ fn program_setting() {
|
|||
log::error!("wrong log level argument.");
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1385,15 +1392,15 @@ fn program_setting() {
|
|||
"real" => {
|
||||
RUNNING_MODE = RunningMode::REAL;
|
||||
println!("*** REAL MODE ***");
|
||||
},
|
||||
}
|
||||
"simul" => {
|
||||
RUNNING_MODE = RunningMode::SIMUL;
|
||||
println!("*** SIMULATION MODE ***");
|
||||
},
|
||||
}
|
||||
"test" => {
|
||||
RUNNING_MODE = RunningMode::TEST;
|
||||
println!("*** TEST MODE ***");
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
log::error!("wrong mode argument.");
|
||||
std::process::exit(0);
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
|
||||
use crate::database_control::*;
|
||||
use crate::time_checking_team::UserTime;
|
||||
use log;
|
||||
use rand::*;
|
||||
use reqwest::{Client, ClientBuilder, Response};
|
||||
use tokio::join;
|
||||
use tokio::time::*;
|
||||
use log;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ServerHealth {
|
||||
|
|
@ -55,7 +55,7 @@ pub async fn execute_server_health_check(
|
|||
if waiting_time > 2 {
|
||||
log::warn!(">>> retry connection after {} second(s).", waiting_time);
|
||||
}
|
||||
|
||||
|
||||
sleep(Duration::from_secs(waiting_time as u64)).await;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,13 +9,15 @@ pub mod strategy_008;
|
|||
// pub mod strategy_test;
|
||||
pub mod strategy_manager;
|
||||
|
||||
use crate::coex::order_team::{limit_order_sell, select_filled_buy_orders};
|
||||
use crate::coex::exchange_team::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::database_control::*;
|
||||
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::dema::{dema, DemaData};
|
||||
use crate::value_estimation_team::indicators::ema::{ema, ema_opclo, EmaData};
|
||||
use crate::value_estimation_team::indicators::heatmap_volume::{
|
||||
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::sma::{sma, sma_opclo, SmaData};
|
||||
use crate::value_estimation_team::indicators::stoch_rsi::{stoch_rsi, StochRsiData};
|
||||
use crate::value_estimation_team::indicators::supertrend::{supertrend, SupertrendData, SuperTrendArea, SuperTrendSignal};
|
||||
use crate::value_estimation_team::indicators::adx::{AdxData, adx};
|
||||
use crate::value_estimation_team::indicators::dema::{DemaData, dema};
|
||||
use crate::value_estimation_team::indicators::tema::{TemaData, tema};
|
||||
use crate::value_estimation_team::indicators::supertrend::{
|
||||
supertrend, SuperTrendArea, SuperTrendSignal, SupertrendData,
|
||||
};
|
||||
use crate::value_estimation_team::indicators::tema::{tema, TemaData};
|
||||
use futures::future::try_join_all;
|
||||
use reqwest::{Client, ClientBuilder};
|
||||
use rust_decimal::{prelude::FromPrimitive, prelude::ToPrimitive, Decimal, RoundingStrategy};
|
||||
use rust_decimal_macros::dec;
|
||||
use sqlx::FromRow;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
use strategy_manager::insert_pre_suggested_coins;
|
||||
use tokio::sync::Mutex;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AllData {
|
||||
|
|
@ -92,9 +94,10 @@ impl FilteredDataValue {
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn duplicate_filter(registerer: i32, original_filtered_data: &HashMap<String, FilteredDataValue>)
|
||||
-> Result<HashMap<String, FilteredDataValue>, Box<dyn std::error::Error + Send + Sync>>
|
||||
{
|
||||
pub async fn duplicate_filter(
|
||||
registerer: i32,
|
||||
original_filtered_data: &HashMap<String, FilteredDataValue>,
|
||||
) -> Result<HashMap<String, FilteredDataValue>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let inspect_table_name_1 = String::from("buy_ordered_coin_list");
|
||||
let inspect_table_name_2 = String::from("sell_ordered_coin_list");
|
||||
let inspect_table_name_3 = String::from("pre_suggested_coin_list");
|
||||
|
|
@ -146,14 +149,17 @@ pub async fn duplicate_filter(registerer: i32, original_filtered_data: &HashMap<
|
|||
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();
|
||||
// remove key-value in filtered_data
|
||||
for symbol in keys_to_remove {
|
||||
filtered_data.remove(&symbol);
|
||||
}
|
||||
let len_now = filtered_data.len();
|
||||
|
||||
|
||||
// shrink capacity of filtered_data
|
||||
if len_now != len_prev {
|
||||
filtered_data.shrink_to_fit();
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
||||
|
||||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, ema, exists_record, insert_pre_suggested_coins,
|
||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
||||
adx, dec, decimal_add, decimal_div, decimal_sub, duplicate_filter, ema, ema_macd,
|
||||
exists_record, get_server_epoch, insert_pre_suggested_coins, limit_order_sell, remove_keys,
|
||||
rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, update_record3, AdxData,
|
||||
AllData, Arc, BollingerBandData, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo,
|
||||
FilteredDataValue, HashMap, HashSet, MacdData, Mutex, RealtimePriceData, RoundingStrategy,
|
||||
RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal, SupertrendData, ToPrimitive, TradeFee,
|
||||
};
|
||||
|
||||
// BB lowerband + SuperTrend + StochRSI
|
||||
|
|
@ -23,7 +24,7 @@ pub async fn list_up_for_buy(
|
|||
for symbol in &alldata.valid_symbol_vec {
|
||||
filtered_data.insert(symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
|
||||
|
||||
// 4th filtering: 0.5% <= the average amplitude of the latest 10 30m candles <= 1.0%
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
|
|
@ -31,12 +32,14 @@ pub async fn list_up_for_buy(
|
|||
let rt_price_30m = alldata.rt_price_30m_vec.get(symbol).unwrap();
|
||||
let vec_len = rt_price_30m.len();
|
||||
|
||||
if let Some(candles) = rt_price_30m.get(vec_len-12..vec_len-1) {
|
||||
if let Some(candles) = rt_price_30m.get(vec_len - 12..vec_len - 1) {
|
||||
let windows = candles.windows(2);
|
||||
let mut average_amplitude = 0.0;
|
||||
|
||||
for window in windows {
|
||||
average_amplitude += (window.last().unwrap().high_price - window.last().unwrap().low_price) / window.first().unwrap().close_price;
|
||||
average_amplitude += (window.last().unwrap().high_price
|
||||
- window.last().unwrap().low_price)
|
||||
/ window.first().unwrap().close_price;
|
||||
}
|
||||
average_amplitude /= 10.0;
|
||||
|
||||
|
|
@ -52,61 +55,48 @@ pub async fn list_up_for_buy(
|
|||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
|
||||
// 2nd filtering: supertrend(ATR period 20, multiplier: 2, 30m close price)
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let supertrend_30m_map = supertrend(20, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let supertrend_30m_map =
|
||||
supertrend(20, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_30m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
// input closetime, current_price
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
|
||||
// input stoploss
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN &&
|
||||
supertrend_vec.last().unwrap().band_value > values.current_price.to_f64().unwrap()
|
||||
{
|
||||
values.stoploss = decimal_sub(values.current_price, decimal_sub(band_value, values.current_price));
|
||||
|
||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
||||
supertrend_vec.last().unwrap().band_value < values.current_price.to_f64().unwrap()
|
||||
{
|
||||
values.stoploss = band_value;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||
supertrend_30m_map.get(symbol),
|
||||
alldata.rt_price_30m_vec.get(symbol),
|
||||
) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
// input closetime, current_price
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
rt_price_vec.last().unwrap().close_price,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// input stoploss
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
supertrend_vec.last().unwrap().band_value,
|
||||
)
|
||||
.unwrap();
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN
|
||||
&& supertrend_vec.last().unwrap().band_value
|
||||
> values.current_price.to_f64().unwrap()
|
||||
{
|
||||
values.stoploss = decimal_sub(
|
||||
values.current_price,
|
||||
decimal_sub(band_value, values.current_price),
|
||||
);
|
||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP
|
||||
&& supertrend_vec.last().unwrap().band_value
|
||||
< values.current_price.to_f64().unwrap()
|
||||
{
|
||||
values.stoploss = band_value;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// filtering: the latest 5 30m candle close prices > EMA 200
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let emas = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if emas.contains_key(symbol) && alldata.rt_price_30m_vec.contains_key(symbol) {
|
||||
let ema = emas.get(symbol).unwrap();
|
||||
let rt_price_30m = alldata.rt_price_30m_vec.get(symbol).unwrap();
|
||||
let rt_price_30m_len = rt_price_30m.len();
|
||||
let search_result = ema.binary_search_by_key(
|
||||
&alldata.rt_price_30m_vec.get(symbol).unwrap().last().unwrap().close_time,
|
||||
|EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| *close_time);
|
||||
if search_result.is_ok_and(|x| ema[search_result.unwrap()].ema_value < rt_price_30m[rt_price_30m_len-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-1].ema_value < rt_price_30m[rt_price_30m_len-2].close_price) &&
|
||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-2].ema_value < rt_price_30m[rt_price_30m_len-3].close_price) &&
|
||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-3].ema_value < rt_price_30m[rt_price_30m_len-4].close_price) &&
|
||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-4].ema_value < rt_price_30m[rt_price_30m_len-5].close_price) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -115,15 +105,65 @@ pub async fn list_up_for_buy(
|
|||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
|
||||
// filtering: the latest 5 30m candle close prices > EMA 200
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let emas = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if emas.contains_key(symbol) && alldata.rt_price_30m_vec.contains_key(symbol) {
|
||||
let ema = emas.get(symbol).unwrap();
|
||||
let rt_price_30m = alldata.rt_price_30m_vec.get(symbol).unwrap();
|
||||
let rt_price_30m_len = rt_price_30m.len();
|
||||
let search_result = ema.binary_search_by_key(
|
||||
&alldata
|
||||
.rt_price_30m_vec
|
||||
.get(symbol)
|
||||
.unwrap()
|
||||
.last()
|
||||
.unwrap()
|
||||
.close_time,
|
||||
|EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
);
|
||||
if search_result.is_ok_and(|x| {
|
||||
ema[search_result.unwrap()].ema_value
|
||||
< rt_price_30m[rt_price_30m_len - 1].close_price
|
||||
}) && search_result.is_ok_and(|x| {
|
||||
ema[search_result.unwrap() - 1].ema_value
|
||||
< rt_price_30m[rt_price_30m_len - 2].close_price
|
||||
}) && search_result.is_ok_and(|x| {
|
||||
ema[search_result.unwrap() - 2].ema_value
|
||||
< rt_price_30m[rt_price_30m_len - 3].close_price
|
||||
}) && search_result.is_ok_and(|x| {
|
||||
ema[search_result.unwrap() - 3].ema_value
|
||||
< rt_price_30m[rt_price_30m_len - 4].close_price
|
||||
}) && search_result.is_ok_and(|x| {
|
||||
ema[search_result.unwrap() - 4].ema_value
|
||||
< rt_price_30m[rt_price_30m_len - 5].close_price
|
||||
}) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// filtering: 30m StochRSI (RSI_len: 10, StochRSI_len: 10, K: 3, D: 3) previous K < 5 && current K > previous K
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let stoch_rsis = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if alldata.rt_price_30m_vec.contains_key(symbol) && stoch_rsis.contains_key(symbol) {
|
||||
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == values.closetime);
|
||||
if search_result.is_some_and(|a| stoch_rsi_vec[a-1].k < 5.0 && stoch_rsi_vec[a].k > stoch_rsi_vec[a-1].k) {
|
||||
let search_result = stoch_rsi_vec
|
||||
.iter()
|
||||
.position(|x| x.close_time == values.closetime);
|
||||
if search_result.is_some_and(|a| {
|
||||
stoch_rsi_vec[a - 1].k < 5.0 && stoch_rsi_vec[a].k > stoch_rsi_vec[a - 1].k
|
||||
}) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -132,17 +172,26 @@ pub async fn list_up_for_buy(
|
|||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
|
||||
// filtering: 1d MACD (3, 7, 30) current MACD-signal > prev MACD-signal
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if macd_vec[macd_vec.len()-1].macd_value - macd_vec[macd_vec.len()-1].signal_value > macd_vec[macd_vec.len()-2].macd_value - macd_vec[macd_vec.len()-2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) =
|
||||
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||
{
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
if macd_vec[macd_vec.len() - 1].macd_value
|
||||
- macd_vec[macd_vec.len() - 1].signal_value
|
||||
> macd_vec[macd_vec.len() - 2].macd_value
|
||||
- macd_vec[macd_vec.len() - 2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
rt_price_vec.last().unwrap().close_price,
|
||||
)
|
||||
.unwrap();
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
|
|
@ -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?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(adx_vec) = adx_vec.get(symbol) {
|
||||
if let Some(last_idx) = adx_vec.iter().position(|elem| elem.close_time == values.closetime) {
|
||||
if
|
||||
adx_vec[last_idx].adx < adx_vec[last_idx-1].adx &&
|
||||
adx_vec[last_idx-1].adx < adx_vec[last_idx-2].adx {
|
||||
if let Some(last_idx) = adx_vec
|
||||
.iter()
|
||||
.position(|elem| elem.close_time == values.closetime)
|
||||
{
|
||||
if adx_vec[last_idx].adx < adx_vec[last_idx - 1].adx
|
||||
&& adx_vec[last_idx - 1].adx < adx_vec[last_idx - 2].adx
|
||||
{
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -173,7 +225,7 @@ pub async fn list_up_for_buy(
|
|||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
|
|
@ -202,37 +254,49 @@ pub async fn list_up_for_sell(
|
|||
for element in &filled_buy_orders {
|
||||
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 stoch_rsis = stoch_rsi(10, 10, 3, 3, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
||||
let supertrend_30m =
|
||||
supertrend(20, 2.0, true, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
||||
let stoch_rsis =
|
||||
stoch_rsi(10, 10, 3, 3, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
||||
for element in filled_buy_orders {
|
||||
if element.used_usdt >= dec!(10.0) {
|
||||
if let (Some(exchange_info), Some(tradefee), Some(stoch_rsi), Some(supertrend_vec)) =
|
||||
(exchange_info_map.get(&element.symbol), trade_fee_map.get(&element.symbol), stoch_rsis.get(&element.symbol), supertrend_30m.get(&element.symbol)) {
|
||||
if let (
|
||||
Some(exchange_info),
|
||||
Some(tradefee),
|
||||
Some(stoch_rsi),
|
||||
Some(supertrend_vec),
|
||||
) = (
|
||||
exchange_info_map.get(&element.symbol),
|
||||
trade_fee_map.get(&element.symbol),
|
||||
stoch_rsis.get(&element.symbol),
|
||||
supertrend_30m.get(&element.symbol),
|
||||
) {
|
||||
// update stoploss
|
||||
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
|
||||
&& band_value > element.stoploss {
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![
|
||||
(String::from("stoploss"), band_value.to_string()),
|
||||
];
|
||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||
update_record3(&update_table_name, &update_value, &update_condition)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
&& band_value > element.stoploss
|
||||
{
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![(String::from("stoploss"), band_value.to_string())];
|
||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||
update_record3(&update_table_name, &update_value, &update_condition)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let base_qty_to_be_ordered = element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let stoch_rsi_k = stoch_rsi.last().unwrap().k;
|
||||
let stoch_rsi_k_prev = stoch_rsi[stoch_rsi.len()-2].k;
|
||||
let stoch_rsi_k_prev = stoch_rsi[stoch_rsi.len() - 2].k;
|
||||
let stoch_rsi_d = stoch_rsi.last().unwrap().d;
|
||||
let stoch_rsi_d_prev = stoch_rsi[stoch_rsi.len()-2].d;
|
||||
let stoch_rsi_d_prev = stoch_rsi[stoch_rsi.len() - 2].d;
|
||||
if (element.is_long == 0 || element.is_long == 1)
|
||||
&& !element.current_price.is_zero()
|
||||
{
|
||||
|
|
@ -266,9 +330,9 @@ pub async fn list_up_for_sell(
|
|||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if stoch_rsi_k >= 90.0 &&
|
||||
(stoch_rsi_k < stoch_rsi_d &&
|
||||
stoch_rsi_k_prev > stoch_rsi_d_prev) {
|
||||
} else if stoch_rsi_k >= 90.0
|
||||
&& (stoch_rsi_k < stoch_rsi_d && stoch_rsi_k_prev > stoch_rsi_d_prev)
|
||||
{
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
|
|
@ -280,7 +344,7 @@ pub async fn list_up_for_sell(
|
|||
.await;
|
||||
}
|
||||
// TODO: sell_count가 1일 때 적용하기
|
||||
// else if (supertrend_vec
|
||||
// else if (supertrend_vec
|
||||
// .last()
|
||||
// .unwrap()
|
||||
// .signal
|
||||
|
|
@ -305,7 +369,6 @@ pub async fn list_up_for_sell(
|
|||
// }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
||||
|
||||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, ema, exists_record, insert_pre_suggested_coins,
|
||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
||||
adx, dec, decimal_add, decimal_div, decimal_sub, duplicate_filter, ema, ema_macd,
|
||||
exists_record, get_server_epoch, insert_pre_suggested_coins, limit_order_sell, remove_keys,
|
||||
rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, update_record3, AdxData,
|
||||
AllData, Arc, BollingerBandData, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo,
|
||||
FilteredDataValue, HashMap, HashSet, MacdData, Mutex, RealtimePriceData, RoundingStrategy,
|
||||
RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal, SupertrendData, ToPrimitive, TradeFee,
|
||||
};
|
||||
|
||||
// BB 30m lowerband + BB 1m lowerband
|
||||
|
|
@ -29,12 +30,14 @@ pub async fn list_up_for_buy(
|
|||
if let Some(rt_price_30m_vec) = alldata.rt_price_30m_vec.get(symbol) {
|
||||
let vec_len = rt_price_30m_vec.len();
|
||||
if vec_len >= 11 {
|
||||
let candles = rt_price_30m_vec.get(vec_len-12..vec_len-1).unwrap();
|
||||
let candles = rt_price_30m_vec.get(vec_len - 12..vec_len - 1).unwrap();
|
||||
let windows = candles.windows(2);
|
||||
let mut average_amplitude = 0.0;
|
||||
|
||||
for window in windows {
|
||||
average_amplitude += (window.last().unwrap().high_price - window.last().unwrap().low_price) / window.first().unwrap().close_price;
|
||||
average_amplitude += (window.last().unwrap().high_price
|
||||
- window.last().unwrap().low_price)
|
||||
/ window.first().unwrap().close_price;
|
||||
}
|
||||
average_amplitude /= 10.0;
|
||||
|
||||
|
|
@ -50,30 +53,46 @@ pub async fn list_up_for_buy(
|
|||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
|
||||
// 2nd filtering: BollingerBand (len:10, multiplier 2.5) previous_30m_price (close or low price) < lower_band
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let bollingerbands_30m_map = bollingerband(10, 2.5, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let bollingerbands_1m_map = bollingerband(30, 3.0, &alldata.rt_price_1m_vec, &filtered_data).await?;
|
||||
let bollingerbands_30m_map =
|
||||
bollingerband(10, 2.5, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let bollingerbands_1m_map =
|
||||
bollingerband(30, 3.0, &alldata.rt_price_1m_vec, &filtered_data).await?;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(bb_30m_vec), Some(bb_1m_vec), Some(rt_30m_vec)) = (bollingerbands_30m_map.get(symbol), bollingerbands_1m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
if rt_30m_vec.len() >= 3 && bb_30m_vec.len() >= 3 && bb_1m_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
if let (Some(bb_30m_vec), Some(bb_1m_vec), Some(rt_30m_vec)) = (
|
||||
bollingerbands_30m_map.get(symbol),
|
||||
bollingerbands_1m_map.get(symbol),
|
||||
alldata.rt_price_30m_vec.get(symbol),
|
||||
) {
|
||||
if rt_30m_vec.len() >= 3
|
||||
&& bb_30m_vec.len() >= 3
|
||||
&& bb_1m_vec.len() >= 3
|
||||
&& rt_30m_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
let bb_30m_search_result = bb_30m_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|BollingerBandData {
|
||||
sma,
|
||||
upperband,
|
||||
lowerband,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
sma,
|
||||
upperband,
|
||||
lowerband,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
);
|
||||
if bb_30m_search_result.is_ok() {
|
||||
if bb_30m_vec[bb_30m_search_result.unwrap()].lowerband > rt_30m_vec[rt_30m_vec.len()-1].close_price &&
|
||||
bb_1m_vec.last().unwrap().lowerband > rt_30m_vec[rt_30m_vec.len()-1].close_price
|
||||
if bb_30m_vec[bb_30m_search_result.unwrap()].lowerband
|
||||
> rt_30m_vec[rt_30m_vec.len() - 1].close_price
|
||||
&& bb_1m_vec.last().unwrap().lowerband
|
||||
> rt_30m_vec[rt_30m_vec.len() - 1].close_price
|
||||
{
|
||||
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 {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -91,26 +110,48 @@ pub async fn list_up_for_buy(
|
|||
|
||||
// 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 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;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(rt_30m_vec), Some(supertrend_vec)) = (alldata.rt_price_30m_vec.get(symbol), supertrend_30m_map.get(symbol)) {
|
||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(rt_30m_vec), Some(supertrend_vec)) = (
|
||||
alldata.rt_price_30m_vec.get(symbol),
|
||||
supertrend_30m_map.get(symbol),
|
||||
) {
|
||||
if rt_30m_vec.len() >= 3
|
||||
&& supertrend_vec.len() >= 3
|
||||
&& rt_30m_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|SupertrendData {
|
||||
band_value,
|
||||
signal,
|
||||
area,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
band_value,
|
||||
signal,
|
||||
area,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
);
|
||||
if supertrend_search_result.is_ok() {
|
||||
if supertrend_vec[supertrend_search_result.unwrap()].area == SuperTrendArea::DOWN
|
||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value > filtered_data.current_price.to_f64().unwrap()
|
||||
if supertrend_vec[supertrend_search_result.unwrap()].area
|
||||
== SuperTrendArea::DOWN
|
||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value
|
||||
> filtered_data.current_price.to_f64().unwrap()
|
||||
{
|
||||
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.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;
|
||||
} else {
|
||||
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 ema_map = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(ema_vec), Some(rt_30m_vec)) = (ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
if let (Some(ema_vec), Some(rt_30m_vec)) =
|
||||
(ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol))
|
||||
{
|
||||
let search_result = ema_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| *close_time);
|
||||
if search_result.is_ok_and(|x| ema_vec[x].ema_value < rt_30m_vec[rt_30m_vec.len()-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[x-1].ema_value < rt_30m_vec[rt_30m_vec.len()-2].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[x-2].ema_value < rt_30m_vec[rt_30m_vec.len()-3].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[x-3].ema_value < rt_30m_vec[rt_30m_vec.len()-4].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[x-4].ema_value < rt_30m_vec[rt_30m_vec.len()-5].close_price) {
|
||||
ema_value,
|
||||
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
|
||||
})
|
||||
&& search_result.is_ok_and(|x| {
|
||||
ema_vec[x - 2].ema_value < rt_30m_vec[rt_30m_vec.len() - 3].close_price
|
||||
})
|
||||
&& search_result.is_ok_and(|x| {
|
||||
ema_vec[x - 3].ema_value < rt_30m_vec[rt_30m_vec.len() - 4].close_price
|
||||
})
|
||||
&& search_result.is_ok_and(|x| {
|
||||
ema_vec[x - 4].ema_value < rt_30m_vec[rt_30m_vec.len() - 5].close_price
|
||||
})
|
||||
{
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -156,12 +210,21 @@ pub async fn list_up_for_buy(
|
|||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if macd_vec[macd_vec.len()-1].macd_value - macd_vec[macd_vec.len()-1].signal_value > macd_vec[macd_vec.len()-2].macd_value - macd_vec[macd_vec.len()-2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) =
|
||||
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||
{
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
if macd_vec[macd_vec.len() - 1].macd_value
|
||||
- macd_vec[macd_vec.len() - 1].signal_value
|
||||
> macd_vec[macd_vec.len() - 2].macd_value
|
||||
- macd_vec[macd_vec.len() - 2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
rt_price_vec.last().unwrap().close_price,
|
||||
)
|
||||
.unwrap();
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
|
|
@ -174,7 +237,7 @@ pub async fn list_up_for_buy(
|
|||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
|
||||
let final_filtered_data = duplicate_filter(2, &filtered_data).await?;
|
||||
insert_pre_suggested_coins(2, false, &final_filtered_data, &alldata).await;
|
||||
|
||||
|
|
@ -199,17 +262,15 @@ pub async fn list_up_for_sell(
|
|||
if let Some(exchange_info) = exchange_info_map.get(&element.symbol) {
|
||||
let lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let base_qty_to_be_ordered = element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
|
||||
if (element.is_long == 0 || element.is_long == 1)
|
||||
&& !element.current_price.is_zero()
|
||||
{
|
||||
if element.current_price >= element.target_price
|
||||
{
|
||||
if element.current_price >= element.target_price {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
|
|
@ -241,7 +302,7 @@ pub async fn list_up_for_sell(
|
|||
.await;
|
||||
}
|
||||
// TODO: sell_count가 1일 때 적용하기
|
||||
// else if (supertrend_vec
|
||||
// else if (supertrend_vec
|
||||
// .last()
|
||||
// .unwrap()
|
||||
// .signal
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
||||
|
||||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, ema, ema_opclo, sma, sma_opclo, exists_record, insert_pre_suggested_coins,
|
||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex, SmaData,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal
|
||||
adx, dec, decimal_add, decimal_div, decimal_sub, duplicate_filter, ema, ema_macd, ema_opclo,
|
||||
exists_record, get_server_epoch, insert_pre_suggested_coins, limit_order_sell, remove_keys,
|
||||
rsi, select_filled_buy_orders, sma, sma_opclo, stoch_rsi, supertrend, try_join_all,
|
||||
update_record3, AdxData, AllData, Arc, BollingerBandData, Client, ClientBuilder, Decimal,
|
||||
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)
|
||||
|
|
@ -25,23 +27,31 @@ pub async fn list_up_for_buy(
|
|||
|
||||
// 3rd filtering: supertrend(ATR period 20, multiplier: 4.0, 30m close price), area should be UP
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let supertrend_30m_map = supertrend(20, 4.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let supertrend_30m_map =
|
||||
supertrend(20, 4.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(rt_30m_vec), Some(supertrend_vec)) = (alldata.rt_price_30m_vec.get(symbol), supertrend_30m_map.get(symbol)) {
|
||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(rt_30m_vec), Some(supertrend_vec)) = (
|
||||
alldata.rt_price_30m_vec.get(symbol),
|
||||
supertrend_30m_map.get(symbol),
|
||||
) {
|
||||
if rt_30m_vec.len() >= 3
|
||||
&& supertrend_vec.len() >= 3
|
||||
&& rt_30m_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|SupertrendData {
|
||||
band_value,
|
||||
signal,
|
||||
area,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
band_value,
|
||||
signal,
|
||||
area,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
);
|
||||
if supertrend_search_result.is_ok() {
|
||||
if supertrend_vec[supertrend_search_result.unwrap()].area == SuperTrendArea::UP
|
||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value < filtered_data.current_price.to_f64().unwrap()
|
||||
&& supertrend_vec[supertrend_search_result.unwrap()].band_value
|
||||
< filtered_data.current_price.to_f64().unwrap()
|
||||
{
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
|
|
@ -57,17 +67,24 @@ pub async fn list_up_for_buy(
|
|||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
|
||||
// 5th filtering: 30m StochRSI (RSI_len: 30, StochRSI_len: 30, K: 3, D: 3) previous K, D / current K, D < 10 && current K > current D
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let stoch_rsis = stoch_rsi(30, 30, 3, 3, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if alldata.rt_price_30m_vec.contains_key(symbol) && stoch_rsis.contains_key(symbol) {
|
||||
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == values.closetime);
|
||||
if search_result.is_some_and(|a| stoch_rsi_vec[a-1].k < 10.0 && stoch_rsi_vec[a].k < 10.0
|
||||
&& stoch_rsi_vec[a-1].d < 10.0 && stoch_rsi_vec[a].d< 10.0 &&
|
||||
stoch_rsi_vec[a-1].k <= stoch_rsi_vec[a-1].d && stoch_rsi_vec[a].k > stoch_rsi_vec[a].d) {
|
||||
let search_result = stoch_rsi_vec
|
||||
.iter()
|
||||
.position(|x| x.close_time == values.closetime);
|
||||
if search_result.is_some_and(|a| {
|
||||
stoch_rsi_vec[a - 1].k < 10.0
|
||||
&& stoch_rsi_vec[a].k < 10.0
|
||||
&& stoch_rsi_vec[a - 1].d < 10.0
|
||||
&& stoch_rsi_vec[a].d < 10.0
|
||||
&& stoch_rsi_vec[a - 1].k <= stoch_rsi_vec[a - 1].d
|
||||
&& stoch_rsi_vec[a].k > stoch_rsi_vec[a].d
|
||||
}) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -80,19 +97,31 @@ pub async fn list_up_for_buy(
|
|||
// 3rd filtering: the latest 5 30m candle close prices > EMA 200
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let emas = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if emas.contains_key(symbol) && alldata.rt_price_30m_vec.contains_key(symbol) {
|
||||
let ema = emas.get(symbol).unwrap();
|
||||
let rt_price_30m = alldata.rt_price_30m_vec.get(symbol).unwrap();
|
||||
let rt_price_30m_len = rt_price_30m.len();
|
||||
let search_result = ema.binary_search_by_key(
|
||||
&alldata.rt_price_30m_vec.get(symbol).unwrap().last().unwrap().close_time,
|
||||
&alldata
|
||||
.rt_price_30m_vec
|
||||
.get(symbol)
|
||||
.unwrap()
|
||||
.last()
|
||||
.unwrap()
|
||||
.close_time,
|
||||
|EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| *close_time);
|
||||
if search_result.is_ok_and(|x| ema[search_result.unwrap()].ema_value < rt_price_30m[rt_price_30m_len-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema[search_result.unwrap()-1].ema_value < rt_price_30m[rt_price_30m_len-2].close_price) {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
);
|
||||
if search_result.is_ok_and(|x| {
|
||||
ema[search_result.unwrap()].ema_value
|
||||
< rt_price_30m[rt_price_30m_len - 1].close_price
|
||||
}) && search_result.is_ok_and(|x| {
|
||||
ema[search_result.unwrap() - 1].ema_value
|
||||
< rt_price_30m[rt_price_30m_len - 2].close_price
|
||||
}) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -106,12 +135,21 @@ pub async fn list_up_for_buy(
|
|||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if macd_vec[macd_vec.len()-1].macd_value - macd_vec[macd_vec.len()-1].signal_value > macd_vec[macd_vec.len()-2].macd_value - macd_vec[macd_vec.len()-2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) =
|
||||
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||
{
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
if macd_vec[macd_vec.len() - 1].macd_value
|
||||
- macd_vec[macd_vec.len() - 1].signal_value
|
||||
> macd_vec[macd_vec.len() - 2].macd_value
|
||||
- macd_vec[macd_vec.len() - 2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
rt_price_vec.last().unwrap().close_price,
|
||||
)
|
||||
.unwrap();
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
|
|
@ -124,7 +162,7 @@ pub async fn list_up_for_buy(
|
|||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
|
||||
let final_filtered_data = duplicate_filter(3, &filtered_data).await?;
|
||||
insert_pre_suggested_coins(3, false, &final_filtered_data, &alldata).await;
|
||||
|
||||
|
|
@ -148,27 +186,29 @@ pub async fn list_up_for_sell(
|
|||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
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 {
|
||||
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 quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let base_qty_to_be_ordered = element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let stoch_rsi_k = stoch_rsi.last().unwrap().k;
|
||||
let stoch_rsi_k_prev = stoch_rsi[stoch_rsi.len()-2].k;
|
||||
let stoch_rsi_k_prev = stoch_rsi[stoch_rsi.len() - 2].k;
|
||||
let stoch_rsi_d = stoch_rsi.last().unwrap().d;
|
||||
let stoch_rsi_d_prev = stoch_rsi[stoch_rsi.len()-2].d;
|
||||
let stoch_rsi_d_prev = stoch_rsi[stoch_rsi.len() - 2].d;
|
||||
|
||||
if (element.is_long == 0 || element.is_long == 1)
|
||||
&& !element.current_price.is_zero()
|
||||
{
|
||||
if element.current_price >= element.target_price
|
||||
{
|
||||
if element.current_price >= element.target_price {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
|
|
@ -208,10 +248,12 @@ pub async fn list_up_for_sell(
|
|||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
} else if stoch_rsi_k >= 20.0 && stoch_rsi_k >= 20.0 &&
|
||||
stoch_rsi_k_prev >= 20.0 && stoch_rsi_k_prev >= 20.0 &&
|
||||
stoch_rsi_k < stoch_rsi_d &&
|
||||
stoch_rsi_k_prev >= stoch_rsi_d_prev
|
||||
} else if stoch_rsi_k >= 20.0
|
||||
&& stoch_rsi_k >= 20.0
|
||||
&& stoch_rsi_k_prev >= 20.0
|
||||
&& stoch_rsi_k_prev >= 20.0
|
||||
&& stoch_rsi_k < stoch_rsi_d
|
||||
&& stoch_rsi_k_prev >= stoch_rsi_d_prev
|
||||
{
|
||||
limit_order_sell(
|
||||
&element,
|
||||
|
|
@ -222,9 +264,9 @@ pub async fn list_up_for_sell(
|
|||
&trade_fee_map,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
}
|
||||
// TODO: sell_count가 1일 때 적용하기
|
||||
// else if (supertrend_vec
|
||||
// else if (supertrend_vec
|
||||
// .last()
|
||||
// .unwrap()
|
||||
// .signal
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
use crate::value_estimation_team::indicators::bollingerband::bollingerband;
|
||||
|
||||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, ema, exists_record, insert_pre_suggested_coins,
|
||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, CandleType
|
||||
adx, dec, decimal_add, decimal_div, decimal_sub, duplicate_filter, ema, ema_macd,
|
||||
exists_record, get_server_epoch, insert_pre_suggested_coins, limit_order_sell, remove_keys,
|
||||
rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, update_record3, AdxData,
|
||||
AllData, Arc, BollingerBandData, CandleType, Client, ClientBuilder, Decimal, EmaData,
|
||||
ExchangeInfo, FilteredDataValue, HashMap, HashSet, MacdData, Mutex, RealtimePriceData,
|
||||
RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal, SupertrendData,
|
||||
ToPrimitive, TradeFee,
|
||||
};
|
||||
|
||||
// BB lowerband + SuperTrend + StochRSI
|
||||
|
|
@ -30,12 +32,14 @@ pub async fn list_up_for_buy(
|
|||
if let Some(rt_price_30m_vec) = alldata.rt_price_30m_vec.get(symbol) {
|
||||
let vec_len = rt_price_30m_vec.len();
|
||||
if vec_len >= 11 {
|
||||
let candles = rt_price_30m_vec.get(vec_len-12..vec_len-1).unwrap();
|
||||
let candles = rt_price_30m_vec.get(vec_len - 12..vec_len - 1).unwrap();
|
||||
let windows = candles.windows(2);
|
||||
let mut average_amplitude = 0.0;
|
||||
|
||||
for window in windows {
|
||||
average_amplitude += (window.last().unwrap().high_price - window.last().unwrap().low_price) / window.first().unwrap().close_price;
|
||||
average_amplitude += (window.last().unwrap().high_price
|
||||
- window.last().unwrap().low_price)
|
||||
/ window.first().unwrap().close_price;
|
||||
}
|
||||
average_amplitude /= 10.0;
|
||||
|
||||
|
|
@ -51,31 +55,45 @@ pub async fn list_up_for_buy(
|
|||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
|
||||
// 2nd filtering: BollingerBand (len:30, multiplier 3) previous_30m_price (close or low price) < lower_band
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let bollingerband_map = bollingerband(30, 3.0, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let bollingerband_map =
|
||||
bollingerband(30, 3.0, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(bb_vec), Some(rt_30m_vec)) = (bollingerband_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
if rt_30m_vec.len() >= 3 && bb_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(bb_vec), Some(rt_30m_vec)) = (
|
||||
bollingerband_map.get(symbol),
|
||||
alldata.rt_price_30m_vec.get(symbol),
|
||||
) {
|
||||
if rt_30m_vec.len() >= 3
|
||||
&& bb_vec.len() >= 3
|
||||
&& rt_30m_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
let bb_search_result = bb_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|BollingerBandData {
|
||||
sma,
|
||||
upperband,
|
||||
lowerband,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
sma,
|
||||
upperband,
|
||||
lowerband,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
);
|
||||
if bb_search_result.is_ok() {
|
||||
if bb_vec[bb_search_result.unwrap()-1].lowerband > rt_30m_vec[rt_30m_vec.len()-2].low_price &&
|
||||
rt_30m_vec[rt_30m_vec.len()-2].opclo_price > rt_30m_vec.last().unwrap().close_price &&
|
||||
rt_30m_vec[rt_30m_vec.len()-2].candle_type == CandleType::DOWN &&
|
||||
rt_30m_vec[rt_30m_vec.len()-2].high_price < bb_vec[bb_search_result.unwrap()-1].sma
|
||||
if bb_vec[bb_search_result.unwrap() - 1].lowerband
|
||||
> rt_30m_vec[rt_30m_vec.len() - 2].low_price
|
||||
&& rt_30m_vec[rt_30m_vec.len() - 2].opclo_price
|
||||
> rt_30m_vec.last().unwrap().close_price
|
||||
&& rt_30m_vec[rt_30m_vec.len() - 2].candle_type == 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.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 {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -94,24 +112,43 @@ pub async fn list_up_for_buy(
|
|||
// 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 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 {
|
||||
if let (Some(supertrend_vec), Some(rt_30m_vec)) = (supertrend_30m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
if rt_30m_vec.len() >= 3 && supertrend_vec.len() >= 3 && rt_30m_vec.last().unwrap().close_time > server_epoch {
|
||||
if let (Some(supertrend_vec), Some(rt_30m_vec)) = (
|
||||
supertrend_30m_map.get(symbol),
|
||||
alldata.rt_price_30m_vec.get(symbol),
|
||||
) {
|
||||
if rt_30m_vec.len() >= 3
|
||||
&& supertrend_vec.len() >= 3
|
||||
&& rt_30m_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
let supertrend_search_result = supertrend_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|SupertrendData {
|
||||
band_value,
|
||||
signal,
|
||||
area,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
band_value,
|
||||
signal,
|
||||
area,
|
||||
close_time,
|
||||
}| *close_time,
|
||||
);
|
||||
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()) {
|
||||
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;
|
||||
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()
|
||||
}) {
|
||||
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;
|
||||
} else {
|
||||
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 ema_map = ema(200, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let (Some(ema_vec), Some(rt_30m_vec)) = (ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
if let (Some(ema_vec), Some(rt_30m_vec)) =
|
||||
(ema_map.get(symbol), alldata.rt_price_30m_vec.get(symbol))
|
||||
{
|
||||
let search_result = ema_vec.binary_search_by_key(
|
||||
&rt_30m_vec.last().unwrap().close_time,
|
||||
|EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| *close_time);
|
||||
if search_result.is_ok_and(|x| ema_vec[search_result.unwrap()].ema_value < rt_30m_vec[rt_30m_vec.len()-1].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-1].ema_value < rt_30m_vec[rt_30m_vec.len()-2].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-2].ema_value < rt_30m_vec[rt_30m_vec.len()-3].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-3].ema_value < rt_30m_vec[rt_30m_vec.len()-4].close_price) &&
|
||||
search_result.is_ok_and(|x| ema_vec[search_result.unwrap()-4].ema_value < rt_30m_vec[rt_30m_vec.len()-5].close_price) {
|
||||
ema_value,
|
||||
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
|
||||
}) && search_result.is_ok_and(|x| {
|
||||
ema_vec[search_result.unwrap() - 2].ema_value
|
||||
< rt_30m_vec[rt_30m_vec.len() - 3].close_price
|
||||
}) && search_result.is_ok_and(|x| {
|
||||
ema_vec[search_result.unwrap() - 3].ema_value
|
||||
< rt_30m_vec[rt_30m_vec.len() - 4].close_price
|
||||
}) && search_result.is_ok_and(|x| {
|
||||
ema_vec[search_result.unwrap() - 4].ema_value
|
||||
< rt_30m_vec[rt_30m_vec.len() - 5].close_price
|
||||
}) {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -152,10 +203,13 @@ pub async fn list_up_for_buy(
|
|||
// 6th filtering: 30m StochRSI (RSI_len: 10, StochRSI_len: 10, K: 3, D: 3) current K, D < 20
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let stoch_rsi_map = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
for (symbol, filtered_data) in &mut filtered_data {
|
||||
if let Some(stoch_rsi_vec) = stoch_rsi_map.get(symbol) {
|
||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == filtered_data.closetime);
|
||||
if search_result.is_some_and(|a| stoch_rsi_vec[a].k < 15.0 && stoch_rsi_vec[a].d < 15.0) {
|
||||
let search_result = stoch_rsi_vec
|
||||
.iter()
|
||||
.position(|x| x.close_time == filtered_data.closetime);
|
||||
if search_result.is_some_and(|a| stoch_rsi_vec[a].k < 15.0 && stoch_rsi_vec[a].d < 15.0)
|
||||
{
|
||||
} else {
|
||||
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 macd_1d_map = ema_macd(3, 7, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if macd_vec[macd_vec.len()-1].macd_value - macd_vec[macd_vec.len()-1].signal_value > macd_vec[macd_vec.len()-2].macd_value - macd_vec[macd_vec.len()-2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) =
|
||||
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||
{
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
if macd_vec[macd_vec.len() - 1].macd_value
|
||||
- macd_vec[macd_vec.len() - 1].signal_value
|
||||
> macd_vec[macd_vec.len() - 2].macd_value
|
||||
- macd_vec[macd_vec.len() - 2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
rt_price_vec.last().unwrap().close_price,
|
||||
)
|
||||
.unwrap();
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
|
|
@ -213,17 +276,15 @@ pub async fn list_up_for_sell(
|
|||
if let Some(exchange_info) = exchange_info_map.get(&element.symbol) {
|
||||
let lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let base_qty_to_be_ordered = element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
|
||||
if (element.is_long == 0 || element.is_long == 1)
|
||||
&& !element.current_price.is_zero()
|
||||
{
|
||||
if element.current_price >= element.target_price
|
||||
{
|
||||
if element.current_price >= element.target_price {
|
||||
limit_order_sell(
|
||||
&element,
|
||||
element.current_price,
|
||||
|
|
@ -255,7 +316,7 @@ pub async fn list_up_for_sell(
|
|||
.await;
|
||||
}
|
||||
// TODO: sell_count가 1일 때 적용하기
|
||||
// else if (supertrend_vec
|
||||
// else if (supertrend_vec
|
||||
// .last()
|
||||
// .unwrap()
|
||||
// .signal
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, decimal_mul, ema, exists_record, insert_pre_suggested_coins,
|
||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, get_current_price
|
||||
adx, dec, decimal_add, decimal_div, decimal_mul, decimal_sub, duplicate_filter, ema, ema_macd,
|
||||
exists_record, get_current_price, get_server_epoch, insert_pre_suggested_coins,
|
||||
limit_order_sell, remove_keys, rsi, select_filled_buy_orders, stoch_rsi, supertrend,
|
||||
try_join_all, update_record3, AdxData, AllData, Arc, BollingerBandData, Client, ClientBuilder,
|
||||
Decimal, EmaData, ExchangeInfo, FilteredDataValue, HashMap, HashSet, MacdData, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal,
|
||||
SupertrendData, ToPrimitive, TradeFee,
|
||||
};
|
||||
|
||||
// BUY conditions
|
||||
// (1) 1d MACD (3, 7, 30) cross
|
||||
// (2) supertrend (30, 3): UP area
|
||||
// stoploss: (update) supertrend(10, 1.5) lowerband
|
||||
// stoploss: (update) supertrend(10, 1.5) lowerband
|
||||
// target price: (fixed) stoploss inverse x 3 times profit
|
||||
pub async fn list_up_for_buy(
|
||||
alldata: &AllData,
|
||||
|
|
@ -27,12 +29,17 @@ pub async fn list_up_for_buy(
|
|||
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
let supertrend_1d_map =
|
||||
supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP{
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||
supertrend_1d_map.get(symbol),
|
||||
alldata.rt_price_1d_vec.get(symbol),
|
||||
) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -49,12 +56,21 @@ pub async fn list_up_for_buy(
|
|||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let macd_1d_map = ema_macd(3, 5, 30, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if macd_vec[macd_vec.len()-1].macd_value > macd_vec[macd_vec.len()-1].signal_value &&
|
||||
macd_vec[macd_vec.len()-2].macd_value < macd_vec[macd_vec.len()-2].signal_value {
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(rt_price_vec.last().unwrap().close_price).unwrap();
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) =
|
||||
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||
{
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
if macd_vec[macd_vec.len() - 1].macd_value
|
||||
> macd_vec[macd_vec.len() - 1].signal_value
|
||||
&& macd_vec[macd_vec.len() - 2].macd_value
|
||||
< macd_vec[macd_vec.len() - 2].signal_value
|
||||
{
|
||||
values.current_price = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
rt_price_vec.last().unwrap().close_price,
|
||||
)
|
||||
.unwrap();
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
|
|
@ -71,24 +87,48 @@ pub async fn list_up_for_buy(
|
|||
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
let supertrend_1d_map =
|
||||
supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||
supertrend_1d_map.get(symbol),
|
||||
alldata.rt_price_1d_vec.get(symbol),
|
||||
) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
// input stoploss, target_price
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN &&
|
||||
supertrend_vec.last().unwrap().band_value > values.current_price.to_f64().unwrap()
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
supertrend_vec.last().unwrap().band_value,
|
||||
)
|
||||
.unwrap();
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN
|
||||
&& supertrend_vec.last().unwrap().band_value
|
||||
> values.current_price.to_f64().unwrap()
|
||||
{
|
||||
values.stoploss = decimal_sub(values.current_price, decimal_sub(band_value, values.current_price));
|
||||
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(2.0)), values.current_price);
|
||||
|
||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
||||
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.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 {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -99,16 +139,18 @@ pub async fn list_up_for_buy(
|
|||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// filtering: the 1 previous ADX(3, 5)s increase
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let adx_vec = adx(3, 5, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(adx_vec) = adx_vec.get(symbol) {
|
||||
if let Some(last_idx) = adx_vec.iter().position(|elem| elem.close_time == values.closetime) {
|
||||
if
|
||||
adx_vec[last_idx].adx > adx_vec[last_idx-1].adx {
|
||||
if let Some(last_idx) = adx_vec
|
||||
.iter()
|
||||
.position(|elem| elem.close_time == values.closetime)
|
||||
{
|
||||
if adx_vec[last_idx].adx > adx_vec[last_idx - 1].adx {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -117,7 +159,7 @@ pub async fn list_up_for_buy(
|
|||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
|
|
@ -126,14 +168,19 @@ pub async fn list_up_for_buy(
|
|||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(rt_price_vec) = alldata.rt_price_1d_vec.get(symbol) {
|
||||
if rt_price_vec.last().unwrap().close_time > server_epoch && rt_price_vec.len() >= 6 {
|
||||
if rt_price_vec.last().unwrap().close_time > server_epoch && rt_price_vec.len() >= 6 {
|
||||
let mut opclo_vec: Vec<f64> = Vec::new();
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-2].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-3].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-4].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-5].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-6].opclo_price);
|
||||
let max_idx = opclo_vec.iter().position(|&x| x == *opclo_vec.iter().max_by(|&a, &b| a.partial_cmp(b).unwrap()).unwrap());
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 2].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 3].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 4].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 5].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 6].opclo_price);
|
||||
let max_idx = opclo_vec.iter().position(|&x| {
|
||||
x == *opclo_vec
|
||||
.iter()
|
||||
.max_by(|&a, &b| a.partial_cmp(b).unwrap())
|
||||
.unwrap()
|
||||
});
|
||||
opclo_vec.remove(max_idx.unwrap());
|
||||
|
||||
let mut mean = 0.0;
|
||||
|
|
@ -155,7 +202,7 @@ pub async fn list_up_for_buy(
|
|||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
let final_filtered_data = duplicate_filter(5, &filtered_data).await?;
|
||||
insert_pre_suggested_coins(5, false, &final_filtered_data, &alldata).await;
|
||||
|
|
@ -181,33 +228,38 @@ pub async fn list_up_for_sell(
|
|||
for element in &filled_buy_orders {
|
||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
let supertrend_1d = supertrend(14, 1.2, true, &all_data.rt_price_1d_vec, &filtered_symbols).await?;
|
||||
let supertrend_1d =
|
||||
supertrend(14, 1.2, true, &all_data.rt_price_1d_vec, &filtered_symbols).await?;
|
||||
for element in filled_buy_orders {
|
||||
if element.used_usdt >= dec!(10.0) {
|
||||
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)) {
|
||||
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) = (
|
||||
exchange_info_map.get(&element.symbol),
|
||||
trade_fee_map.get(&element.symbol),
|
||||
supertrend_1d.get(&element.symbol),
|
||||
) {
|
||||
// update stoploss
|
||||
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
|
||||
&& band_value > element.stoploss {
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![
|
||||
(String::from("stoploss"), band_value.to_string()),
|
||||
];
|
||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||
update_record3(&update_table_name, &update_value, &update_condition)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
&& band_value > element.stoploss
|
||||
{
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![(String::from("stoploss"), band_value.to_string())];
|
||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||
update_record3(&update_table_name, &update_value, &update_condition)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
|
||||
let base_qty_to_be_ordered = element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
|
||||
if (element.is_long == 0 || element.is_long == 1)
|
||||
&& !element.current_price.is_zero()
|
||||
{
|
||||
|
|
@ -231,7 +283,8 @@ pub async fn list_up_for_sell(
|
|||
&trade_fee_map,
|
||||
)
|
||||
.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(
|
||||
&element,
|
||||
element.current_price,
|
||||
|
|
@ -243,7 +296,7 @@ pub async fn list_up_for_sell(
|
|||
.await;
|
||||
}
|
||||
// TODO: sell_count가 1일 때 적용하기
|
||||
// else if (supertrend_vec
|
||||
// else if (supertrend_vec
|
||||
// .last()
|
||||
// .unwrap()
|
||||
// .signal
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, decimal_mul, ema, exists_record, insert_pre_suggested_coins,
|
||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, get_current_price, dema, DemaData, tema, TemaData
|
||||
adx, dec, decimal_add, decimal_div, decimal_mul, decimal_sub, dema, duplicate_filter, ema,
|
||||
ema_macd, exists_record, get_current_price, get_server_epoch, insert_pre_suggested_coins,
|
||||
limit_order_sell, remove_keys, rsi, select_filled_buy_orders, stoch_rsi, supertrend, tema,
|
||||
try_join_all, update_record3, AdxData, AllData, Arc, BollingerBandData, Client, ClientBuilder,
|
||||
Decimal, DemaData, EmaData, ExchangeInfo, FilteredDataValue, HashMap, HashSet, MacdData, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal,
|
||||
SupertrendData, TemaData, ToPrimitive, TradeFee,
|
||||
};
|
||||
|
||||
// BUY conditions
|
||||
// (1) 1d MACD (3, 7, 30): MACD_current - Signal_current < 0, MACD_prev - Signal_prev < MACD_current - Signal_current
|
||||
// (2) stoch RSI(30, 30, 2, 2): K_prev < 10, K_prev < K_current
|
||||
// stoploss: (update) supertrend(10, 1.5) lowerband
|
||||
// (2) stoch RSI(30, 30, 2, 2): K_prev < 10, K_prev < K_current
|
||||
// stoploss: (update) supertrend(10, 1.5) lowerband
|
||||
// target price: (fixed) stoploss inverse x 3 times profit
|
||||
pub async fn list_up_for_buy(
|
||||
alldata: &AllData,
|
||||
|
|
@ -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 server_epoch = get_server_epoch().await;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) = (macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if macd_vec.len() >= 30 &&
|
||||
(macd_vec[macd_vec.len()-1].macd_value - 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();
|
||||
if let (Some(macd_vec), Some(rt_price_vec)) =
|
||||
(macd_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol))
|
||||
{
|
||||
if macd_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
if macd_vec.len() >= 30
|
||||
&& (macd_vec[macd_vec.len() - 1].macd_value
|
||||
- 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;
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
|
|
@ -51,20 +66,26 @@ pub async fn list_up_for_buy(
|
|||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 1d StochRSI (RSI_len: 30, StochRSI_len: 30, K: 3, D: 3) K_prev < 10, K_prev < K_current
|
||||
// 1d StochRSI (RSI_len: 30, StochRSI_len: 30, K: 3, D: 3) K_prev < 10, K_prev < K_current
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let stoch_rsis = stoch_rsi(30, 30, 3, 3, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if stoch_rsis.contains_key(symbol) {
|
||||
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == values.closetime);
|
||||
if stoch_rsi_vec.len() > 10 && search_result.is_some_and(|a| stoch_rsi_vec[a-3].k < 20.0 &&
|
||||
stoch_rsi_vec[a-2].k < 15.0 &&
|
||||
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) {
|
||||
let search_result = stoch_rsi_vec
|
||||
.iter()
|
||||
.position(|x| x.close_time == values.closetime);
|
||||
if stoch_rsi_vec.len() > 10
|
||||
&& search_result.is_some_and(|a| {
|
||||
stoch_rsi_vec[a - 3].k < 20.0
|
||||
&& stoch_rsi_vec[a - 2].k < 15.0
|
||||
&& 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 {
|
||||
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
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
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 {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||
supertrend_1d_map.get(symbol),
|
||||
alldata.rt_price_1d_vec.get(symbol),
|
||||
) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
|
|
@ -93,29 +119,53 @@ pub async fn list_up_for_buy(
|
|||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 2nd filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
let supertrend_1d_map =
|
||||
supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||
supertrend_1d_map.get(symbol),
|
||||
alldata.rt_price_1d_vec.get(symbol),
|
||||
) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
// input stoploss, target_price
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN &&
|
||||
supertrend_vec.last().unwrap().band_value > values.current_price.to_f64().unwrap()
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
supertrend_vec.last().unwrap().band_value,
|
||||
)
|
||||
.unwrap();
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN
|
||||
&& supertrend_vec.last().unwrap().band_value
|
||||
> values.current_price.to_f64().unwrap()
|
||||
{
|
||||
values.stoploss = decimal_sub(values.current_price, decimal_sub(band_value, values.current_price));
|
||||
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(2.0)), values.current_price);
|
||||
|
||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
||||
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.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 {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -126,21 +176,26 @@ pub async fn list_up_for_buy(
|
|||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// limit buy price: 3 * abs(이전 3 개 중 최대값 제거 한 opclo 값 평균 - 현재 open 값) + 현재 open 값 > current_price
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(rt_price_vec) = alldata.rt_price_1d_vec.get(symbol) {
|
||||
if rt_price_vec.last().unwrap().close_time > server_epoch && rt_price_vec.len() >= 6 {
|
||||
if rt_price_vec.last().unwrap().close_time > server_epoch && rt_price_vec.len() >= 6 {
|
||||
let mut opclo_vec: Vec<f64> = Vec::new();
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-2].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-3].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-4].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-5].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-6].opclo_price);
|
||||
let max_idx = opclo_vec.iter().position(|&x| x == *opclo_vec.iter().max_by(|&a, &b| a.partial_cmp(b).unwrap()).unwrap());
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 2].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 3].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 4].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 5].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 6].opclo_price);
|
||||
let max_idx = opclo_vec.iter().position(|&x| {
|
||||
x == *opclo_vec
|
||||
.iter()
|
||||
.max_by(|&a, &b| a.partial_cmp(b).unwrap())
|
||||
.unwrap()
|
||||
});
|
||||
opclo_vec.remove(max_idx.unwrap());
|
||||
|
||||
let mut mean = 0.0;
|
||||
|
|
@ -162,7 +217,7 @@ pub async fn list_up_for_buy(
|
|||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
let final_filtered_data = duplicate_filter(6, &filtered_data).await?;
|
||||
insert_pre_suggested_coins(6, false, &final_filtered_data, &alldata).await;
|
||||
|
|
@ -188,63 +243,76 @@ pub async fn list_up_for_sell(
|
|||
for element in &filled_buy_orders {
|
||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
let supertrend_1d = supertrend(14, 1.2, true, &all_data.rt_price_1d_vec, &filtered_symbols).await?;
|
||||
let supertrend_1d =
|
||||
supertrend(14, 1.2, true, &all_data.rt_price_1d_vec, &filtered_symbols).await?;
|
||||
for element in filled_buy_orders {
|
||||
let mut is_sell = false;
|
||||
let opclo_sample_length: usize = 15; // 15 candle samsples
|
||||
let mut target_profit_percent = 0.0;
|
||||
if let Some(price_1d_vec) = all_data
|
||||
.rt_price_1d_vec
|
||||
.get(&element.symbol)
|
||||
{
|
||||
if let Some(price_1d_vec) = all_data.rt_price_1d_vec.get(&element.symbol) {
|
||||
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 mut sum_amplitude_candles = 0.0;
|
||||
let mut sum_ratio_amp_body = 0.0;
|
||||
let mut average_amplitude = 0.0;
|
||||
|
||||
|
||||
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 mut amplitude_variance = 0.0;
|
||||
|
||||
let windows = candles.windows(2);
|
||||
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;
|
||||
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 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)) {
|
||||
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) = (
|
||||
exchange_info_map.get(&element.symbol),
|
||||
trade_fee_map.get(&element.symbol),
|
||||
supertrend_1d.get(&element.symbol),
|
||||
) {
|
||||
// update stoploss
|
||||
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
|
||||
&& band_value > element.stoploss {
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![
|
||||
(String::from("stoploss"), band_value.to_string()),
|
||||
];
|
||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||
update_record3(&update_table_name, &update_value, &update_condition)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
&& band_value > element.stoploss
|
||||
{
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![(String::from("stoploss"), band_value.to_string())];
|
||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||
update_record3(&update_table_name, &update_value, &update_condition)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
|
||||
let base_qty_to_be_ordered = element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
|
||||
if (element.is_long == 0 || element.is_long == 1)
|
||||
&& !element.current_price.is_zero()
|
||||
{
|
||||
|
|
@ -252,19 +320,32 @@ pub async fn list_up_for_sell(
|
|||
is_sell = true;
|
||||
} else if element.current_price >= element.target_price {
|
||||
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;
|
||||
} 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)
|
||||
} 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)
|
||||
is_sell = true;
|
||||
} 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)
|
||||
} 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)
|
||||
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;
|
||||
}
|
||||
// TODO: sell_count가 1일 때 적용하기
|
||||
// else if (supertrend_vec
|
||||
// else if (supertrend_vec
|
||||
// .last()
|
||||
// .unwrap()
|
||||
// .signal
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, decimal_mul, ema, exists_record, insert_pre_suggested_coins,
|
||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, get_current_price
|
||||
adx, dec, decimal_add, decimal_div, decimal_mul, decimal_sub, duplicate_filter, ema, ema_macd,
|
||||
exists_record, get_current_price, get_server_epoch, insert_pre_suggested_coins,
|
||||
limit_order_sell, remove_keys, rsi, select_filled_buy_orders, stoch_rsi, supertrend,
|
||||
try_join_all, update_record3, AdxData, AllData, Arc, BollingerBandData, Client, ClientBuilder,
|
||||
Decimal, EmaData, ExchangeInfo, FilteredDataValue, HashMap, HashSet, MacdData, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal,
|
||||
SupertrendData, ToPrimitive, TradeFee,
|
||||
};
|
||||
|
||||
// BUY conditions
|
||||
|
|
@ -31,80 +33,15 @@ pub async fn list_up_for_buy(
|
|||
let adx_vec = adx(10, 10, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(adx_vec) = adx_vec.get(symbol) {
|
||||
if let Some(last_idx) = adx_vec.iter().position(|elem| elem.close_time == values.closetime) {
|
||||
if
|
||||
adx_vec[last_idx].adx > adx_vec[last_idx-1].adx &&
|
||||
adx_vec[last_idx-1].adx > adx_vec[last_idx-2].adx &&
|
||||
adx_vec[last_idx].adx < 25.0 {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 2nd filtering: the 2 previous ADX(5, 5)s increase, ADX < 40
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let adx_vec = adx(10, 10, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(adx_vec) = adx_vec.get(symbol) {
|
||||
if let Some(last_idx) = adx_vec.iter().position(|elem| elem.close_time == values.closetime) {
|
||||
if
|
||||
adx_vec[last_idx].adx > adx_vec[last_idx-1].adx &&
|
||||
adx_vec[last_idx-1].adx > adx_vec[last_idx-2].adx &&
|
||||
adx_vec[last_idx].adx < 40.0 {
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 3rd filtering: RSI 5 < 75.0
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let rsi_map = rsi(5, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
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 rsi_vec[last_idx].rsi_value > 75.0 {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 4th filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let supertrend_1d_map = supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_1d_map.get(symbol), alldata.rt_price_1d_vec.get(symbol)) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
// input stoploss, target_price
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::UP &&
|
||||
supertrend_vec.last().unwrap().band_value < values.current_price.to_f64().unwrap()
|
||||
if let Some(last_idx) = adx_vec
|
||||
.iter()
|
||||
.position(|elem| elem.close_time == values.closetime)
|
||||
{
|
||||
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
|
||||
{
|
||||
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.stoploss = band_value;
|
||||
values.target_price = decimal_add(decimal_mul(decimal_sub(values.current_price, values.stoploss), dec!(3.0)), values.current_price);
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -115,21 +52,120 @@ pub async fn list_up_for_buy(
|
|||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
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
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let adx_vec = adx(10, 10, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(adx_vec) = adx_vec.get(symbol) {
|
||||
if let Some(last_idx) = adx_vec
|
||||
.iter()
|
||||
.position(|elem| elem.close_time == values.closetime)
|
||||
{
|
||||
if adx_vec.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 {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 3rd filtering: RSI 5 < 75.0
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let rsi_map = rsi(5, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
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 rsi_vec[last_idx].rsi_value > 75.0 {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// 4th filtering: supertrend(ATR period 14, multiplier: 1.2, 1d close price)
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let supertrend_1d_map =
|
||||
supertrend(14, 1.2, true, &alldata.rt_price_1d_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||
supertrend_1d_map.get(symbol),
|
||||
alldata.rt_price_1d_vec.get(symbol),
|
||||
) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
// input stoploss, target_price
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
supertrend_vec.last().unwrap().band_value,
|
||||
)
|
||||
.unwrap();
|
||||
if supertrend_vec.last().unwrap().area == SuperTrendArea::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.stoploss = band_value;
|
||||
values.target_price = decimal_add(
|
||||
decimal_mul(
|
||||
decimal_sub(values.current_price, values.stoploss),
|
||||
dec!(3.0),
|
||||
),
|
||||
values.current_price,
|
||||
);
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
} else {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// limit buy price: 3 * abs(이전 3 개 중 최대값 제거 한 opclo 값 평균 - 현재 open 값) + 현재 open 값 > current_price
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(rt_price_vec) = alldata.rt_price_1d_vec.get(symbol) {
|
||||
if rt_price_vec.last().unwrap().close_time > server_epoch && rt_price_vec.len() >= 6 {
|
||||
if rt_price_vec.last().unwrap().close_time > server_epoch && rt_price_vec.len() >= 6 {
|
||||
let mut opclo_vec: Vec<f64> = Vec::new();
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-2].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-3].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-4].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-5].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-6].opclo_price);
|
||||
let max_idx = opclo_vec.iter().position(|&x| x == *opclo_vec.iter().max_by(|&a, &b| a.partial_cmp(b).unwrap()).unwrap());
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 2].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 3].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 4].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 5].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 6].opclo_price);
|
||||
let max_idx = opclo_vec.iter().position(|&x| {
|
||||
x == *opclo_vec
|
||||
.iter()
|
||||
.max_by(|&a, &b| a.partial_cmp(b).unwrap())
|
||||
.unwrap()
|
||||
});
|
||||
opclo_vec.remove(max_idx.unwrap());
|
||||
|
||||
let mut mean = 0.0;
|
||||
|
|
@ -151,7 +187,7 @@ pub async fn list_up_for_buy(
|
|||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
let final_filtered_data = duplicate_filter(7, &filtered_data).await?;
|
||||
insert_pre_suggested_coins(7, false, &final_filtered_data, &alldata).await;
|
||||
|
|
@ -180,36 +216,45 @@ pub async fn list_up_for_sell(
|
|||
for element in &filled_buy_orders {
|
||||
filtered_symbols.insert(element.symbol.clone(), FilteredDataValue::new());
|
||||
}
|
||||
let supertrend_1d = supertrend(14, 1.2, true, &all_data.rt_price_1d_vec, &filtered_symbols).await?;
|
||||
let supertrend_1d =
|
||||
supertrend(14, 1.2, true, &all_data.rt_price_1d_vec, &filtered_symbols).await?;
|
||||
for element in filled_buy_orders {
|
||||
let mut is_sell = false;
|
||||
|
||||
|
||||
if element.used_usdt >= dec!(10.0) {
|
||||
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)) {
|
||||
if let (Some(exchange_info), Some(tradefee), Some(supertrend_vec)) = (
|
||||
exchange_info_map.get(&element.symbol),
|
||||
trade_fee_map.get(&element.symbol),
|
||||
supertrend_1d.get(&element.symbol),
|
||||
) {
|
||||
// update stoploss
|
||||
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
|
||||
&& band_value > element.stoploss {
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![
|
||||
(String::from("stoploss"), band_value.to_string()),
|
||||
];
|
||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||
update_record3(&update_table_name, &update_value, &update_condition)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
&& band_value > element.stoploss
|
||||
{
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![(String::from("stoploss"), band_value.to_string())];
|
||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||
update_record3(&update_table_name, &update_value, &update_condition)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let target_profit_percent = decimal_div(decimal_sub(element.stoploss, element.buy_price), element.buy_price).to_f64().unwrap();
|
||||
let base_qty_to_be_ordered = element.base_qty_ordered.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
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)
|
||||
&& !element.current_price.is_zero()
|
||||
{
|
||||
|
|
@ -217,32 +262,62 @@ pub async fn list_up_for_sell(
|
|||
is_sell = true;
|
||||
} else if element.current_price >= element.target_price {
|
||||
is_sell = true;
|
||||
} 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) {
|
||||
} 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)
|
||||
{
|
||||
is_sell = true;
|
||||
} 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) {
|
||||
} 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)
|
||||
{
|
||||
is_sell = true;
|
||||
} 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) {
|
||||
} 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)
|
||||
{
|
||||
is_sell = true;
|
||||
} 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) {
|
||||
} 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)
|
||||
{
|
||||
is_sell = true;
|
||||
} 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) {
|
||||
} 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)
|
||||
{
|
||||
is_sell = true;
|
||||
} 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) {
|
||||
} 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)
|
||||
{
|
||||
is_sell = true;
|
||||
} 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){
|
||||
} 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){
|
||||
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;
|
||||
}
|
||||
// TODO: sell_count가 1일 때 적용하기
|
||||
// else if (supertrend_vec
|
||||
// else if (supertrend_vec
|
||||
// .last()
|
||||
// .unwrap()
|
||||
// .signal
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use super::{
|
||||
dec, decimal_add, decimal_sub, decimal_div, decimal_mul, ema, exists_record, insert_pre_suggested_coins,
|
||||
limit_order_sell, rsi, select_filled_buy_orders, stoch_rsi, supertrend, try_join_all, AllData,
|
||||
Arc, Client, ClientBuilder, Decimal, EmaData, ExchangeInfo, FilteredDataValue, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SupertrendData, TradeFee, update_record3, adx, AdxData, get_server_epoch, MacdData, ema_macd,
|
||||
BollingerBandData, ToPrimitive, duplicate_filter, HashMap, HashSet, remove_keys, SuperTrendArea, SuperTrendSignal, get_current_price, dema, DemaData, tema, TemaData,
|
||||
heatmap_volume, HeatMapLevel, HeatmapVolumeData
|
||||
adx, dec, decimal_add, decimal_div, decimal_mul, decimal_sub, dema, duplicate_filter, ema,
|
||||
ema_macd, exists_record, get_current_price, get_server_epoch, heatmap_volume,
|
||||
insert_pre_suggested_coins, limit_order_sell, remove_keys, rsi, select_filled_buy_orders,
|
||||
stoch_rsi, supertrend, tema, try_join_all, update_record3, AdxData, AllData, Arc,
|
||||
BollingerBandData, Client, ClientBuilder, Decimal, DemaData, EmaData, ExchangeInfo,
|
||||
FilteredDataValue, HashMap, HashSet, HeatMapLevel, HeatmapVolumeData, MacdData, Mutex,
|
||||
RealtimePriceData, RoundingStrategy, RsiData, StochRsiData, SuperTrendArea, SuperTrendSignal,
|
||||
SupertrendData, TemaData, ToPrimitive, TradeFee,
|
||||
};
|
||||
|
||||
// BUY conditions
|
||||
|
|
@ -28,10 +30,12 @@ pub async fn list_up_for_buy(
|
|||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
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 &&
|
||||
tema5_vec.last().unwrap().close_time == tema10_vec.last().unwrap().close_time &&
|
||||
tema5_vec.last().unwrap().close_time > server_epoch &&
|
||||
tema10_vec.last().unwrap().close_time > server_epoch {
|
||||
if tema5_vec.len() > 2
|
||||
&& tema10_vec.len() > 2
|
||||
&& tema5_vec.last().unwrap().close_time == tema10_vec.last().unwrap().close_time
|
||||
&& 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 {
|
||||
} else {
|
||||
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 server_epoch = get_server_epoch().await;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
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)) {
|
||||
if (tema30_vec.len() > 10 && tema5_vec.len() > 10 && tema_200_vec.len() > 10 && rt_price_vec.len() > 10) &&
|
||||
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{
|
||||
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),
|
||||
) {
|
||||
if (tema30_vec.len() > 10
|
||||
&& tema5_vec.len() > 10
|
||||
&& tema_200_vec.len() > 10
|
||||
&& rt_price_vec.len() > 10)
|
||||
&& 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 {
|
||||
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)
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let server_epoch = get_server_epoch().await;
|
||||
let supertrend_30m_map = supertrend(10, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
let supertrend_30m_map =
|
||||
supertrend(10, 2.0, true, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (supertrend_30m_map.get(symbol), alldata.rt_price_30m_vec.get(symbol)) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time &&
|
||||
rt_price_vec.last().unwrap().close_time > server_epoch {
|
||||
if let (Some(supertrend_vec), Some(rt_price_vec)) = (
|
||||
supertrend_30m_map.get(symbol),
|
||||
alldata.rt_price_30m_vec.get(symbol),
|
||||
) {
|
||||
if supertrend_vec.last().unwrap().close_time == rt_price_vec.last().unwrap().close_time
|
||||
&& rt_price_vec.last().unwrap().close_time > server_epoch
|
||||
{
|
||||
// input stoploss, target_price
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(supertrend_vec.last().unwrap().band_value).unwrap();
|
||||
let open_price: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(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
|
||||
let band_value: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
supertrend_vec.last().unwrap().band_value,
|
||||
)
|
||||
.unwrap();
|
||||
let open_price: Decimal = rust_decimal::prelude::FromPrimitive::from_f64(
|
||||
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.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
values.stoploss = band_value;
|
||||
values.target_price = decimal_add(decimal_mul(decimal_sub(current_price, values.stoploss), dec!(3.0)), current_price);
|
||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN &&
|
||||
band_value > current_price &&
|
||||
band_value > open_price
|
||||
values.target_price = decimal_add(
|
||||
decimal_mul(decimal_sub(current_price, values.stoploss), dec!(3.0)),
|
||||
current_price,
|
||||
);
|
||||
} else if supertrend_vec.last().unwrap().area == SuperTrendArea::DOWN
|
||||
&& band_value > current_price
|
||||
&& band_value > open_price
|
||||
{
|
||||
values.current_price = current_price;
|
||||
values.closetime = rt_price_vec.last().unwrap().close_time;
|
||||
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 {
|
||||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
|
|
@ -115,7 +151,7 @@ pub async fn list_up_for_buy(
|
|||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// current ADX(15, 15) < 25
|
||||
// let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
|
|
@ -133,21 +169,27 @@ pub async fn list_up_for_buy(
|
|||
// }
|
||||
// } else {
|
||||
// keys_to_remove.insert(symbol.clone());
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
// StochRSI (RSI_len: 10, StochRSI_len: 10, K: 3, D: 3) K_current < 70, K_current > d_current
|
||||
// StochRSI (RSI_len: 10, StochRSI_len: 10, K: 3, D: 3) K_current < 70, K_current > d_current
|
||||
let mut keys_to_remove: HashSet<String> = HashSet::new();
|
||||
let stoch_rsis = stoch_rsi(10, 10, 3, 3, &alldata.rt_price_30m_vec, &filtered_data).await?;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if stoch_rsis.contains_key(symbol) {
|
||||
let stoch_rsi_vec = stoch_rsis.get(symbol).unwrap();
|
||||
let search_result = stoch_rsi_vec.iter().position(|x| x.close_time == values.closetime);
|
||||
if stoch_rsi_vec.len() > 10 && 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) {
|
||||
let search_result = stoch_rsi_vec
|
||||
.iter()
|
||||
.position(|x| x.close_time == values.closetime);
|
||||
if stoch_rsi_vec.len() > 10
|
||||
&& 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 {
|
||||
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
|
||||
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 {
|
||||
if stoch_rsis.contains_key(symbol) {
|
||||
let heatmap_volume_vec = heatmap_volumes.get(symbol).unwrap();
|
||||
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);
|
||||
for slice in windows {
|
||||
if slice[1].heatmap_level == HeatMapLevel::ExtraHigh {
|
||||
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.rt_price_30m_vec.get(symbol).unwrap().iter().position(|x| x.close_time == slice[1].close_time)).unwrap()
|
||||
(&alldata
|
||||
.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 current_candle = &alldata.rt_price_30m_vec.get(symbol).unwrap()[current_candle_idx];
|
||||
if current_candle.close_price > prev_candle.close_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 {
|
||||
let prev_candle =
|
||||
&alldata.rt_price_30m_vec.get(symbol).unwrap()[prev_candle_idx];
|
||||
let current_candle =
|
||||
&alldata.rt_price_30m_vec.get(symbol).unwrap()[current_candle_idx];
|
||||
if current_candle.close_price > prev_candle.close_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());
|
||||
}
|
||||
}
|
||||
|
|
@ -193,14 +262,19 @@ pub async fn list_up_for_buy(
|
|||
let server_epoch = get_server_epoch().await;
|
||||
for (symbol, values) in &mut filtered_data {
|
||||
if let Some(rt_price_vec) = alldata.rt_price_30m_vec.get(symbol) {
|
||||
if rt_price_vec.last().unwrap().close_time > server_epoch && rt_price_vec.len() >= 6 {
|
||||
if rt_price_vec.last().unwrap().close_time > server_epoch && rt_price_vec.len() >= 6 {
|
||||
let mut opclo_vec: Vec<f64> = Vec::new();
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-2].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-3].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-4].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-5].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len()-6].opclo_price);
|
||||
let max_idx = opclo_vec.iter().position(|&x| x == *opclo_vec.iter().max_by(|&a, &b| a.partial_cmp(b).unwrap()).unwrap());
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 2].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 3].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 4].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 5].opclo_price);
|
||||
opclo_vec.push(rt_price_vec[rt_price_vec.len() - 6].opclo_price);
|
||||
let max_idx = opclo_vec.iter().position(|&x| {
|
||||
x == *opclo_vec
|
||||
.iter()
|
||||
.max_by(|&a, &b| a.partial_cmp(b).unwrap())
|
||||
.unwrap()
|
||||
});
|
||||
opclo_vec.remove(max_idx.unwrap());
|
||||
|
||||
let mut mean = 0.0;
|
||||
|
|
@ -222,7 +296,7 @@ pub async fn list_up_for_buy(
|
|||
keys_to_remove.insert(symbol.clone());
|
||||
}
|
||||
}
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
remove_keys(&mut filtered_data, keys_to_remove).await;
|
||||
|
||||
let final_filtered_data = duplicate_filter(8, &filtered_data).await?;
|
||||
insert_pre_suggested_coins(8, false, &final_filtered_data, &alldata).await;
|
||||
|
|
@ -248,43 +322,56 @@ pub async fn list_up_for_sell(
|
|||
for element in &filled_buy_orders {
|
||||
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_5 = tema(5, &all_data.rt_price_30m_vec, &filtered_symbols).await?;
|
||||
for element in filled_buy_orders {
|
||||
let mut is_sell = false;
|
||||
let mut is_overturned = false;
|
||||
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 tema30_vec.len() > 2 && tema5_vec.len() > 2 &&
|
||||
tema30_vec.last().unwrap().close_time == 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 {
|
||||
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 tema30_vec.len() > 2
|
||||
&& tema5_vec.len() > 2
|
||||
&& tema30_vec.last().unwrap().close_time
|
||||
== 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;
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
) {
|
||||
// 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
|
||||
&& band_value > element.stoploss {
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![
|
||||
(String::from("stoploss"), band_value.to_string()),
|
||||
];
|
||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||
update_record3(&update_table_name, &update_value, &update_condition)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
&& band_value > element.stoploss
|
||||
{
|
||||
let update_table_name = String::from("buy_ordered_coin_list");
|
||||
let update_value = vec![(String::from("stoploss"), band_value.to_string())];
|
||||
let update_condition = vec![(String::from("id"), element.id.to_string())];
|
||||
update_record3(&update_table_name, &update_value, &update_condition)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let lot_step_size = exchange_info.stepsize;
|
||||
let quote_commission_precision = exchange_info.quote_commission_precision;
|
||||
|
||||
|
||||
// TODO: BNB 코인이 있으면
|
||||
// let base_qty_to_be_ordered =
|
||||
// element.base_qty_ordered.round_dp_with_strategy(
|
||||
|
|
@ -293,40 +380,53 @@ pub async fn list_up_for_sell(
|
|||
// );
|
||||
// TODO: BNB 코인이 없으면
|
||||
let base_qty_to_be_ordered =
|
||||
element.base_qty_fee_adjusted.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let target_profit_percent = decimal_div(decimal_sub(element.target_price, element.buy_price), element.buy_price).to_f64().unwrap();
|
||||
if !element.current_price.is_zero()
|
||||
{
|
||||
element.base_qty_fee_adjusted.round_dp_with_strategy(
|
||||
lot_step_size.normalize().scale(),
|
||||
RoundingStrategy::ToZero,
|
||||
);
|
||||
let target_profit_percent = decimal_div(
|
||||
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 {
|
||||
is_sell = true;
|
||||
} else if element.current_price >= element.target_price {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let minimum_candles = 5;
|
||||
let maximum_candles = 30;
|
||||
for count_candles in minimum_candles..=maximum_candles {
|
||||
if count_candles < maximum_candles &&
|
||||
server_epoch - element.transact_time > (1_800_000) * count_candles &&
|
||||
(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) {
|
||||
if count_candles < maximum_candles
|
||||
&& server_epoch - element.transact_time
|
||||
> (1_800_000) * count_candles
|
||||
&& (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;
|
||||
break;
|
||||
} else if count_candles == maximum_candles { // time up selling
|
||||
} else if count_candles == maximum_candles {
|
||||
// time up selling
|
||||
is_sell = true;
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: sell_count가 1일 때 적용하기
|
||||
// else if (supertrend_vec
|
||||
// else if (supertrend_vec
|
||||
// .last()
|
||||
// .unwrap()
|
||||
// .signal
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use serde::Deserialize;
|
|||
// use super::strategy_test;
|
||||
use super::{
|
||||
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 tokio::time::{sleep, Duration, Instant};
|
||||
|
|
@ -39,7 +39,7 @@ pub async fn execute_list_up_for_buy(
|
|||
crate::strategy_team::strategy_006::list_up_for_buy(all_data).await;
|
||||
crate::strategy_team::strategy_007::list_up_for_buy(all_data).await;
|
||||
crate::strategy_team::strategy_008::list_up_for_buy(all_data).await;
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -47,16 +47,31 @@ pub async fn execute_list_up_for_sell(
|
|||
all_data: &AllData,
|
||||
exchange_info_map: &HashMap<String, ExchangeInfo>,
|
||||
trade_fee_map: &HashMap<String, TradeFee>,
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
// crate::strategy_team::strategy_001::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||
// crate::strategy_team::strategy_002::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||
// crate::strategy_team::strategy_003::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||
// crate::strategy_team::strategy_004::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||
// crate::strategy_team::strategy_005::list_up_for_sell(&all_data, &exchange_info_map, &trade_fee_map).await;
|
||||
crate::strategy_team::strategy_006::list_up_for_sell(&all_data, &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;
|
||||
|
||||
crate::strategy_team::strategy_006::list_up_for_sell(
|
||||
&all_data,
|
||||
&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(())
|
||||
}
|
||||
|
||||
|
|
@ -172,13 +187,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
symbol.clone(), // symbol
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
0.0.to_string(), // profit_percent
|
||||
0.0.to_string(), // minimum_profit_percent
|
||||
0.0.to_string(), // maximum_profit_percent
|
||||
|
|
@ -258,13 +273,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
symbol.clone(), // symbol
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
0.0.to_string(), // profit_percent
|
||||
0.0.to_string(), // minimum_profit_percent
|
||||
0.0.to_string(), // maximum_profit_percent
|
||||
|
|
@ -334,13 +349,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
symbol.clone(), // symbol
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
0.0.to_string(), // profit_percent
|
||||
0.0.to_string(), // minimum_profit_percent
|
||||
0.0.to_string(), // maximum_profit_percent
|
||||
|
|
@ -394,13 +409,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
symbol.clone(), // symbol
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
0.0.to_string(), // profit_percent
|
||||
0.0.to_string(), // minimum_profit_percent
|
||||
0.0.to_string(), // maximum_profit_percent
|
||||
|
|
@ -480,13 +495,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
symbol.clone(), // symbol
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
0.0.to_string(), // profit_percent
|
||||
0.0.to_string(), // minimum_profit_percent
|
||||
0.0.to_string(), // maximum_profit_percent
|
||||
|
|
@ -550,13 +565,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
symbol.clone(), // symbol
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
0.0.to_string(), // profit_percent
|
||||
0.0.to_string(), // minimum_profit_percent
|
||||
0.0.to_string(), // maximum_profit_percent
|
||||
|
|
@ -610,13 +625,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
|
||||
if is_dupe == false {
|
||||
let mut insert_values = vec![
|
||||
symbol.clone(), // symbol
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
0.0.to_string(), // profit_percent
|
||||
0.0.to_string(), // minimum_profit_percent
|
||||
0.0.to_string(), // maximum_profit_percent
|
||||
|
|
@ -635,13 +650,13 @@ pub async fn insert_pre_suggested_coins(
|
|||
} else {
|
||||
for (symbol, filtered_data) in filtered_coins {
|
||||
let mut insert_values = vec![
|
||||
symbol.clone(), // symbol
|
||||
symbol.clone(), // symbol
|
||||
filtered_data.closetime.to_string(), // close_time
|
||||
filtered_data.current_price.to_string(), // suggested_price
|
||||
filtered_data.current_price.to_string(), // current_price
|
||||
filtered_data.stoploss.to_string(), // stoploss
|
||||
filtered_data.target_price.to_string(), // target_price
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
get_server_epoch().await.to_string(), // registered_server_epoch
|
||||
0.0.to_string(), // profit_percent
|
||||
0.0.to_string(), // minimum_profit_percent
|
||||
0.0.to_string(), // maximum_profit_percent
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use super::{
|
||||
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,
|
||||
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
|
||||
};
|
||||
|
||||
|
|
@ -14,13 +14,13 @@ pub async fn strategist_test(
|
|||
// println!("BTCUSDT: {:?}", alldata.rt_price_30m_vec[a.unwrap()].1.last().unwrap());
|
||||
|
||||
// 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_3 = FilteredData::new();
|
||||
symbol_1.symbol = String::from("BTCUSDT");
|
||||
// symbol_2.symbol = String::from("XRPUSDT");
|
||||
// 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_2);
|
||||
// test_symbols.push(symbol_3);
|
||||
|
|
|
|||
|
|
@ -7,12 +7,15 @@ use csv::{DeserializeRecordsIter, StringRecord};
|
|||
use rust_decimal::{prelude::ToPrimitive, Decimal};
|
||||
use serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, sync::Mutex, time::*};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum CandleType { UP, DOWN }
|
||||
pub enum CandleType {
|
||||
UP,
|
||||
DOWN,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct RealtimePriceData {
|
||||
|
|
@ -93,15 +96,11 @@ pub async fn update_realtime_price_data(
|
|||
rt_price_vec.last_mut().unwrap().candle_type = CandleType::DOWN;
|
||||
}
|
||||
// update high_price
|
||||
if rt_price_vec.last_mut().unwrap().high_price
|
||||
< *current_price
|
||||
{
|
||||
if rt_price_vec.last_mut().unwrap().high_price < *current_price {
|
||||
rt_price_vec.last_mut().unwrap().high_price = *current_price;
|
||||
}
|
||||
// update low_price
|
||||
if rt_price_vec.last_mut().unwrap().low_price
|
||||
> *current_price
|
||||
{
|
||||
if rt_price_vec.last_mut().unwrap().low_price > *current_price {
|
||||
rt_price_vec.last_mut().unwrap().low_price = *current_price;
|
||||
}
|
||||
}
|
||||
|
|
@ -112,7 +111,7 @@ pub async fn update_realtime_price_data(
|
|||
// for 1mon, uses 1w candle
|
||||
if let Some(rt_vec) = read_candle_for_rt.get(element) {
|
||||
if rt_vec.len() >= 2 && rt_price_vec.len() >= 2 {
|
||||
let previous_close_time = rt_price_vec[rt_price_vec.len()-2].close_time;
|
||||
let previous_close_time = rt_price_vec[rt_price_vec.len() - 2].close_time;
|
||||
// update realtime information for the latest candle
|
||||
let mut update_closeprice = 0.0;
|
||||
let mut update_highprice = 0.0;
|
||||
|
|
@ -134,25 +133,22 @@ pub async fn update_realtime_price_data(
|
|||
}| *close_time,
|
||||
);
|
||||
if prev_closetime_result.is_ok() {
|
||||
let result =
|
||||
rt_vec.get(prev_closetime_result.unwrap() + 1..);
|
||||
let result = rt_vec.get(prev_closetime_result.unwrap() + 1..);
|
||||
if result.is_some() {
|
||||
let update_highprice_result =
|
||||
result.unwrap().iter().max_by(|x, y| {
|
||||
x.high_price.partial_cmp(&y.high_price).unwrap()
|
||||
});
|
||||
if update_highprice_result.is_some() {
|
||||
update_highprice =
|
||||
update_highprice_result.unwrap().high_price;
|
||||
update_highprice = update_highprice_result.unwrap().high_price;
|
||||
}
|
||||
|
||||
let update_lowprice_result =
|
||||
result.unwrap().iter().min_by(|x, y| {
|
||||
x.low_price.partial_cmp(&y.low_price).unwrap()
|
||||
});
|
||||
let update_lowprice_result = result
|
||||
.unwrap()
|
||||
.iter()
|
||||
.min_by(|x, y| x.low_price.partial_cmp(&y.low_price).unwrap());
|
||||
if update_lowprice_result.is_some() {
|
||||
update_lowprice =
|
||||
update_lowprice_result.unwrap().low_price;
|
||||
update_lowprice = update_lowprice_result.unwrap().low_price;
|
||||
}
|
||||
|
||||
for element in result.unwrap() {
|
||||
|
|
@ -189,12 +185,10 @@ pub async fn update_realtime_price_data(
|
|||
&& !update_closeprice.is_nan()
|
||||
&& update_closeprice.is_finite()
|
||||
{
|
||||
rt_price_vec.last_mut().unwrap().close_price =
|
||||
update_closeprice;
|
||||
rt_price_vec.last_mut().unwrap().opclo_price =
|
||||
(update_closeprice
|
||||
+ rt_price_vec.last_mut().unwrap().open_price)
|
||||
/ 2.0;
|
||||
rt_price_vec.last_mut().unwrap().close_price = update_closeprice;
|
||||
rt_price_vec.last_mut().unwrap().opclo_price = (update_closeprice
|
||||
+ rt_price_vec.last_mut().unwrap().open_price)
|
||||
/ 2.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)]
|
||||
pub struct AdxData {
|
||||
pub adx: f64,
|
||||
pub close_time: i64
|
||||
pub close_time: i64,
|
||||
}
|
||||
|
||||
struct BasicData {
|
||||
|
|
@ -19,12 +19,16 @@ struct DiData {
|
|||
close_time: i64,
|
||||
}
|
||||
|
||||
pub async fn adx(adx_len: usize, di_len: usize, input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String, Vec<AdxData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
pub async fn adx(
|
||||
adx_len: usize,
|
||||
di_len: usize,
|
||||
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
||||
filtered_symbols: &HashMap<String, FilteredDataValue>,
|
||||
) -> Result<HashMap<String, Vec<AdxData>>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
if filtered_symbols.is_empty() {
|
||||
Err(("Err"))?;
|
||||
}
|
||||
|
||||
|
||||
let mut adx_vec: HashMap<String, Vec<AdxData>> = HashMap::new();
|
||||
let mut adx_vec_arc = Arc::new(Mutex::new(adx_vec));
|
||||
let mut task_vec = Vec::new();
|
||||
|
|
@ -32,9 +36,9 @@ filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String
|
|||
let mut rt_data_map = input_rt_data.clone();
|
||||
let adx_vec_arc_c = Arc::clone(&adx_vec_arc);
|
||||
let symbol = filtered_symbol.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
if let Some(rt_price_data) = rt_data_map.get(&symbol) {
|
||||
if rt_price_data.len()-1 > adx_len && rt_price_data.len() > di_len {
|
||||
if rt_price_data.len() - 1 > adx_len && rt_price_data.len() > di_len {
|
||||
// step 1: calculate +DM, -DM, TR
|
||||
let windows = rt_price_data.windows(2);
|
||||
let mut basic_data_vec: Vec<BasicData> = Vec::new();
|
||||
|
|
@ -46,17 +50,21 @@ filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String
|
|||
let basic_data = BasicData {
|
||||
dm_plus: if up > down && up > 0.0 { up } else { 0.0 },
|
||||
dm_minus: if down > up && down > 0.0 { down } else { 0.0 },
|
||||
true_range: f64::max(f64::max(current_rt_data.high_price - current_rt_data.low_price,
|
||||
current_rt_data.high_price - prev_rt_data.close_price),
|
||||
current_rt_data.low_price - prev_rt_data.close_price),
|
||||
true_range: f64::max(
|
||||
f64::max(
|
||||
current_rt_data.high_price - current_rt_data.low_price,
|
||||
current_rt_data.high_price - prev_rt_data.close_price,
|
||||
),
|
||||
current_rt_data.low_price - prev_rt_data.close_price,
|
||||
),
|
||||
close_time: current_rt_data.close_time,
|
||||
};
|
||||
basic_data_vec.push(basic_data);
|
||||
}
|
||||
// step 2: smoothing +DM, -DM, TR
|
||||
let alpha: f64 = 1.0/(di_len as f64);
|
||||
let alpha: f64 = 1.0 / (di_len as f64);
|
||||
let mut smoothed_basic_data_vec: Vec<BasicData> = Vec::new();
|
||||
|
||||
|
||||
let partial_vec1 = basic_data_vec.get(..di_len).unwrap(); // for calculation of initial value
|
||||
let partial_vec2 = basic_data_vec.get(di_len..).unwrap(); // for calculation of the rest
|
||||
|
||||
|
|
@ -71,22 +79,38 @@ filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String
|
|||
dm_plus_calculated /= di_len as f64;
|
||||
dm_minus_calculated /= di_len as f64;
|
||||
tr_calculated /= di_len as f64;
|
||||
|
||||
let basic_data = BasicData { dm_plus: dm_plus_calculated, dm_minus: dm_minus_calculated, true_range: tr_calculated, close_time: partial_vec1.last().unwrap().close_time };
|
||||
|
||||
let basic_data = BasicData {
|
||||
dm_plus: dm_plus_calculated,
|
||||
dm_minus: dm_minus_calculated,
|
||||
true_range: tr_calculated,
|
||||
close_time: partial_vec1.last().unwrap().close_time,
|
||||
};
|
||||
smoothed_basic_data_vec.push(basic_data);
|
||||
|
||||
for element in partial_vec2 {
|
||||
dm_plus_calculated = alpha * element.dm_plus + (1.0 - alpha) * dm_plus_calculated;
|
||||
dm_minus_calculated = alpha * element.dm_minus + (1.0 - alpha) * dm_minus_calculated;
|
||||
dm_plus_calculated =
|
||||
alpha * element.dm_plus + (1.0 - alpha) * dm_plus_calculated;
|
||||
dm_minus_calculated =
|
||||
alpha * element.dm_minus + (1.0 - alpha) * dm_minus_calculated;
|
||||
tr_calculated = alpha * element.true_range + (1.0 - alpha) * tr_calculated;
|
||||
let basic_data = BasicData { dm_plus: dm_plus_calculated, dm_minus: dm_minus_calculated, true_range: tr_calculated, close_time: element.close_time };
|
||||
let basic_data = BasicData {
|
||||
dm_plus: dm_plus_calculated,
|
||||
dm_minus: dm_minus_calculated,
|
||||
true_range: tr_calculated,
|
||||
close_time: element.close_time,
|
||||
};
|
||||
smoothed_basic_data_vec.push(basic_data);
|
||||
}
|
||||
|
||||
// step 3: calculate DI
|
||||
let mut di_data_vec: Vec<DiData> = Vec::new();
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -96,11 +120,17 @@ filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String
|
|||
let sum = di_data.di_plus + di_data.di_minus;
|
||||
let difference = (di_data.di_plus - di_data.di_minus).abs();
|
||||
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);
|
||||
}
|
||||
|
||||
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_vec2 is for calculation of the rest
|
||||
let mut smoothed_adx_vec: Vec<AdxData> = Vec::new();
|
||||
|
|
@ -109,14 +139,20 @@ filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String
|
|||
adx_calculated += element.adx;
|
||||
}
|
||||
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);
|
||||
|
||||
let alpha: f64 = 1.0 /(adx_len as f64);
|
||||
|
||||
let alpha: f64 = 1.0 / (adx_len as f64);
|
||||
for element in partial_vec2 {
|
||||
adx_calculated = alpha * element.adx + (1.0 - alpha) * adx_calculated;
|
||||
let adx_data = AdxData { adx: 100.0 * adx_calculated, close_time: element.close_time };
|
||||
let adx_data = AdxData {
|
||||
adx: 100.0 * adx_calculated,
|
||||
close_time: element.close_time,
|
||||
};
|
||||
smoothed_adx_vec.push(adx_data);
|
||||
}
|
||||
|
||||
|
|
@ -128,8 +164,7 @@ filtered_symbols: &HashMap<String, FilteredDataValue>,) -> Result<HashMap<String
|
|||
}));
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
|
||||
|
||||
let a = adx_vec_arc.lock().await.to_owned();
|
||||
Ok(a)
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
#![allow(unused)]
|
||||
#![allow(warnings)]
|
||||
|
||||
use super::HashMap;
|
||||
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::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use crate::value_estimation_team::indicators::sma::{sma, SmaData};
|
||||
use futures::future::try_join_all;
|
||||
use serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use super::{HashMap};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BollingerBandData {
|
||||
|
|
@ -43,7 +43,8 @@ pub async fn bollingerband(
|
|||
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_arc = Arc::new(Mutex::new(bb_data_wrapper));
|
||||
let mut task_vec = Vec::new();
|
||||
|
|
@ -56,33 +57,31 @@ pub async fn bollingerband(
|
|||
task_vec.push(tokio::spawn(async move {
|
||||
let mut bb_data = BollingerBandData::new();
|
||||
let mut bb_data_vec: Vec<BollingerBandData> = Vec::new();
|
||||
|
||||
|
||||
// if the data has shorter than buffer
|
||||
if sma_data_vec_c.len() > period {
|
||||
let result = rt_data_vec_c.binary_search_by_key(
|
||||
&sma_data_vec_c.first().unwrap().close_time,
|
||||
|RealtimePriceData {
|
||||
opclo_price,
|
||||
open_price,
|
||||
close_price,
|
||||
high_price,
|
||||
low_price,
|
||||
close_time,
|
||||
quote_asset_volume,
|
||||
candle_type,
|
||||
}| *close_time,
|
||||
opclo_price,
|
||||
open_price,
|
||||
close_price,
|
||||
high_price,
|
||||
low_price,
|
||||
close_time,
|
||||
quote_asset_volume,
|
||||
candle_type,
|
||||
}| *close_time,
|
||||
);
|
||||
|
||||
|
||||
match result {
|
||||
Ok(T) => {
|
||||
if T <= period - 1 {
|
||||
let mut read_data_iter =
|
||||
sma_data_vec_c.iter();
|
||||
let mut read_data_iter = sma_data_vec_c.iter();
|
||||
for _ in T..period - 1 {
|
||||
read_data_iter.next();
|
||||
}
|
||||
let window_iter =
|
||||
rt_data_vec_c.windows(period);
|
||||
let window_iter = rt_data_vec_c.windows(period);
|
||||
for buffer in window_iter {
|
||||
let mut sd_mean = 0.0;
|
||||
let mut standard_deviation = 0.0;
|
||||
|
|
@ -94,16 +93,14 @@ pub async fn bollingerband(
|
|||
standard_deviation +=
|
||||
(element.close_price - sd_mean).powi(2);
|
||||
}
|
||||
standard_deviation = sd_factor
|
||||
* ((standard_deviation / period as f64).sqrt());
|
||||
|
||||
standard_deviation =
|
||||
sd_factor * ((standard_deviation / period as f64).sqrt());
|
||||
|
||||
match read_data_iter.next() {
|
||||
Some(T) => {
|
||||
bb_data.sma = T.sma_value;
|
||||
bb_data.upperband =
|
||||
T.sma_value + standard_deviation;
|
||||
bb_data.lowerband =
|
||||
T.sma_value - standard_deviation;
|
||||
bb_data.upperband = T.sma_value + standard_deviation;
|
||||
bb_data.lowerband = T.sma_value - standard_deviation;
|
||||
bb_data.close_time = T.close_time;
|
||||
bb_data_vec.push(bb_data.clone());
|
||||
}
|
||||
|
|
@ -115,8 +112,7 @@ pub async fn bollingerband(
|
|||
Err(E) => {}
|
||||
}
|
||||
let mut bb_data_wrapper_lock = bb_data_wrapper_arc_c.lock().await;
|
||||
bb_data_wrapper_lock
|
||||
.insert(symbol_c, bb_data_vec.clone());
|
||||
bb_data_wrapper_lock.insert(symbol_c, bb_data_vec.clone());
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
#![allow(unused)]
|
||||
#![allow(warnings)]
|
||||
use super::ema::{ema, EmaData};
|
||||
use super::FilteredDataValue;
|
||||
use crate::database_control::*;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use futures::future::try_join_all;
|
||||
use serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::collections::HashMap;
|
||||
use std::{iter::zip, sync::Arc};
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use super::FilteredDataValue;
|
||||
use std::collections::HashMap;
|
||||
use super::ema::{ema, EmaData};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DemaData {
|
||||
|
|
@ -81,7 +81,6 @@ pub async fn dema(
|
|||
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
let e2 = ema_data_wrapper_arc.lock().await.to_owned();
|
||||
|
|
@ -91,14 +90,16 @@ pub async fn dema(
|
|||
let mut task_vec = Vec::new();
|
||||
for (symbol, e2_vec) in e2 {
|
||||
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 e1_vec_c = e1_vec.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
if e2_vec.last().unwrap().close_time == e1_vec_c.last().unwrap().close_time &&
|
||||
e2_vec.len() < e1_vec_c.len() {
|
||||
if e2_vec.last().unwrap().close_time == e1_vec_c.last().unwrap().close_time
|
||||
&& e2_vec.len() < e1_vec_c.len()
|
||||
{
|
||||
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());
|
||||
for element in zipped {
|
||||
let mut dema_data = DemaData::new();
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
#![allow(unused)]
|
||||
#![allow(warnings)]
|
||||
use super::FilteredDataValue;
|
||||
use crate::database_control::*;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use futures::future::try_join_all;
|
||||
use serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use super::FilteredDataValue;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EmaData {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
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 tokio::sync::Mutex;
|
||||
use futures::future::try_join_all;
|
||||
use super::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum HeatMapLevel {
|
||||
|
|
@ -49,7 +49,7 @@ pub async fn heatmap_volume(
|
|||
mean_value: f64,
|
||||
close_time: i64,
|
||||
}
|
||||
|
||||
|
||||
let mut mean_vec: Vec<MeanData> = Vec::new();
|
||||
let mut mean_data = MeanData {
|
||||
mean_value: 0.0,
|
||||
|
|
@ -65,10 +65,10 @@ pub async fn heatmap_volume(
|
|||
}
|
||||
mean_data.mean_value /= ma_len as f64;
|
||||
mean_data.close_time = buffer.last().unwrap().close_time;
|
||||
|
||||
|
||||
mean_vec.push(mean_data.clone());
|
||||
}
|
||||
|
||||
|
||||
// calc pstdev
|
||||
#[derive(Debug, Clone)]
|
||||
struct PstdevData {
|
||||
|
|
@ -94,18 +94,18 @@ pub async fn heatmap_volume(
|
|||
mean += element.quote_asset_volume;
|
||||
}
|
||||
mean /= std_len as f64;
|
||||
|
||||
|
||||
for element in buffer {
|
||||
sample_minus_mean = element.quote_asset_volume - mean;
|
||||
summation += sample_minus_mean.powi(2);
|
||||
}
|
||||
|
||||
|
||||
pstdev_data.pstdev_value = (summation / std_len as f64).sqrt();
|
||||
pstdev_data.close_time = buffer.last().unwrap().close_time;
|
||||
|
||||
|
||||
pstdev_vec.push(pstdev_data.clone());
|
||||
}
|
||||
|
||||
|
||||
// calc stdbar and heatmap volume
|
||||
let mut heatmap_vol_vec: Vec<HeatmapVolumeData> = Vec::new();
|
||||
let mut heatmap_vol_data = HeatmapVolumeData {
|
||||
|
|
@ -113,11 +113,11 @@ pub async fn heatmap_volume(
|
|||
heatmap_level: HeatMapLevel::Normal,
|
||||
close_time: 0,
|
||||
};
|
||||
|
||||
|
||||
if ma_len == std_len {
|
||||
let mut rt_data_trunc_vec =
|
||||
rt_price_vec_c.get(ma_len - 1..).unwrap().iter();
|
||||
|
||||
rt_price_vec_c.get(ma_len - 1..).unwrap().iter();
|
||||
|
||||
let zipped = mean_vec.iter().zip(pstdev_vec.iter());
|
||||
for element in zipped {
|
||||
heatmap_vol_data.heatmap_value =
|
||||
|
|
@ -140,7 +140,7 @@ pub async fn heatmap_volume(
|
|||
}
|
||||
} else if ma_len > std_len {
|
||||
let mut rt_data_trunc_vec =
|
||||
rt_price_vec_c.get(std_len - 1..).unwrap().iter();
|
||||
rt_price_vec_c.get(std_len - 1..).unwrap().iter();
|
||||
let mut mean_trunc_vec =
|
||||
mean_vec.get(mean_vec.len() - std_len..).unwrap().iter();
|
||||
let zipped = mean_trunc_vec.zip(pstdev_vec.iter());
|
||||
|
|
@ -154,7 +154,7 @@ pub async fn heatmap_volume(
|
|||
}
|
||||
} else {
|
||||
let mut rt_data_trunc_vec =
|
||||
rt_price_vec_c.get(ma_len - 1..).unwrap().iter();
|
||||
rt_price_vec_c.get(ma_len - 1..).unwrap().iter();
|
||||
let mut pstdev_trunc_vec =
|
||||
pstdev_vec.get(pstdev_vec.len() - ma_len..).unwrap().iter();
|
||||
let zipped = mean_vec.iter().zip(pstdev_trunc_vec);
|
||||
|
|
@ -172,7 +172,6 @@ pub async fn heatmap_volume(
|
|||
}
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
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 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 tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use futures::future::try_join_all;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MacdData {
|
||||
|
|
@ -44,7 +44,7 @@ pub async fn ema_macd(
|
|||
slow_len: usize,
|
||||
signal_smoothing: usize,
|
||||
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>> {
|
||||
let mut macd_oscil_vec: HashMap<String, Vec<MacdData>> = HashMap::new();
|
||||
|
||||
|
|
@ -56,19 +56,23 @@ pub async fn ema_macd(
|
|||
for (symbol, filtered_data) in filtered_symbols {
|
||||
let fast_emas_c = fast_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 fast_ema_vec_c = fast_ema_vec.clone();
|
||||
let slow_ema_vec_c = slow_ema_vec.clone();
|
||||
let macd_data_wrapper_arc_c = Arc::clone(&macd_data_wrapper_arc);
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
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(
|
||||
&slow_ema_vec_c.first().unwrap().close_time,
|
||||
|&EmaData {
|
||||
ema_value,
|
||||
close_time,
|
||||
}| close_time,
|
||||
ema_value,
|
||||
close_time,
|
||||
}| close_time,
|
||||
);
|
||||
if result.is_ok() {
|
||||
// making MACD
|
||||
|
|
@ -81,7 +85,7 @@ pub async fn ema_macd(
|
|||
macd.close_time = element.0.close_time;
|
||||
macd_vec.push(macd.clone());
|
||||
}
|
||||
|
||||
|
||||
// making signal (smoothed MACD)
|
||||
// TODO: this should be calculated in EMA (currently, SMA)
|
||||
// let macd_vec_window = macd_vec.windows(signal_smoothing);
|
||||
|
|
@ -121,20 +125,17 @@ pub async fn ema_macd(
|
|||
|
||||
ema_prev = ema_t;
|
||||
}
|
||||
|
||||
|
||||
let result = macd_vec.binary_search_by_key(
|
||||
&macd_signal_vec.first().unwrap().close_time,
|
||||
|&TempData {
|
||||
value,
|
||||
close_time,
|
||||
}| close_time,
|
||||
|&TempData { value, close_time }| close_time,
|
||||
);
|
||||
|
||||
if result.is_ok() {
|
||||
let result = macd_vec.get(result.unwrap()..);
|
||||
if result.is_some() {
|
||||
let zipped = result.unwrap().iter().zip(macd_signal_vec);
|
||||
|
||||
|
||||
let mut macd_vec: Vec<MacdData> = Vec::new();
|
||||
for element in zipped {
|
||||
let mut macd = MacdData::new();
|
||||
|
|
@ -143,14 +144,15 @@ pub async fn ema_macd(
|
|||
macd.close_time = element.0.close_time;
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
let a = macd_data_wrapper_arc.lock().await.to_owned();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
pub mod adx;
|
||||
pub mod bollingerband;
|
||||
pub mod dema;
|
||||
pub mod ema;
|
||||
pub mod heatmap_volume;
|
||||
pub mod macd;
|
||||
|
|
@ -8,11 +9,10 @@ pub mod sma;
|
|||
pub mod stoch_rsi;
|
||||
pub mod supertrend;
|
||||
pub mod tema;
|
||||
pub mod dema;
|
||||
|
||||
use crate::strategy_team::FilteredDataValue;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use futures::future::try_join_all;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use std::collections::HashMap;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
#![allow(unused)]
|
||||
#![allow(warnings)]
|
||||
|
||||
use super::HashMap;
|
||||
use crate::database_control::*;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use crate::strategy_team::FilteredDataValue;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use futures::future::try_join_all;
|
||||
use serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::f64::NAN;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use super::HashMap;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RsiData {
|
||||
|
|
@ -132,8 +132,8 @@ pub async fn rsi(
|
|||
prev_avg_ups = current_avg_ups;
|
||||
prev_avg_downs = current_avg_downs;
|
||||
|
||||
let rs = current_avg_ups.unwrap()
|
||||
/ (current_avg_downs.unwrap() + 0.00000001); // 0.00000001 is used to avoid division by 0
|
||||
let rs =
|
||||
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));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
#![allow(unused)]
|
||||
#![allow(warnings)]
|
||||
|
||||
use super::HashMap;
|
||||
use crate::database_control::*;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use crate::strategy_team::FilteredDataValue;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use futures::future::try_join_all;
|
||||
use serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use super::HashMap;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SmaData {
|
||||
|
|
@ -48,7 +48,7 @@ pub async fn sma(
|
|||
task_vec.push(tokio::spawn(async move {
|
||||
let mut sma_data = SmaData::new();
|
||||
let mut sma_data_vec: Vec<SmaData> = Vec::new();
|
||||
|
||||
|
||||
if rt_price_data.len() >= moving_number {
|
||||
let mut iter = rt_price_data.windows(moving_number);
|
||||
for buffer in iter {
|
||||
|
|
@ -95,7 +95,7 @@ pub async fn sma_opclo(
|
|||
task_vec.push(tokio::spawn(async move {
|
||||
let mut sma_data = SmaData::new();
|
||||
let mut sma_data_vec: Vec<SmaData> = Vec::new();
|
||||
|
||||
|
||||
if rt_price_data.len() >= moving_number {
|
||||
let mut iter = rt_price_data.windows(moving_number);
|
||||
for buffer in iter {
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@
|
|||
#![allow(warnings)]
|
||||
|
||||
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::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 serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::f64::NAN;
|
||||
use std::sync::Arc;
|
||||
use tokio::{fs::*, io::AsyncWriteExt, time::*};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StochRsiData {
|
||||
|
|
|
|||
|
|
@ -1,21 +1,27 @@
|
|||
use super::{FilteredDataValue, HashMap};
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use super::{HashMap, FilteredDataValue};
|
||||
use std::sync::Arc;
|
||||
use futures::future::try_join_all;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub enum SuperTrendArea { UP, DOWN }
|
||||
pub enum SuperTrendArea {
|
||||
UP,
|
||||
DOWN,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub enum SuperTrendSignal { BUY, SELL }
|
||||
pub enum SuperTrendSignal {
|
||||
BUY,
|
||||
SELL,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SupertrendData {
|
||||
pub band_value: f64,
|
||||
pub signal: Option<SuperTrendSignal>, // BUY or SELL
|
||||
pub area: SuperTrendArea, // UP or DOWN
|
||||
pub close_time: i64
|
||||
pub area: SuperTrendArea, // UP or DOWN
|
||||
pub close_time: i64,
|
||||
}
|
||||
|
||||
impl SupertrendData {
|
||||
|
|
@ -24,7 +30,7 @@ impl SupertrendData {
|
|||
band_value: 0.0,
|
||||
signal: None,
|
||||
area: SuperTrendArea::DOWN,
|
||||
close_time: 0
|
||||
close_time: 0,
|
||||
};
|
||||
|
||||
a
|
||||
|
|
@ -68,7 +74,7 @@ impl ATRData {
|
|||
// TODO: should return type be Option?
|
||||
// Implementation from TradingView Script (SuperTrend by KivancOzbilgic, source price: closeprice)
|
||||
// return key: close_time
|
||||
pub async fn supertrend(
|
||||
pub async fn supertrend(
|
||||
atr_period: usize,
|
||||
multiplier: f64,
|
||||
is_original_method: bool,
|
||||
|
|
@ -81,7 +87,7 @@ pub async fn supertrend(
|
|||
let mut task_vec = Vec::new();
|
||||
for (symbol, filtered_data) in filtered_symbols {
|
||||
if let Some(rt_price_vec) = input_rt_data.get(symbol) {
|
||||
if atr_period < rt_price_vec.len()-1 {
|
||||
if atr_period < rt_price_vec.len() - 1 {
|
||||
let symbol_c = symbol.clone();
|
||||
let supertrend_data_wrapper_arc_c = Arc::clone(&supertrend_data_wrapper_arc);
|
||||
let rt_price_vec_c = rt_price_vec.clone();
|
||||
|
|
@ -92,34 +98,34 @@ pub async fn supertrend(
|
|||
let mut tr_val_hl = 0.0; // High - Low
|
||||
let mut tr_val_hcp = 0.0; // Abs(High - Close_previous)
|
||||
let mut tr_val_lcp = 0.0; // Abs(Low - Close_previous)
|
||||
|
||||
|
||||
let window_vec = rt_price_vec_c.windows(2);
|
||||
|
||||
|
||||
tr_data.tr_value = rt_price_vec_c.first().unwrap().high_price
|
||||
- rt_price_vec_c.first().unwrap().low_price;
|
||||
tr_data.close_time = rt_price_vec_c.first().unwrap().close_time;
|
||||
true_range_vec.push(tr_data.clone());
|
||||
|
||||
|
||||
for buffer in window_vec {
|
||||
tr_val_hl = buffer[1].high_price - buffer[1].low_price;
|
||||
tr_val_hcp = (buffer[1].high_price - buffer[0].close_price).abs();
|
||||
tr_val_lcp = (buffer[1].low_price - buffer[0].close_price).abs();
|
||||
|
||||
|
||||
tr_data.tr_value = tr_val_hl.max(tr_val_hcp.max(tr_val_lcp));
|
||||
tr_data.close_time = buffer[1].close_time;
|
||||
|
||||
|
||||
true_range_vec.push(tr_data.clone());
|
||||
}
|
||||
|
||||
|
||||
// making Average True Range
|
||||
let mut average_true_range_vec: Vec<ATRData> = Vec::new();
|
||||
let mut atr_data = ATRData::new();
|
||||
|
||||
|
||||
if is_original_method == true {
|
||||
// original calculation of ATR
|
||||
let mut first_value = 0.0;
|
||||
let mut first_vec = &true_range_vec[0..atr_period];
|
||||
|
||||
|
||||
for element in first_vec {
|
||||
first_value += element.tr_value;
|
||||
}
|
||||
|
|
@ -127,35 +133,36 @@ pub async fn supertrend(
|
|||
atr_data.atr_value = first_value;
|
||||
atr_data.close_time = first_vec.last().unwrap().close_time;
|
||||
average_true_range_vec.push(atr_data.clone());
|
||||
|
||||
|
||||
let mut temp_prev_atr_value = first_value;
|
||||
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)
|
||||
/ atr_period as f64;
|
||||
atr_data.close_time = element.close_time;
|
||||
|
||||
|
||||
average_true_range_vec.push(atr_data.clone());
|
||||
temp_prev_atr_value = atr_data.atr_value;
|
||||
}
|
||||
} else {
|
||||
// Calculation of ATR from SMA True Range with atr_period
|
||||
let window = true_range_vec.windows(atr_period);
|
||||
|
||||
|
||||
let mut sum = 0.0;
|
||||
for buffer in window {
|
||||
for element in buffer {
|
||||
sum += element.tr_value;
|
||||
}
|
||||
|
||||
|
||||
atr_data.atr_value = sum / atr_period as f64;
|
||||
atr_data.close_time = buffer.last().unwrap().close_time;
|
||||
average_true_range_vec.push(atr_data.clone());
|
||||
|
||||
|
||||
sum = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// making Supertrend
|
||||
#[derive(Clone)]
|
||||
struct BandData {
|
||||
|
|
@ -163,7 +170,7 @@ pub async fn supertrend(
|
|||
basic_lowerband: f64,
|
||||
close_time: i64,
|
||||
}
|
||||
|
||||
|
||||
let mut supertrend_vec: Vec<SupertrendData> = Vec::new();
|
||||
let mut supertrend_data = SupertrendData::new();
|
||||
let mut band_vec: Vec<BandData> = Vec::new();
|
||||
|
|
@ -172,13 +179,13 @@ pub async fn supertrend(
|
|||
basic_lowerband: 0.0,
|
||||
close_time: 0,
|
||||
};
|
||||
|
||||
|
||||
let closetime_search_result = rt_price_vec_c.iter().position(|x| {
|
||||
x.close_time == average_true_range_vec.first().unwrap().close_time
|
||||
});
|
||||
let mut rt_data = &rt_price_vec_c[closetime_search_result.unwrap()..];
|
||||
let zipped = rt_data.iter().zip(average_true_range_vec);
|
||||
|
||||
|
||||
for element in zipped {
|
||||
band_data.basic_upperband = ((element.0.high_price + element.0.low_price)
|
||||
/ 2.0)
|
||||
|
|
@ -189,7 +196,7 @@ pub async fn supertrend(
|
|||
band_data.close_time = element.1.close_time;
|
||||
band_vec.push(band_data.clone());
|
||||
}
|
||||
|
||||
|
||||
let mut zipped = rt_data.iter().zip(band_vec);
|
||||
let first_element = zipped.next().unwrap();
|
||||
let mut prev_close_price = first_element.0.close_price;
|
||||
|
|
@ -206,14 +213,14 @@ pub async fn supertrend(
|
|||
} else {
|
||||
final_upperband = element.1.basic_upperband;
|
||||
}
|
||||
|
||||
|
||||
// set final lowerband
|
||||
if prev_close_price < prev_final_lowerband {
|
||||
final_lowerband = prev_final_lowerband.min(element.1.basic_lowerband);
|
||||
} else {
|
||||
final_lowerband = element.1.basic_lowerband;
|
||||
}
|
||||
|
||||
|
||||
// set supertrend
|
||||
if trend == -1 && element.0.close_price > prev_final_lowerband {
|
||||
supertrend_data.area = SuperTrendArea::UP;
|
||||
|
|
@ -222,13 +229,13 @@ pub async fn supertrend(
|
|||
supertrend_data.area = SuperTrendArea::DOWN;
|
||||
trend = -1;
|
||||
}
|
||||
|
||||
|
||||
if supertrend_data.area == SuperTrendArea::UP {
|
||||
supertrend_data.band_value = final_upperband;
|
||||
} else {
|
||||
supertrend_data.band_value = final_lowerband;
|
||||
}
|
||||
|
||||
|
||||
if trend == 1 && prev_trend == -1 {
|
||||
supertrend_data.signal = Some(SuperTrendSignal::BUY);
|
||||
} else if trend == -1 && prev_trend == 1 {
|
||||
|
|
@ -236,16 +243,17 @@ pub async fn supertrend(
|
|||
} else {
|
||||
supertrend_data.signal = None;
|
||||
}
|
||||
|
||||
|
||||
supertrend_data.close_time = element.1.close_time;
|
||||
supertrend_vec.push(supertrend_data.clone());
|
||||
|
||||
|
||||
prev_close_price = element.0.close_price;
|
||||
prev_final_upperband = final_upperband;
|
||||
prev_final_lowerband = final_lowerband;
|
||||
prev_trend = trend;
|
||||
}
|
||||
let mut supertrend_data_wrapper_lock = supertrend_data_wrapper_arc_c.lock().await;
|
||||
let mut supertrend_data_wrapper_lock =
|
||||
supertrend_data_wrapper_arc_c.lock().await;
|
||||
supertrend_data_wrapper_lock.insert(symbol_c, supertrend_vec.clone());
|
||||
}));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
#![allow(unused)]
|
||||
#![allow(warnings)]
|
||||
use super::ema::{ema, EmaData};
|
||||
use super::FilteredDataValue;
|
||||
use crate::database_control::*;
|
||||
use crate::value_estimation_team::datapoints::price_data::RealtimePriceData;
|
||||
use futures::future::try_join_all;
|
||||
use serde::Deserialize;
|
||||
use sqlx::FromRow;
|
||||
use std::collections::HashMap;
|
||||
use std::{iter::zip, sync::Arc};
|
||||
use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};
|
||||
use super::FilteredDataValue;
|
||||
use std::collections::HashMap;
|
||||
use super::ema::{ema, EmaData};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TemaData {
|
||||
|
|
@ -81,7 +81,6 @@ pub async fn tema(
|
|||
ema_data_wrapper_lock.insert(symbol_c, ema_data_vec.clone());
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
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());
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
try_join_all(task_vec).await?;
|
||||
let e3 = ema_data_wrapper_arc.lock().await.to_owned();
|
||||
|
|
@ -136,25 +134,29 @@ pub async fn tema(
|
|||
let mut task_vec = Vec::new();
|
||||
for (symbol, e3_vec) in e3 {
|
||||
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 e1_vec_c = e1_vec.clone();
|
||||
let e2_vec_c = e2_vec.clone();
|
||||
task_vec.push(tokio::spawn(async move {
|
||||
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.len() < e1_vec_c.len() &&
|
||||
e3_vec.len() < e2_vec_c.len() &&
|
||||
e2_vec_c.len() < e1_vec_c.len() {
|
||||
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.len() < e1_vec_c.len()
|
||||
&& e3_vec.len() < e2_vec_c.len()
|
||||
&& e2_vec_c.len() < e1_vec_c.len()
|
||||
{
|
||||
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 e2_vec_part = e2_vec_c.get(e2_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 zipped_e1_e2 = e1_vec_part.iter().zip(e2_vec_part.iter());
|
||||
let zipped_e1_e2_e3 = zipped_e1_e2.zip(e3_vec.iter());
|
||||
for element in zipped_e1_e2_e3 {
|
||||
let mut tema_data = TemaData::new();
|
||||
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.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_vec.push(tema_data);
|
||||
}
|
||||
let mut dema_data_wrapper_lock = tema_data_wrapper_arc_c.lock().await;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user