diff --git a/Cargo.toml b/Cargo.toml index 761fb9f..1791f6d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,5 @@ edition = "2021" [dependencies] chrono = "0.4.23" regex = "1.7.0" -polars = "0.25.1" \ No newline at end of file +polars = "0.25.1" +probability = "0.20.3" diff --git a/src/data/timeseries.rs b/src/data/timeseries.rs index 73ba2d6..c759f97 100644 --- a/src/data/timeseries.rs +++ b/src/data/timeseries.rs @@ -2,8 +2,9 @@ use chrono::{DateTime, Utc}; use super::{Volume, TimeStamp, DynResult}; use polars::{prelude::DataFrame, df, prelude::{NamedFrom}}; use super::quotes::HOLC; +use probability::prelude::*; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Candle { pub high: f64, pub open: f64, @@ -40,11 +41,16 @@ impl HOLC for Candle { fn low(&self) -> f64 { self.low } fn close(&self) -> f64 { self.close} } +impl TimeStamp for Candle { + fn timestamp(&self) -> DateTime { + self.timestamp + } +} pub struct TimeSeries { - candles: Vec + pub candles: Vec } impl TimeSeries { pub fn new(candles: Vec) -> Self { @@ -65,8 +71,33 @@ impl TimeSeries { pub fn as_vec(&self) -> Vec{ return self.candles.clone() } + pub fn generate_random(n_datapoints: usize, mut start_price: f64) -> Self { + + let mut data: Vec = vec![]; + + let inter_day_dist = Gaussian::new(1.0043,0.021); + let mut source = source::default(420); + let mut inter_sampler = Independent(&inter_day_dist, &mut source); + + let intra_day_dist = Gaussian::new(1.003,0.011); + let mut source2 = source::default(69); + let mut intra_sampler = Independent(&intra_day_dist, &mut source2); + + let day_moves = inter_sampler.take(n_datapoints).collect::>(); + let intraday_moves = intra_sampler.take(n_datapoints * 3).collect::>(); + + for n in 0..n_datapoints { + + let close = start_price * day_moves[n]; + data.push( Candle::new(start_price * intraday_moves[n], start_price, start_price * intraday_moves[n+1], close, Some((18183.0 * intraday_moves[n+3]) as u64), Utc::now())); + start_price = close; + } + TimeSeries { candles: data } + } } + + pub fn create_timeseries_dataframe(timeseries_data: &Vec) -> DynResult { let mut high = vec![]; let mut open = vec![]; diff --git a/src/indicators.rs b/src/indicators.rs index ea99ef9..bda0d9e 100644 --- a/src/indicators.rs +++ b/src/indicators.rs @@ -1,2 +1,3 @@ pub mod ma; -pub mod rsi; \ No newline at end of file +pub mod rsi; +pub mod macd; \ No newline at end of file diff --git a/src/indicators/macd.rs b/src/indicators/macd.rs new file mode 100644 index 0000000..09a3eee --- /dev/null +++ b/src/indicators/macd.rs @@ -0,0 +1,35 @@ +use crate::indicators::ma::exponential_moving_average; +use crate::data::quotes::HOLC; +use crate::data::TimeStamp; + +pub struct MACD { + upperBand: Vec, + lowerBand: Vec, + signalLine: Vec, +} +impl MACD { + pub fn new(data: Vec, upperBand: Option, lowerBand: Option, signalBand: Option) { + // This is going to need a custom implementation. It's not efficent to clone and iterate through the data 3 seperate times + let ub = upperBand.unwrap_or(26); + let lb = lowerBand.unwrap_or(12); + let sb = signalBand.unwrap_or(9); + + let u_ema = exponential_moving_average(data.clone(), ub); + let l_ema = exponential_moving_average(data.clone(), lb); + let s_ema = exponential_moving_average(data.clone(), sb); + + println!("u_ema = {:?}", u_ema); + println!("u_ema.len() = {:?}", u_ema.len()); + + println!("l_ema = {:?}", l_ema); + println!("l_ema.len() = {:?}", l_ema.len()); + + println!("s_ema = {:?}", s_ema); + println!("s_ema.len() = {:?}", s_ema.len()); + } +} + + +fn moving_average_convergence_divergence(data: Vec) { + +} \ No newline at end of file diff --git a/src/tests.rs b/src/tests.rs index b48a4a1..6f6147d 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,8 +1,9 @@ #[cfg(test)] mod tests { - use crate::data::timeseries::Candle; + use crate::data::timeseries::{Candle, TimeSeries}; use crate::indicators::ma::exponential_moving_average; use crate::indicators::rsi::relative_strength_index; + use crate::indicators::macd::MACD; use crate::indicators::{ma}; use crate::data::quotes::{HOLC}; use chrono::Utc; @@ -109,4 +110,17 @@ mod tests { let rsi_d = relative_strength_index(data, 14); println!("rsi_d = {:?}", rsi_d); } + #[test] + fn candle_gen() { + let data = TimeSeries::generate_random(50, 100.0); + for c in data.candles.iter() { + println!("c = {:?}", c); + } + } + #[test] + fn macd(){ + let data = TimeSeries::generate_random(50, 100.0); + + let x = MACD::new(data.candles, None,None,None); + } } \ No newline at end of file