161 lines
6.8 KiB
Rust
161 lines
6.8 KiB
Rust
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::*};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct MacdData {
|
|
pub macd_value: f64,
|
|
pub signal_value: f64,
|
|
pub close_time: i64,
|
|
}
|
|
|
|
impl MacdData {
|
|
fn new() -> MacdData {
|
|
let a = MacdData {
|
|
macd_value: 0.0,
|
|
signal_value: 0.0,
|
|
close_time: 0,
|
|
};
|
|
a
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct TempData {
|
|
pub value: f64,
|
|
pub close_time: i64,
|
|
}
|
|
|
|
impl TempData {
|
|
fn new() -> TempData {
|
|
let a = TempData {
|
|
value: 0.0,
|
|
close_time: 0,
|
|
};
|
|
a
|
|
}
|
|
}
|
|
|
|
pub async fn ema_macd(
|
|
fast_len: usize,
|
|
slow_len: usize,
|
|
signal_smoothing: usize,
|
|
input_rt_data: &HashMap<String, Vec<RealtimePriceData>>,
|
|
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();
|
|
|
|
let fast_emas = ema(fast_len, input_rt_data, filtered_symbols).await?;
|
|
let slow_emas = ema(slow_len, input_rt_data, filtered_symbols).await?;
|
|
let mut macd_data_wrapper: HashMap<String, Vec<MacdData>> = HashMap::new();
|
|
let mut macd_data_wrapper_arc = Arc::new(Mutex::new(macd_data_wrapper));
|
|
let mut task_vec = Vec::new();
|
|
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))
|
|
{
|
|
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
|
|
{
|
|
let result = fast_ema_vec_c.binary_search_by_key(
|
|
&slow_ema_vec_c.first().unwrap().close_time,
|
|
|&EmaData {
|
|
ema_value,
|
|
close_time,
|
|
}| close_time,
|
|
);
|
|
if result.is_ok() {
|
|
// making MACD
|
|
let temp_vec = fast_ema_vec_c.get(result.unwrap()..).unwrap();
|
|
let zipped = temp_vec.iter().zip(slow_ema_vec_c);
|
|
let mut macd = TempData::new();
|
|
let mut macd_vec: Vec<TempData> = Vec::new();
|
|
for element in zipped {
|
|
macd.value = element.0.ema_value - element.1.ema_value;
|
|
macd.close_time = element.0.close_time;
|
|
macd_vec.push(macd.clone());
|
|
}
|
|
|
|
// making signal (smoothed MACD)
|
|
// TODO: this should be calculated in EMA (currently, SMA)
|
|
// let macd_vec_window = macd_vec.windows(signal_smoothing);
|
|
// let mut macd_signal_vec: Vec<TempData> = Vec::new();
|
|
// for window in macd_vec_window {
|
|
// let mut sum_value = 0.0;
|
|
// for element in window {
|
|
// sum_value += element.value;
|
|
// }
|
|
// macd.value = sum_value / signal_smoothing as f64;
|
|
// macd.close_time = window.last().unwrap().close_time;
|
|
// macd_signal_vec.push(macd.clone());
|
|
// }
|
|
let mut macd_signal = TempData::new();
|
|
let mut macd_signal_vec: Vec<TempData> = Vec::new();
|
|
let partial_vec1 = macd_vec.get(..signal_smoothing).unwrap();
|
|
let partial_vec2 = macd_vec.get(signal_smoothing..).unwrap();
|
|
|
|
let mut sma_for_initial_value = 0.0;
|
|
for element in partial_vec1 {
|
|
sma_for_initial_value += element.value;
|
|
}
|
|
sma_for_initial_value /= signal_smoothing as f64;
|
|
|
|
macd_signal.value = sma_for_initial_value;
|
|
macd_signal.close_time = partial_vec1.last().unwrap().close_time;
|
|
macd_signal_vec.push(macd_signal.clone());
|
|
|
|
let alpha: f64 = 2.0 / (signal_smoothing as f64 + 1.0);
|
|
let mut ema_prev = sma_for_initial_value;
|
|
for element in partial_vec2 {
|
|
let ema_t = (1.0 - alpha) * ema_prev + alpha * element.value;
|
|
|
|
macd_signal.value = ema_t;
|
|
macd_signal.close_time = element.close_time;
|
|
macd_signal_vec.push(macd_signal.clone());
|
|
|
|
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,
|
|
);
|
|
|
|
if result.is_ok() {
|
|
let result = macd_vec.get(result.unwrap()..);
|
|
if result.is_some() {
|
|
let zipped = result.unwrap().iter().zip(macd_signal_vec);
|
|
|
|
let mut macd_vec: Vec<MacdData> = Vec::new();
|
|
for element in zipped {
|
|
let mut macd = MacdData::new();
|
|
macd.macd_value = element.0.value;
|
|
macd.signal_value = element.1.value;
|
|
macd.close_time = element.0.close_time;
|
|
macd_vec.push(macd);
|
|
}
|
|
let mut macd_data_wrapper_lock =
|
|
macd_data_wrapper_arc_c.lock().await;
|
|
macd_data_wrapper_lock.insert(symbol_c, macd_vec.clone());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
try_join_all(task_vec).await?;
|
|
let a = macd_data_wrapper_arc.lock().await.to_owned();
|
|
Ok(a)
|
|
}
|