From 17dd137abfb558800c44865670c2bdeb4112a630 Mon Sep 17 00:00:00 2001 From: Sik Yoon Date: Mon, 18 Dec 2023 00:39:35 +0900 Subject: [PATCH] Add ADX indicator --- src/value_estimation_team/indicators/adx.rs | 134 ++++++++++++++++++++ src/value_estimation_team/indicators/mod.rs | 5 + 2 files changed, 139 insertions(+) create mode 100644 src/value_estimation_team/indicators/adx.rs diff --git a/src/value_estimation_team/indicators/adx.rs b/src/value_estimation_team/indicators/adx.rs new file mode 100644 index 0000000..0698698 --- /dev/null +++ b/src/value_estimation_team/indicators/adx.rs @@ -0,0 +1,134 @@ +// use std::thread::current; + +use super::{FilteredData, RealtimePriceData, try_join_all, Arc, Mutex}; + +#[derive(Clone)] +pub struct AdxData { + pub adx: f64, + pub close_time: i64 +} + +struct BasicData { + dm_plus: f64, + dm_minus: f64, + true_range: f64, + close_time: i64, +} + +struct DiData { + di_plus: f64, + di_minus: f64, + close_time: i64, +} + +pub async fn adx(adx_len: usize, di_len: usize, input_rt_data: &Vec<(String, Vec)>, +filtered_symbols: &Vec,) -> Result)>, Box> { + if filtered_symbols.is_empty() { + Err(("Err"))?; + } + + let mut adx_vec: Vec<(String, Vec)> = Vec::new(); + let mut adx_vec_arc = Arc::new(Mutex::new(adx_vec)); + let mut task_vec = Vec::new(); + for element in filtered_symbols { + let mut rt_data_vec = input_rt_data.clone(); + let adx_vec_arc_c = Arc::clone(&adx_vec_arc); + let symbol = element.symbol.clone(); + task_vec.push(tokio::spawn(async move { + let idx_result = rt_data_vec.iter().position(|a| a.0 == symbol); + + if idx_result.is_some() { + // step 1: calculate +DM, -DM, TR + let windows = rt_data_vec[idx_result.unwrap()].1.windows(2); + let mut basic_data_vec: Vec = Vec::new(); + for window in windows { + let prev_rt_data = window.first().unwrap(); + let current_rt_data = window.last().unwrap(); + let mut up = current_rt_data.high_price - prev_rt_data.high_price; + let mut down = prev_rt_data.low_price - current_rt_data.low_price; + let basic_data = BasicData { + dm_plus: if up > down && up > 0.0 { up } else { 0.0 }, + dm_minus: if down > up && down > 0.0 { down } else { 0.0 }, + true_range: f64::max(f64::max(current_rt_data.high_price - current_rt_data.low_price, + current_rt_data.high_price - prev_rt_data.close_price), + current_rt_data.low_price - prev_rt_data.close_price), + close_time: current_rt_data.close_time, + }; + basic_data_vec.push(basic_data); + } + // step 2: smoothing +DM, -DM, TR + let alpha: f64 = 1.0/(di_len as f64); + let mut smoothed_basic_data_vec: Vec = 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 + + let mut dm_plus_calculated = 0.0; + let mut dm_minus_calculated = 0.0; + let mut tr_calculated = 0.0; + for element in partial_vec1 { + dm_plus_calculated += element.dm_plus; + dm_minus_calculated += element.dm_minus; + tr_calculated += element.true_range; + } + dm_plus_calculated /= di_len as f64; + dm_minus_calculated /= di_len as f64; + tr_calculated /= di_len as f64; + + let basic_data = BasicData { dm_plus: dm_plus_calculated, dm_minus: dm_minus_calculated, true_range: tr_calculated, close_time: partial_vec1.last().unwrap().close_time }; + smoothed_basic_data_vec.push(basic_data); + + for element in partial_vec2 { + dm_plus_calculated = alpha * element.dm_plus + (1.0 - alpha) * dm_plus_calculated; + dm_minus_calculated = alpha * element.dm_minus + (1.0 - alpha) * dm_minus_calculated; + tr_calculated = alpha * element.true_range + (1.0 - alpha) * tr_calculated; + let basic_data = BasicData { dm_plus: dm_plus_calculated, dm_minus: dm_minus_calculated, true_range: tr_calculated, close_time: element.close_time }; + smoothed_basic_data_vec.push(basic_data); + } + + // step 3: calculate DI + let mut di_data_vec: Vec = 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}; + di_data_vec.push(di_data); + } + + // step 4: calculate ADX + let mut initial_adx_vec: Vec = Vec::new(); + for di_data in di_data_vec { + let sum = di_data.di_plus - di_data.di_minus; + let divisor = if sum <= 0.00000001 { 1.0 } else { sum }; + let adx_data = AdxData { adx: sum.abs()/divisor, close_time: di_data.close_time }; + initial_adx_vec.push(adx_data); + } + let partial_vec1 = initial_adx_vec.get(..adx_len).unwrap(); // for calculation of initial value + let partial_vec2 = initial_adx_vec.get(di_len..).unwrap(); // for calculation of the rest + + let mut smoothed_adx_vec: Vec = Vec::new(); + let mut adx_calculated = 0.0; + for element in partial_vec1 { + 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 }; + smoothed_adx_vec.push(adx_data); + + 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 }; + smoothed_adx_vec.push(adx_data); + } + + let mut adx_vec_arc_lock = adx_vec_arc_c.lock().await; + adx_vec_arc_lock.push((symbol.clone(), smoothed_adx_vec.clone())); + } + })); + } + try_join_all(task_vec).await?; + + let a = adx_vec_arc.lock().await.to_owned(); + Ok(a) + +} \ No newline at end of file diff --git a/src/value_estimation_team/indicators/mod.rs b/src/value_estimation_team/indicators/mod.rs index 29cae2a..a7172f3 100644 --- a/src/value_estimation_team/indicators/mod.rs +++ b/src/value_estimation_team/indicators/mod.rs @@ -1,3 +1,4 @@ +pub mod adx; pub mod bollingerband; pub mod ema; pub mod heatmap_volume; @@ -9,3 +10,7 @@ pub mod supertrend; pub mod tema; use crate::strategy_team::FilteredData; +use crate::value_estimation_team::datapoints::price_data::RealtimePriceData; +use futures::future::try_join_all; +use std::sync::Arc; +use tokio::{fs::*, io::AsyncWriteExt, sync::Mutex, time::*};