parent
c3e62e36bb
commit
7fd3d80504
@ -0,0 +1,2 @@ |
||||
pub mod ma; |
||||
pub mod rsi; |
||||
@ -0,0 +1,42 @@ |
||||
use crate::data::quotes::HOLC; |
||||
|
||||
|
||||
pub fn simple_moving_avg<C: HOLC> (data: Vec<C>, period: usize) -> Vec<f64> { |
||||
assert!(data.len() >= period, "Cannot create SMA! : Data is shorter than requested period."); |
||||
let mut ma_data = vec![]; |
||||
let n: f64 = period as f64; |
||||
// Get the initial average value
|
||||
let mut avg = data[..period].iter().fold(0.0, |acc, d| acc + d.close()) / n; |
||||
ma_data.push(avg); |
||||
// calculate the rest of the averages going forward
|
||||
for (i, d) in data[period..].iter().enumerate() { |
||||
// subtract the data that is no longer part of the period
|
||||
// Not that i corresponds to the index of data 1 period away since we are starting
|
||||
// iteraction 1 period in. This means it's perfect for getting the oldest data.
|
||||
avg -= data[i].close()/n; |
||||
// add the new data to the average
|
||||
avg += d.close() / n; |
||||
ma_data.push(avg); |
||||
} |
||||
ma_data |
||||
} |
||||
|
||||
fn cur_ema(closing_price: f64, prev_ema: f64, smoothing: f64) -> f64 { |
||||
(closing_price * smoothing) + (prev_ema * (1.0 - smoothing)) |
||||
} |
||||
|
||||
pub fn exponential_moving_average<C: HOLC> (data: Vec<C>, period: usize) -> Vec<f64> { |
||||
assert!(data.len() >= period + 1, "EMA requires period + 1 # of datapoints!"); |
||||
let mut ema_data = vec![]; |
||||
let n: f64 = period as f64; |
||||
// Get the average closing price over the original period
|
||||
let ma = data[..period].iter().fold(0.0, |acc, d| acc + d.close()) / n; |
||||
// Calculates our weighthing factor (using 2 as base)
|
||||
let smoothing = 2.0 / (n + 1.0); |
||||
for (i, d) in data[period..].iter().enumerate() { |
||||
// Use the previously calced MA for the first iteration
|
||||
if i == 0 {ema_data.push(cur_ema(d.close(), ma, smoothing)); continue;} |
||||
ema_data.push(cur_ema(d.close(), *ema_data.last().unwrap(), smoothing)); |
||||
} |
||||
ema_data |
||||
} |
||||
@ -0,0 +1,45 @@ |
||||
use crate::data::quotes::HOLC; |
||||
|
||||
pub fn relative_strength_index<C: HOLC>(data: Vec<C>, period: usize) -> Vec<f64> { |
||||
assert!(data.len() >= period + 2); |
||||
let mut rsi_data: Vec<f64> = vec![]; |
||||
let n = period as f64; |
||||
|
||||
let mut g_avg = 0.0; |
||||
let mut l_avg = 0.0; |
||||
|
||||
for (i, d) in data[1..period+1].iter().enumerate() { |
||||
let chg = d.close() - data[i].close(); |
||||
if chg >= 0.0 {g_avg += chg;} |
||||
else if chg <= 0.0 { l_avg += chg.abs();} |
||||
|
||||
if i == period -1 { |
||||
g_avg /=n; |
||||
l_avg /=n; |
||||
rsi_data.push(100.0 - (100.0/(1.0+((g_avg)/(l_avg))))); |
||||
} |
||||
} |
||||
// This is magic. Don't touch it. The periods just work.
|
||||
|
||||
for (i, d) in data[period+1..].iter().enumerate() { |
||||
|
||||
let chg = d.close() - data[period + i ].close(); |
||||
|
||||
if chg > 0.0 { |
||||
g_avg = (g_avg * (n - 1.0) + chg) / n; |
||||
l_avg = (l_avg * (n - 1.0) + 0.0) / n; |
||||
} else if chg < 0.0 { |
||||
g_avg = (g_avg * (n - 1.0) + 0.0) / n; |
||||
l_avg = (l_avg * (n - 1.0) + chg.abs()) / n; |
||||
} |
||||
else { |
||||
g_avg = (g_avg * (n - 1.0) + 0.0) / n; |
||||
l_avg = (l_avg * (n - 1.0) + 0.0) / n; |
||||
} |
||||
|
||||
rsi_data.push(100.0 - (100.0/(1.0+((g_avg)/(l_avg))))); |
||||
|
||||
} |
||||
rsi_data |
||||
|
||||
} |
||||
@ -0,0 +1,112 @@ |
||||
#[cfg(test)] |
||||
mod tests { |
||||
use crate::data::timeseries::Candle; |
||||
use crate::indicators::ma::exponential_moving_average; |
||||
use crate::indicators::rsi::relative_strength_index; |
||||
use crate::indicators::{ma}; |
||||
use crate::data::quotes::{HOLC}; |
||||
use chrono::Utc; |
||||
|
||||
|
||||
#[test] |
||||
fn sma() { |
||||
let data = vec![ |
||||
Candle::new(0.0,0.0,0.0, 4.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 8.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 11.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 8.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 14.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 6.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 6.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 1.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 4.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 4.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 9.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 7.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 12.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 5.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 1.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 10.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 5.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 9.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 6.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 2.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 8.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 9.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 11.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 14.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 9.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 12.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 4.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 6.0, None,Utc::now()), |
||||
]; |
||||
println!("data.len() = {:?}", data.len()); |
||||
|
||||
let sma_d = ma::simple_moving_avg(data, 3); |
||||
println!("sma_d = {:?}", sma_d); |
||||
|
||||
} |
||||
#[test] |
||||
fn ema(){ |
||||
let data = vec![ |
||||
Candle::new(0.0,0.0,0.0, 4.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 8.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 11.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 8.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 14.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 6.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 6.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 1.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 4.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 4.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 9.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 7.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 12.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 5.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 1.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 10.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 5.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 9.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 6.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 2.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 8.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 9.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 11.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 14.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 9.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 12.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 4.0, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 6.0, None,Utc::now()), |
||||
]; |
||||
|
||||
let ema_d = exponential_moving_average(data, 3); |
||||
println!("ema_d = {:?}", ema_d); |
||||
} |
||||
|
||||
#[test] |
||||
fn rsi() { |
||||
let data = vec![ |
||||
Candle::new(0.0,0.0,0.0, 140.06, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 144.28, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 147.64, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 150.6, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 151.92, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 154.79, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 152.61, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 150.26, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 150.47, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 146.68, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 145.14, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 148.1, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 148.82, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 148.91, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 147.21, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 142.84, None,Utc::now()), |
||||
Candle::new(0.0,0.0,0.0, 145.48, None,Utc::now()), |
||||
|
||||
]; |
||||
|
||||
let rsi_d = relative_strength_index(data, 14); |
||||
println!("rsi_d = {:?}", rsi_d); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue