Skip to content

Commit

Permalink
add tema and trima moving averages (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
chungg authored May 17, 2024
1 parent 8bbfe98 commit 38ea0b5
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 2 deletions.
27 changes: 25 additions & 2 deletions src/smooth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub fn sma(data: &[f64], window: usize) -> Vec<f64> {
}

/// double exponential moving average
/// https://www.investopedia.com/terms/d/double-exponential-moving-average.asp
pub fn dema(data: &[f64], window: usize) -> Vec<f64> {
let ma = ewma(data, window);
let mama = ewma(&ma, window);
Expand All @@ -31,6 +32,21 @@ pub fn dema(data: &[f64], window: usize) -> Vec<f64> {
.collect::<Vec<f64>>()
}

/// triple exponential moving average
/// https://www.investopedia.com/terms/t/triple-exponential-moving-average.asp
pub fn tema(data: &[f64], window: usize) -> Vec<f64> {
let ma = ewma(data, window);
let ma2 = ewma(&ma, window);
let ma3 = ewma(&ma2, window);
izip!(
&ma[ma.len() - ma3.len()..],
&ma2[ma2.len() - ma3.len()..],
&ma3
)
.map(|(ma1, ma2, ma3)| 3.0 * ma1 - 3.0 * ma2 + ma3)
.collect::<Vec<f64>>()
}

/// weighted moving average
pub fn wma(data: &[f64], window: usize) -> Vec<f64> {
let denom = (u64::pow(window as u64, 2) + window as u64) as f64 / 2.0;
Expand Down Expand Up @@ -127,8 +143,7 @@ pub fn vma(data: &[f64], window: usize) -> Vec<f64> {
.collect::<Vec<f64>>()
}

/// Linear Regression Forecast
/// aka Time series forecast
/// Linear Regression Forecast aka Time Series Forecast
/// https://quantstrategy.io/blog/what-is-tsf-understanding-time-series-forecast-indicator/
pub fn lrf(data: &[f64], window: usize) -> Vec<f64> {
let x_sum = (window * (window + 1)) as f64 / 2.0;
Expand All @@ -149,3 +164,11 @@ pub fn lrf(data: &[f64], window: usize) -> Vec<f64> {
})
.collect::<Vec<f64>>()
}

/// triangular moving average
/// computes sma(N/2) and then sma(N/2) again.
pub fn trima(data: &[f64], window: usize) -> Vec<f64> {
let win1 = window.div_ceil(2);
let win2 = if window & 2 == 0 { win1 + 1 } else { win1 };
sma(&sma(data, win1), win2)
}
112 changes: 112 additions & 0 deletions tests/ma_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,57 @@ fn test_dema_odd() {
);
}

#[test]
fn test_tema_even() {
let stats = common::test_data();
let results = smooth::tema(&stats.close, 8);
assert_eq!(
vec![
41.85245710750277,
42.65215910237417,
42.76254104206679,
44.39142477599313,
45.78886401297522,
45.58937539753736,
46.155610612438615,
47.3905754872981,
47.49247104352258,
48.329598253168975,
49.34731815107276,
50.92541420046855,
50.65205563565898,
],
results
);
}

#[test]
fn test_tema_odd() {
let stats = common::test_data();
let results = smooth::tema(&stats.close, 7);
assert_eq!(
vec![
40.30171911199053,
40.4845463271717,
41.32284194234779,
42.27944706651046,
43.00666092250643,
42.981805405622296,
44.653369906246084,
46.02578255948713,
45.63917998399449,
46.16091377840394,
47.42462810599313,
47.42758713990865,
48.27542907351973,
49.312771023085006,
50.948867388256396,
50.52826712062671,
],
results
);
}

#[test]
fn test_wilder_even() {
let stats = common::test_data();
Expand Down Expand Up @@ -510,3 +561,64 @@ fn test_lrf() {
result
);
}

#[test]
fn test_trima_even() {
let stats = common::test_data();
let result = smooth::trima(&stats.close, 16);
assert_eq!(
vec![
48.20791710747613,
47.198889308505585,
46.07638925976224,
45.06236139933268,
44.254444652133515,
43.622916804419624,
43.068055629730225,
42.5454167260064,
42.1704167260064,
41.95208342870077,
41.89694457583957,
41.99611128701104,
42.22625022464328,
42.59222247865465,
43.011944717831085,
43.52652804056803,
44.12541691462199,
44.77319468392266,
45.403264098697235,
],
result
);
}

#[test]
fn test_trima_odd() {
let stats = common::test_data();
let result = smooth::trima(&stats.close, 15);
assert_eq!(
vec![
48.712344229221344,
47.64968794584274,
46.51796919107437,
45.4464066028595,
44.60187524557114,
43.892187654972076,
43.29468756914139,
42.69296878576279,
42.23281252384186,
41.9201563000679,
41.74703133106232,
41.81609392166138,
41.99687522649765,
42.32015651464462,
42.73265653848648,
43.23156279325485,
43.79671901464462,
44.43218773603439,
45.093906462192535,
45.69164079427719,
],
result
);
}

0 comments on commit 38ea0b5

Please sign in to comment.