From 7083139b40862e5958cbbd7eff5d2c17a5196c54 Mon Sep 17 00:00:00 2001 From: gord chung <gord@live.ca> Date: Tue, 14 May 2024 11:46:08 -0400 Subject: [PATCH] add swing index and acc swing index --- src/indicator.rs | 53 +++++++++++++++++++++++++ src/main.rs | 8 +++- tests/indicator_test.rs | 88 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 1 deletion(-) diff --git a/src/indicator.rs b/src/indicator.rs index 67b6eea..6411844 100644 --- a/src/indicator.rs +++ b/src/indicator.rs @@ -466,3 +466,56 @@ pub fn pgo(high: &[f64], low: &[f64], close: &[f64], window: u8) -> Vec<f64> { .map(|(c, c_ma, tr_ma)| (c - c_ma) / tr_ma) .collect::<Vec<f64>>() } + +fn _swing<'a>( + open: &'a [f64], + high: &'a [f64], + low: &'a [f64], + close: &'a [f64], + limit: f64, +) -> impl Iterator<Item = f64> + 'a { + izip!( + &open[..open.len() - 1], + &open[1..], + &high[1..], + &low[1..], + &close[..close.len() - 1], + &close[1..], + ) + .map(move |(prevo, o, h, l, prevc, c)| { + let r1 = (h - prevc).abs(); + let r2 = (l - prevc).abs(); + let r3 = h - l; + let r4 = (prevc - prevo).abs() / 4.0; + let max_r = r1.max(r2).max(r3); + let r = if r1 == max_r { + r1 - r2 / 2.0 + r4 + } else if r2 == max_r { + r2 - r1 / 2.0 + r4 + } else { + r3 + r4 + }; + // does not use formula described in investopedia as it appears to be wrong? + // it seems to overweight previous period's values + ((c - prevc + (c - o) / 2.0 + (prevc - prevo) / 4.0) / r) * 50.0 * r1.max(r2) / limit + }) +} + +/// Swing Index +/// https://www.investopedia.com/terms/a/asi.asp +/// https://quantstrategy.io/blog/accumulative-swing-index-how-to-trade/ +pub fn si(open: &[f64], high: &[f64], low: &[f64], close: &[f64], limit: f64) -> Vec<f64> { + _swing(open, high, low, close, limit).collect::<Vec<f64>>() +} + +/// Accumulative Swing Index +/// https://www.investopedia.com/terms/a/asi.asp +/// https://quantstrategy.io/blog/accumulative-swing-index-how-to-trade/ +pub fn asi(open: &[f64], high: &[f64], low: &[f64], close: &[f64], limit: f64) -> Vec<f64> { + _swing(open, high, low, close, limit) + .scan(0.0, |acc, x| { + *acc += x; + Some(*acc) + }) + .collect::<Vec<f64>>() +} diff --git a/src/main.rs b/src/main.rs index cd291e6..8308d2d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,5 +16,11 @@ fn main() { let data = fs::read_to_string("./tests/rddt.input").expect("Unable to read file"); let stats: SecStats = serde_json::from_str(&data).expect("JSON does not have correct format."); - dbg!(indicator::pgo(&stats.high, &stats.low, &stats.close, 16,)); + dbg!(indicator::si( + &stats.open, + &stats.high, + &stats.low, + &stats.close, + 0.5 + )); } diff --git a/tests/indicator_test.rs b/tests/indicator_test.rs index ccbb54e..94581cf 100644 --- a/tests/indicator_test.rs +++ b/tests/indicator_test.rs @@ -755,3 +755,91 @@ fn test_pgo() { result ); } + +#[test] +fn test_si() { + let stats = common::test_data(); + let result = indicator::si(&stats.open, &stats.high, &stats.low, &stats.close, 0.5); + assert_eq!( + vec![ + 1863.9824746176116, + 654.8878036623194, + -1104.4095193965052, + -1214.2944568105527, + -487.3407354098372, + 427.5088169169998, + -223.860381128408, + -110.7121065452446, + 162.75807618131765, + -98.12145222473158, + -101.13846512002326, + -403.1845902647818, + 283.1891569876117, + -199.95462669308907, + -326.86640146468073, + 63.131576090683794, + -253.67664708736052, + 215.41843387212208, + 2.1629182406584904, + 143.69919207899204, + 115.4626169352983, + 51.354553395932655, + -18.304465830729768, + 429.0203486740835, + 141.26847935246593, + -183.79992761728568, + 160.03660663696868, + 235.8667734660081, + -90.16470772181825, + 162.16835332629032, + 144.83405393167723, + 59.009650555611834, + -321.26018448483165, + ], + result + ); +} + +#[test] +fn test_asi() { + let stats = common::test_data(); + let result = indicator::asi(&stats.open, &stats.high, &stats.low, &stats.close, 0.5); + assert_eq!( + vec![ + 1863.9824746176116, + 2518.870278279931, + 1414.4607588834258, + 200.16630207287312, + -287.17443333696406, + 140.33438358003576, + -83.52599754837223, + -194.2381040936168, + -31.480027912299164, + -129.60148013703076, + -230.73994525705402, + -633.9245355218358, + -350.7353785342241, + -550.6900052273131, + -877.5564066919939, + -814.4248306013101, + -1068.1014776886707, + -852.6830438165487, + -850.5201255758901, + -706.8209334968981, + -591.3583165615997, + -540.0037631656671, + -558.3082289963969, + -129.2878803223134, + 11.980599030152518, + -171.81932858713316, + -11.782721950164472, + 224.08405151584364, + 133.9193437940254, + 296.08769712031574, + 440.92175105199294, + 499.93140160760476, + 178.6712171227731, + ], + result + ); +}