Add ADX indicator
This commit is contained in:
parent
73a968b839
commit
17dd137abf
134
src/value_estimation_team/indicators/adx.rs
Normal file
134
src/value_estimation_team/indicators/adx.rs
Normal file
|
|
@ -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<RealtimePriceData>)>,
|
||||||
|
filtered_symbols: &Vec<FilteredData>,) -> Result<Vec<(String, Vec<AdxData>)>, Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
if filtered_symbols.is_empty() {
|
||||||
|
Err(("Err"))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut adx_vec: Vec<(String, Vec<AdxData>)> = Vec::new();
|
||||||
|
let mut adx_vec_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<BasicData> = Vec::new();
|
||||||
|
for window in windows {
|
||||||
|
let prev_rt_data = window.first().unwrap();
|
||||||
|
let current_rt_data = window.last().unwrap();
|
||||||
|
let mut up = current_rt_data.high_price - prev_rt_data.high_price;
|
||||||
|
let mut down = prev_rt_data.low_price - current_rt_data.low_price;
|
||||||
|
let basic_data = BasicData {
|
||||||
|
dm_plus: if up > down && up > 0.0 { up } else { 0.0 },
|
||||||
|
dm_minus: if down > up && down > 0.0 { down } else { 0.0 },
|
||||||
|
true_range: f64::max(f64::max(current_rt_data.high_price - current_rt_data.low_price,
|
||||||
|
current_rt_data.high_price - prev_rt_data.close_price),
|
||||||
|
current_rt_data.low_price - prev_rt_data.close_price),
|
||||||
|
close_time: current_rt_data.close_time,
|
||||||
|
};
|
||||||
|
basic_data_vec.push(basic_data);
|
||||||
|
}
|
||||||
|
// step 2: smoothing +DM, -DM, TR
|
||||||
|
let alpha: f64 = 1.0/(di_len as f64);
|
||||||
|
let mut smoothed_basic_data_vec: Vec<BasicData> = Vec::new();
|
||||||
|
|
||||||
|
let partial_vec1 = basic_data_vec.get(..di_len).unwrap(); // for calculation of initial value
|
||||||
|
let 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<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};
|
||||||
|
di_data_vec.push(di_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 4: calculate ADX
|
||||||
|
let mut initial_adx_vec: Vec<AdxData> = 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<AdxData> = 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)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod adx;
|
||||||
pub mod bollingerband;
|
pub mod bollingerband;
|
||||||
pub mod ema;
|
pub mod ema;
|
||||||
pub mod heatmap_volume;
|
pub mod heatmap_volume;
|
||||||
|
|
@ -9,3 +10,7 @@ pub mod supertrend;
|
||||||
pub mod tema;
|
pub mod tema;
|
||||||
|
|
||||||
use crate::strategy_team::FilteredData;
|
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::*};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user